Skip to content
Snippets Groups Projects
Select Git revision
  • 15037876e66f288ed60e740a26dca476e6f75ae1
  • release default protected
  • 11-22-implement-kv-interface-defined-in-collectiveversionedkvgo
  • hotfix/TestHostPool_UpdateNdf_AddFilter
  • XX-4719/announcementChannels
  • xx-4717/logLevel
  • jonah/noob-channel
  • master protected
  • XX-4707/tagDiskJson
  • xx-4698/notification-retry
  • hotfix/notifylockup
  • syncNodes
  • hotfix/localCB
  • XX-4677/NewChanManagerMobile
  • XX-4689/DmSync
  • duplicatePrefix
  • XX-4601/HavenInvites
  • finalizedUICallbacks
  • XX-4673/AdminKeySync
  • debugNotifID
  • anne/test
  • v4.7.5
  • v4.7.4
  • v4.7.3
  • v4.7.2
  • v4.7.1
  • v4.6.3
  • v4.6.1
  • v4.5.0
  • v4.4.4
  • v4.3.11
  • v4.3.8
  • v4.3.7
  • v4.3.6
  • v4.3.5
  • v4.2.0
  • v4.3.0
  • v4.3.4
  • v4.3.3
  • v4.3.2
  • v4.3.1
41 results

cmix.go

