diff --git a/cmd/group.go b/cmd/group.go index 0595779059bae5297255cab14a74f573cd1b5247..7e9b8c63b1dcd5a034c168e9984d7f2020d8fd87 100644 --- a/cmd/group.go +++ b/cmd/group.go @@ -128,10 +128,8 @@ func initGroupManager(messenger *xxdk.E2e) (groupChat.GroupChat, } jww.INFO.Print("[GC] Creating new group manager.") - manager, err := groupChat.NewManager(messenger.GetCmix(), - messenger.GetE2E(), messenger.GetReceptionIdentity().ID, - messenger.GetRng(), messenger.GetStorage().GetE2EGroup(), - messenger.GetStorage().GetKV(), requestCb, &receiveProcessor{recChan}) + manager, err := groupChat.NewManager(messenger, requestCb, + &receiveProcessor{recChan}) if err != nil { jww.FATAL.Panicf("[GC] Failed to initialize group chat manager: %+v", err) } diff --git a/groupChat/e2eManager_test.go b/groupChat/e2eManager_test.go new file mode 100644 index 0000000000000000000000000000000000000000..cc66b2b7dfd6e0c6b4d489fd4a710974250ddd57 --- /dev/null +++ b/groupChat/e2eManager_test.go @@ -0,0 +1,191 @@ +package groupChat + +import ( + "github.com/cloudflare/circl/dh/sidh" + "github.com/pkg/errors" + "gitlab.com/elixxir/client/catalog" + "gitlab.com/elixxir/client/cmix/message" + clientE2E "gitlab.com/elixxir/client/e2e" + "gitlab.com/elixxir/client/e2e/ratchet/partner" + sessionImport "gitlab.com/elixxir/client/e2e/ratchet/partner/session" + "gitlab.com/elixxir/client/e2e/receive" + "gitlab.com/elixxir/client/stoppable" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/e2e" + "gitlab.com/xx_network/primitives/id" + "sync" + "testing" + "time" +) + +// testE2eManager is a test implementation of NetworkManager interface. +type testE2eManager struct { + e2eMessages []testE2eMessage + partners map[id.ID]partner.Manager + errSkip int + sendErr int + dhPubKey *cyclic.Int + grp *cyclic.Group + sync.RWMutex +} + +type testE2eMessage struct { + Recipient *id.ID + Payload []byte +} + +func (tnm *testE2eManager) AddPartner(partnerID *id.ID, partnerPubKey, + myPrivKey *cyclic.Int, _ *sidh.PublicKey, _ *sidh.PrivateKey, + _, _ sessionImport.Params) (partner.Manager, error) { + + testPartner := partner.NewTestManager(partnerID, partnerPubKey, myPrivKey, &testing.T{}) + tnm.partners[*partnerID] = testPartner + return testPartner, nil +} + +func (tnm *testE2eManager) GetPartner(partnerID *id.ID) (partner.Manager, error) { + if p, ok := tnm.partners[*partnerID]; ok { + return p, nil + } + return nil, errors.New("Unable to find partner") +} + +func (tnm *testE2eManager) GetHistoricalDHPubkey() *cyclic.Int { + return tnm.dhPubKey +} + +func (tnm *testE2eManager) GetHistoricalDHPrivkey() *cyclic.Int { + return tnm.dhPubKey +} + +func (tnm *testE2eManager) GetE2eMsg(i int) testE2eMessage { + tnm.RLock() + defer tnm.RUnlock() + return tnm.e2eMessages[i] +} + +func (tnm *testE2eManager) SendE2E(_ catalog.MessageType, recipient *id.ID, + payload []byte, _ clientE2E.Params) ([]id.Round, e2e.MessageID, time.Time, + error) { + tnm.Lock() + defer tnm.Unlock() + + tnm.errSkip++ + if tnm.sendErr == 1 { + return nil, e2e.MessageID{}, time.Time{}, errors.New("SendE2E error") + } else if tnm.sendErr == 2 && tnm.errSkip%2 == 0 { + return nil, e2e.MessageID{}, time.Time{}, errors.New("SendE2E error") + } + + tnm.e2eMessages = append(tnm.e2eMessages, testE2eMessage{ + Recipient: recipient, + Payload: payload, + }) + + return []id.Round{0, 1, 2, 3}, e2e.MessageID{}, time.Time{}, nil +} + +func (*testE2eManager) RegisterListener(*id.ID, catalog.MessageType, receive.Listener) receive.ListenerID { + return receive.ListenerID{} +} + +func (*testE2eManager) AddService(string, message.Processor) error { + return nil +} + +///////////////////////////////////////////////////////////////////////////////////// +// Unused & unimplemented methods of the test object //////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// + +func (*testE2eManager) GetDefaultHistoricalDHPubkey() *cyclic.Int { + panic("implement me") +} + +func (*testE2eManager) GetDefaultHistoricalDHPrivkey() *cyclic.Int { + panic("implement me") +} + +func (tnm *testE2eManager) StartProcesses() (stoppable.Stoppable, error) { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) RegisterFunc(name string, senderID *id.ID, messageType catalog.MessageType, newListener receive.ListenerFunc) receive.ListenerID { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) RegisterChannel(name string, senderID *id.ID, messageType catalog.MessageType, newListener chan receive.Message) receive.ListenerID { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) Unregister(listenerID receive.ListenerID) { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) UnregisterUserListeners(userID *id.ID) { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) DeletePartner(partnerId *id.ID) error { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) GetAllPartnerIDs() []*id.ID { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) HasAuthenticatedChannel(partner *id.ID) bool { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) RemoveService(tag string) error { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) SendUnsafe(mt catalog.MessageType, recipient *id.ID, payload []byte, params clientE2E.Params) ([]id.Round, time.Time, error) { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) EnableUnsafeReception() { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) GetGroup() *cyclic.Group { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) GetReceptionID() *id.ID { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) FirstPartitionSize() uint { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) SecondPartitionSize() uint { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) PartitionSize(payloadIndex uint) uint { + //TODO implement me + panic("implement me") +} + +func (tnm *testE2eManager) PayloadSize() uint { + //TODO implement me + panic("implement me") +} diff --git a/groupChat/interface.go b/groupChat/interface.go index 9604b5d8b39726460f374d3531715be7697510f7..0355c90943797cb7ab98d7e02e648ba946f1692b 100644 --- a/groupChat/interface.go +++ b/groupChat/interface.go @@ -20,9 +20,23 @@ package groupChat import ( + "github.com/cloudflare/circl/dh/sidh" + "gitlab.com/elixxir/client/catalog" + "gitlab.com/elixxir/client/cmix" + "gitlab.com/elixxir/client/cmix/message" + "gitlab.com/elixxir/client/e2e" + "gitlab.com/elixxir/client/e2e/ratchet/partner" + sessionImport "gitlab.com/elixxir/client/e2e/ratchet/partner/session" + "gitlab.com/elixxir/client/e2e/receive" gs "gitlab.com/elixxir/client/groupChat/groupStore" + "gitlab.com/elixxir/client/storage" + "gitlab.com/elixxir/client/xxdk" + "gitlab.com/elixxir/crypto/cyclic" + crypto "gitlab.com/elixxir/crypto/e2e" + "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/crypto/group" "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/id/ephemeral" "time" ) @@ -81,3 +95,45 @@ type RequestCallback func(g gs.Group) // ReceiveCallback is called when a GroupChat message is received. type ReceiveCallback func(msg MessageReceive) + +//////////////////////////////////////////////////////////////////////////////////// +// Sub-interfaces from other packages ////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// + +// groupE2e is a sub-interface mocking the xxdk.E2e object. +// This contains methods specific for this package. +type groupE2e interface { + GetCmix() cmix.Client + GetE2E() e2e.Handler + GetReceptionIdentity() xxdk.ReceptionIdentity + GetRng() *fastRNG.StreamGenerator + GetStorage() storage.Session +} + +// groupCmix is a subset of the cmix.Client interface containing only the +// methods needed by GroupChat +type groupCmix interface { + SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) ( + id.Round, []ephemeral.Id, error) + AddService( + clientID *id.ID, newService message.Service, response message.Processor) + DeleteService( + clientID *id.ID, toDelete message.Service, processor message.Processor) + GetMaxMessageLength() int +} + +// groupE2eHandler is a subset of the e2e.Handler interface containing only the methods +// needed by GroupChat +type groupE2eHandler interface { + SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, + params e2e.Params) ([]id.Round, crypto.MessageID, time.Time, error) + RegisterListener(senderID *id.ID, messageType catalog.MessageType, + newListener receive.Listener) receive.ListenerID + AddService(tag string, processor message.Processor) error + AddPartner(partnerID *id.ID, partnerPubKey, myPrivKey *cyclic.Int, + partnerSIDHPubKey *sidh.PublicKey, mySIDHPrivKey *sidh.PrivateKey, + sendParams, receiveParams sessionImport.Params) (partner.Manager, error) + GetPartner(partnerID *id.ID) (partner.Manager, error) + GetHistoricalDHPubkey() *cyclic.Int + GetHistoricalDHPrivkey() *cyclic.Int +} diff --git a/groupChat/makeGroup.go b/groupChat/makeGroup.go index 900221e423db1fca1249ac61d6f6e30ed313c8b1..b7db0a1033a848009ac63e58f0357920382136fa 100644 --- a/groupChat/makeGroup.go +++ b/groupChat/makeGroup.go @@ -66,7 +66,7 @@ func (m *manager) MakeGroup(membership []*id.ID, name, msg []byte) (gs.Group, } // Generate ID and key preimages - idPreimage, keyPreimage, err := getPreimages(m.rng) + idPreimage, keyPreimage, err := getPreimages(m.getRng()) if err != nil { return gs.Group{}, nil, NotSent, err } @@ -114,7 +114,7 @@ func (m *manager) buildMembership(members []*id.ID) (group.Membership, contacts := make([]contact.Contact, len(members)) var err error for i, uid := range members { - partner, err := m.e2e.GetPartner(uid) + partner, err := m.getE2eHandler().GetPartner(uid) if err != nil { return nil, nil, errors.Errorf(getPartnerErr, uid, err) } @@ -127,7 +127,7 @@ func (m *manager) buildMembership(members []*id.ID) (group.Membership, dkl.Add(partner.MyRootPrivateKey(), group.Member{ ID: partner.PartnerId(), DhKey: partner.PartnerRootPublicKey(), - }, m.grp) + }, m.getE2eGroup()) } // Create new Membership from contact list and client's own contact. diff --git a/groupChat/makeGroup_test.go b/groupChat/makeGroup_test.go index b08b9766a3f8397bb37e3c8f896f05c236849bc0..737ca52cae289725ccd264abe90020e5b0c64ea2 100644 --- a/groupChat/makeGroup_test.go +++ b/groupChat/makeGroup_test.go @@ -11,7 +11,7 @@ import ( "bytes" "fmt" "github.com/cloudflare/circl/dh/sidh" - "gitlab.com/elixxir/client/e2e/ratchet/partner/session" + sessionImport "gitlab.com/elixxir/client/e2e/ratchet/partner/session" gs "gitlab.com/elixxir/client/groupChat/groupStore" util "gitlab.com/elixxir/client/storage/utility" "gitlab.com/elixxir/crypto/fastRNG" @@ -132,8 +132,7 @@ func Test_manager_MakeGroup_AddGroupError(t *testing.T) { // Unit test of manager.buildMembership. func Test_manager_buildMembership(t *testing.T) { - prng := rand.New(rand.NewSource(42)) - m, _ := newTestManager(prng, t) + m, _ := newTestManager(t) memberIDs, expected, expectedDKL := addPartners(m, t) membership, dkl, err := m.buildMembership(memberIDs) @@ -155,7 +154,7 @@ func Test_manager_buildMembership(t *testing.T) { // Error path: an error is returned when the number of members in the membership // list is too few. func Test_manager_buildMembership_MinParticipantsError(t *testing.T) { - m, _ := newTestManager(rand.New(rand.NewSource(42)), t) + m, _ := newTestManager(t) memberIDs := make([]*id.ID, group.MinParticipants-1) expectedErr := fmt.Sprintf( minMembersErr, len(memberIDs), group.MinParticipants) @@ -170,7 +169,7 @@ func Test_manager_buildMembership_MinParticipantsError(t *testing.T) { // Error path: an error is returned when the number of members in the membership // list is too many. func Test_manager_buildMembership_MaxParticipantsError(t *testing.T) { - m, _ := newTestManager(rand.New(rand.NewSource(42)), t) + m, _ := newTestManager(t) memberIDs := make([]*id.ID, group.MaxParticipants+1) expectedErr := fmt.Sprintf( maxMembersErr, len(memberIDs), group.MaxParticipants) @@ -184,8 +183,7 @@ func Test_manager_buildMembership_MaxParticipantsError(t *testing.T) { // Error path: error returned when a partner cannot be found func Test_manager_buildMembership_GetPartnerContactError(t *testing.T) { - prng := rand.New(rand.NewSource(42)) - m, _ := newTestManager(prng, t) + m, _ := newTestManager(t) memberIDs, _, _ := addPartners(m, t) expectedErr := strings.SplitN(getPartnerErr, "%", 2)[0] @@ -201,8 +199,7 @@ func Test_manager_buildMembership_GetPartnerContactError(t *testing.T) { // Error path: error returned when a member ID appears twice on the list. func Test_manager_buildMembership_DuplicateContactError(t *testing.T) { - prng := rand.New(rand.NewSource(42)) - m, _ := newTestManager(prng, t) + m, _ := newTestManager(t) memberIDs, _, _ := addPartners(m, t) expectedErr := strings.SplitN(makeMembershipErr, "%", 2)[0] @@ -290,7 +287,7 @@ func addPartners(m *manager, t *testing.T) ([]*id.ID, group.Membership, for i := range memberIDs { // Build member data uid := id.NewIdFromUInt(uint64(i), id.User, t) - dhKey := m.grp.NewInt(int64(i + 42)) + dhKey := m.getE2eGroup().NewInt(int64(i + 42)) myVariant := sidh.KeyVariantSidhA prng := rand.New(rand.NewSource(int64(i + 42))) @@ -309,13 +306,13 @@ func addPartners(m *manager, t *testing.T) ([]*id.ID, group.Membership, memberIDs[i] = uid members = append(members, group.Member{ID: uid, DhKey: dhKey}) dkl.Add(dhKey, group.Member{ID: uid, DhKey: dhKey}, - m.grp) + m.getE2eGroup()) // Add partner - _, err := m.e2e.AddPartner(uid, dhKey, dhKey, + _, err := m.getE2eHandler().AddPartner(uid, dhKey, dhKey, theirSIDHPubKey, mySIDHPrivKey, - session.GetDefaultParams(), - session.GetDefaultParams()) + sessionImport.GetDefaultParams(), + sessionImport.GetDefaultParams()) if err != nil { t.Errorf("Failed to add partner %d: %+v", i, err) } diff --git a/groupChat/manager.go b/groupChat/manager.go index f040e6498a6c8bcfc40634e7e0f7cb023cf29ba3..37ef25a0a621d598d7eedc4556bcbb85971a8fb4 100644 --- a/groupChat/manager.go +++ b/groupChat/manager.go @@ -8,27 +8,16 @@ package groupChat import ( - "sync" - "time" - - "github.com/cloudflare/circl/dh/sidh" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/catalog" - "gitlab.com/elixxir/client/cmix" - "gitlab.com/elixxir/client/cmix/message" - "gitlab.com/elixxir/client/e2e" - "gitlab.com/elixxir/client/e2e/ratchet/partner" - "gitlab.com/elixxir/client/e2e/ratchet/partner/session" - "gitlab.com/elixxir/client/e2e/receive" gs "gitlab.com/elixxir/client/groupChat/groupStore" - "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/client/xxdk" "gitlab.com/elixxir/crypto/cyclic" - crypto "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/crypto/group" "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/id/ephemeral" + "sync" ) // Error messages. @@ -46,34 +35,6 @@ const ( const defaultServiceTag = "default" -// GroupCmix is a subset of the cmix.Client interface containing only the -// methods needed by GroupChat -type GroupCmix interface { - SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) ( - id.Round, []ephemeral.Id, error) - AddService( - clientID *id.ID, newService message.Service, response message.Processor) - DeleteService( - clientID *id.ID, toDelete message.Service, processor message.Processor) - GetMaxMessageLength() int -} - -// GroupE2e is a subset of the e2e.Handler interface containing only the methods -// needed by GroupChat -type GroupE2e interface { - SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, - params e2e.Params) ([]id.Round, crypto.MessageID, time.Time, error) - RegisterListener(senderID *id.ID, messageType catalog.MessageType, - newListener receive.Listener) receive.ListenerID - AddService(tag string, processor message.Processor) error - AddPartner(partnerID *id.ID, partnerPubKey, myPrivKey *cyclic.Int, - partnerSIDHPubKey *sidh.PublicKey, mySIDHPrivKey *sidh.PrivateKey, - sendParams, receiveParams session.Params) (partner.Manager, error) - GetPartner(partnerID *id.ID) (partner.Manager, error) - GetHistoricalDHPubkey() *cyclic.Int - GetHistoricalDHPrivkey() *cyclic.Int -} - // manager handles the list of groups a user is a part of. type manager struct { // Group storage @@ -86,21 +47,23 @@ type manager struct { // Callback that is called when a new group request is received requestFunc RequestCallback - receptionId *id.ID - net GroupCmix - e2e GroupE2e - grp *cyclic.Group - rng *fastRNG.StreamGenerator + messenger groupE2e } // NewManager creates a new group chat manager -func NewManager(services GroupCmix, e2e GroupE2e, receptionId *id.ID, - rng *fastRNG.StreamGenerator, grp *cyclic.Group, kv *versioned.KV, +func NewManager(messenger groupE2e, requestFunc RequestCallback, receiveFunc Processor) (GroupChat, error) { + // Initialize a member object + handler := messenger.GetE2E() + member := group.Member{ + ID: messenger.GetReceptionIdentity().ID, + DhKey: handler.GetHistoricalDHPubkey(), + } + // Load the group chat storage or create one if one does not exist - gStore, err := gs.NewOrLoadStore( - kv, group.Member{ID: receptionId, DhKey: e2e.GetHistoricalDHPubkey()}) + kv := messenger.GetStorage().GetKV() + gStore, err := gs.NewOrLoadStore(kv, member) if err != nil { return nil, errors.Errorf(newGroupStoreErr, err) } @@ -110,19 +73,15 @@ func NewManager(services GroupCmix, e2e GroupE2e, receptionId *id.ID, gs: gStore, services: make(map[string]Processor), requestFunc: requestFunc, - receptionId: receptionId, - net: services, - e2e: e2e, - grp: grp, - rng: rng, + messenger: messenger, } // Register listener for incoming e2e group chat requests - e2e.RegisterListener( + handler.RegisterListener( &id.ZeroUser, catalog.GroupCreationRequest, &requestListener{m}) // Register notifications listener for incoming e2e group chat requests - err = e2e.AddService(catalog.GroupRq, nil) + err = handler.AddService(catalog.GroupRq, nil) if err != nil { return nil, err } @@ -179,3 +138,27 @@ func (m *manager) GetGroup(groupID *id.ID) (gs.Group, bool) { func (m *manager) NumGroups() int { return m.gs.Len() } + +///////////////////////////////////////////////////////////////////////////////////////// +// Internal getters ///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +func (m *manager) getCMix() groupCmix { + return m.messenger.GetCmix() +} + +func (m *manager) getE2eHandler() groupE2eHandler { + return m.messenger.GetE2E() +} + +func (m *manager) getReceptionIdentity() xxdk.ReceptionIdentity { + return m.messenger.GetReceptionIdentity() +} + +func (m *manager) getRng() *fastRNG.StreamGenerator { + return m.messenger.GetRng() +} + +func (m *manager) getE2eGroup() *cyclic.Group { + return m.messenger.GetStorage().GetE2EGroup() +} diff --git a/groupChat/manager_test.go b/groupChat/manager_test.go index de32491e49f2b7555783abc49d26d131c81a877e..07009a543eb81165ffb2e6c6f4397bf1b8ce4712 100644 --- a/groupChat/manager_test.go +++ b/groupChat/manager_test.go @@ -11,7 +11,7 @@ import ( "gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/rounds" - "gitlab.com/elixxir/client/e2e" + e2eImport "gitlab.com/elixxir/client/e2e" gs "gitlab.com/elixxir/client/groupChat/groupStore" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/group" @@ -28,11 +28,11 @@ import ( // Tests that manager adheres to the GroupChat interface. var _ GroupChat = (*manager)(nil) -// Tests that GroupCmix adheres to the cmix.Client interface. -var _ GroupCmix = (cmix.Client)(nil) +// Tests that groupCmix adheres to the cmix.Client interface. +var _ groupCmix = (cmix.Client)(nil) -// Tests that GroupE2e adheres to the e2e.Handler interface. -var _ GroupE2e = (e2e.Handler)(nil) +// Tests that groupE2eHandler adheres to the e2e.Handler interface. +var _ groupE2eHandler = (e2eImport.Handler)(nil) type mockProcessor struct{ receiveChan chan MessageReceive } @@ -44,20 +44,23 @@ func (m mockProcessor) String() string { return "mockProcessor" } // Unit test of NewManager. func TestNewManager(t *testing.T) { - kv := versioned.NewKV(ekv.MakeMemstore()) - user := group.Member{ - ID: id.NewIdFromString("userID", id.User, t), - DhKey: randCycInt(rand.New(rand.NewSource(42))), - } + requestChan := make(chan gs.Group) requestFunc := func(g gs.Group) { requestChan <- g } receiveChan := make(chan MessageReceive) - gcInt, err := NewManager(nil, newTestE2eManager(user.DhKey), user.ID, nil, - nil, kv, requestFunc, mockProcessor{receiveChan}) + mockMess := newMockMessenger(t, nil) + gcInt, err := NewManager(mockMess, requestFunc, + mockProcessor{receiveChan}) if err != nil { t.Errorf("NewManager returned an error: %+v", err) } + dhKeyPub := mockMess.GetE2E().GetHistoricalDHPubkey() + user := group.Member{ + ID: mockMess.GetReceptionIdentity().ID, + DhKey: dhKeyPub, + } + m := gcInt.(*manager) if !m.gs.GetUser().Equal(user) { @@ -85,7 +88,7 @@ func TestNewManager_LoadStorage(t *testing.T) { kv := versioned.NewKV(ekv.MakeMemstore()) user := group.Member{ ID: id.NewIdFromString("userID", id.User, t), - DhKey: randCycInt(rand.New(rand.NewSource(42))), + DhKey: randCycInt(prng), } gStore, err := gs.NewStore(kv, user) @@ -93,25 +96,28 @@ func TestNewManager_LoadStorage(t *testing.T) { t.Errorf("Failed to create new group storage: %+v", err) } + expectedGroups := make([]gs.Group, 0) for i := 0; i < 10; i++ { - err := gStore.Add( - newTestGroup(getGroup(), getGroup().NewInt(42), prng, t)) + grp := newTestGroup(getGroup(), getGroup().NewInt(42), prng, t) + err := gStore.Add(grp) if err != nil { t.Errorf("Failed to add group %d: %+v", i, err) } + expectedGroups = append(expectedGroups, grp) } - gcInt, err := NewManager(newTestNetworkManager(0, t), - newTestE2eManager(user.DhKey), user.ID, nil, nil, kv, nil, nil) + mockMess := newMockMessenger(t, kv) + gcInt, err := NewManager(mockMess, nil, nil) if err != nil { t.Errorf("NewManager returned an error: %+v", err) } m := gcInt.(*manager) - if !reflect.DeepEqual(gStore, m.gs) { - t.Errorf("NewManager failed to load the expected storage."+ - "\nexpected: %+v\nreceived: %+v", gStore, m.gs) + for _, grp := range expectedGroups { + if _, exists := m.gs.Get(grp.ID); !exists { + t.Errorf("NewManager failed to load the expected storage.") + } } } @@ -138,7 +144,8 @@ func TestNewManager_LoadError(t *testing.T) { expectedErr := strings.SplitN(newGroupStoreErr, "%", 2)[0] - _, err = NewManager(nil, newTestE2eManager(user.DhKey), user.ID, nil, nil, kv, nil, nil) + mockMess := newMockMessenger(t, kv) + _, err = NewManager(mockMess, nil, nil) if err == nil || !strings.Contains(err.Error(), expectedErr) { t.Errorf("NewManager did not return the expected error."+ "\nexpected: %s\nreceived: %+v", expectedErr, err) @@ -294,7 +301,7 @@ func TestNewManager_LoadError(t *testing.T) { func Test_manager_JoinGroup(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, t) - g := newTestGroup(m.grp, m.e2e.GetHistoricalDHPubkey(), prng, t) + g := newTestGroup(m.getE2eGroup(), m.getE2eHandler().GetHistoricalDHPubkey(), prng, t) err := m.JoinGroup(g) if err != nil { diff --git a/groupChat/messenger_test.go b/groupChat/messenger_test.go new file mode 100644 index 0000000000000000000000000000000000000000..91894745298dff434b9459d2dffcbae870fb29b0 --- /dev/null +++ b/groupChat/messenger_test.go @@ -0,0 +1,95 @@ +package groupChat + +import ( + "gitlab.com/elixxir/client/cmix" + clientE2E "gitlab.com/elixxir/client/e2e" + "gitlab.com/elixxir/client/e2e/ratchet/partner" + "gitlab.com/elixxir/client/storage" + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/client/xxdk" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/fastRNG" + "gitlab.com/xx_network/crypto/csprng" + "gitlab.com/xx_network/primitives/id" + "math/rand" + "testing" +) + +// mockMessenger implementation for groupE2e interface +type mockMessenger struct { + receptionId *id.ID + net cmix.Client + e2e clientE2E.Handler + e2eGroup *cyclic.Group + rng *fastRNG.StreamGenerator + storage storage.Session +} + +func newMockMessenger(t testing.TB, kv *versioned.KV) groupE2e { + receptionId := id.NewIdFromString("test", id.User, t) + mockCmix := newTestNetworkManager(0) + prng := rand.New(rand.NewSource(42)) + e2eHandler := newTestE2eManager(randCycInt(prng), t) + grp := getGroup() + rng := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG) + mockSession := newMockSesion(kv) + + return mockMessenger{ + receptionId: receptionId, + net: mockCmix, + e2e: e2eHandler, + e2eGroup: grp, + rng: rng, + storage: mockSession, + } +} + +func newMockMessengerWithStore(t testing.TB, sendErr int) groupE2e { + receptionId := id.NewIdFromString("test", id.User, t) + mockCmix := newTestNetworkManager(sendErr) + prng := rand.New(rand.NewSource(42)) + grp := getGroup() + rng := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG) + mockSession := newMockSesion(nil) + + return mockMessenger{ + receptionId: receptionId, + net: mockCmix, + e2e: &testE2eManager{ + e2eMessages: []testE2eMessage{}, + sendErr: sendErr, + grp: getGroup(), + dhPubKey: randCycInt(prng), + partners: make(map[id.ID]partner.Manager), + }, + e2eGroup: grp, + rng: rng, + storage: mockSession, + } +} + +func (m mockMessenger) GetCmix() cmix.Client { + return m.net +} + +func (m mockMessenger) GetE2E() clientE2E.Handler { + return m.e2e +} + +func (m mockMessenger) GetReceptionIdentity() xxdk.ReceptionIdentity { + keyData, _ := m.e2e.GetHistoricalDHPrivkey().MarshalJSON() + groupData, _ := getGroup().MarshalJSON() + return xxdk.ReceptionIdentity{ + ID: m.receptionId, + DHKeyPrivate: keyData, + E2eGrp: groupData, + } +} + +func (m mockMessenger) GetRng() *fastRNG.StreamGenerator { + return m.rng +} + +func (m mockMessenger) GetStorage() storage.Session { + return m.storage +} diff --git a/groupChat/networkManager_test.go b/groupChat/networkManager_test.go new file mode 100644 index 0000000000000000000000000000000000000000..a6df5a6427d976a21a652d89db81e8941348f34e --- /dev/null +++ b/groupChat/networkManager_test.go @@ -0,0 +1,216 @@ +package groupChat + +import ( + "github.com/pkg/errors" + "gitlab.com/elixxir/client/cmix" + "gitlab.com/elixxir/client/cmix/gateway" + "gitlab.com/elixxir/client/cmix/identity" + "gitlab.com/elixxir/client/cmix/message" + "gitlab.com/elixxir/client/cmix/rounds" + "gitlab.com/elixxir/client/stoppable" + "gitlab.com/elixxir/comms/network" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/primitives/format" + "gitlab.com/xx_network/comms/connect" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/id/ephemeral" + "sync" + "time" +) + +// testNetworkManager is a test implementation of NetworkManager interface. +type testNetworkManager struct { + receptionMessages [][]format.Message + sendMessages [][]cmix.TargetedCmixMessage + errSkip int + sendErr int + grp *cyclic.Group + sync.RWMutex +} + +func newTestNetworkManager(sendErr int) cmix.Client { + return &testNetworkManager{ + receptionMessages: [][]format.Message{}, + sendMessages: [][]cmix.TargetedCmixMessage{}, + grp: getGroup(), + sendErr: sendErr, + } +} + +func (tnm *testNetworkManager) SendMany(messages []cmix.TargetedCmixMessage, _ cmix.CMIXParams) (id.Round, []ephemeral.Id, error) { + if tnm.sendErr == 1 { + return 0, nil, errors.New("SendManyCMIX error") + } + + tnm.Lock() + defer tnm.Unlock() + + tnm.sendMessages = append(tnm.sendMessages, messages) + + var receiveMessages []format.Message + for _, msg := range messages { + receiveMsg := format.NewMessage(tnm.grp.GetP().ByteLen()) + receiveMsg.SetMac(msg.Mac) + receiveMsg.SetContents(msg.Payload) + receiveMsg.SetKeyFP(msg.Fingerprint) + receiveMessages = append(receiveMessages, receiveMsg) + } + tnm.receptionMessages = append(tnm.receptionMessages, receiveMessages) + return 0, nil, nil +} + +func (*testNetworkManager) AddService(*id.ID, message.Service, message.Processor) {} +func (*testNetworkManager) DeleteService(*id.ID, message.Service, message.Processor) {} + +///////////////////////////////////////////////////////////////////////////////////// +// Unused & unimplemented methods of the test object //////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// + +func (tnm *testNetworkManager) Follow(report cmix.ClientErrorReport) (stoppable.Stoppable, error) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) Send(recipient *id.ID, fingerprint format.Fingerprint, service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) AddIdentity(id *id.ID, validUntil time.Time, persistent bool) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) RemoveIdentity(id *id.ID) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) GetIdentity(get *id.ID) (identity.TrackedID, error) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) AddFingerprint(identity *id.ID, fingerprint format.Fingerprint, mp message.Processor) error { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) DeleteFingerprint(identity *id.ID, fingerprint format.Fingerprint) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) DeleteClientFingerprints(identity *id.ID) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) DeleteClientService(clientID *id.ID) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) TrackServices(tracker message.ServicesTracker) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) CheckInProgressMessages() { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) IsHealthy() bool { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) WasHealthy() bool { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) AddHealthCallback(f func(bool)) uint64 { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) RemoveHealthCallback(u uint64) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) HasNode(nid *id.ID) bool { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) NumRegisteredNodes() int { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) TriggerNodeRegistration(nid *id.ID) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback, roundList ...id.Round) error { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) LookupHistoricalRound(rid id.Round, callback rounds.RoundResultCallback) error { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) SendToAny(sendFunc func(host *connect.Host) (interface{}, error), stop *stoppable.Single) (interface{}, error) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) SendToPreferred(targets []*id.ID, sendFunc gateway.SendToPreferredFunc, stop *stoppable.Single, timeout time.Duration) (interface{}, error) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) SetGatewayFilter(f gateway.Filter) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) GetHostParams() connect.HostParams { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) GetAddressSpace() uint8 { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) RegisterAddressSpaceNotification(tag string) (chan uint8, error) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) UnregisterAddressSpaceNotification(tag string) { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) GetInstance() *network.Instance { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) GetVerboseRounds() string { + //TODO implement me + panic("implement me") +} + +func (tnm *testNetworkManager) GetMaxMessageLength() int { + return format.NewMessage(tnm.grp.GetP().ByteLen()).ContentsSize() +} diff --git a/groupChat/receive.go b/groupChat/receive.go index 63e6f91c0c904351d2c8590d29ebb7aa9a6d98d8..aecbfad2ee37d9242a70e3e5f1a8d21773854340 100644 --- a/groupChat/receive.go +++ b/groupChat/receive.go @@ -86,9 +86,11 @@ func (p *receptionProcessor) Process(message format.Message, func (p *receptionProcessor) String() string { if p.p == nil { - return fmt.Sprintf("GroupChatReception(%s)", p.m.receptionId) + return fmt.Sprintf("GroupChatReception(%s)", + p.m.getReceptionIdentity().ID) } - return fmt.Sprintf("GroupChatReception(%s)-%s", p.m.receptionId, p.p) + return fmt.Sprintf("GroupChatReception(%s)-%s", + p.m.getReceptionIdentity().ID, p.p) } // decryptMessage decrypts the group message payload and returns its message ID, diff --git a/groupChat/receiveRequest.go b/groupChat/receiveRequest.go index d76744315edf613ca05cb5efbdfba889e7cfadd9..104a326f1101f966510daea00db75a0c613efa67 100644 --- a/groupChat/receiveRequest.go +++ b/groupChat/receiveRequest.go @@ -78,7 +78,7 @@ func (m *manager) readRequest(msg receive.Message) (gs.Group, error) { } // get the relationship with the group leader - partner, err := m.e2e.GetPartner(membership[0].ID) + partner, err := m.getE2eHandler().GetPartner(membership[0].ID) if err != nil { return gs.Group{}, errors.Errorf(getPrivKeyErr, err) } @@ -89,7 +89,7 @@ func (m *manager) readRequest(msg receive.Message) (gs.Group, error) { // Generate the DH keys with each group member privKey := partner.MyRootPrivateKey() - dkl := gs.GenerateDhKeyList(m.receptionId, privKey, membership, m.grp) + dkl := gs.GenerateDhKeyList(m.getReceptionIdentity().ID, privKey, membership, m.getE2eGroup()) // Restore the original public key for the leader so that the membership // digest generated later is correct diff --git a/groupChat/receiveRequest_test.go b/groupChat/receiveRequest_test.go index 04ba441bf308d2e68ab20985630b36c2a65a4b00..d1283b8955f319e526322882d5b609e96282c3c2 100644 --- a/groupChat/receiveRequest_test.go +++ b/groupChat/receiveRequest_test.go @@ -11,7 +11,7 @@ import ( "github.com/cloudflare/circl/dh/sidh" "github.com/golang/protobuf/proto" "gitlab.com/elixxir/client/catalog" - "gitlab.com/elixxir/client/e2e/ratchet/partner/session" + sessionImport "gitlab.com/elixxir/client/e2e/ratchet/partner/session" "gitlab.com/elixxir/client/e2e/receive" gs "gitlab.com/elixxir/client/groupChat/groupStore" util "gitlab.com/elixxir/client/storage/utility" @@ -28,9 +28,9 @@ func TestRequestListener_Hear(t *testing.T) { requestChan := make(chan gs.Group) requestFunc := func(g gs.Group) { requestChan <- g } m, _ := newTestManagerWithStore(prng, 10, 0, requestFunc, t) - g := newTestGroupWithUser(m.grp, - m.receptionId, m.e2e.GetHistoricalDHPubkey(), - m.e2e.GetHistoricalDHPrivkey(), prng, t) + g := newTestGroupWithUser(m.getE2eGroup(), + m.getReceptionIdentity().ID, m.getE2eHandler().GetHistoricalDHPubkey(), + m.getE2eHandler().GetHistoricalDHPrivkey(), prng, t) requestMarshaled, err := proto.Marshal(&Request{ Name: g.Name, @@ -63,13 +63,13 @@ func TestRequestListener_Hear(t *testing.T) { _ = theirSIDHPrivKey.Generate(prng) theirSIDHPrivKey.GeneratePublicKey(theirSIDHPubKey) - _, _ = m.e2e.AddPartner( + _, _ = m.getE2eHandler().AddPartner( g.Members[0].ID, g.Members[0].DhKey, - m.e2e.GetHistoricalDHPrivkey(), + m.getE2eHandler().GetHistoricalDHPrivkey(), theirSIDHPubKey, mySIDHPrivKey, - session.GetDefaultParams(), - session.GetDefaultParams(), + sessionImport.GetDefaultParams(), + sessionImport.GetDefaultParams(), ) go listener.Hear(msg) @@ -148,7 +148,7 @@ func TestRequestListener_Hear_BadMessageType(t *testing.T) { // Unit test of readRequest. func Test_manager_readRequest(t *testing.T) { prng := rand.New(rand.NewSource(42)) - m, g := newTestManager(prng, t) + m, g := newTestManager(t) myVariant := sidh.KeyVariantSidhA mySIDHPrivKey := util.NewSIDHPrivateKey(myVariant) @@ -162,13 +162,13 @@ func Test_manager_readRequest(t *testing.T) { _ = theirSIDHPrivKey.Generate(prng) theirSIDHPrivKey.GeneratePublicKey(theirSIDHPubKey) - _, _ = m.e2e.AddPartner( + _, _ = m.getE2eHandler().AddPartner( g.Members[0].ID, g.Members[0].DhKey, - m.e2e.GetHistoricalDHPrivkey(), + m.getE2eHandler().GetHistoricalDHPrivkey(), theirSIDHPubKey, mySIDHPrivKey, - session.GetDefaultParams(), - session.GetDefaultParams(), + sessionImport.GetDefaultParams(), + sessionImport.GetDefaultParams(), ) requestMarshaled, err := proto.Marshal(&Request{ @@ -201,7 +201,7 @@ func Test_manager_readRequest(t *testing.T) { // Error path: an error is returned if the message type is incorrect. func Test_manager_readRequest_MessageTypeError(t *testing.T) { - m, _ := newTestManager(rand.New(rand.NewSource(42)), t) + m, _ := newTestManager(t) expectedErr := sendMessageTypeErr msg := receive.Message{ MessageType: catalog.NoType, @@ -217,7 +217,7 @@ func Test_manager_readRequest_MessageTypeError(t *testing.T) { // Error path: an error is returned if the proto message cannot be unmarshalled. func Test_manager_readRequest_ProtoUnmarshalError(t *testing.T) { expectedErr := strings.SplitN(deserializeMembershipErr, "%", 2)[0] - m, _ := newTestManager(rand.New(rand.NewSource(42)), t) + m, _ := newTestManager(t) requestMarshaled, err := proto.Marshal(&Request{ Members: []byte("Invalid membership serial."), @@ -240,7 +240,7 @@ func Test_manager_readRequest_ProtoUnmarshalError(t *testing.T) { // Error path: an error is returned if the membership cannot be deserialized. func Test_manager_readRequest_DeserializeMembershipError(t *testing.T) { - m, _ := newTestManager(rand.New(rand.NewSource(42)), t) + m, _ := newTestManager(t) expectedErr := strings.SplitN(protoUnmarshalErr, "%", 2)[0] msg := receive.Message{ Payload: []byte("Invalid message."), diff --git a/groupChat/send.go b/groupChat/send.go index 71624079ad5d42f1adce834249f8bdc9965edd4b..efa0e11639c261256fd200cbaac31389b9d7168f 100644 --- a/groupChat/send.go +++ b/groupChat/send.go @@ -71,7 +71,7 @@ func (m *manager) Send(groupID *id.ID, tag string, message []byte) ( // Obtain message ID msgId, err := getGroupMessageId( - m.grp, groupID, m.receptionId, timeNow, message) + m.getE2eGroup(), groupID, m.getReceptionIdentity().ID, timeNow, message) if err != nil { return 0, time.Time{}, group.MessageID{}, err } @@ -79,10 +79,10 @@ func (m *manager) Send(groupID *id.ID, tag string, message []byte) ( // Send all the groupMessages param := cmix.GetDefaultCMIXParams() param.DebugTag = "group.Message" - rid, _, err := m.net.SendMany(groupMessages, param) + rid, _, err := m.getCMix().SendMany(groupMessages, param) if err != nil { return 0, time.Time{}, group.MessageID{}, - errors.Errorf(sendManyCmixErr, m.receptionId, g.Name, g.ID, err) + errors.Errorf(sendManyCmixErr, m.getReceptionIdentity().ID, g.Name, g.ID, err) } jww.DEBUG.Printf("[GC] Sent message to %d members in group %s at %s.", @@ -96,19 +96,19 @@ func (m *manager) newMessages(g gs.Group, tag string, msg []byte, // Create list of cMix messages messages := make([]cmix.TargetedCmixMessage, 0, len(g.Members)) - rng := m.rng.GetStream() + rng := m.getRng().GetStream() defer rng.Close() // Create cMix messages in parallel for _, member := range g.Members { // Do not send to the sender - if m.receptionId.Cmp(member.ID) { + if m.getReceptionIdentity().ID.Cmp(member.ID) { continue } // Add cMix message to list cMixMsg, err := newCmixMsg(g, tag, msg, timestamp, member, rng, - m.receptionId, m.net.GetMaxMessageLength()) + m.getReceptionIdentity().ID, m.getCMix().GetMaxMessageLength()) if err != nil { return nil, err } diff --git a/groupChat/sendRequests.go b/groupChat/sendRequests.go index dca54c2c951523d6b8af49064f78352d5116ab8b..b28985361e09183b6b4d807e10c770b454386bda 100644 --- a/groupChat/sendRequests.go +++ b/groupChat/sendRequests.go @@ -120,7 +120,7 @@ func (m *manager) sendRequest(memberID *id.ID, request []byte) ([]id.Round, erro p.LastServiceTag = catalog.GroupRq p.DebugTag = "group.Request" - rounds, _, _, err := m.e2e.SendE2E( + rounds, _, _, err := m.getE2eHandler().SendE2E( catalog.GroupCreationRequest, memberID, request, p) if err != nil { return nil, errors.Errorf(sendE2eErr, memberID, err) diff --git a/groupChat/sendRequests_test.go b/groupChat/sendRequests_test.go index b87e70adbe46899862a6f7ebd304df42076e50b2..bb2589689e40f70b997ddd250da33c50f0c2c99a 100644 --- a/groupChat/sendRequests_test.go +++ b/groupChat/sendRequests_test.go @@ -11,7 +11,7 @@ import ( "fmt" "github.com/cloudflare/circl/dh/sidh" "github.com/golang/protobuf/proto" - "gitlab.com/elixxir/client/e2e/ratchet/partner/session" + sessionImport "gitlab.com/elixxir/client/e2e/ratchet/partner/session" util "gitlab.com/elixxir/client/storage/utility" "gitlab.com/elixxir/crypto/diffieHellman" "gitlab.com/xx_network/crypto/csprng" @@ -38,16 +38,16 @@ func Test_manager_ResendRequest(t *testing.T) { } for i := range g.Members { - grp := m.grp + grp := m.getE2eGroup() dhKey := grp.NewInt(int64(i + 42)) pubKey := diffieHellman.GeneratePublicKey(dhKey, grp) - p := session.GetDefaultParams() + p := sessionImport.GetDefaultParams() rng := csprng.NewSystemRNG() _, mySidhPriv := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhA, rng) theirSidhPub, _ := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhB, rng) - _, err := m.e2e.AddPartner(g.Members[i].ID, pubKey, dhKey, + _, err := m.getE2eHandler().AddPartner(g.Members[i].ID, pubKey, dhKey, mySidhPriv, theirSidhPub, p, p) if err != nil { t.Errorf("Failed to add partner #%d %s: %+v", i, g.Members[i].ID, err) @@ -64,14 +64,14 @@ func Test_manager_ResendRequest(t *testing.T) { "\nexpected: %s\nreceived: %s", AllSent, status) } - if len(m.e2e.(*testE2eManager).e2eMessages) < len(g.Members)-1 { + if len(m.getE2eHandler().(*testE2eManager).e2eMessages) < len(g.Members)-1 { t.Errorf("ResendRequest() failed to send the correct number of requests."+ "\nexpected: %d\nreceived: %d", len(g.Members)-1, - len(m.e2e.(*testE2eManager).e2eMessages)) + len(m.getE2eHandler().(*testE2eManager).e2eMessages)) } - for i := 0; i < len(m.e2e.(*testE2eManager).e2eMessages); i++ { - msg := m.e2e.(*testE2eManager).GetE2eMsg(i) + for i := 0; i < len(m.getE2eHandler().(*testE2eManager).e2eMessages); i++ { + msg := m.getE2eHandler().(*testE2eManager).GetE2eMsg(i) // Check if the message recipient is a member in the group matchesMember := false @@ -134,16 +134,16 @@ func Test_manager_sendRequests(t *testing.T) { } for i := range g.Members { - grp := m.grp + grp := m.getE2eGroup() dhKey := grp.NewInt(int64(i + 42)) pubKey := diffieHellman.GeneratePublicKey(dhKey, grp) - p := session.GetDefaultParams() + p := sessionImport.GetDefaultParams() rng := csprng.NewSystemRNG() _, mySidhPriv := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhA, rng) theirSidhPub, _ := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhB, rng) - _, err := m.e2e.AddPartner(g.Members[i].ID, pubKey, dhKey, + _, err := m.getE2eHandler().AddPartner(g.Members[i].ID, pubKey, dhKey, mySidhPriv, theirSidhPub, p, p) if err != nil { t.Errorf("Failed to add partner #%d %s: %+v", i, g.Members[i].ID, err) @@ -160,14 +160,14 @@ func Test_manager_sendRequests(t *testing.T) { "\nexpected: %s\nreceived: %s", AllSent, status) } - if len(m.e2e.(*testE2eManager).e2eMessages) < len(g.Members)-1 { + if len(m.getE2eHandler().(*testE2eManager).e2eMessages) < len(g.Members)-1 { t.Errorf("sendRequests() failed to send the correct number of requests."+ "\nexpected: %d\nreceived: %d", len(g.Members)-1, - len(m.e2e.(*testE2eManager).e2eMessages)) + len(m.getE2eHandler().(*testE2eManager).e2eMessages)) } - for i := 0; i < len(m.e2e.(*testE2eManager).e2eMessages); i++ { - msg := m.e2e.(*testE2eManager).GetE2eMsg(i) + for i := 0; i < len(m.getE2eHandler().(*testE2eManager).e2eMessages); i++ { + msg := m.getE2eHandler().(*testE2eManager).GetE2eMsg(i) // Check if the message recipient is a member in the group matchesMember := false @@ -219,9 +219,9 @@ func Test_manager_sendRequests_SendAllFail(t *testing.T) { "\nexpected: %v\nreceived: %v", nil, rounds) } - if len(m.e2e.(*testE2eManager).e2eMessages) != 0 { + if len(m.getE2eHandler().(*testE2eManager).e2eMessages) != 0 { t.Errorf("sendRequests() sent %d messages when sending should have failed.", - len(m.e2e.(*testE2eManager).e2eMessages)) + len(m.getE2eHandler().(*testE2eManager).e2eMessages)) } } @@ -234,16 +234,16 @@ func Test_manager_sendRequests_SendPartialSent(t *testing.T) { len(g.Members)-1, "") for i := range g.Members { - grp := m.grp + grp := m.getE2eGroup() dhKey := grp.NewInt(int64(i + 42)) pubKey := diffieHellman.GeneratePublicKey(dhKey, grp) - p := session.GetDefaultParams() + p := sessionImport.GetDefaultParams() rng := csprng.NewSystemRNG() _, mySidhPriv := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhA, rng) theirSidhPub, _ := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhB, rng) - _, err := m.e2e.AddPartner(g.Members[i].ID, pubKey, dhKey, + _, err := m.getE2eHandler().AddPartner(g.Members[i].ID, pubKey, dhKey, mySidhPriv, theirSidhPub, p, p) if err != nil { t.Errorf("Failed to add partner #%d %s: %+v", i, g.Members[i].ID, err) @@ -261,9 +261,9 @@ func Test_manager_sendRequests_SendPartialSent(t *testing.T) { "\nexpected: %s\nreceived: %s", PartialSent, status) } - if len(m.e2e.(*testE2eManager).e2eMessages) != (len(g.Members)-1)/2+1 { + if len(m.getE2eHandler().(*testE2eManager).e2eMessages) != (len(g.Members)-1)/2+1 { t.Errorf("sendRequests() sent %d out of %d expected messages.", - len(m.e2e.(*testE2eManager).e2eMessages), (len(g.Members)-1)/2+1) + len(m.getE2eHandler().(*testE2eManager).e2eMessages), (len(g.Members)-1)/2+1) } } @@ -273,16 +273,16 @@ func Test_manager_sendRequest(t *testing.T) { m, g := newTestManagerWithStore(prng, 10, 0, nil, t) for i := range g.Members { - grp := m.grp + grp := m.getE2eGroup() dhKey := grp.NewInt(int64(i + 42)) pubKey := diffieHellman.GeneratePublicKey(dhKey, grp) - p := session.GetDefaultParams() + p := sessionImport.GetDefaultParams() rng := csprng.NewSystemRNG() _, mySidhPriv := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhA, rng) theirSidhPub, _ := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhB, rng) - _, err := m.e2e.AddPartner(g.Members[i].ID, pubKey, dhKey, + _, err := m.getE2eHandler().AddPartner(g.Members[i].ID, pubKey, dhKey, mySidhPriv, theirSidhPub, p, p) if err != nil { t.Errorf("Failed to add partner #%d %s: %+v", i, g.Members[i].ID, err) @@ -298,7 +298,7 @@ func Test_manager_sendRequest(t *testing.T) { Payload: []byte("request message"), } - received := m.e2e.(*testE2eManager).GetE2eMsg(0) + received := m.getE2eHandler().(*testE2eManager).GetE2eMsg(0) if !reflect.DeepEqual(expected, received) { t.Errorf("sendRequest() did not send the correct message."+ @@ -314,16 +314,16 @@ func Test_manager_sendRequest_SendE2eError(t *testing.T) { recipientID := id.NewIdFromString("memberID", id.User, t) - grp := m.grp + grp := m.getE2eGroup() dhKey := grp.NewInt(int64(42)) pubKey := diffieHellman.GeneratePublicKey(dhKey, grp) - p := session.GetDefaultParams() + p := sessionImport.GetDefaultParams() rng := csprng.NewSystemRNG() _, mySidhPriv := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhA, rng) theirSidhPub, _ := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhB, rng) - _, err := m.e2e.AddPartner(recipientID, pubKey, dhKey, + _, err := m.getE2eHandler().AddPartner(recipientID, pubKey, dhKey, mySidhPriv, theirSidhPub, p, p) if err != nil { t.Errorf("Failed to add partner %s: %+v", recipientID, err) diff --git a/groupChat/send_test.go b/groupChat/send_test.go index 71e252e5835ba1834f6108dbba0e6e813884df0b..be68cb2e8bccca341785038e8596302ba63ba9d5 100644 --- a/groupChat/send_test.go +++ b/groupChat/send_test.go @@ -44,8 +44,8 @@ func Test_manager_Send(t *testing.T) { // Get messages sent with or return an error if no messages were sent var messages []format.Message - if len(m.net.(*testNetworkManager).receptionMessages) > 0 { - messages = m.net.(*testNetworkManager).receptionMessages[0] + if len(m.getCMix().(*testNetworkManager).receptionMessages) > 0 { + messages = m.getCMix().(*testNetworkManager).receptionMessages[0] } else { t.Error("No group cMix messages received.") } @@ -59,7 +59,7 @@ func Test_manager_Send(t *testing.T) { rounds.Round{ID: roundId, Timestamps: timestamps}) select { case result := <-msgChan: - if !result.SenderID.Cmp(m.receptionId) { + if !result.SenderID.Cmp(m.getReceptionIdentity().ID) { t.Errorf("Sender mismatch") } if result.ID.String() != msgId.String() { @@ -75,12 +75,12 @@ func Test_manager_Send(t *testing.T) { // Error path: reader returns an error. func TestGroup_newCmixMsg_SaltReaderError(t *testing.T) { expectedErr := strings.SplitN(saltReadErr, "%", 2)[0] - m, _ := newTestManager(rand.New(rand.NewSource(42)), t) + m, _ := newTestManager(t) _, err := newCmixMsg( gs.Group{ID: id.NewIdFromString("test", id.User, t)}, "", []byte{}, time.Time{}, group.Member{}, strings.NewReader(""), - m.receptionId, m.net.GetMaxMessageLength()) + m.getReceptionIdentity().ID, m.getCMix().GetMaxMessageLength()) if err == nil || !strings.Contains(err.Error(), expectedErr) { t.Errorf("newCmixMsg failed to return the expected error"+ "\nexpected: %s\nreceived: %+v", expectedErr, err) @@ -102,7 +102,7 @@ func TestGroup_newCmixMsg_InternalMsgSizeError(t *testing.T) { // Create cMix message prng = rand.New(rand.NewSource(42)) _, err := newCmixMsg(g, "", testMsg, netTime.Now(), mem, prng, - m.receptionId, m.net.GetMaxMessageLength()) + m.getReceptionIdentity().ID, m.getCMix().GetMaxMessageLength()) if err == nil || !strings.Contains(err.Error(), expectedErr) { t.Errorf("newCmixMsg failed to return the expected error"+ "\nexpected: %s\nreceived: %+v", expectedErr, err) diff --git a/groupChat/service.go b/groupChat/service.go index db893354a1bad3cdd7885cc3f6ef8c5b87ff40e8..d2a5916aaa7975a8d20065f88ce0a9047bbbed74 100644 --- a/groupChat/service.go +++ b/groupChat/service.go @@ -39,7 +39,8 @@ func (m *manager) AddService(tag string, p Processor) error { // Add a service for every group for _, g := range m.gs.Groups() { newService := makeService(g.ID, tag) - m.net.AddService(m.receptionId, newService, &receptionProcessor{m, g, p}) + m.getCMix().AddService(m.getReceptionIdentity().ID, newService, + &receptionProcessor{m, g, p}) } return nil @@ -60,7 +61,8 @@ func (m *manager) RemoveService(tag string) error { // Delete service for every group for _, g := range m.gs.Groups() { toDelete := makeService(g.ID, tag) - m.net.DeleteService(m.receptionId, toDelete, &receptionProcessor{m, g, oldProcess}) + m.getCMix().DeleteService(m.getReceptionIdentity().ID, toDelete, + &receptionProcessor{m, g, oldProcess}) } return nil @@ -70,7 +72,8 @@ func (m *manager) RemoveService(tag string) error { func (m *manager) addAllServices(g gs.Group) { for tag, p := range m.services { newService := makeService(g.ID, tag) - m.net.AddService(m.receptionId, newService, &receptionProcessor{m, g, p}) + m.getCMix().AddService(m.getReceptionIdentity().ID, newService, + &receptionProcessor{m, g, p}) } } @@ -78,7 +81,7 @@ func (m *manager) addAllServices(g gs.Group) { func (m *manager) deleteAllServices(groupID *id.ID) { for tag := range m.services { toDelete := makeService(groupID, tag) - m.net.DeleteService(m.receptionId, toDelete, nil) + m.getCMix().DeleteService(m.getReceptionIdentity().ID, toDelete, nil) } } diff --git a/groupChat/session_test.go b/groupChat/session_test.go new file mode 100644 index 0000000000000000000000000000000000000000..15877e7af4c0afcb9a7b8276810ebdd21b91eb26 --- /dev/null +++ b/groupChat/session_test.go @@ -0,0 +1,174 @@ +package groupChat + +import ( + "gitlab.com/elixxir/client/storage" + "gitlab.com/elixxir/client/storage/user" + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/ekv" + "gitlab.com/elixxir/primitives/version" + "gitlab.com/xx_network/crypto/signature/rsa" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/ndf" + "time" +) + +// mockSession is a storage.Session implementation for testing. +type mockSession struct { + kv *versioned.KV +} + +func newMockSesion(kv *versioned.KV) storage.Session { + return mockSession{kv: kv} +} + +func (m mockSession) GetE2EGroup() *cyclic.Group { + return getGroup() +} + +func (m mockSession) GetKV() *versioned.KV { + if m.kv != nil { + return m.kv + } + + return versioned.NewKV(ekv.MakeMemstore()) +} + +///////////////////////////////////////////////////////////////////////////////////// +// Unused & unimplemented methods of the test object //////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// + +func (m mockSession) GetClientVersion() version.Version { + //TODO implement me + panic("implement me") +} + +func (m mockSession) Get(key string) (*versioned.Object, error) { + //TODO implement me + panic("implement me") +} + +func (m mockSession) Set(key string, object *versioned.Object) error { + //TODO implement me + panic("implement me") +} + +func (m mockSession) Delete(key string) error { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetCmixGroup() *cyclic.Group { + //TODO implement me + panic("implement me") +} + +func (m mockSession) ForwardRegistrationStatus(regStatus storage.RegistrationStatus) error { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetRegistrationStatus() storage.RegistrationStatus { + //TODO implement me + panic("implement me") +} + +func (m mockSession) SetRegCode(regCode string) { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetRegCode() (string, error) { + //TODO implement me + panic("implement me") +} + +func (m mockSession) SetNDF(def *ndf.NetworkDefinition) { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetNDF() *ndf.NetworkDefinition { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetTransmissionID() *id.ID { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetTransmissionSalt() []byte { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetReceptionID() *id.ID { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetReceptionSalt() []byte { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetReceptionRSA() *rsa.PrivateKey { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetTransmissionRSA() *rsa.PrivateKey { + //TODO implement me + panic("implement me") +} + +func (m mockSession) IsPrecanned() bool { + //TODO implement me + panic("implement me") +} + +func (m mockSession) SetUsername(username string) error { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetUsername() (string, error) { + //TODO implement me + panic("implement me") +} + +func (m mockSession) PortableUserInfo() user.Info { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetTransmissionRegistrationValidationSignature() []byte { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetReceptionRegistrationValidationSignature() []byte { + //TODO implement me + panic("implement me") +} + +func (m mockSession) GetRegistrationTimestamp() time.Time { + //TODO implement me + panic("implement me") +} + +func (m mockSession) SetTransmissionRegistrationValidationSignature(b []byte) { + //TODO implement me + panic("implement me") +} + +func (m mockSession) SetReceptionRegistrationValidationSignature(b []byte) { + //TODO implement me + panic("implement me") +} + +func (m mockSession) SetRegistrationTimestamp(tsNano int64) { + //TODO implement me + panic("implement me") +} diff --git a/groupChat/utils_test.go b/groupChat/utils_test.go index 7b9778e10938f4d626594543ad7f609c704702f5..f672c61cc117d7dfa2b2d55d50ce50fdee44c819 100644 --- a/groupChat/utils_test.go +++ b/groupChat/utils_test.go @@ -9,54 +9,41 @@ package groupChat import ( "encoding/base64" - "math/rand" - "sync" - "testing" - "time" - - "github.com/cloudflare/circl/dh/sidh" - "github.com/pkg/errors" - "gitlab.com/elixxir/client/catalog" - "gitlab.com/elixxir/client/cmix" - "gitlab.com/elixxir/client/cmix/message" - clientE2E "gitlab.com/elixxir/client/e2e" "gitlab.com/elixxir/client/e2e/ratchet/partner" - "gitlab.com/elixxir/client/e2e/ratchet/partner/session" - "gitlab.com/elixxir/client/e2e/receive" "gitlab.com/elixxir/client/event" gs "gitlab.com/elixxir/client/groupChat/groupStore" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/e2e" - "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/crypto/group" "gitlab.com/elixxir/ekv" - "gitlab.com/elixxir/primitives/format" - "gitlab.com/xx_network/crypto/csprng" "gitlab.com/xx_network/crypto/large" "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/id/ephemeral" "gitlab.com/xx_network/primitives/ndf" "gitlab.com/xx_network/primitives/netTime" + "math/rand" + "testing" ) +///////////////////////////////////////////////////////////////////////////////////////// +// mock manager implementation ////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + // newTestManager creates a new manager for testing. -func newTestManager(rng *rand.Rand, t *testing.T) (*manager, gs.Group) { +func newTestManager(t testing.TB) (*manager, gs.Group) { + prng := rand.New(rand.NewSource(42)) + mockMess := newMockMessenger(t, nil) + m := &manager{ - receptionId: id.NewIdFromString("test", id.User, t), - net: newTestNetworkManager(0, t), - e2e: newTestE2eManager(randCycInt(rng)), - grp: getGroup(), - rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG), + messenger: mockMess, } user := group.Member{ - ID: m.receptionId, - DhKey: m.e2e.GetHistoricalDHPubkey(), + ID: m.getReceptionIdentity().ID, + DhKey: m.getE2eHandler().GetHistoricalDHPubkey(), } - g := newTestGroupWithUser(m.grp, user.ID, user.DhKey, - m.e2e.GetHistoricalDHPrivkey(), rng, t) + g := newTestGroupWithUser(m.getE2eGroup(), user.ID, user.DhKey, + m.getE2eHandler().GetHistoricalDHPrivkey(), prng, t) gStore, err := gs.NewStore(versioned.NewKV(ekv.MakeMemstore()), user) if err != nil { t.Fatalf("Failed to create new group store: %+v", err) @@ -70,25 +57,16 @@ func newTestManager(rng *rand.Rand, t *testing.T) (*manager, gs.Group) { // of the groups in the list is also returned. func newTestManagerWithStore(rng *rand.Rand, numGroups int, sendErr int, requestFunc RequestCallback, t *testing.T) (*manager, gs.Group) { + mockMess := newMockMessengerWithStore(t, sendErr) m := &manager{ services: make(map[string]Processor), requestFunc: requestFunc, - receptionId: id.NewIdFromString("test", id.User, t), - net: newTestNetworkManager(sendErr, t), - e2e: &testE2eManager{ - e2eMessages: []testE2eMessage{}, - sendErr: sendErr, - grp: getGroup(), - dhPubKey: randCycInt(rng), - partners: make(map[id.ID]partner.Manager), - }, - grp: getGroup(), - rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG), + messenger: mockMess, } user := group.Member{ - ID: m.receptionId, - DhKey: m.e2e.GetHistoricalDHPubkey(), + ID: m.getReceptionIdentity().ID, + DhKey: m.getE2eHandler().GetHistoricalDHPubkey(), } gStore, err := gs.NewStore(versioned.NewKV(ekv.MakeMemstore()), user) @@ -99,7 +77,7 @@ func newTestManagerWithStore(rng *rand.Rand, numGroups int, sendErr int, var g gs.Group for i := 0; i < numGroups; i++ { - g = newTestGroupWithUser(m.grp, user.ID, user.DhKey, + g = newTestGroupWithUser(m.getE2eGroup(), user.ID, user.DhKey, randCycInt(rng), rng, t) if err = gStore.Add(g); err != nil { t.Fatalf("Failed to add group %d to group store: %+v", i, err) @@ -108,7 +86,7 @@ func newTestManagerWithStore(rng *rand.Rand, numGroups int, sendErr int, return m, g } -func newTestE2eManager(dhPubKey *cyclic.Int) *testE2eManager { +func newTestE2eManager(dhPubKey *cyclic.Int, t testing.TB) *testE2eManager { return &testE2eManager{ e2eMessages: []testE2eMessage{}, errSkip: 0, @@ -120,7 +98,7 @@ func newTestE2eManager(dhPubKey *cyclic.Int) *testE2eManager { // getMembership returns a Membership with random members for testing. func getMembership(size int, uid *id.ID, pubKey *cyclic.Int, grp *cyclic.Group, - prng *rand.Rand, t *testing.T) group.Membership { + prng *rand.Rand, t testing.TB) group.Membership { contacts := make([]contact.Contact, size) for i := range contacts { randId, _ := id.NewRandomID(prng, id.User) @@ -179,7 +157,7 @@ func newTestGroup(grp *cyclic.Group, privKey *cyclic.Int, rng *rand.Rand, // newTestGroup generates a new group with random values for testing. func newTestGroupWithUser(grp *cyclic.Group, uid *id.ID, pubKey, - privKey *cyclic.Int, rng *rand.Rand, t *testing.T) gs.Group { + privKey *cyclic.Int, rng *rand.Rand, t testing.TB) gs.Group { // Generate name from base 64 encoded random data nameBytes := make([]byte, 16) rng.Read(nameBytes) @@ -222,137 +200,6 @@ func getGroup() *cyclic.Group { large.NewIntFromString(getNDF().E2E.Generator, 16)) } -func newTestNetworkManager(sendErr int, _ *testing.T) GroupCmix { - return &testNetworkManager{ - receptionMessages: [][]format.Message{}, - sendMessages: [][]cmix.TargetedCmixMessage{}, - grp: getGroup(), - sendErr: sendErr, - } -} - -// testE2eManager is a test implementation of NetworkManager interface. -type testE2eManager struct { - e2eMessages []testE2eMessage - partners map[id.ID]partner.Manager - errSkip int - sendErr int - dhPubKey *cyclic.Int - grp *cyclic.Group - sync.RWMutex -} - -type testE2eMessage struct { - Recipient *id.ID - Payload []byte -} - -func (tnm *testE2eManager) AddPartner(partnerID *id.ID, partnerPubKey, - myPrivKey *cyclic.Int, _ *sidh.PublicKey, _ *sidh.PrivateKey, - _, _ session.Params) (partner.Manager, error) { - - testPartner := partner.NewTestManager(partnerID, partnerPubKey, myPrivKey, &testing.T{}) - tnm.partners[*partnerID] = testPartner - return testPartner, nil -} - -func (tnm *testE2eManager) GetPartner(partnerID *id.ID) (partner.Manager, error) { - if p, ok := tnm.partners[*partnerID]; ok { - return p, nil - } - return nil, errors.New("Unable to find partner") -} - -func (tnm *testE2eManager) GetHistoricalDHPubkey() *cyclic.Int { - return tnm.dhPubKey -} - -func (tnm *testE2eManager) GetHistoricalDHPrivkey() *cyclic.Int { - return tnm.dhPubKey -} - -func (tnm *testE2eManager) SendE2E(_ catalog.MessageType, recipient *id.ID, - payload []byte, _ clientE2E.Params) ([]id.Round, e2e.MessageID, time.Time, - error) { - tnm.Lock() - defer tnm.Unlock() - - tnm.errSkip++ - if tnm.sendErr == 1 { - return nil, e2e.MessageID{}, time.Time{}, errors.New("SendE2E error") - } else if tnm.sendErr == 2 && tnm.errSkip%2 == 0 { - return nil, e2e.MessageID{}, time.Time{}, errors.New("SendE2E error") - } - - tnm.e2eMessages = append(tnm.e2eMessages, testE2eMessage{ - Recipient: recipient, - Payload: payload, - }) - - return []id.Round{0, 1, 2, 3}, e2e.MessageID{}, time.Time{}, nil -} - -func (*testE2eManager) RegisterListener(*id.ID, catalog.MessageType, receive.Listener) receive.ListenerID { - return receive.ListenerID{} -} - -func (*testE2eManager) AddService(string, message.Processor) error { - return nil -} - -func (*testE2eManager) GetDefaultHistoricalDHPubkey() *cyclic.Int { - panic("implement me") -} - -func (*testE2eManager) GetDefaultHistoricalDHPrivkey() *cyclic.Int { - panic("implement me") -} - -func (tnm *testE2eManager) GetE2eMsg(i int) testE2eMessage { - tnm.RLock() - defer tnm.RUnlock() - return tnm.e2eMessages[i] -} - -// testNetworkManager is a test implementation of NetworkManager interface. -type testNetworkManager struct { - receptionMessages [][]format.Message - sendMessages [][]cmix.TargetedCmixMessage - errSkip int - sendErr int - grp *cyclic.Group - sync.RWMutex -} - -func (tnm *testNetworkManager) GetMaxMessageLength() int { - return format.NewMessage(tnm.grp.GetP().ByteLen()).ContentsSize() -} - -func (tnm *testNetworkManager) SendMany(messages []cmix.TargetedCmixMessage, _ cmix.CMIXParams) (id.Round, []ephemeral.Id, error) { - if tnm.sendErr == 1 { - return 0, nil, errors.New("SendManyCMIX error") - } - - tnm.Lock() - defer tnm.Unlock() - - tnm.sendMessages = append(tnm.sendMessages, messages) - - var receiveMessages []format.Message - for _, msg := range messages { - receiveMsg := format.NewMessage(tnm.grp.GetP().ByteLen()) - receiveMsg.SetMac(msg.Mac) - receiveMsg.SetContents(msg.Payload) - receiveMsg.SetKeyFP(msg.Fingerprint) - receiveMessages = append(receiveMessages, receiveMsg) - } - tnm.receptionMessages = append(tnm.receptionMessages, receiveMessages) - return 0, nil, nil -} - -func (*testNetworkManager) AddService(*id.ID, message.Service, message.Processor) {} -func (*testNetworkManager) DeleteService(*id.ID, message.Service, message.Processor) {} - type dummyEventMgr struct{} func (d *dummyEventMgr) Report(int, string, string, string) {}