Select Git revision
sendRequests_test.go
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)
}
}