Blame
  • makeGroup_test.go 10.77 KiB
    ///////////////////////////////////////////////////////////////////////////////
    // Copyright © 2020 xx network SEZC                                          //
    //                                                                           //
    // Use of this source code is governed by a license that can be found in the //
    // LICENSE file                                                              //
    ///////////////////////////////////////////////////////////////////////////////
    
    package groupChat
    
    import (
    	"bytes"
    	"fmt"
    	"github.com/cloudflare/circl/dh/sidh"
    	"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"
    	"gitlab.com/elixxir/crypto/group"
    	"gitlab.com/xx_network/crypto/csprng"
    	"gitlab.com/xx_network/primitives/id"
    	"math/rand"
    	"reflect"
    	"strconv"
    	"strings"
    	"testing"
    )
    
    // Tests that manager.MakeGroup adds a group and returns the expected status.
    func Test_manager_MakeGroup(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, _ := newTestManagerWithStore(prng, 10, 0, nil, t)
    	memberIDs, members, dkl := addPartners(m, t)
    	name := []byte("groupName")
    	message := []byte("Invite message.")
    
    	g, _, status, err := m.MakeGroup(memberIDs, name, message)
    	if err != nil {
    		t.Errorf("MakeGroup() returned an error: %+v", err)
    	}
    
    	if status != AllSent {
    		t.Errorf("MakeGroup() did not return the expected status."+
    			"\nexpected: %s\nreceived: %s", AllSent, status)
    	}
    
    	_, exists := m.gs.Get(g.ID)
    	if !exists {
    		t.Errorf("Failed to get group %#v.", g)
    	}
    
    	if !reflect.DeepEqual(members, g.Members) {
    		t.Errorf("New group does not have expected membership."+
    			"\nexpected: %s\nreceived: %s", members, g.Members)
    	}
    
    	if !reflect.DeepEqual(dkl, g.DhKeys) {
    		t.Errorf("New group does not have expected DH key list."+
    			"\nexpected: %#v\nreceived: %#v", dkl, g.DhKeys)
    	}
    
    	if !g.ID.Cmp(g.ID) {
    		t.Errorf("New group does not have expected ID."+
    			"\nexpected: %s\nreceived: %s", g.ID, g.ID)
    	}
    
    	if !bytes.Equal(name, g.Name) {
    		t.Errorf("New group does not have expected name."+
    			"\nexpected: %q\nreceived: %q", name, g.Name)
    	}
    
    	if !bytes.Equal(message, g.InitMessage) {
    		t.Errorf("New group does not have expected message."+
    			"\nexpected: %q\nreceived: %q", message, g.InitMessage)
    	}
    }
    
    // Error path: make sure an error and the correct status is returned when the
    // message is too large.
    func Test_manager_MakeGroup_MaxMessageSizeError(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, _ := newTestManagerWithStore(prng, 10, 0, nil, t)
    	expectedErr := fmt.Sprintf(
    		maxInitMsgSizeErr, MaxInitMessageSize+1, MaxInitMessageSize)
    
    	_, _, status, err := m.MakeGroup(nil, nil, make([]byte, MaxInitMessageSize+1))
    	if err == nil || err.Error() != expectedErr {
    		t.Errorf("MakeGroup() did not return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    
    	if status != NotSent {
    		t.Errorf("MakeGroup() did not return the expected status."+
    			"\nexpected: %s\nreceived: %s", NotSent, status)
    	}
    }
    
    // Error path: make sure an error and the correct status is returned when the
    // membership list is too small.
    func Test_manager_MakeGroup_MembershipSizeError(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, _ := newTestManagerWithStore(prng, 10, 0, nil, t)
    	expectedErr := fmt.Sprintf(
    		maxMembersErr, group.MaxParticipants+1, group.MaxParticipants)
    
    	_, _, status, err := m.MakeGroup(make([]*id.ID, group.MaxParticipants+1),
    		nil, []byte{})
    	if err == nil || err.Error() != expectedErr {
    		t.Errorf("MakeGroup() did not return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    
    	if status != NotSent {
    		t.Errorf("MakeGroup() did not return the expected status."+
    			"\nexpected: %s\nreceived: %s", NotSent, status)
    	}
    }
    
    // Error path: make sure an error and the correct status is returned when adding
    // a group failed because the user is a part of too many groups already.
    func Test_manager_MakeGroup_AddGroupError(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, _ := newTestManagerWithStore(prng, gs.MaxGroupChats, 0, nil, t)
    	memberIDs, _, _ := addPartners(m, t)
    	expectedErr := strings.SplitN(joinGroupErr, "%", 2)[0]
    
    	_, _, _, err := m.MakeGroup(memberIDs, []byte{}, []byte{})
    	if err == nil || !strings.Contains(err.Error(), expectedErr) {
    		t.Errorf("MakeGroup() did not return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    }
    
    // Unit test of manager.buildMembership.
    func Test_manager_buildMembership(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, _ := newTestManager(prng, t)
    	memberIDs, expected, expectedDKL := addPartners(m, t)
    
    	membership, dkl, err := m.buildMembership(memberIDs)
    	if err != nil {
    		t.Errorf("buildMembership() returned an error: %+v", err)
    	}
    
    	if !reflect.DeepEqual(expected, membership) {
    		t.Errorf("buildMembership() failed to return the expected membership."+
    			"\nexpected: %s\nrecieved: %s", expected, membership)
    	}
    
    	if !reflect.DeepEqual(expectedDKL, dkl) {
    		t.Errorf("buildMembership() failed to return the expected DH key list."+
    			"\nexpected: %#v\nrecieved: %#v", expectedDKL, dkl)
    	}
    }
    
    // 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)
    	memberIDs := make([]*id.ID, group.MinParticipants-1)
    	expectedErr := fmt.Sprintf(
    		minMembersErr, len(memberIDs), group.MinParticipants)
    
    	_, _, err := m.buildMembership(memberIDs)
    	if err == nil || !strings.Contains(err.Error(), expectedErr) {
    		t.Errorf("buildMembership() did not return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    }
    
    // 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)
    	memberIDs := make([]*id.ID, group.MaxParticipants+1)
    	expectedErr := fmt.Sprintf(
    		maxMembersErr, len(memberIDs), group.MaxParticipants)
    
    	_, _, err := m.buildMembership(memberIDs)
    	if err == nil || !strings.Contains(err.Error(), expectedErr) {
    		t.Errorf("buildMembership() did not return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    }
    
    // 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)
    	memberIDs, _, _ := addPartners(m, t)
    	expectedErr := strings.SplitN(getPartnerErr, "%", 2)[0]
    
    	// Replace a partner ID
    	memberIDs[len(memberIDs)/2] = id.NewIdFromString("nonPartnerID", id.User, t)
    
    	_, _, err := m.buildMembership(memberIDs)
    	if err == nil || !strings.Contains(err.Error(), expectedErr) {
    		t.Errorf("buildMembership() did not return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    }
    
    // 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)
    	memberIDs, _, _ := addPartners(m, t)
    	expectedErr := strings.SplitN(makeMembershipErr, "%", 2)[0]
    
    	// Replace a partner ID
    	memberIDs[5] = memberIDs[4]
    
    	_, _, err := m.buildMembership(memberIDs)
    	if err == nil || !strings.Contains(err.Error(), expectedErr) {
    		t.Errorf("buildMembership() did not return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    }
    
    // Test that getPreimages produces unique preimages.
    func Test_getPreimages_Unique(t *testing.T) {
    	streamGen := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG)
    	n := 100
    	idPreimages := make(map[group.IdPreimage]bool, n)
    	keyPreimages := make(map[group.KeyPreimage]bool, n)
    
    	for i := 0; i < n; i++ {
    		idPreimage, keyPreimage, err := getPreimages(streamGen)
    		if err != nil {
    			t.Errorf("getPreimages() returned an error: %+v", err)
    		}
    
    		if idPreimages[idPreimage] {
    			t.Errorf("getPreimages() produced a duplicate idPreimage: %s", idPreimage)
    		} else {
    			idPreimages[idPreimage] = true
    		}
    
    		if keyPreimages[keyPreimage] {
    			t.Errorf("getPreimages() produced a duplicate keyPreimage: %s", keyPreimage)
    		} else {
    			keyPreimages[keyPreimage] = true
    		}
    	}
    }
    
    // Unit test of RequestStatus.String.
    func TestRequestStatus_String(t *testing.T) {
    	statusCodes := map[RequestStatus]string{
    		NotSent:     "NotSent",
    		AllFail:     "AllFail",
    		PartialSent: "PartialSent",
    		AllSent:     "AllSent",
    		AllSent + 1: "INVALID STATUS",
    	}
    
    	for status, expected := range statusCodes {
    		if status.String() != expected {
    			t.Errorf("String() failed to return the expected name."+
    				"\nexpected: %s\nreceived: %s", expected, status.String())
    		}
    	}
    }
    
    // Unit test of RequestStatus.Message.
    func TestRequestStatus_Message(t *testing.T) {
    	statusCodes := map[RequestStatus]string{
    		NotSent:     "an error occurred before sending any group requests",
    		AllFail:     "all group requests failed to send",
    		PartialSent: "some group requests failed to send",
    		AllSent:     "all groups requests successfully sent",
    		AllSent + 1: "INVALID STATUS " + strconv.Itoa(int(AllSent)+1),
    	}
    
    	for status, expected := range statusCodes {
    		if status.Message() != expected {
    			t.Errorf("Message() failed to return the expected message."+
    				"\nexpected: %s\nreceived: %s", expected, status.Message())
    		}
    	}
    }
    
    // addPartners returns a list of user IDs and their matching membership and adds
    // them as partners.
    func addPartners(m *manager, t *testing.T) ([]*id.ID, group.Membership,
    	gs.DhKeyList) {
    	memberIDs := make([]*id.ID, 10)
    	members := group.Membership{m.gs.GetUser()}
    	dkl := gs.DhKeyList{}
    
    	for i := range memberIDs {
    		// Build member data
    		uid := id.NewIdFromUInt(uint64(i), id.User, t)
    		dhKey := m.grp.NewInt(int64(i + 42))
    
    		myVariant := sidh.KeyVariantSidhA
    		prng := rand.New(rand.NewSource(int64(i + 42)))
    		mySIDHPrivKey := util.NewSIDHPrivateKey(myVariant)
    		mySIDHPubKey := util.NewSIDHPublicKey(myVariant)
    		_ = mySIDHPrivKey.Generate(prng)
    		mySIDHPrivKey.GeneratePublicKey(mySIDHPubKey)
    
    		theirVariant := sidh.KeyVariant(sidh.KeyVariantSidhB)
    		theirSIDHPrivKey := util.NewSIDHPrivateKey(theirVariant)
    		theirSIDHPubKey := util.NewSIDHPublicKey(theirVariant)
    		_ = theirSIDHPrivKey.Generate(prng)
    		theirSIDHPrivKey.GeneratePublicKey(theirSIDHPubKey)
    
    		// Add to lists
    		memberIDs[i] = uid
    		members = append(members, group.Member{ID: uid, DhKey: dhKey})
    		dkl.Add(dhKey, group.Member{ID: uid, DhKey: dhKey},
    			m.grp)
    
    		// Add partner
    		_, err := m.e2e.AddPartner(uid, dhKey, dhKey,
    			theirSIDHPubKey, mySIDHPrivKey,
    			session.GetDefaultParams(),
    			session.GetDefaultParams())
    		if err != nil {
    			t.Errorf("Failed to add partner %d: %+v", i, err)
    		}
    	}
    
    	return memberIDs, members, dkl
    }