Skip to content
Snippets Groups Projects
Select Git revision
  • 40b80af39d764de7ada42d8d77f4492b8a957c57
  • 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

utils_test.go

Blame
  • sendRequests_test.go 11.82 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 (
    	"fmt"
    	"github.com/cloudflare/circl/dh/sidh"
    	"github.com/golang/protobuf/proto"
    	"gitlab.com/elixxir/client/interfaces/message"
    	"gitlab.com/elixxir/client/interfaces/params"
    	util "gitlab.com/elixxir/client/storage/utility"
    	"gitlab.com/elixxir/crypto/diffieHellman"
    	"gitlab.com/xx_network/crypto/csprng"
    	"gitlab.com/xx_network/primitives/id"
    	"math/rand"
    	"reflect"
    	"sort"
    	"strings"
    	"testing"
    )
    
    // Tests that Manager.ResendRequest sends all expected requests successfully.
    func TestManager_ResendRequest(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t)
    
    	expected := &Request{
    		Name:        g.Name,
    		IdPreimage:  g.IdPreimage.Bytes(),
    		KeyPreimage: g.KeyPreimage.Bytes(),
    		Members:     g.Members.Serialize(),
    		Message:     g.InitMessage,
    		Created:     g.Created.UnixNano(),
    	}
    
    	for i := range g.Members {
    		grp := m.store.E2e().GetGroup()
    		dhKey := grp.NewInt(int64(i + 42))
    		pubKey := diffieHellman.GeneratePublicKey(dhKey, grp)
    		p := params.GetDefaultE2ESessionParams()
    		rng := csprng.NewSystemRNG()
    		_, mySidhPriv := util.GenerateSIDHKeyPair(
    			sidh.KeyVariantSidhA, rng)
    		theirSidhPub, _ := util.GenerateSIDHKeyPair(
    			sidh.KeyVariantSidhB, rng)
    		err := m.store.E2e().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)
    		}
    	}
    
    	_, status, err := m.ResendRequest(g.ID)
    	if err != nil {
    		t.Errorf("ResendRequest() returned an error: %+v", err)
    	}
    
    	if status != AllSent {
    		t.Errorf("ResendRequest() failed to return the expected status."+
    			"\nexpected: %s\nreceived: %s", AllSent, status)
    	}
    
    	if len(m.net.(*testNetworkManager).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.net.(*testNetworkManager).e2eMessages))
    	}
    
    	for i := 0; i < len(m.net.(*testNetworkManager).e2eMessages); i++ {
    		msg := m.net.(*testNetworkManager).GetE2eMsg(i)
    
    		// Check if the message recipient is a member in the group
    		matchesMember := false
    		for j, m := range g.Members {
    			if msg.Recipient.Cmp(m.ID) {
    				matchesMember = true
    				g.Members = append(g.Members[:j], g.Members[j+1:]...)
    				break
    			}
    		}
    		if !matchesMember {
    			t.Errorf("Message %d has recipient ID %s that is not in membership.",
    				i, msg.Recipient)
    		}
    
    		testRequest := &Request{}
    		err = proto.Unmarshal(msg.Payload, testRequest)
    		if err != nil {
    			t.Errorf("Failed to unmarshal proto message (%d): %+v", i, err)
    		}
    
    		if expected.String() != testRequest.String() {
    			t.Errorf("Message %d has unexpected payload."+
    				"\nexpected: %s\nreceived: %s", i, expected, testRequest)
    		}
    	}
    }
    
    // Error path: an error is returned when no group with the corresponding group
    // ID exists.
    func TestManager_ResendRequest_GetGroupError(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t)
    	expectedErr := strings.SplitN(resendGroupIdErr, "%", 2)[0]
    
    	_, status, err := m.ResendRequest(id.NewIdFromString("invalidID", id.Group, t))
    	if err == nil || !strings.Contains(err.Error(), expectedErr) {
    		t.Errorf("ResendRequest() failed to return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    
    	if status != NotSent {
    		t.Errorf("ResendRequest() failed to return the expected status."+
    			"\nexpected: %s\nreceived: %s", NotSent, status)
    	}
    }
    
    // Tests that Manager.sendRequests sends all expected requests successfully.
    func TestManager_sendRequests(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t)
    
    	expected := &Request{
    		Name:        g.Name,
    		IdPreimage:  g.IdPreimage.Bytes(),
    		KeyPreimage: g.KeyPreimage.Bytes(),
    		Members:     g.Members.Serialize(),
    		Message:     g.InitMessage,
    		Created:     g.Created.UnixNano(),
    	}
    
    	for i := range g.Members {
    		grp := m.store.E2e().GetGroup()
    		dhKey := grp.NewInt(int64(i + 42))
    		pubKey := diffieHellman.GeneratePublicKey(dhKey, grp)
    		p := params.GetDefaultE2ESessionParams()
    		rng := csprng.NewSystemRNG()
    		_, mySidhPriv := util.GenerateSIDHKeyPair(
    			sidh.KeyVariantSidhA, rng)
    		theirSidhPub, _ := util.GenerateSIDHKeyPair(
    			sidh.KeyVariantSidhB, rng)
    		err := m.store.E2e().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)
    		}
    	}
    
    	_, status, err := m.sendRequests(g)
    	if err != nil {
    		t.Errorf("sendRequests() returned an error: %+v", err)
    	}
    
    	if status != AllSent {
    		t.Errorf("sendRequests() failed to return the expected status."+
    			"\nexpected: %s\nreceived: %s", AllSent, status)
    	}
    
    	if len(m.net.(*testNetworkManager).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.net.(*testNetworkManager).e2eMessages))
    	}
    
    	for i := 0; i < len(m.net.(*testNetworkManager).e2eMessages); i++ {
    		msg := m.net.(*testNetworkManager).GetE2eMsg(i)
    
    		// Check if the message recipient is a member in the group
    		matchesMember := false
    		for j, m := range g.Members {
    			if msg.Recipient.Cmp(m.ID) {
    				matchesMember = true
    				g.Members = append(g.Members[:j], g.Members[j+1:]...)
    				break
    			}
    		}
    		if !matchesMember {
    			t.Errorf("Message %d has recipient ID %s that is not in membership.",
    				i, msg.Recipient)
    		}
    
    		testRequest := &Request{}
    		err = proto.Unmarshal(msg.Payload, testRequest)
    		if err != nil {
    			t.Errorf("Failed to unmarshal proto message (%d): %+v", i, err)
    		}
    
    		if expected.String() != testRequest.String() {
    			t.Errorf("Message %d has unexpected payload."+
    				"\nexpected: %s\nreceived: %s", i, expected, testRequest)
    		}
    	}
    }
    
    // Tests that Manager.sendRequests returns the correct status when all sends
    // fail.
    func TestManager_sendRequests_SendAllFail(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, g := newTestManagerWithStore(prng, 10, 1, nil, nil, t)
    	expectedErr := fmt.Sprintf(sendRequestAllErr, len(g.Members)-1, "")
    
    	rounds, status, err := m.sendRequests(g)
    	if err == nil || !strings.Contains(err.Error(), expectedErr) {
    		t.Errorf("sendRequests() failed to return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    
    	if status != AllFail {
    		t.Errorf("sendRequests() failed to return the expected status."+
    			"\nexpected: %s\nreceived: %s", AllFail, status)
    	}
    
    	if rounds != nil {
    		t.Errorf("sendRequests() returned rounds on failure."+
    			"\nexpected: %v\nreceived: %v", nil, rounds)
    	}
    
    	if len(m.net.(*testNetworkManager).e2eMessages) != 0 {
    		t.Errorf("sendRequests() sent %d messages when sending should have failed.",
    			len(m.net.(*testNetworkManager).e2eMessages))
    	}
    }
    
    // Tests that Manager.sendRequests returns the correct status when some sends
    // fail.
    func TestManager_sendRequests_SendPartialSent(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, g := newTestManagerWithStore(prng, 10, 2, nil, nil, t)
    	expectedErr := fmt.Sprintf(sendRequestPartialErr, (len(g.Members)-1)/2,
    		len(g.Members)-1, "")
    
    	for i := range g.Members {
    		grp := m.store.E2e().GetGroup()
    		dhKey := grp.NewInt(int64(i + 42))
    		pubKey := diffieHellman.GeneratePublicKey(dhKey, grp)
    		p := params.GetDefaultE2ESessionParams()
    		rng := csprng.NewSystemRNG()
    		_, mySidhPriv := util.GenerateSIDHKeyPair(
    			sidh.KeyVariantSidhA, rng)
    		theirSidhPub, _ := util.GenerateSIDHKeyPair(
    			sidh.KeyVariantSidhB, rng)
    		err := m.store.E2e().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)
    		}
    	}
    
    	_, status, err := m.sendRequests(g)
    	if err == nil || !strings.Contains(err.Error(), expectedErr) {
    		t.Errorf("sendRequests() failed to return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    
    	if status != PartialSent {
    		t.Errorf("sendRequests() failed to return the expected status."+
    			"\nexpected: %s\nreceived: %s", PartialSent, status)
    	}
    
    	if len(m.net.(*testNetworkManager).e2eMessages) != (len(g.Members)-1)/2+1 {
    		t.Errorf("sendRequests() sent %d out of %d expected messages.",
    			len(m.net.(*testNetworkManager).e2eMessages), (len(g.Members)-1)/2+1)
    	}
    }
    
    // Unit test of Manager.sendRequest.
    func TestManager_sendRequest(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t)
    
    	for i := range g.Members {
    		grp := m.store.E2e().GetGroup()
    		dhKey := grp.NewInt(int64(i + 42))
    		pubKey := diffieHellman.GeneratePublicKey(dhKey, grp)
    		p := params.GetDefaultE2ESessionParams()
    		rng := csprng.NewSystemRNG()
    		_, mySidhPriv := util.GenerateSIDHKeyPair(
    			sidh.KeyVariantSidhA, rng)
    		theirSidhPub, _ := util.GenerateSIDHKeyPair(
    			sidh.KeyVariantSidhB, rng)
    		err := m.store.E2e().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)
    		}
    	}
    
    	expected := message.Send{
    		Recipient:   g.Members[0].ID,
    		Payload:     []byte("request message"),
    		MessageType: message.GroupCreationRequest,
    	}
    	_, err := m.sendRequest(expected.Recipient, expected.Payload)
    	if err != nil {
    		t.Errorf("sendRequest() returned an error: %+v", err)
    	}
    
    	received := m.net.(*testNetworkManager).GetE2eMsg(0)
    
    	if !reflect.DeepEqual(expected, received) {
    		t.Errorf("sendRequest() did not send the correct message."+
    			"\nexpected: %+v\nreceived: %+v", expected, received)
    	}
    }
    
    // Error path: an error is returned when SendE2E fails
    func TestManager_sendRequest_SendE2eError(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    	m, _ := newTestManagerWithStore(prng, 10, 1, nil, nil, t)
    	expectedErr := strings.SplitN(sendE2eErr, "%", 2)[0]
    
    	recipientID := id.NewIdFromString("memberID", id.User, t)
    
    	grp := m.store.E2e().GetGroup()
    	dhKey := grp.NewInt(int64(42))
    	pubKey := diffieHellman.GeneratePublicKey(dhKey, grp)
    	p := params.GetDefaultE2ESessionParams()
    	rng := csprng.NewSystemRNG()
    	_, mySidhPriv := util.GenerateSIDHKeyPair(
    		sidh.KeyVariantSidhA, rng)
    	theirSidhPub, _ := util.GenerateSIDHKeyPair(
    		sidh.KeyVariantSidhB, rng)
    	err := m.store.E2e().AddPartner(recipientID, pubKey, dhKey,
    		mySidhPriv, theirSidhPub, p, p)
    	if err != nil {
    		t.Errorf("Failed to add partner %s: %+v", recipientID, err)
    	}
    
    	_, err = m.sendRequest(recipientID, nil)
    	if err == nil || !strings.Contains(err.Error(), expectedErr) {
    		t.Errorf("sendRequest() failed to return the expected error."+
    			"\nexpected: %s\nreceived: %+v", expectedErr, err)
    	}
    }
    
    // Unit test of roundIdMap2List.
    func Test_roundIdMap2List(t *testing.T) {
    	prng := rand.New(rand.NewSource(42))
    
    	// Construct map and expected list
    	n := 100
    	expected := make([]id.Round, n)
    	ridMap := make(map[id.Round]struct{}, n)
    	for i := 0; i < n; i++ {
    		expected[i] = id.Round(prng.Uint64())
    		ridMap[expected[i]] = struct{}{}
    	}
    
    	// Create list of IDs from map
    	ridList := roundIdMap2List(ridMap)
    
    	// Sort expected and received slices to see if they match
    	sort.Slice(expected, func(i, j int) bool { return expected[i] < expected[j] })
    	sort.Slice(ridList, func(i, j int) bool { return ridList[i] < ridList[j] })
    
    	if !reflect.DeepEqual(expected, ridList) {
    		t.Errorf("roundIdMap2List() failed to return the expected list."+
    			"\nexpected: %v\nreceived: %v", expected, ridList)
    	}
    
    }