Skip to content
Snippets Groups Projects
Commit 9ab731a9 authored by Jake Taylor's avatar Jake Taylor :lips:
Browse files

Merge branch 'XX-3134/GwHostPoolTest' into 'XX-3134/GwHostPool'

Resolve XX-3134 "/gwhostpooltest"

See merge request !569
parents 88f41d14 db1a9f0d
Branches
Tags
No related merge requests found
......@@ -6,7 +6,7 @@ require (
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
github.com/golang/protobuf v1.4.3
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
github.com/liyue201/goqr v0.0.0-20200803022322-df443203d4ea // indirect
github.com/liyue201/goqr v0.0.0-20200803022322-df443203d4ea
github.com/magiconair/properties v1.8.4 // indirect
github.com/mitchellh/mapstructure v1.4.0 // indirect
github.com/pelletier/go-toml v1.8.1 // indirect
......@@ -23,7 +23,7 @@ require (
gitlab.com/elixxir/crypto v0.0.7-0.20210319231554-b73b6e62ddbc
gitlab.com/elixxir/ekv v0.1.4
gitlab.com/elixxir/primitives v0.0.3-0.20210309193003-ef42ebb4800b
gitlab.com/xx_network/comms v0.0.4-0.20210323205910-f01316c830dd
gitlab.com/xx_network/comms v0.0.4-0.20210331153942-daf17c8b6b47
gitlab.com/xx_network/crypto v0.0.5-0.20210319231335-249c6b1aa323
gitlab.com/xx_network/primitives v0.0.4-0.20210309173740-eb8cd411334a
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
......
......@@ -292,6 +292,12 @@ gitlab.com/xx_network/comms v0.0.4-0.20210323140408-2b2613abb5a3 h1:Mh+YiOX89vG9
gitlab.com/xx_network/comms v0.0.4-0.20210323140408-2b2613abb5a3/go.mod h1:0Hx+zO3Pr4uYw4RZXFnPM3ocjY6bPIKDiHCjWTZLOSI=
gitlab.com/xx_network/comms v0.0.4-0.20210323205910-f01316c830dd h1:WZn6y52gqigTXBAdsDRM3KWNBwnPEnYoGcBrsSAuphI=
gitlab.com/xx_network/comms v0.0.4-0.20210323205910-f01316c830dd/go.mod h1:0Hx+zO3Pr4uYw4RZXFnPM3ocjY6bPIKDiHCjWTZLOSI=
gitlab.com/xx_network/comms v0.0.4-0.20210329190058-55f9bdf16249 h1:dDcesEGcAzN1C6PP7Y8T0Ky5c4mpRfhVFMZJKBrbQzk=
gitlab.com/xx_network/comms v0.0.4-0.20210329190058-55f9bdf16249/go.mod h1:0Hx+zO3Pr4uYw4RZXFnPM3ocjY6bPIKDiHCjWTZLOSI=
gitlab.com/xx_network/comms v0.0.4-0.20210330224545-2d0e07fb64c6 h1:LsxlArrT5mIM5rRbMuNp+PQPWrCbPKhunHO2MfznbsE=
gitlab.com/xx_network/comms v0.0.4-0.20210330224545-2d0e07fb64c6/go.mod h1:0Hx+zO3Pr4uYw4RZXFnPM3ocjY6bPIKDiHCjWTZLOSI=
gitlab.com/xx_network/comms v0.0.4-0.20210331153942-daf17c8b6b47 h1:r8qBdMtuQouVylWl5RPctlXzPldcbhI2bvYkeUB1Ia0=
gitlab.com/xx_network/comms v0.0.4-0.20210331153942-daf17c8b6b47/go.mod h1:0Hx+zO3Pr4uYw4RZXFnPM3ocjY6bPIKDiHCjWTZLOSI=
gitlab.com/xx_network/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt3t17VRqRE=
gitlab.com/xx_network/crypto v0.0.4 h1:lpKOL5mTJ2awWMfgBy30oD/UvJVrWZzUimSHlOdZZxo=
gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk=
......
......@@ -115,7 +115,6 @@ func (h *HostPool) GetAny(length int) []*connect.Host {
length = int(h.poolParams.poolSize)
}
result := make([]*connect.Host, length)
h.hostMux.RLock()
for i := 0; i < length; {
gwIdx := readRangeUint32(0, h.poolParams.poolSize, h.rng)
......@@ -212,9 +211,8 @@ func (h *HostPool) pruneHostPool() error {
for poolIdx := uint32(0); poolIdx < h.poolParams.poolSize; {
host := h.hostList[poolIdx]
// Check the Host for errors
if host == nil || *host.GetMetrics().ErrCounter >= h.poolParams.errThreshold {
if host == nil || host.GetMetrics().GetErrorCounter() >= h.poolParams.errThreshold {
// If errors occurred, randomly select a new Gw by index in the NDF
ndfIdx := readRangeUint32(0, uint32(len(h.ndf.Gateways)), h.rng)
......@@ -227,6 +225,7 @@ func (h *HostPool) pruneHostPool() error {
// Verify the GwId is not already in the hostMap
if _, ok := h.hostMap[*gwId]; !ok {
// If it is a new GwId, replace the old Host with the new Host
err = h.replaceHost(gwId, poolIdx)
if err != nil {
......
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package gateway
import (
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/storage"
"gitlab.com/elixxir/comms/network"
"gitlab.com/xx_network/comms/connect"
"gitlab.com/xx_network/crypto/csprng"
"gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/ndf"
"reflect"
"testing"
"time"
)
// Unit test
func TestNewHostPool(t *testing.T) {
manager := newMockManager()
rng := csprng.NewSystemRNG()
testNdf := getTestNdf(t)
testStorage := storage.InitTestingSession(t)
addGwChan := make(chan network.NodeGateway)
params := DefaultPoolParams()
params.poolSize = uint32(len(testNdf.Gateways))
// Pull all gateways from ndf into host manager
for _, gw := range testNdf.Gateways {
gwId, err := id.Unmarshal(gw.ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add mock gateway to manager
_, err = manager.AddHost(gwId, "", nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
t.FailNow()
}
}
// Call the constructor
_, err := NewHostPool(params, rng, testNdf, manager,
testStorage, addGwChan)
if err != nil {
t.Errorf("Failed to create mock host pool: %v", err)
}
}
// Unit test
func TestHostPool_ManageHostPool(t *testing.T) {
manager := newMockManager()
rng := csprng.NewSystemRNG()
testNdf := getTestNdf(t)
testStorage := storage.InitTestingSession(t)
addGwChan := make(chan network.NodeGateway)
// Construct custom params
params := DefaultPoolParams()
params.poolSize = uint32(len(testNdf.Gateways))
params.pruneInterval = 1 * time.Second
// Pull all gateways from ndf into host manager
for _, gw := range testNdf.Gateways {
gwId, err := id.Unmarshal(gw.ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add mock gateway to manager
_, err = manager.AddHost(gwId, gw.Address, nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
t.FailNow()
}
}
// Call the constructor
testPool, err := NewHostPool(params, rng, testNdf, manager,
testStorage, addGwChan)
if err != nil {
t.Errorf("Failed to create mock host pool: %v", err)
}
stopper := testPool.StartHostPool()
stopper.Close(3 * time.Second)
// Construct a list of new gateways/nodes to add to ndf
newGatewayLen := len(testNdf.Gateways)
newGateways := make([]ndf.Gateway, newGatewayLen)
newNodes := make([]ndf.Node, newGatewayLen)
for i := 0; i < newGatewayLen; i++ {
// Construct gateways
gwId := id.NewIdFromUInt(uint64(100+i), id.Gateway, t)
newGateways[i] = ndf.Gateway{ID: gwId.Bytes()}
// Construct nodes
nodeId := gwId.DeepCopy()
nodeId.SetType(id.Node)
newNodes[i] = ndf.Node{ID: nodeId.Bytes()}
}
newNdf := getTestNdf(t)
// Update the ndf, removing some gateways at a cutoff
newNdf.Gateways = newGateways
newNdf.Nodes = newNodes
testPool.UpdateNdf(newNdf)
time.Sleep(2 * time.Second)
// Check that old gateways are not in pool
for _, ndfGw := range testNdf.Gateways {
gwId, err := id.Unmarshal(ndfGw.ID)
if err != nil {
t.Errorf("Failed to marshal gateway id for %v", ndfGw)
}
if _, ok := testPool.hostMap[*gwId]; ok {
t.Errorf("Expected gateway %v to be removed from pool", gwId)
}
}
}
// Full happy path test
func TestHostPool_ReplaceHost(t *testing.T) {
manager := newMockManager()
testNdf := getTestNdf(t)
newIndex := uint32(20)
// Construct a manager (bypass business logic in constructor)
hostPool := &HostPool{
manager: manager,
hostList: make([]*connect.Host, newIndex+1),
hostMap: make(map[id.ID]uint32),
ndf: testNdf,
}
/* "Replace" a host with no entry */
// Pull a gateway ID from the ndf
gwIdOne, err := id.Unmarshal(testNdf.Gateways[0].ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add mock gateway to manager
_, err = manager.AddHost(gwIdOne, "", nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
}
// "Replace" (insert) the host
err = hostPool.replaceHost(gwIdOne, newIndex)
if err != nil {
t.Errorf("Could not replace host: %v", err)
}
// Check the state of the map has been correctly updated
retrievedIndex, ok := hostPool.hostMap[*gwIdOne]
if !ok {
t.Errorf("Expected insertion of gateway ID into map")
}
if retrievedIndex != newIndex {
t.Errorf("Index pulled from map not expected value."+
"\n\tExpected: %d"+
"\n\tReceived: %d", newIndex, retrievedIndex)
}
// Check that the state of the list list been correctly updated
retrievedHost := hostPool.hostList[newIndex]
if !gwIdOne.Cmp(retrievedHost.GetId()) {
t.Errorf("Id pulled from list is not expected."+
"\n\tExpected: %s"+
"\n\tReceived: %s", gwIdOne, retrievedHost.GetId())
}
/* Replace the initial host with a new host */
// Pull a different gateway ID from the ndf
gwIdTwo, err := id.Unmarshal(testNdf.Gateways[1].ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add second mock gateway to manager
_, err = manager.AddHost(gwIdTwo, "", nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
}
// Replace the old host
err = hostPool.replaceHost(gwIdTwo, newIndex)
if err != nil {
t.Errorf("Could not replace host: %v", err)
}
// Check that the state of the list been correctly updated for new host
retrievedHost = hostPool.hostList[newIndex]
if !gwIdTwo.Cmp(retrievedHost.GetId()) {
t.Errorf("Id pulled from list is not expected."+
"\n\tExpected: %s"+
"\n\tReceived: %s", gwIdTwo, retrievedHost.GetId())
}
// Check the state of the map has been correctly removed for the old gateway
retrievedOldIndex, ok := hostPool.hostMap[*gwIdOne]
if ok {
t.Errorf("Exoected old gateway to be cleared from map")
}
if retrievedOldIndex != 0 {
t.Errorf("Index pulled from map with old gateway as the key "+
"was not cleared."+
"\n\tExpected: %d"+
"\n\tReceived: %d", 0, retrievedOldIndex)
}
// Check the state of the map has been correctly updated for the old gateway
retrievedIndex, ok = hostPool.hostMap[*gwIdTwo]
if !ok {
t.Errorf("Expected insertion of gateway ID into map")
}
if retrievedIndex != newIndex {
t.Errorf("Index pulled from map using new gateway as the key "+
"was not updated."+
"\n\tExpected: %d"+
"\n\tReceived: %d", newIndex, retrievedIndex)
}
}
// Error path, could not get host
func TestHostPool_ReplaceHost_Error(t *testing.T) {
manager := newMockManager()
// Construct a manager (bypass business logic in constructor)
hostPool := &HostPool{
manager: manager,
hostList: make([]*connect.Host, 1),
hostMap: make(map[id.ID]uint32),
}
// Construct an unknown gateway ID to the manager
gatewayId := id.NewIdFromString("BadGateway", id.Gateway, t)
err := hostPool.replaceHost(gatewayId, 0)
if err == nil {
t.Errorf("Expected error in happy path: Should not be able to find a host")
}
}
// Happy path
func TestHostPool_PruneHostPool(t *testing.T) {
manager := newMockManager()
testNdf := getTestNdf(t)
newIndex := uint32(20)
params := DefaultPoolParams()
params.poolSize = uint32(len(testNdf.Gateways))
rng := csprng.NewSystemRNG()
// Construct a manager (bypass business logic in constructor)
hostPool := &HostPool{
manager: manager,
hostList: make([]*connect.Host, newIndex+1),
hostMap: make(map[id.ID]uint32),
ndf: testNdf,
poolParams: params,
rng: rng,
}
// Pull all gateways from ndf into host manager
hostList := make([]*connect.Host, 0)
for _, gw := range testNdf.Gateways {
gwId, err := id.Unmarshal(gw.ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add mock gateway to manager
h, err := manager.AddHost(gwId, "", nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
t.FailNow()
}
hostList = append(hostList, h)
}
// Construct a host past the error threshold
errorThresholdIndex := 0
overThreshold := params.errThreshold + 25
hostList[errorThresholdIndex].SetMetricsTesting(connect.NewMetricTesting(overThreshold, t), t)
oldHost := hostList[0]
// Call prune host pool
err := hostPool.pruneHostPool()
if err != nil {
t.Errorf("Unexpected error in happy path: %v", err)
}
// Check that the host map has been properly updated
for _, h := range hostList {
_, ok := hostPool.hostMap[*h.GetId()]
if !ok {
t.Errorf("Gateway %s was not placed in host map after pruning", h.GetId().String())
}
}
// Check that the host list has been has been properly updated
// at the index with a host past the error threshold
retrievedHost := hostPool.hostList[errorThresholdIndex]
if reflect.DeepEqual(oldHost, retrievedHost) {
t.Errorf("Expected host list to have it's bad host replaced. " +
"Contains old host information after pruning")
}
}
// Error path: not enough gateways in ndf compared to
// required pool size
func TestHostPool_PruneHostPool_Error(t *testing.T) {
manager := newMockManager()
testNdf := getTestNdf(t)
newIndex := uint32(20)
params := DefaultPoolParams()
// Trigger the case where the Ndf doesn't have enough gateways
params.poolSize = uint32(len(testNdf.Gateways)) + 1
rng := csprng.NewSystemRNG()
// Construct a manager (bypass business logic in constructor)
hostPool := &HostPool{
manager: manager,
hostList: make([]*connect.Host, newIndex+1),
hostMap: make(map[id.ID]uint32),
ndf: testNdf,
poolParams: params,
rng: rng,
}
// Call prune
err := hostPool.pruneHostPool()
if err == nil {
t.Errorf("Gateways should not be available: " +
"not enough gateways in ndf compared to param's pool size")
}
}
// Unit test
func TestHostPool_UpdateNdf(t *testing.T) {
manager := newMockManager()
testNdf := getTestNdf(t)
newIndex := uint32(20)
// Construct a manager (bypass business logic in constructor)
hostPool := &HostPool{
manager: manager,
hostList: make([]*connect.Host, newIndex+1),
hostMap: make(map[id.ID]uint32),
ndf: testNdf,
}
// Construct a new Ndf different from original one above
newNdf := getTestNdf(t)
newGateway := ndf.Gateway{
ID: id.NewIdFromUInt(27, id.Gateway, t).Bytes(),
}
newNdf.Gateways = append(newNdf.Gateways, newGateway)
// Update pool with the new Ndf
hostPool.UpdateNdf(newNdf)
// Check that the ndf update flag has been set
if !hostPool.isNdfUpdated {
t.Errorf("Expected ndf updated flag to be set after updateNdf call")
}
// Check that the host pool's ndf has been modified properly
if !reflect.DeepEqual(newNdf, hostPool.ndf) {
t.Errorf("Host pool ndf not updated to new ndf.")
}
}
// Full test
func TestHostPool_GetPreferred(t *testing.T) {
manager := newMockManager()
rng := csprng.NewSystemRNG()
testNdf := getTestNdf(t)
testStorage := storage.InitTestingSession(t)
addGwChan := make(chan network.NodeGateway)
params := DefaultPoolParams()
params.poolSize = uint32(len(testNdf.Gateways))
// Pull all gateways from ndf into host manager
hostMap := make(map[id.ID]bool, 0)
targets := make([]*id.ID, 0)
for _, gw := range testNdf.Gateways {
gwId, err := id.Unmarshal(gw.ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add mock gateway to manager
_, err = manager.AddHost(gwId, gw.Address, nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
t.FailNow()
}
hostMap[*gwId] = true
targets = append(targets, gwId)
}
// Call the constructor
testPool, err := NewHostPool(params, rng, testNdf, manager,
testStorage, addGwChan)
if err != nil {
t.Errorf("Failed to create mock host pool: %v", err)
}
retrievedList := testPool.GetPreferred(targets)
if len(retrievedList) != len(targets) {
t.Errorf("Requested list did not output requested length."+
"\n\tExpected: %d"+
"\n\tReceived: %v", len(targets), len(retrievedList))
}
// In case where all requested gateways are present
// ensure requested hosts were returned
for _, h := range retrievedList {
if !hostMap[*h.GetId()] {
t.Errorf("A target gateways which should have been returned was not."+
"\n\tExpected: %v", h.GetId())
}
}
// Replace a request with a gateway not in pool
targets[3] = id.NewIdFromUInt(74, id.Gateway, t)
retrievedList = testPool.GetPreferred(targets)
if len(retrievedList) != len(targets) {
t.Errorf("Requested list did not output requested length."+
"\n\tExpected: %d"+
"\n\tReceived: %v", len(targets), len(retrievedList))
}
// In case where a requested gateway is not present
for _, h := range retrievedList {
if h.GetId().Cmp(targets[3]) {
t.Errorf("Should not have returned ID not in pool")
}
}
}
// Unit test
func TestHostPool_GetAny(t *testing.T) {
manager := newMockManager()
rng := csprng.NewSystemRNG()
testNdf := getTestNdf(t)
testStorage := storage.InitTestingSession(t)
addGwChan := make(chan network.NodeGateway)
params := DefaultPoolParams()
params.poolSize = uint32(len(testNdf.Gateways))
// Pull all gateways from ndf into host manager
for _, gw := range testNdf.Gateways {
gwId, err := id.Unmarshal(gw.ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add mock gateway to manager
_, err = manager.AddHost(gwId, gw.Address, nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
t.FailNow()
}
}
// Call the constructor
testPool, err := NewHostPool(params, rng, testNdf, manager,
testStorage, addGwChan)
if err != nil {
t.Errorf("Failed to create mock host pool: %v", err)
}
requested := 3
anyList := testPool.GetAny(requested)
if len(anyList) != requested {
t.Errorf("GetAnyList did not get requested length."+
"\n\tExpected: %v"+
"\n\tReceived: %v", requested, len(anyList))
}
for _, h := range anyList {
_, ok := manager.GetHost(h.GetId())
if !ok {
t.Errorf("Host %s in retrieved list not in manager", h)
}
}
// Request more than are in host list
largeRequest := requested * 1000
largeRetrieved := testPool.GetAny(largeRequest)
if len(largeRetrieved) != len(testPool.hostList) {
t.Errorf("Large request should result in a list of all in host list")
}
}
// Unit test
func TestHostPool_ForceAdd(t *testing.T) {
manager := newMockManager()
rng := csprng.NewSystemRNG()
testNdf := getTestNdf(t)
testStorage := storage.InitTestingSession(t)
addGwChan := make(chan network.NodeGateway)
params := DefaultPoolParams()
params.poolSize = uint32(len(testNdf.Gateways))
// Pull all gateways from ndf into host manager
for _, gw := range testNdf.Gateways {
gwId, err := id.Unmarshal(gw.ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add mock gateway to manager
_, err = manager.AddHost(gwId, gw.Address, nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
t.FailNow()
}
}
// Call the constructor
testPool, err := NewHostPool(params, rng, testNdf, manager,
testStorage, addGwChan)
if err != nil {
t.Errorf("Failed to create mock host pool: %v", err)
}
// Construct a list of new gateways to add
newGatewayLen := 10
newGateways := make([]*id.ID, newGatewayLen)
for i := 0; i < newGatewayLen; i++ {
gwId := id.NewIdFromUInt(uint64(100+i), id.Gateway, t)
// Add mock gateway to manager
_, err = manager.AddHost(gwId, "", nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
t.FailNow()
}
newGateways[i] = gwId
}
// ForceAdd list of gateways
err = testPool.ForceAdd(newGateways)
if err != nil {
t.Errorf("Could not add gateways: %v", err)
}
for _, gw := range newGateways {
if _, ok := testPool.hostMap[*gw]; !ok {
t.Errorf("Failed to forcefully add new gateway ID: %v", gw)
}
}
}
// Unit test which only adds information to ndf
func TestHostPool_UpdateConns_AddGateways(t *testing.T) {
manager := newMockManager()
rng := csprng.NewSystemRNG()
testNdf := getTestNdf(t)
testStorage := storage.InitTestingSession(t)
addGwChan := make(chan network.NodeGateway)
params := DefaultPoolParams()
params.poolSize = uint32(len(testNdf.Gateways))
// Pull all gateways from ndf into host manager
for _, gw := range testNdf.Gateways {
gwId, err := id.Unmarshal(gw.ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add mock gateway to manager
_, err = manager.AddHost(gwId, gw.Address, nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
t.FailNow()
}
}
// Call the constructor
testPool, err := NewHostPool(params, rng, testNdf, manager,
testStorage, addGwChan)
if err != nil {
t.Errorf("Failed to create mock host pool: %v", err)
}
// Construct a list of new gateways/nodes to add to ndf
newGatewayLen := 10
newGateways := make([]ndf.Gateway, newGatewayLen)
newNodes := make([]ndf.Node, newGatewayLen)
for i := 0; i < newGatewayLen; i++ {
// Construct gateways
gwId := id.NewIdFromUInt(uint64(100+i), id.Gateway, t)
newGateways[i] = ndf.Gateway{ID: gwId.Bytes()}
// Construct nodes
nodeId := gwId.DeepCopy()
nodeId.SetType(id.Node)
newNodes[i] = ndf.Node{ID: nodeId.Bytes()}
}
// Update the ndf
newNdf := getTestNdf(t)
newNdf.Gateways = append(newNdf.Gateways, newGateways...)
newNdf.Nodes = append(newNdf.Nodes, newNodes...)
testPool.UpdateNdf(newNdf)
// Update the connections
err = testPool.updateConns()
if err != nil {
t.Errorf("Failed to update connections: %v", err)
}
// Check that new gateways are in manager
for _, ndfGw := range newGateways {
gwId, err := id.Unmarshal(ndfGw.ID)
if err != nil {
t.Errorf("Failed to marshal gateway id for %v", ndfGw)
}
_, ok := testPool.GetSpecific(gwId)
if !ok {
t.Errorf("Failed to find gateway %v in manager", gwId)
}
}
}
// Unit test which only adds information to ndf
func TestHostPool_UpdateConns_RemoveGateways(t *testing.T) {
manager := newMockManager()
rng := csprng.NewSystemRNG()
testNdf := getTestNdf(t)
testStorage := storage.InitTestingSession(t)
addGwChan := make(chan network.NodeGateway)
params := DefaultPoolParams()
params.poolSize = uint32(len(testNdf.Gateways))
// Pull all gateways from ndf into host manager
for _, gw := range testNdf.Gateways {
gwId, err := id.Unmarshal(gw.ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add mock gateway to manager
_, err = manager.AddHost(gwId, gw.Address, nil, connect.GetDefaultHostParams())
if err != nil {
t.Errorf("Could not add mock host to manager: %v", err)
t.FailNow()
}
}
// Call the constructor
testPool, err := NewHostPool(params, rng, testNdf, manager,
testStorage, addGwChan)
if err != nil {
t.Errorf("Failed to create mock host pool: %v", err)
}
// Construct a list of new gateways/nodes to add to ndf
newGatewayLen := len(testNdf.Gateways)
newGateways := make([]ndf.Gateway, newGatewayLen)
newNodes := make([]ndf.Node, newGatewayLen)
for i := 0; i < newGatewayLen; i++ {
// Construct gateways
gwId := id.NewIdFromUInt(uint64(100+i), id.Gateway, t)
newGateways[i] = ndf.Gateway{ID: gwId.Bytes()}
// Construct nodes
nodeId := gwId.DeepCopy()
nodeId.SetType(id.Node)
newNodes[i] = ndf.Node{ID: nodeId.Bytes()}
}
// Update the ndf, replacing old data entirely
newNdf := getTestNdf(t)
newNdf.Gateways = newGateways
newNdf.Nodes = newNodes
testPool.UpdateNdf(newNdf)
// Update the connections
err = testPool.updateConns()
if err != nil {
t.Errorf("Failed to update connections: %v", err)
}
// Check that old gateways are not in pool
for _, ndfGw := range testNdf.Gateways {
gwId, err := id.Unmarshal(ndfGw.ID)
if err != nil {
t.Errorf("Failed to marshal gateway id for %v", ndfGw)
}
if _, ok := testPool.hostMap[*gwId]; ok {
t.Errorf("Expected gateway %v to be removed from pool", gwId)
}
}
}
// Unit test
func TestHostPool_AddGateway(t *testing.T) {
manager := newMockManager()
testNdf := getTestNdf(t)
newIndex := uint32(20)
params := DefaultPoolParams()
params.poolSize = uint32(len(testNdf.Gateways))
// Construct a manager (bypass business logic in constructor)
hostPool := &HostPool{
manager: manager,
hostList: make([]*connect.Host, newIndex+1),
hostMap: make(map[id.ID]uint32),
ndf: testNdf,
addGatewayChan: make(chan network.NodeGateway),
storage: storage.InitTestingSession(t),
}
ndfIndex := 0
gwId, err := id.Unmarshal(testNdf.Gateways[ndfIndex].ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
hostPool.addGateway(gwId, ndfIndex)
_, ok := manager.GetHost(gwId)
if !ok {
t.Errorf("Unsuccessfully added host to manager")
}
}
// Unit test
func TestHostPool_RemoveGateway(t *testing.T) {
manager := newMockManager()
testNdf := getTestNdf(t)
newIndex := uint32(20)
params := DefaultPoolParams()
params.poolSize = uint32(len(testNdf.Gateways))
// Construct a manager (bypass business logic in constructor)
hostPool := &HostPool{
manager: manager,
hostList: make([]*connect.Host, newIndex+1),
hostMap: make(map[id.ID]uint32),
ndf: testNdf,
addGatewayChan: make(chan network.NodeGateway),
storage: storage.InitTestingSession(t),
}
ndfIndex := 0
gwId, err := id.Unmarshal(testNdf.Gateways[ndfIndex].ID)
if err != nil {
t.Errorf("Failed to unmarshal ID in mock ndf: %v", err)
}
// Add the new gateway host
h, err := hostPool.manager.AddHost(gwId, "", nil, params.hostParams)
if err != nil {
jww.ERROR.Printf("Could not add gateway host %s: %+v", gwId, err)
}
// Manually add host information
hostPool.hostMap[*gwId] = uint32(ndfIndex)
hostPool.hostList[ndfIndex] = h
// Call the removal
hostPool.removeGateway(gwId)
// Check that the map and list have been updated
if hostPool.hostList[ndfIndex] != nil {
t.Errorf("Host list index was not set to nil after removal")
}
if _, ok := hostPool.hostMap[*gwId]; ok {
t.Errorf("Host map did not delete host entry")
}
}
package gateway
import (
"gitlab.com/xx_network/comms/connect"
"gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/ndf"
)
// Mock structure adhering to HostManager to be used for happy path
type mockManager struct {
hosts map[string]*connect.Host
}
// Constructor for mockManager
func newMockManager() *mockManager {
return &mockManager{
hosts: make(map[string]*connect.Host),
}
}
func (mhp *mockManager) GetHost(hostId *id.ID) (*connect.Host, bool) {
h, ok := mhp.hosts[hostId.String()]
return h, ok
}
func (mhp *mockManager) AddHost(hid *id.ID, address string,
cert []byte, params connect.HostParams) (host *connect.Host, err error) {
host, err = connect.NewHost(hid, address, cert, params)
if err != nil {
return nil, err
}
mhp.hosts[hid.String()] = host
return
}
func (mhp *mockManager) RemoveHost(hid *id.ID) {
delete(mhp.hosts, hid.String())
}
// Returns a mock
func getTestNdf(face interface{}) *ndf.NetworkDefinition {
return &ndf.NetworkDefinition{
Gateways: []ndf.Gateway{{
ID: id.NewIdFromUInt(0, id.Gateway, face)[:],
Address: "0.0.0.1",
}, {
ID: id.NewIdFromUInt(1, id.Gateway, face)[:],
Address: "0.0.0.2",
}, {
ID: id.NewIdFromUInt(2, id.Gateway, face)[:],
Address: "0.0.0.3",
}, {
ID: id.NewIdFromUInt(3, id.Gateway, face)[:],
Address: "0.0.0.1",
}, {
ID: id.NewIdFromUInt(4, id.Gateway, face)[:],
Address: "0.0.0.2",
}, {
ID: id.NewIdFromUInt(5, id.Gateway, face)[:],
Address: "0.0.0.3",
}, {
ID: id.NewIdFromUInt(6, id.Gateway, face)[:],
Address: "0.0.0.1",
}, {
ID: id.NewIdFromUInt(7, id.Gateway, face)[:],
Address: "0.0.0.2",
}, {
ID: id.NewIdFromUInt(8, id.Gateway, face)[:],
Address: "0.0.0.3",
}, {
ID: id.NewIdFromUInt(9, id.Gateway, face)[:],
Address: "0.0.0.1",
}, {
ID: id.NewIdFromUInt(10, id.Gateway, face)[:],
Address: "0.0.0.2",
}, {
ID: id.NewIdFromUInt(11, id.Gateway, face)[:],
Address: "0.0.0.3",
}},
Nodes: []ndf.Node{{
ID: id.NewIdFromUInt(0, id.Node, face)[:],
Address: "0.0.0.1",
}, {
ID: id.NewIdFromUInt(1, id.Node, face)[:],
Address: "0.0.0.2",
}, {
ID: id.NewIdFromUInt(2, id.Node, face)[:],
Address: "0.0.0.3",
}, {
ID: id.NewIdFromUInt(3, id.Node, face)[:],
Address: "0.0.0.1",
}, {
ID: id.NewIdFromUInt(4, id.Node, face)[:],
Address: "0.0.0.2",
}, {
ID: id.NewIdFromUInt(5, id.Node, face)[:],
Address: "0.0.0.3",
}, {
ID: id.NewIdFromUInt(6, id.Node, face)[:],
Address: "0.0.0.1",
}, {
ID: id.NewIdFromUInt(7, id.Node, face)[:],
Address: "0.0.0.2",
}, {
ID: id.NewIdFromUInt(8, id.Node, face)[:],
Address: "0.0.0.3",
}, {
ID: id.NewIdFromUInt(9, id.Node, face)[:],
Address: "0.0.0.1",
}, {
ID: id.NewIdFromUInt(10, id.Node, face)[:],
Address: "0.0.0.2",
}, {
ID: id.NewIdFromUInt(11, id.Node, face)[:],
Address: "0.0.0.3",
}},
}
}
......@@ -39,6 +39,7 @@ const ReturningGateway = "GetMessageRequest"
const FalsePositive = "FalsePositive"
const PayloadMessage = "Payload"
const ErrorGateway = "Error"
type mockMessageRetrievalComms struct {
testingSignature *testing.T
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment