/////////////////////////////////////////////////////////////////////////////// // Copyright © 2020 xx network SEZC // // // // Use of this source code is governed by a license that can be found in the // // LICENSE file // /////////////////////////////////////////////////////////////////////////////// package switchboard import ( "gitlab.com/elixxir/client/interfaces/message" "gitlab.com/xx_network/primitives/id" "strings" "testing" "time" ) // tests that New create a correctly structured switchboard func TestNew(t *testing.T) { sw := New() if sw.id == nil { t.Errorf("did not create an id map") } if sw.messageType == nil { t.Errorf("did not create a messageType map") } } //Tests that register listener handles errors properly func TestSwitchboard_RegisterListener_Error_NilUserID(t *testing.T) { defer func() { if r := recover(); r != nil && !strings.Contains(r.(string), "cannot register listener to nil user") { t.Errorf("A nil userID caused the wrong error: %s", r) } }() sw := New() sw.RegisterListener(nil, 0, &funcListener{}) t.Errorf("A nil userID should have caused an panic") } //Tests that register listener handles errors properly func TestSwitchboard_RegisterListener_Error_NilListener(t *testing.T) { defer func() { if r := recover(); r != nil && !strings.Contains(r.(string), "cannot register nil listener") { t.Errorf("A nil listener caused the wrong error: %s", r) } }() sw := New() sw.RegisterListener(id.NewIdFromUInt(42, id.User, t), 0, nil) t.Errorf("A nil listener should have caused an error") } //Tests that RegisterListener properly registers the listeners func TestSwitchboard_RegisterListener(t *testing.T) { sw := New() l := &funcListener{} uid := id.NewIdFromUInt(42, id.User, t) mt := message.Type(69) lid := sw.RegisterListener(uid, mt, l) if lid.messageType != mt { t.Errorf("ListenerID message type is wrong") } if !lid.userID.Cmp(uid) { t.Errorf("ListenerID userID is wrong") } if lid.listener != l { t.Errorf("ListenerID listener is wrong") } //check that the listener is registered in the appropriate location setID := sw.id.Get(uid) if !setID.Has(l) { t.Errorf("Listener is not registered by ID") } setType := sw.messageType.Get(mt) if !setType.Has(l) { t.Errorf("Listener is not registered by Message Type") } } //Tests that register funcListener handles errors properly func TestSwitchboard_RegisterFunc_Error_NilUserID(t *testing.T) { defer func() { if r := recover(); r != nil && !strings.Contains(r.(string), "cannot register listener to nil user") { t.Errorf("A nil userID caused the wrong error: %s", r) } }() sw := New() sw.RegisterFunc("test", nil, 0, func(receive message.Receive) {}) t.Errorf("A nil user ID should have caused an error") } //Tests that register funcListener handles errors properly func TestSwitchboard_RegisterFunc_Error_NilFunc(t *testing.T) { defer func() { if r := recover(); r != nil && !strings.Contains(r.(string), "cannot register function listener 'test' with nil func") { t.Errorf("A nil func caused the wrong error: %s", r) } }() sw := New() sw.RegisterFunc("test", id.NewIdFromUInt(42, id.User, t), 0, nil) t.Errorf("A nil listener func should have caused an error") } //Tests that RegisterFunc properly registers the listeners func TestSwitchboard_RegisterFunc(t *testing.T) { sw := New() heard := false l := func(receive message.Receive) { heard = true } uid := id.NewIdFromUInt(42, id.User, t) mt := message.Type(69) lid := sw.RegisterFunc("test", uid, mt, l) if lid.messageType != mt { t.Errorf("ListenerID message type is wrong") } if !lid.userID.Cmp(uid) { t.Errorf("ListenerID userID is wrong") } //check that the listener is registered in the appropriate location setID := sw.id.Get(uid) if !setID.Has(lid.listener) { t.Errorf("Listener is not registered by ID") } setType := sw.messageType.Get(mt) if !setType.Has(lid.listener) { t.Errorf("Listener is not registered by Message Type") } lid.listener.Hear(message.Receive{}) if !heard { t.Errorf("Func listener not registered correctly") } } //Tests that register chanListener handles errors properly func TestSwitchboard_RegisterChan_Error_NilUser(t *testing.T) { defer func() { if r := recover(); r != nil && !strings.Contains(r.(string), "cannot register listener to nil user") { t.Errorf("A nil user ID caused the wrong error: %s", r) } }() sw := New() sw.RegisterChannel("test", nil, 0, make(chan message.Receive)) t.Errorf("A nil userID should have caused an error") } //Tests that register chanListener handles errors properly func TestSwitchboard_RegisterChan_Error_NilChan(t *testing.T) { defer func() { if r := recover(); r != nil && !strings.Contains(r.(string), "cannot register channel listener 'test' with nil channel") { t.Errorf("A nil channel caused the wrong error: %s", r) } }() sw := New() sw.RegisterChannel("test", &id.ID{}, 0, nil) t.Errorf("A nil channel func should have caused an error") } //Tests that RegisterChan properly registers the listeners func TestSwitchboard_RegisterChan(t *testing.T) { sw := New() ch := make(chan message.Receive, 1) uid := id.NewIdFromUInt(42, id.User, t) mt := message.Type(69) lid := sw.RegisterChannel("test", uid, mt, ch) //check the returns if lid.messageType != mt { t.Errorf("ListenerID message type is wrong") } if !lid.userID.Cmp(uid) { t.Errorf("ListenerID userID is wrong") } //check that the listener is registered in the appropriate location setID := sw.id.Get(uid) if !setID.Has(lid.listener) { t.Errorf("Listener is not registered by ID") } setType := sw.messageType.Get(mt) if !setType.Has(lid.listener) { t.Errorf("Listener is not registered by Message Type") } lid.listener.Hear(message.Receive{}) select { case <-ch: case <-time.After(5 * time.Millisecond): t.Errorf("Chan listener not registered correctly") } } //tests all combinations of hits and misses for speak func TestSwitchboard_Speak(t *testing.T) { uids := []*id.ID{{}, AnyUser(), id.NewIdFromUInt(42, id.User, t), id.NewIdFromUInt(69, id.User, t)} mts := []message.Type{AnyType, 42, 69} for _, uidReg := range uids { for _, mtReg := range mts { //create the registrations sw := New() ch1 := make(chan message.Receive, 1) ch2 := make(chan message.Receive, 1) sw.RegisterChannel("test", uidReg, mtReg, ch1) sw.RegisterChannel("test", uidReg, mtReg, ch2) //send every possible message for _, uid := range uids { for _, mt := range mts { if uid.Cmp(&id.ID{}) || mt == AnyType { continue } m := message.Receive{ Payload: []byte{0, 1, 2, 3}, Sender: uid, MessageType: mt, } sw.Speak(m) shouldHear := (m.Sender.Cmp(uidReg) || uidReg.Cmp(&id.ID{}) || uidReg.Cmp(AnyUser())) && (m.MessageType == mtReg || mtReg == AnyType) var heard1 bool select { case <-ch1: heard1 = true case <-time.After(5 * time.Millisecond): heard1 = false } if shouldHear != heard1 { t.Errorf("Correct operation not recorded "+ "for listener 1: Expected: %v, Occured: %v", shouldHear, heard1) } var heard2 bool select { case <-ch2: heard2 = true case <-time.After(5 * time.Millisecond): heard2 = false } if shouldHear != heard2 { t.Errorf("Correct operation not recorded "+ "for listener 2: Expected: %v, Occured: %v", shouldHear, heard2) } } } } } } //tests that Unregister removes the listener and only the listener func TestSwitchboard_Unregister(t *testing.T) { sw := New() uid := id.NewIdFromUInt(42, id.User, t) mt := message.Type(69) l := func(receive message.Receive) {} lid1 := sw.RegisterFunc("a", uid, mt, l) lid2 := sw.RegisterFunc("a", uid, mt, l) sw.Unregister(lid1) //get sets to check setID := sw.id.Get(uid) setType := sw.messageType.Get(mt) //check that the removed listener is not registered if setID.Has(lid1.listener) { t.Errorf("Removed Listener is registered by ID, should not be") } if setType.Has(lid1.listener) { t.Errorf("Removed Listener not registered by Message Type, " + "should not be") } //check that the not removed listener is still registered if !setID.Has(lid2.listener) { t.Errorf("Remaining Listener is not registered by ID") } if !setType.Has(lid2.listener) { t.Errorf("Remaining Listener is not registered by Message Type") } }