From e472274ffab046509a83d7823cc98f8de80611b8 Mon Sep 17 00:00:00 2001
From: josh <josh@elixxir.io>
Date: Tue, 20 Apr 2021 10:54:32 -0700
Subject: [PATCH] Add testing for new functions

---
 network/gateway/hostpool_test.go | 153 ++++++++++++++++++-
 network/gateway/sender_test.go   | 251 +++++++++++++++++++++++++++++++
 network/gateway/utils_test.go    |  42 ++++++
 3 files changed, 442 insertions(+), 4 deletions(-)
 create mode 100644 network/gateway/sender_test.go

diff --git a/network/gateway/hostpool_test.go b/network/gateway/hostpool_test.go
index 1f3ffcc7c..9e48d9ae5 100644
--- a/network/gateway/hostpool_test.go
+++ b/network/gateway/hostpool_test.go
@@ -8,6 +8,7 @@
 package gateway
 
 import (
+	"fmt"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/comms/network"
@@ -250,8 +251,152 @@ func TestHostPool_ReplaceHost_Error(t *testing.T) {
 
 }
 
+// Unit test
+func TestHostPool_ForceReplace(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))
+
+	// 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.Fatalf("Failed to create mock host pool: %v", err)
+	}
+
+	// Add all gateways to hostPool's map
+	for index, gw := range testNdf.Gateways {
+		gwId, err := id.Unmarshal(gw.ID)
+		if err != nil {
+			t.Fatalf("Failed to unmarshal ID in mock ndf: %v", err)
+		}
+
+		err = testPool.replaceHost(gwId, uint32(index))
+		if err != nil {
+			t.Fatalf("Failed to replace host in set-up: %v", err)
+		}
+	}
+
+	oldGatewayIndex := 0
+	oldHost := testPool.hostList[oldGatewayIndex]
+
+	// Force replace the gateway at a given index
+	err = testPool.forceReplace(uint32(oldGatewayIndex))
+	if err != nil {
+		t.Errorf("Failed to force replace: %v", err)
+	}
+
+	// Ensure that old gateway has been removed from the map
+	if _, ok := testPool.hostMap[*oldHost.GetId()]; ok {
+		t.Errorf("Expected old host to be removed from map")
+	}
+
+	// Ensure we are disconnected from the old host
+	if isConnected, _ := oldHost.Connected(); isConnected {
+		t.Errorf("Failed to disconnect from old host %s", oldHost)
+	}
+
+}
+
+// Unit test
+func TestHostPool_CheckReplace(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)) - 5
+
+	// 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.Fatalf("Failed to create mock host pool: %v", err)
+	}
+
+	// Call check replace
+	oldGatewayIndex := 0
+	oldHost := testPool.hostList[oldGatewayIndex]
+	expectedError := fmt.Errorf(errorsList[0])
+	err = testPool.checkReplace(oldHost.GetId(), expectedError)
+	if err != nil {
+		t.Errorf("Failed to check replace: %v", err)
+	}
+
+	// Ensure that old gateway has been removed from the map
+	if _, ok := testPool.hostMap[*oldHost.GetId()]; ok {
+		t.Errorf("Expected old host to be removed from map")
+	}
+
+	// Ensure we are disconnected from the old host
+	if isConnected, _ := oldHost.Connected(); isConnected {
+		t.Errorf("Failed to disconnect from old host %s", oldHost)
+	}
+
+	// Check that an error not in the global list results in a no-op
+	goodGatewayIndex := 0
+	goodGateway := testPool.hostList[goodGatewayIndex]
+	unexpectedErr := fmt.Errorf("Not in global error list")
+	err = testPool.checkReplace(oldHost.GetId(), unexpectedErr)
+	if err != nil {
+		t.Errorf("Failed to check replace: %v", err)
+	}
+
+	// Ensure that gateway with an unexpected error was not modified
+	if _, ok := testPool.hostMap[*goodGateway.GetId()]; !ok {
+		t.Errorf("Expected gateway with non-expected error to not be modified")
+	}
+
+	// Ensure gateway host has not been disconnected
+	if isConnected, _ := oldHost.Connected(); isConnected {
+		t.Errorf("Should not disconnect from  %s", oldHost)
+	}
+
+}
+
 // TODO: Adapt to new methods
-//// Happy path
+// Happy path
 //func TestHostPool_PruneHostPool(t *testing.T) {
 //	manager := newMockManager()
 //	testNdf := getTestNdf(t)
@@ -544,7 +689,7 @@ func TestHostPool_ForceAdd(t *testing.T) {
 	testPool, err := newHostPool(params, rng, testNdf, manager,
 		testStorage, addGwChan)
 	if err != nil {
-		t.Errorf("Failed to create mock host pool: %v", err)
+		t.Fatalf("Failed to create mock host pool: %v", err)
 	}
 
 	// Construct a list of new gateways to add
@@ -555,8 +700,7 @@ func TestHostPool_ForceAdd(t *testing.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()
+			t.Fatalf("Could not add mock host to manager: %v", err)
 		}
 		newGateways[i] = gwId
 	}
@@ -567,6 +711,7 @@ func TestHostPool_ForceAdd(t *testing.T) {
 		t.Errorf("Could not add gateways: %v", err)
 	}
 
+	// check that gateways have been added to the map
 	for _, gw := range newGateways {
 		if _, ok := testPool.hostMap[*gw]; !ok {
 			t.Errorf("Failed to forcefully add new gateway ID: %v", gw)
diff --git a/network/gateway/sender_test.go b/network/gateway/sender_test.go
new file mode 100644
index 000000000..5b4d50e27
--- /dev/null
+++ b/network/gateway/sender_test.go
@@ -0,0 +1,251 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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/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"
+	"reflect"
+	"testing"
+)
+
+// Unit test
+func TestNewSender(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))
+
+	_, err := NewSender(params, rng, testNdf, manager, testStorage, addGwChan)
+	if err != nil {
+		t.Fatalf("Failed to create mock sender: %v", err)
+	}
+}
+
+// Unit test
+func TestSender_SendToAny(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()
+		}
+
+	}
+
+	sender, err := NewSender(params, rng, testNdf, manager, testStorage, addGwChan)
+	if err != nil {
+		t.Fatalf("Failed to create mock sender: %v", err)
+	}
+
+	// Add all gateways to hostPool's map
+	for index, gw := range testNdf.Gateways {
+		gwId, err := id.Unmarshal(gw.ID)
+		if err != nil {
+			t.Fatalf("Failed to unmarshal ID in mock ndf: %v", err)
+		}
+
+		err = sender.replaceHost(gwId, uint32(index))
+		if err != nil {
+			t.Fatalf("Failed to replace host in set-up: %v", err)
+		}
+	}
+
+	// Test sendToAny with test interfaces
+	result, err := sender.SendToAny(SendToAny_HappyPath)
+	if err != nil {
+		t.Errorf("Should not error in SendToAny happy path: %v", err)
+	}
+
+	if !reflect.DeepEqual(result, happyPathReturn) {
+		t.Errorf("Expected result not returnev via SendToAny interface."+
+			"\n\tExpected: %v"+
+			"\n\tReceived: %v", happyPathReturn, result)
+	}
+
+	_, err = sender.SendToAny(SendToAny_KnownError)
+	if err == nil {
+		t.Fatalf("Expected error path did not receive error")
+	}
+
+	_, err = sender.SendToAny(SendToAny_UnknownError)
+	if err == nil {
+		t.Fatalf("Expected error path did not receive error")
+	}
+
+}
+
+// Unit test
+func TestSender_SendToPreferred(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)) - 5
+
+	// Do not test proxy attempts code in this test
+	// (self contain to code specific in sendPreferred)
+	params.ProxyAttempts = 0
+
+	// 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()
+		}
+
+	}
+
+	sender, err := NewSender(params, rng, testNdf, manager, testStorage, addGwChan)
+	if err != nil {
+		t.Fatalf("Failed to create mock sender: %v", err)
+	}
+
+	preferredIndex := 0
+	preferredHost := sender.hostList[preferredIndex]
+
+	// Happy path
+	result, err := sender.SendToPreferred([]*id.ID{preferredHost.GetId()}, SendToPreferred_HappyPath)
+	if err != nil {
+		t.Errorf("Should not error in SendToPreferred happy path: %v", err)
+	}
+
+	if !reflect.DeepEqual(result, happyPathReturn) {
+		t.Errorf("Expected result not returnev via SendToPreferred interface."+
+			"\n\tExpected: %v"+
+			"\n\tReceived: %v", happyPathReturn, result)
+	}
+
+	// Call a send which returns an error which triggers replacement
+	_, err = sender.SendToPreferred([]*id.ID{preferredHost.GetId()}, SendToPreferred_KnownError)
+	if err == nil {
+		t.Fatalf("Expected error path did not receive error")
+	}
+
+	// Check the host has been replaced
+	if _, ok := sender.hostMap[*preferredHost.GetId()]; ok {
+		t.Errorf("Expected host %s to be removed due to error", preferredHost)
+	}
+
+	// Ensure we are disconnected from the old host
+	if isConnected, _ := preferredHost.Connected(); isConnected {
+		t.Errorf("ForceReplace error: Failed to disconnect from old host %s", preferredHost)
+	}
+
+	// Get a new host to test on
+	preferredIndex = 4
+	preferredHost = sender.hostList[preferredIndex]
+
+	// Unknown error return will not trigger replacement
+	_, err = sender.SendToPreferred([]*id.ID{preferredHost.GetId()}, SendToPreferred_UnknownError)
+	if err == nil {
+		t.Fatalf("Expected error path did not receive error")
+	}
+
+	// Check the host has not been replaced
+	if _, ok := sender.hostMap[*preferredHost.GetId()]; !ok {
+		t.Errorf("Host %s should not have been removed due on an unknown error", preferredHost)
+	}
+
+	// Ensure we are disconnected from the old host
+	if isConnected, _ := preferredHost.Connected(); isConnected {
+		t.Errorf("Should not disconnect from  %s", preferredHost)
+	}
+
+}
+
+func TestSender_SendToSpecific(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)) - 5
+
+	// Do not test proxy attempts code in this test
+	// (self contain to code specific in sendPreferred)
+	params.ProxyAttempts = 0
+
+	// 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()
+		}
+
+	}
+
+	sender, err := NewSender(params, rng, testNdf, manager, testStorage, addGwChan)
+	if err != nil {
+		t.Fatalf("Failed to create mock sender: %v", err)
+	}
+
+	preferredIndex := 0
+	preferredHost := sender.hostList[preferredIndex]
+
+	// Happy path
+	result, err := sender.SendToSpecific(preferredHost.GetId(), SendToSpecific_HappyPath)
+	if err != nil {
+		t.Errorf("Should not error in SendToSpecific happy path: %v", err)
+	}
+
+	if !reflect.DeepEqual(result, happyPathReturn) {
+		t.Errorf("Expected result not returnev via SendToSpecific interface."+
+			"\n\tExpected: %v"+
+			"\n\tReceived: %v", happyPathReturn, result)
+	}
+
+	// Ensure host is now in map
+	if _, ok := sender.hostMap[*preferredHost.GetId()]; !ok {
+		t.Errorf("Failed to forcefully add new gateway ID: %v", preferredHost.GetId())
+	}
+
+	_, err = sender.SendToSpecific(preferredHost.GetId(), SendToSpecific_Abort)
+	if err == nil {
+		t.Errorf("Expected sendSpecific to return an abort")
+	}
+
+}
diff --git a/network/gateway/utils_test.go b/network/gateway/utils_test.go
index 9cb76c783..0ec7dc11f 100644
--- a/network/gateway/utils_test.go
+++ b/network/gateway/utils_test.go
@@ -1,6 +1,14 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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 (
+	"fmt"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/ndf"
@@ -118,3 +126,37 @@ func getTestNdf(face interface{}) *ndf.NetworkDefinition {
 		}},
 	}
 }
+
+const happyPathReturn = "happyPathReturn"
+
+func SendToPreferred_HappyPath(host *connect.Host, target *id.ID) (interface{}, error) {
+	return happyPathReturn, nil
+}
+
+func SendToPreferred_KnownError(host *connect.Host, target *id.ID) (interface{}, error) {
+	return nil, fmt.Errorf(errorsList[0])
+}
+
+func SendToPreferred_UnknownError(host *connect.Host, target *id.ID) (interface{}, error) {
+	return nil, fmt.Errorf("Unexpected error: Oopsie")
+}
+
+func SendToAny_HappyPath(host *connect.Host) (interface{}, error) {
+	return happyPathReturn, nil
+}
+
+func SendToAny_KnownError(host *connect.Host) (interface{}, error) {
+	return nil, fmt.Errorf(errorsList[0])
+}
+
+func SendToAny_UnknownError(host *connect.Host) (interface{}, error) {
+	return nil, fmt.Errorf("Unexpected error: Oopsie")
+}
+
+func SendToSpecific_HappyPath(host *connect.Host, target *id.ID) (interface{}, bool, error) {
+	return happyPathReturn, false, nil
+}
+
+func SendToSpecific_Abort(host *connect.Host, target *id.ID) (interface{}, bool, error) {
+	return nil, true, fmt.Errorf(errorsList[0])
+}
-- 
GitLab