Skip to content
Snippets Groups Projects
Commit aef81486 authored by Josh Brooks's avatar Josh Brooks
Browse files

Add tests for pruneHostPool & replaceHost

parent b24060a7
No related branches found
No related tags found
No related merge requests found
...@@ -21,7 +21,7 @@ require ( ...@@ -21,7 +21,7 @@ require (
gitlab.com/elixxir/crypto v0.0.7-0.20210319231554-b73b6e62ddbc gitlab.com/elixxir/crypto v0.0.7-0.20210319231554-b73b6e62ddbc
gitlab.com/elixxir/ekv v0.1.4 gitlab.com/elixxir/ekv v0.1.4
gitlab.com/elixxir/primitives v0.0.3-0.20210309193003-ef42ebb4800b 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.20210329190058-55f9bdf16249
gitlab.com/xx_network/crypto v0.0.5-0.20210319231335-249c6b1aa323 gitlab.com/xx_network/crypto v0.0.5-0.20210319231335-249c6b1aa323
gitlab.com/xx_network/primitives v0.0.4-0.20210309173740-eb8cd411334a gitlab.com/xx_network/primitives v0.0.4-0.20210309173740-eb8cd411334a
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
......
...@@ -284,6 +284,8 @@ gitlab.com/xx_network/comms v0.0.4-0.20210323140408-2b2613abb5a3 h1:Mh+YiOX89vG9 ...@@ -284,6 +284,8 @@ 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.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 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.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/crypto v0.0.3/go.mod h1:DF2HYvvCw9wkBybXcXAgQMzX+MiGbFPjwt3t17VRqRE= 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 h1:lpKOL5mTJ2awWMfgBy30oD/UvJVrWZzUimSHlOdZZxo=
gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk= gitlab.com/xx_network/crypto v0.0.4/go.mod h1:+lcQEy+Th4eswFgQDwT0EXKp4AXrlubxalwQFH5O0Mk=
......
...@@ -205,9 +205,8 @@ func (h *HostPool) pruneHostPool() error { ...@@ -205,9 +205,8 @@ func (h *HostPool) pruneHostPool() error {
for poolIdx := uint32(0); poolIdx < h.poolParams.poolSize; { for poolIdx := uint32(0); poolIdx < h.poolParams.poolSize; {
host := h.hostList[poolIdx] host := h.hostList[poolIdx]
// Check the Host for errors // 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 // If errors occurred, randomly select a new Gw by index in the NDF
ndfIdx := readRangeUint32(0, uint32(len(h.ndf.Gateways)), h.rng) ndfIdx := readRangeUint32(0, uint32(len(h.ndf.Gateways)), h.rng)
...@@ -220,6 +219,7 @@ func (h *HostPool) pruneHostPool() error { ...@@ -220,6 +219,7 @@ func (h *HostPool) pruneHostPool() error {
// Verify the GwId is not already in the hostMap // Verify the GwId is not already in the hostMap
if _, ok := h.hostMap[*gwId]; !ok { if _, ok := h.hostMap[*gwId]; !ok {
// If it is a new GwId, replace the old Host with the new Host // If it is a new GwId, replace the old Host with the new Host
err = h.replaceHost(gwId, poolIdx) err = h.replaceHost(gwId, poolIdx)
if err != nil { 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 (
"gitlab.com/xx_network/comms/connect"
"gitlab.com/xx_network/crypto/csprng"
"gitlab.com/xx_network/primitives/id"
"testing"
)
// Full happy path test
func TestReplaceHost(t *testing.T) {
manager := newHappyManager()
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 TestReplaceHost_Error(t *testing.T) {
manager := newHappyManager()
// 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 TestPruneHostPool(t *testing.T) {
manager := newHappyManager()
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)
}
// fixme: have a case where host's error threshold is met?
// 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())
}
}
}
// Error path: not enough gateways in ndf compared to
// required pool size
func TestPruneHostPool_Error(t *testing.T) {
manager := newHappyManager()
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")
}
}
\ No newline at end of file
package gateway
import (
"errors"
"gitlab.com/xx_network/comms/connect"
"gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/ndf"
)
// Mock structure adhering to HostManager which returns the error
// path for all it's methods
type MangerErrorPath struct {}
// Constructor for MangerErrorPath
func newErrorManager() *MangerErrorPath {
return &MangerErrorPath{}
}
func (mep *MangerErrorPath) GetHost(hostId *id.ID) (*connect.Host, bool) {
return nil, false
}
func (mep *MangerErrorPath) AddHost(hid *id.ID, address string,
cert []byte, params connect.HostParams) (host *connect.Host, err error) {
return nil, errors.New("Failed to add host")
}
func (mep *MangerErrorPath) RemoveHost(hid *id.ID) {}
// Mock structure adhering to HostManager to be used for happy path
type ManagerHappyPath struct {
hosts map[string]*connect.Host
}
// Constructor for ManagerHappyPath
func newHappyManager() *ManagerHappyPath {
return &ManagerHappyPath{
hosts: make(map[string]*connect.Host),
}
}
func (mhp *ManagerHappyPath) GetHost(hostId *id.ID) (*connect.Host, bool) {
h, ok := mhp.hosts[hostId.String()]
return h, ok
}
func (mhp *ManagerHappyPath) 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 *ManagerHappyPath) 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",
}},
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment