From df3cce95a83953184d2da06996d5aae46c2d76b4 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 11:51:51 +0200 Subject: [PATCH 01/22] wip: testutils --- consensus/e2e_tests/utils_test.go | 25 +- internal/testutil/bus.go | 93 +++++++ internal/testutil/consensus/mocks.go | 24 ++ .../testutil/constructors/constructors.go | 103 ++++++++ internal/testutil/identity.go | 1 + internal/testutil/keys.go | 44 ++++ internal/testutil/mockdns.go | 21 +- internal/testutil/p2p/constants.go | 15 ++ internal/testutil/p2p/mocknet.go | 45 ++++ internal/testutil/p2p/mocks.go | 41 ++++ internal/testutil/p2p/network.go | 111 +++++++++ internal/testutil/persistence/mocks.go | 85 +++++++ internal/testutil/runtime/genesis.go | 44 ++++ internal/testutil/runtime/mocks.go | 51 ++++ .../testutil/telemetry/event_metrics_agent.go | 38 +++ internal/testutil/telemetry/mocks.go | 49 ++++ .../testutil/telemetry/time_series_agent.go | 31 +++ p2p/module_raintree_test.go | 221 +++++++++-------- p2p/module_test.go | 22 +- p2p/raintree/peers_manager_test.go | 3 +- p2p/transport_encryption_test.go | 28 +-- p2p/utils_test.go | 226 +++--------------- 22 files changed, 969 insertions(+), 352 deletions(-) create mode 100644 internal/testutil/bus.go create mode 100644 internal/testutil/consensus/mocks.go create mode 100644 internal/testutil/constructors/constructors.go create mode 100644 internal/testutil/identity.go create mode 100644 internal/testutil/keys.go create mode 100644 internal/testutil/p2p/constants.go create mode 100644 internal/testutil/p2p/mocknet.go create mode 100644 internal/testutil/p2p/mocks.go create mode 100644 internal/testutil/p2p/network.go create mode 100644 internal/testutil/persistence/mocks.go create mode 100644 internal/testutil/runtime/genesis.go create mode 100644 internal/testutil/runtime/mocks.go create mode 100644 internal/testutil/telemetry/event_metrics_agent.go create mode 100644 internal/testutil/telemetry/mocks.go create mode 100644 internal/testutil/telemetry/time_series_agent.go diff --git a/consensus/e2e_tests/utils_test.go b/consensus/e2e_tests/utils_test.go index 41340abc6..2f533b21b 100644 --- a/consensus/e2e_tests/utils_test.go +++ b/consensus/e2e_tests/utils_test.go @@ -3,6 +3,9 @@ package e2e_tests import ( "context" "fmt" + "github.com/pokt-network/pocket/internal/testutil/p2p" + "github.com/pokt-network/pocket/internal/testutil/persistence" + telemetry_testutil "github.com/pokt-network/pocket/internal/testutil/telemetry" "os" "reflect" "sort" @@ -13,7 +16,6 @@ import ( "github.com/golang/mock/gomock" "github.com/pokt-network/pocket/consensus" typesCons "github.com/pokt-network/pocket/consensus/types" - persistenceMocks "github.com/pokt-network/pocket/persistence/types/mocks" "github.com/pokt-network/pocket/runtime" "github.com/pokt-network/pocket/runtime/configs" "github.com/pokt-network/pocket/runtime/defaults" @@ -101,7 +103,7 @@ func CreateTestConsensusPocketNode( bus modules.Bus, eventsChannel modules.EventsChannel, ) *shared.Node { - persistenceMock := basePersistenceMock(t, eventsChannel, bus) + persistenceMock := persistence_testutil.PersistenceMockWithBlockStore(t, eventsChannel, bus) bus.RegisterModule(persistenceMock) consensusMod, err := consensus.Create(bus) @@ -115,9 +117,9 @@ func CreateTestConsensusPocketNode( runtimeMgr := (bus).GetRuntimeMgr() // TODO(olshansky): At the moment we are using the same base mocks for all the tests, // but note that they will need to be customized on a per test basis. - p2pMock := baseP2PMock(t, eventsChannel) + p2pMock := p2p_testutil.BaseP2PMock(t, eventsChannel) utilityMock := baseUtilityMock(t, eventsChannel, runtimeMgr.GetGenesis(), consensusModule) - telemetryMock := baseTelemetryMock(t, eventsChannel) + telemetryMock := telemetry_testutil.MinimalTelemetryMock(t) loggerMock := baseLoggerMock(t, eventsChannel) rpcMock := baseRpcMock(t, eventsChannel) @@ -548,21 +550,6 @@ func baseReplicaUtilityUnitOfWorkMock(t *testing.T, genesisState *genesis.Genesi return utilityReplicaUnitOfWorkMock } -func baseTelemetryMock(t *testing.T, _ modules.EventsChannel) *mockModules.MockTelemetryModule { - ctrl := gomock.NewController(t) - telemetryMock := mockModules.NewMockTelemetryModule(ctrl) - timeSeriesAgentMock := baseTelemetryTimeSeriesAgentMock(t) - eventMetricsAgentMock := baseTelemetryEventMetricsAgentMock(t) - - telemetryMock.EXPECT().Start().Return(nil).AnyTimes() - telemetryMock.EXPECT().SetBus(gomock.Any()).Return().AnyTimes() - telemetryMock.EXPECT().GetTimeSeriesAgent().Return(timeSeriesAgentMock).AnyTimes() - telemetryMock.EXPECT().GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() - telemetryMock.EXPECT().GetModuleName().Return(modules.TelemetryModuleName).AnyTimes() - - return telemetryMock -} - func baseRpcMock(t *testing.T, _ modules.EventsChannel) *mockModules.MockRPCModule { ctrl := gomock.NewController(t) rpcMock := mockModules.NewMockRPCModule(ctrl) diff --git a/internal/testutil/bus.go b/internal/testutil/bus.go new file mode 100644 index 000000000..6a0ea6102 --- /dev/null +++ b/internal/testutil/bus.go @@ -0,0 +1,93 @@ +package testutil + +import ( + "github.com/golang/mock/gomock" + "github.com/pokt-network/pocket/p2p/providers/current_height_provider" + "github.com/pokt-network/pocket/p2p/providers/peerstore_provider" + "github.com/pokt-network/pocket/runtime" + "github.com/pokt-network/pocket/shared/messaging" + "github.com/regen-network/gocuke" + + "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/mocks" +) + +type BusEventHandler func(*messaging.PocketEnvelope) +type BusEventHandlerFactory func(t gocuke.TestingT, bus modules.Bus) BusEventHandler + +// MinimalBusMock returns a bus mock with a module registry and minimal +// expectations registered to maximize re-usability. +func MinimalBusMock( + t gocuke.TestingT, + runtimeMgr modules.RuntimeMgr, +) *mock_modules.MockBus { + t.Helper() + + ctrl := gomock.NewController(t) + busMock := mock_modules.NewMockBus(ctrl) + busMock.EXPECT().GetRuntimeMgr().Return(runtimeMgr).AnyTimes() + busMock.EXPECT().RegisterModule(gomock.Any()).DoAndReturn(func(m modules.Module) { + m.SetBus(busMock) + }).AnyTimes() + + mockModulesRegistry := mock_modules.NewMockModulesRegistry(ctrl) + + // TODO_THIS_COMMIT: refactor - this doesn't belong here + mockModulesRegistry.EXPECT().GetModule(peerstore_provider.ModuleName).Return(nil, runtime.ErrModuleNotRegistered(peerstore_provider.ModuleName)).AnyTimes() + mockModulesRegistry.EXPECT().GetModule(current_height_provider.ModuleName).Return(nil, runtime.ErrModuleNotRegistered(current_height_provider.ModuleName)).AnyTimes() + + busMock.EXPECT().GetModulesRegistry().Return(mockModulesRegistry).AnyTimes() + return busMock +} + +// BaseBusMock returns a base bus mock which will accept any event, +// passing it to the provided handler function, any number of times. +func BaseBusMock( + t gocuke.TestingT, + runtimeMgr modules.RuntimeMgr, +) *mock_modules.MockBus { + t.Helper() + + return WithoutBusEventHandler(t, MinimalBusMock(t, runtimeMgr)) +} + +// BusMockWithEventHandler returns a base bus mock which will accept any event, +// any number of times, calling the `handler` returned from `handlerFactory` +// with the event as an argument. +func BusMockWithEventHandler( + t gocuke.TestingT, + runtimeMgr modules.RuntimeMgr, + handlerFactory BusEventHandlerFactory, +) *mock_modules.MockBus { + t.Helper() + + busMock := MinimalBusMock(t, runtimeMgr) + return WithBusEventHandler(t, busMock, handlerFactory) +} + +// WithBusEventHandler adds an expectation to a bus mock such that it will accept +// any event, any number of times, calling the `handler` returned from `handlerFactory` +// with the event as an argument. +func WithBusEventHandler( + t gocuke.TestingT, + busMock *mock_modules.MockBus, + handlerFactory BusEventHandlerFactory, +) *mock_modules.MockBus { + t.Helper() + + handler := handlerFactory(t, busMock) + busMock.EXPECT().PublishEventToBus(gomock.Any()).Do(handler).AnyTimes() + return busMock +} + +// WithoutBusEventHandler adds an expectation to a bus mock such that it will accept +// any event, any number of times. +func WithoutBusEventHandler( + t gocuke.TestingT, + busMock *mock_modules.MockBus, +) *mock_modules.MockBus { + t.Helper() + + busMock.EXPECT().PublishEventToBus(gomock.Any()).AnyTimes() + return busMock +} diff --git a/internal/testutil/consensus/mocks.go b/internal/testutil/consensus/mocks.go new file mode 100644 index 000000000..64888cfcb --- /dev/null +++ b/internal/testutil/consensus/mocks.go @@ -0,0 +1,24 @@ +package consensus_testutil + +import ( + "testing" + + "github.com/golang/mock/gomock" + + "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/mocks" +) + +// Consensus mock - only needed for validatorMap access +func PrepareConsensusMock(t *testing.T, busMock *mock_modules.MockBus) *mock_modules.MockConsensusModule { + ctrl := gomock.NewController(t) + consensusMock := mock_modules.NewMockConsensusModule(ctrl) + consensusMock.EXPECT().CurrentHeight().Return(uint64(1)).AnyTimes() + + consensusMock.EXPECT().GetBus().Return(busMock).AnyTimes() + consensusMock.EXPECT().SetBus(busMock).AnyTimes() + consensusMock.EXPECT().GetModuleName().Return(modules.ConsensusModuleName).AnyTimes() + busMock.RegisterModule(consensusMock) + + return consensusMock +} diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go new file mode 100644 index 000000000..6de6b7910 --- /dev/null +++ b/internal/testutil/constructors/constructors.go @@ -0,0 +1,103 @@ +package constructors + +import ( + "net" + + "github.com/golang/mock/gomock" + libp2pHost "github.com/libp2p/go-libp2p/core/host" + mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/regen-network/gocuke" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/pocket/internal/testutil" + p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" + "github.com/pokt-network/pocket/p2p" + "github.com/pokt-network/pocket/runtime/configs" + "github.com/pokt-network/pocket/runtime/configs/types" + "github.com/pokt-network/pocket/runtime/genesis" + cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/modules" + mock_modules "github.com/pokt-network/pocket/shared/modules/mocks" +) + +type peerIDString = string + +// NewP2PMocknetModules returns a map of peer IDs to P2PModules using libp2p mocknet hosts. +func NewP2PModulesAndMocknet( + t gocuke.TestingT, + count int, + genesisState *genesis.GenesisState, + busEventHandlerFactory testutil.BusEventHandlerFactory, +) ( + buses map[peerIDString]modules.Bus, + p2pModules map[peerIDString]modules.P2PModule, + libp2pNetworkMock mocknet.Mocknet, +) { + libp2pNetworkMock = mocknet.New() + // destroy mocknet on test cleanup + t.Cleanup(func() { + err := libp2pNetworkMock.Close() + require.NoError(t, err) + }) + + // CONSIDERATION: using an iterator/generator would prevent unintentional + // ID collisions + privKeys := testutil.LoadLocalnetPrivateKeys(t, count) + + // CONSIDERATION: using an iterator/generator would prevent unintentional + // serviceURL collisions + serviceURLs := p2p_testutil.SequentialServiceURLs(t, count) + peerIDs := p2p_testutil.SetupMockNetPeers(t, libp2pNetworkMock, privKeys, serviceURLs) + + for i, peerID := range peerIDs { + // TECHDEBT: refactor + host := libp2pNetworkMock.Hosts()[i] + peerIDStr := peerID.String() + buses[peerIDStr], p2pModules[peerIDStr] = NewP2PModuleWithHost( + t, privKeys[i], + serviceURLs[i], + host, + genesisState, + busEventHandlerFactory, + ) + } + return buses, p2pModules, libp2pNetworkMock +} + +// TODO_THIS_COMMIT: consider following create factory convention (?) +func NewP2PModuleWithHost( + t gocuke.TestingT, + privKey cryptoPocket.PrivateKey, + serviceURL string, + host libp2pHost.Host, + genesisState *genesis.GenesisState, + busEventHandlerFactory testutil.BusEventHandlerFactory, +) (modules.Bus, modules.P2PModule) { + t.Helper() + + hostname, _, err := net.SplitHostPort(serviceURL) + require.NoError(t, err) + + // TODO_THIS_COMMIT: refactor to `BaseNodeMocks` or something + ctrl := gomock.NewController(t) + runtimeMgrMock := mock_modules.NewMockRuntimeMgr(ctrl) + runtimeMgrMock.EXPECT().GetConfig().Return(&configs.Config{ + P2P: &configs.P2PConfig{ + PrivateKey: privKey.String(), + Hostname: hostname, + //Port: 0, + ConnectionType: types.ConnectionType_TCPConnection, + MaxNonces: 100, + //IsClientOnly: false, + //BootstrapNodesCsv: "", + }, + }).AnyTimes() + + busMock := testutil.BusMockWithEventHandler(t, runtimeMgrMock, busEventHandlerFactory) + busMock.EXPECT().GetRuntimeMgr().Return(runtimeMgrMock).AnyTimes() + + mod, err := p2p.Create(busMock, p2p.WithHostOption(host)) + require.NoError(t, err) + + return busMock, mod.(modules.P2PModule) +} diff --git a/internal/testutil/identity.go b/internal/testutil/identity.go new file mode 100644 index 000000000..110b2e6a7 --- /dev/null +++ b/internal/testutil/identity.go @@ -0,0 +1 @@ +package testutil diff --git a/internal/testutil/keys.go b/internal/testutil/keys.go new file mode 100644 index 000000000..c9de34064 --- /dev/null +++ b/internal/testutil/keys.go @@ -0,0 +1,44 @@ +package testutil + +import ( + "bufio" + "os" + "path/filepath" + "regexp" + "runtime" + + cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + "github.com/stretchr/testify/require" +) + +var ( + privKeyManifestKeyRegex = regexp.MustCompile(`\s+"\d+":\s+(\w+)\s+`) +) + +func LoadLocalnetPrivateKeys(t require.TestingT, keyCount int) (privKeys []cryptoPocket.PrivateKey) { + _, filename, _, _ := runtime.Caller(0) + pkgDir := filepath.Dir(filename) + relativePathToKeys := filepath.Join(pkgDir, "..", "..", "build", "localnet", "manifests", "private-keys.yaml") + + privKeyManifest, err := os.Open(relativePathToKeys) + require.NoError(t, err) + + privKeys = make([]cryptoPocket.PrivateKey, 0, keyCount) + + // scann through file & extract private keys + scanner := bufio.NewScanner(privKeyManifest) + scanner.Split(bufio.ScanLines) + + for i, done := 0, false; i < keyCount || !done; i++ { + done = !scanner.Scan() + line := scanner.Text() + matches := privKeyManifestKeyRegex.FindStringSubmatch(line) + if len(matches) > 0 { + privKey, err := cryptoPocket.NewPrivateKey(matches[1]) + require.NoError(t, err) + + privKeys = append(privKeys, privKey) + } + } + return privKeys +} diff --git a/internal/testutil/mockdns.go b/internal/testutil/mockdns.go index 009a0e0fa..019a97860 100644 --- a/internal/testutil/mockdns.go +++ b/internal/testutil/mockdns.go @@ -2,15 +2,16 @@ package testutil import ( "fmt" - "net" - "net/url" - "testing" - "github.com/foxcpp/go-mockdns" + "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" + "net" + "net/url" ) -func PrepareDNSMockFromServiceURLs(t *testing.T, serviceURLs []string) (done func()) { +func PrepareDNSMockFromServiceURLs(t gocuke.TestingT, serviceURLs []string) (srv *mockdns.Server, done func()) { + t.Helper() + zones := make(map[string]mockdns.Zone) for i, u := range serviceURLs { // Perpend `scheme://` as serviceURLs are currently scheme-less. @@ -30,13 +31,15 @@ func PrepareDNSMockFromServiceURLs(t *testing.T, serviceURLs []string) (done fun } } - return PrepareDNSMock(zones) + return PrepareDNSMock(t, zones) } -func PrepareDNSMock(zones map[string]mockdns.Zone) (done func()) { - srv, _ := mockdns.NewServerWithLogger(zones, noopLogger{}, false) +func PrepareDNSMock(t gocuke.TestingT, zones map[string]mockdns.Zone) (srv *mockdns.Server, done func()) { + t.Helper() + + srv, _ = mockdns.NewServerWithLogger(zones, noopLogger{}, false) srv.PatchNet(net.DefaultResolver) - return func() { + return srv, func() { _ = srv.Close() mockdns.UnpatchNet(net.DefaultResolver) } diff --git a/internal/testutil/p2p/constants.go b/internal/testutil/p2p/constants.go new file mode 100644 index 000000000..8cc1f0bc9 --- /dev/null +++ b/internal/testutil/p2p/constants.go @@ -0,0 +1,15 @@ +package p2p_testutil + +import ( + "fmt" + + "github.com/pokt-network/pocket/runtime/defaults" +) + +var ( + // IP4ServiceURL is a string representing a valid IPv4 based ServiceURL using the loopback interface. + IP4ServiceURL = fmt.Sprintf("127.0.0.1:%d", defaults.DefaultP2PPort) + // IP6ServiceURL is a string representing a valid IPv6 based ServiceURL. + // (see: https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2) + IP6ServiceURL = fmt.Sprintf("[2a00:1450:4005:802::2004]:%d", defaults.DefaultP2PPort) +) diff --git a/internal/testutil/p2p/mocknet.go b/internal/testutil/p2p/mocknet.go new file mode 100644 index 000000000..e97234510 --- /dev/null +++ b/internal/testutil/p2p/mocknet.go @@ -0,0 +1,45 @@ +package p2p_testutil + +import ( + "testing" + + libp2pCrypto "github.com/libp2p/go-libp2p/core/crypto" + libp2pHost "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/pocket/p2p/types" + "github.com/pokt-network/pocket/p2p/utils" + "github.com/pokt-network/pocket/shared/crypto" +) + +func NewTestPeer(t *testing.T) (*types.NetworkPeer, libp2pHost.Host) { + t.Helper() + + selfPrivKey, err := crypto.GeneratePrivateKey() + require.NoError(t, err) + + selfAddr := selfPrivKey.Address() + selfPeer := &types.NetworkPeer{ + PublicKey: selfPrivKey.PublicKey(), + Address: selfAddr, + ServiceURL: IP4ServiceURL, + } + return selfPeer, NewLibp2pMockNetHost(t, selfPrivKey, selfPeer) +} + +func NewLibp2pMockNetHost(t *testing.T, privKey crypto.PrivateKey, peer *types.NetworkPeer) libp2pHost.Host { + t.Helper() + + libp2pPrivKey, err := libp2pCrypto.UnmarshalEd25519PrivateKey(privKey.Bytes()) + require.NoError(t, err) + + libp2pMultiAddr, err := utils.Libp2pMultiaddrFromServiceURL(peer.ServiceURL) + require.NoError(t, err) + + libp2pMockNet := mocknet.New() + host, err := libp2pMockNet.AddPeer(libp2pPrivKey, libp2pMultiAddr) + require.NoError(t, err) + + return host +} diff --git a/internal/testutil/p2p/mocks.go b/internal/testutil/p2p/mocks.go new file mode 100644 index 000000000..61c437a34 --- /dev/null +++ b/internal/testutil/p2p/mocks.go @@ -0,0 +1,41 @@ +package p2p_testutil + +import ( + "testing" + + "github.com/golang/mock/gomock" + "google.golang.org/protobuf/types/known/anypb" + + "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/messaging" + "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/mocks" +) + +// Creates a p2p module mock with mock implementations of some basic functionality +func BaseP2PMock(t *testing.T, eventsChannel modules.EventsChannel) *mock_modules.MockP2PModule { + ctrl := gomock.NewController(t) + p2pMock := mock_modules.NewMockP2PModule(ctrl) + + p2pMock.EXPECT().Start().Return(nil).AnyTimes() + p2pMock.EXPECT().SetBus(gomock.Any()).Return().AnyTimes() + p2pMock.EXPECT(). + Broadcast(gomock.Any()). + Do(func(msg *anypb.Any) { + e := &messaging.PocketEnvelope{Content: msg} + eventsChannel <- e + }). + AnyTimes() + // CONSIDERATION: Adding a check to not to send message to itself + p2pMock.EXPECT(). + Send(gomock.Any(), gomock.Any()). + Do(func(addr crypto.Address, msg *anypb.Any) { + e := &messaging.PocketEnvelope{Content: msg} + eventsChannel <- e + }). + AnyTimes() + p2pMock.EXPECT().GetModuleName().Return(modules.P2PModuleName).AnyTimes() + p2pMock.EXPECT().HandleEvent(gomock.Any()).Return(nil).AnyTimes() + + return p2pMock +} diff --git a/internal/testutil/p2p/network.go b/internal/testutil/p2p/network.go new file mode 100644 index 000000000..6ae35b1b9 --- /dev/null +++ b/internal/testutil/p2p/network.go @@ -0,0 +1,111 @@ +package p2p_testutil + +import ( + "fmt" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + libp2pPeer "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/regen-network/gocuke" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/pocket/internal/testutil" + "github.com/pokt-network/pocket/p2p/types" + "github.com/pokt-network/pocket/p2p/utils" + cryptoPocket "github.com/pokt-network/pocket/shared/crypto" +) + +func NewMocknetWithNPeers(t gocuke.TestingT, peerCount int) (mocknet.Mocknet, []string) { + t.Helper() + + // load pre-generated validator keypairs + libp2pNetworkMock := mocknet.New() + privKeys := testutil.LoadLocalnetPrivateKeys(t, peerCount) + serviceURLs := SequentialServiceURLs(t, peerCount) + _ = SetupMockNetPeers(t, libp2pNetworkMock, privKeys, serviceURLs) + + return libp2pNetworkMock, serviceURLs +} + +func SetupMockNetPeers( + t gocuke.TestingT, + netMock mocknet.Mocknet, + privKeys []cryptoPocket.PrivateKey, + serviceURLs []string, +) (peerIDs []peer.ID) { + t.Helper() + + // MUST add mockdns before any libp2p host comes online. Otherwise, it will + // error while attempting to resolve its own hostname. + _, dnsSrvDone := testutil.PrepareDNSMockFromServiceURLs(t, serviceURLs) + t.Cleanup(dnsSrvDone) + + // Add a libp2p peers/hosts to the `MockNet` with the keypairs corresponding + // to the genesis validators' keypairs + for i, peerInfo := range PeersFromPrivKeysAndServiceURLs(t, privKeys, serviceURLs) { + libp2pPrivKey, err := crypto.UnmarshalEd25519PrivateKey(privKeys[i].Bytes()) + require.NoError(t, err) + + _, err = netMock.AddPeer(libp2pPrivKey, peerInfo.Addrs[0]) + require.NoError(t, err) + + peerIDs = append(peerIDs, peerInfo.ID) + } + + // Link all peers such that any may dial/connect to any other. + err := netMock.LinkAll() + require.NoError(t, err) + + return peerIDs +} + +// CONSIDERATION: serviceURLs are only unique within their respective slice; +// consider building an iterator/generator instead. +func SequentialServiceURLs(t gocuke.TestingT, count int) (serviceURLs []string) { + t.Helper() + + for i := 0; i < count; i++ { + serviceURLs = append(serviceURLs, NewServiceURL(i+1)) + } + return serviceURLs +} + +func PeersFromPrivKeysAndServiceURLs( + t gocuke.TestingT, + privKeys []cryptoPocket.PrivateKey, + serviceURLs []string, +) (peersInfo []libp2pPeer.AddrInfo) { + t.Helper() + + serviceURLCount, privKeyCount := len(serviceURLs), len(privKeys) + maxCount := serviceURLCount + if privKeyCount < serviceURLCount { + maxCount = privKeyCount + } + + for i, privKey := range privKeys[:maxCount] { + peerInfo := peerFromPrivKeyAndServiceURL(t, privKey, NewServiceURL(i+1)) + peersInfo = append(peersInfo, peerInfo) + } + return peersInfo +} + +func peerFromPrivKeyAndServiceURL(t gocuke.TestingT, privKey cryptoPocket.PrivateKey, serviceURL string) libp2pPeer.AddrInfo { + t.Helper() + + peerInfo, err := utils.Libp2pAddrInfoFromPeer(&types.NetworkPeer{ + PublicKey: privKey.PublicKey(), + Address: privKey.Address(), + ServiceURL: serviceURL, + }) + require.NoError(t, err) + + return peerInfo +} + +const ServiceURLFormat = "node%d.consensus:42069" + +// TECHDEBT: rename `validatorId()` to `serviceURL()` +func NewServiceURL(i int) string { + return fmt.Sprintf(ServiceURLFormat, i) +} diff --git a/internal/testutil/persistence/mocks.go b/internal/testutil/persistence/mocks.go new file mode 100644 index 000000000..07702b867 --- /dev/null +++ b/internal/testutil/persistence/mocks.go @@ -0,0 +1,85 @@ +package persistence_testutil + +import ( + "fmt" + "github.com/pokt-network/pocket/persistence/types/mocks" + "github.com/pokt-network/pocket/shared/codec" + "github.com/pokt-network/pocket/shared/core/types" + "github.com/pokt-network/pocket/shared/utils" + "testing" + + "github.com/golang/mock/gomock" + + "github.com/pokt-network/pocket/runtime/genesis" + "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/mocks" +) + +// Persistence mock - only needed for validatorMap access +func BasePersistenceMock(t *testing.T, busMock *mock_modules.MockBus, genesisState *genesis.GenesisState) *mock_modules.MockPersistenceModule { + ctrl := gomock.NewController(t) + + persistenceModuleMock := mock_modules.NewMockPersistenceModule(ctrl) + readCtxMock := mock_modules.NewMockPersistenceReadContext(ctrl) + + readCtxMock.EXPECT().GetAllValidators(gomock.Any()).Return(genesisState.GetValidators(), nil).AnyTimes() + persistenceModuleMock.EXPECT().NewReadContext(gomock.Any()).Return(readCtxMock, nil).AnyTimes() + readCtxMock.EXPECT().Release().AnyTimes() + + persistenceModuleMock.EXPECT().GetBus().Return(busMock).AnyTimes() + persistenceModuleMock.EXPECT().SetBus(busMock).AnyTimes() + persistenceModuleMock.EXPECT().GetModuleName().Return(modules.PersistenceModuleName).AnyTimes() + busMock.RegisterModule(persistenceModuleMock) + + return persistenceModuleMock +} + +// Creates a persistence module mock with mock implementations of some basic functionality +func PersistenceMockWithBlockStore(t *testing.T, _ modules.EventsChannel, bus modules.Bus) *mock_modules.MockPersistenceModule { + ctrl := gomock.NewController(t) + persistenceMock := mock_modules.NewMockPersistenceModule(ctrl) + persistenceReadContextMock := mock_modules.NewMockPersistenceReadContext(ctrl) + + persistenceMock.EXPECT().GetModuleName().Return(modules.PersistenceModuleName).AnyTimes() + persistenceMock.EXPECT().Start().Return(nil).AnyTimes() + persistenceMock.EXPECT().SetBus(gomock.Any()).Return().AnyTimes() + persistenceMock.EXPECT().NewReadContext(gomock.Any()).Return(persistenceReadContextMock, nil).AnyTimes() + + persistenceMock.EXPECT().ReleaseWriteContext().Return(nil).AnyTimes() + + blockStoreMock := mock_kvstore.NewMockKVStore(ctrl) + + blockStoreMock.EXPECT().Get(gomock.Any()).DoAndReturn(func(height []byte) ([]byte, error) { + heightInt := utils.HeightFromBytes(height) + if bus.GetConsensusModule().CurrentHeight() < heightInt { + return nil, fmt.Errorf("requested height is higher than current height of the node's consensus module") + } + blockWithHeight := &types.Block{ + BlockHeader: &types.BlockHeader{ + Height: utils.HeightFromBytes(height), + }, + } + return codec.GetCodec().Marshal(blockWithHeight) + }).AnyTimes() + + persistenceMock.EXPECT().GetBlockStore().Return(blockStoreMock).AnyTimes() + + persistenceReadContextMock.EXPECT().GetMaximumBlockHeight().DoAndReturn(func() (uint64, error) { + height := bus.GetConsensusModule().CurrentHeight() + return height, nil + }).AnyTimes() + + persistenceReadContextMock.EXPECT().GetMinimumBlockHeight().DoAndReturn(func() (uint64, error) { + // mock minimum block height in persistence module to 1 if current height is equal or more than 1, else return 0 as the minimum height + if bus.GetConsensusModule().CurrentHeight() >= 1 { + return 1, nil + } + return 0, nil + }).AnyTimes() + + persistenceReadContextMock.EXPECT().GetAllValidators(gomock.Any()).Return(bus.GetRuntimeMgr().GetGenesis().Validators, nil).AnyTimes() + persistenceReadContextMock.EXPECT().GetBlockHash(gomock.Any()).Return("", nil).AnyTimes() + persistenceReadContextMock.EXPECT().Release().AnyTimes() + + return persistenceMock +} diff --git a/internal/testutil/runtime/genesis.go b/internal/testutil/runtime/genesis.go new file mode 100644 index 000000000..b1d30deb5 --- /dev/null +++ b/internal/testutil/runtime/genesis.go @@ -0,0 +1,44 @@ +package runtime_testutil + +import ( + "github.com/pokt-network/pocket/internal/testutil/p2p" + "github.com/pokt-network/pocket/runtime/genesis" + "github.com/pokt-network/pocket/runtime/test_artifacts" + "github.com/pokt-network/pocket/shared/core/types" + cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + "github.com/regen-network/gocuke" +) + +func BaseGenesisStateMock(t gocuke.TestingT, valKeys []cryptoPocket.PrivateKey, serviceURLs []string) *genesis.GenesisState { + t.Helper() + + genesisState := new(genesis.GenesisState) + validators := make([]*types.Actor, len(valKeys)) + for i, valKey := range valKeys { + addr := valKey.Address().String() + mockActor := &types.Actor{ + ActorType: types.ActorType_ACTOR_TYPE_VAL, + Address: addr, + PublicKey: valKey.PublicKey().String(), + ServiceUrl: serviceURLs[i], + StakedAmount: test_artifacts.DefaultStakeAmountString, + PausedHeight: int64(0), + UnstakingHeight: int64(0), + Output: addr, + } + validators[i] = mockActor + } + genesisState.Validators = validators + + return genesisState +} + +func GenesisWithSequentialServiceURLs(t gocuke.TestingT, valKeys []cryptoPocket.PrivateKey) *genesis.GenesisState { + t.Helper() + + serviceURLs := make([]string, len(valKeys)) + for i := range valKeys { + serviceURLs[i] = p2p_testutil.NewServiceURL(i) + } + return BaseGenesisStateMock(t, valKeys, serviceURLs) +} diff --git a/internal/testutil/runtime/mocks.go b/internal/testutil/runtime/mocks.go new file mode 100644 index 000000000..cf6549a08 --- /dev/null +++ b/internal/testutil/runtime/mocks.go @@ -0,0 +1,51 @@ +package runtime_testutil + +import ( + "net" + "strconv" + + "github.com/golang/mock/gomock" + "github.com/regen-network/gocuke" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/pocket/runtime/configs" + "github.com/pokt-network/pocket/runtime/configs/types" + "github.com/pokt-network/pocket/runtime/defaults" + "github.com/pokt-network/pocket/runtime/genesis" + cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/modules" + mock_modules "github.com/pokt-network/pocket/shared/modules/mocks" +) + +func BaseRuntimeManagerMock( + t gocuke.TestingT, + privKey cryptoPocket.PrivateKey, + serviceURL string, + genesisState *genesis.GenesisState, +) modules.RuntimeMgr { + ctrl := gomock.NewController(t) + runtimeMgrMock := mock_modules.NewMockRuntimeMgr(ctrl) + + hostname, portStr, err := net.SplitHostPort(serviceURL) + require.NoError(t, err) + + port, err := strconv.Atoi(portStr) + require.NoError(t, err) + + cfg := &configs.Config{ + RootDirectory: "", + // TODO: need this? + //PrivateKey: privKey.String(), + P2P: &configs.P2PConfig{ + Hostname: hostname, + PrivateKey: privKey.String(), + Port: uint32(port), + ConnectionType: types.ConnectionType_EmptyConnection, + MaxNonces: defaults.DefaultP2PMaxNonces, + }, + } + + runtimeMgrMock.EXPECT().GetConfig().Return(cfg).AnyTimes() + runtimeMgrMock.EXPECT().GetGenesis().Return(genesisState).AnyTimes() + return runtimeMgrMock +} diff --git a/internal/testutil/telemetry/event_metrics_agent.go b/internal/testutil/telemetry/event_metrics_agent.go new file mode 100644 index 000000000..f100c994a --- /dev/null +++ b/internal/testutil/telemetry/event_metrics_agent.go @@ -0,0 +1,38 @@ +package telemetry_testutil + +import ( + "log" + "sync" + "testing" + + "github.com/golang/mock/gomock" + "github.com/regen-network/gocuke" + + "github.com/pokt-network/pocket/shared/modules/mocks" + "github.com/pokt-network/pocket/telemetry" +) + +func BaseEventMetricsAgentMock(t gocuke.TestingT) *mock_modules.MockEventMetricsAgent { + t.Helper() + + ctrl := gomock.NewController(t) + eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + return eventMetricsAgentMock +} + +// TODO_THIS_COMMIT: refactor... +// Events metric mock - Needed to help with proper counts for number of expected network writes +func PrepareEventMetricsAgentMock(t *testing.T, valId string, wg *sync.WaitGroup, expectedNumNetworkWrites int) *mock_modules.MockEventMetricsAgent { + ctrl := gomock.NewController(t) + eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) + + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Eq(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).Do(func(n, e any, l ...any) { + log.Printf("[valId: %s] Write\n", valId) + wg.Done() + }).Times(expectedNumNetworkWrites) + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Not(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).AnyTimes() + + return eventMetricsAgentMock +} diff --git a/internal/testutil/telemetry/mocks.go b/internal/testutil/telemetry/mocks.go new file mode 100644 index 000000000..fa68c690b --- /dev/null +++ b/internal/testutil/telemetry/mocks.go @@ -0,0 +1,49 @@ +package telemetry_testutil + +import ( + "github.com/golang/mock/gomock" + "github.com/regen-network/gocuke" + + "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/mocks" +) + +func MinimalTelemetryMock(t gocuke.TestingT) modules.TelemetryModule { + t.Helper() + + ctrl := gomock.NewController(t) + telemetryMock := mock_modules.NewMockTelemetryModule(ctrl) + + telemetryMock.EXPECT().Start().Return(nil).AnyTimes() + telemetryMock.EXPECT().SetBus(gomock.Any()).Return().AnyTimes() + telemetryMock.EXPECT().GetModuleName().Return(modules.TelemetryModuleName).AnyTimes() + + return telemetryMock +} + +func BaseTelemetryMock(t gocuke.TestingT) modules.TelemetryModule { + t.Helper() + return WithTimeSeriesAgent(t, WithEventMetricsAgent(t, MinimalTelemetryMock(t))) +} + +func WithTimeSeriesAgent(t gocuke.TestingT, telemetryMod modules.TelemetryModule) modules.TelemetryModule { + t.Helper() + + telemetryMock := telemetryMod.(*mock_modules.MockTelemetryModule) + timeSeriesAgentMock := BaseTimeSeriesAgentMock(t) + eventMetricsAgentMock := BaseEventMetricsAgentMock(t) + + telemetryMock.EXPECT().GetTimeSeriesAgent().Return(timeSeriesAgentMock).AnyTimes() + telemetryMock.EXPECT().GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() + return telemetryMock +} + +func WithEventMetricsAgent(t gocuke.TestingT, telemetryMod modules.TelemetryModule) modules.TelemetryModule { + t.Helper() + + telemetryMock := telemetryMod.(*mock_modules.MockTelemetryModule) + eventMetricsAgentMock := BaseEventMetricsAgentMock(t) + + telemetryMock.EXPECT().GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() + return telemetryMock +} diff --git a/internal/testutil/telemetry/time_series_agent.go b/internal/testutil/telemetry/time_series_agent.go new file mode 100644 index 000000000..9d63dbd03 --- /dev/null +++ b/internal/testutil/telemetry/time_series_agent.go @@ -0,0 +1,31 @@ +package telemetry_testutil + +import ( + "testing" + + "github.com/golang/mock/gomock" + "github.com/regen-network/gocuke" + + "github.com/pokt-network/pocket/shared/modules/mocks" +) + +func BaseTimeSeriesAgentMock(t gocuke.TestingT) *mock_modules.MockTimeSeriesAgent { + t.Helper() + + ctrl := gomock.NewController(t) + timeSeriesAgentMock := mock_modules.NewMockTimeSeriesAgent(ctrl) + timeSeriesAgentMock.EXPECT().CounterRegister(gomock.Any(), gomock.Any()).AnyTimes() + timeSeriesAgentMock.EXPECT().CounterIncrement(gomock.Any()).AnyTimes() + return timeSeriesAgentMock +} + +// Noop mock - no specific business logic to tend to in the timeseries agent mock +func NoopTelemetryTimeSeriesAgentMock(t *testing.T) *mock_modules.MockTimeSeriesAgent { + ctrl := gomock.NewController(t) + timeseriesAgentMock := mock_modules.NewMockTimeSeriesAgent(ctrl) + + timeseriesAgentMock.EXPECT().CounterRegister(gomock.Any(), gomock.Any()).AnyTimes() + timeseriesAgentMock.EXPECT().CounterIncrement(gomock.Any()).AnyTimes() + + return timeseriesAgentMock +} diff --git a/p2p/module_raintree_test.go b/p2p/module_raintree_test.go index 9bd873913..085eacb65 100644 --- a/p2p/module_raintree_test.go +++ b/p2p/module_raintree_test.go @@ -1,24 +1,28 @@ //go:build test -package p2p +package p2p_test import ( + "github.com/pokt-network/pocket/internal/testutil" + "github.com/pokt-network/pocket/internal/testutil/constructors" + "github.com/pokt-network/pocket/internal/testutil/p2p" + "github.com/pokt-network/pocket/shared/messaging" + "github.com/pokt-network/pocket/shared/modules" + "github.com/regen-network/gocuke" "log" "os" "path/filepath" "regexp" "sort" "strconv" - "strings" "sync" "testing" - libp2pNetwork "github.com/libp2p/go-libp2p/core/network" - mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/anypb" - "github.com/pokt-network/pocket/internal/testutil" + consensus_testutil "github.com/pokt-network/pocket/internal/testutil/consensus" + persistence_testutil "github.com/pokt-network/pocket/internal/testutil/persistence" "github.com/pokt-network/pocket/p2p/protocol" "github.com/pokt-network/pocket/p2p/raintree" ) @@ -40,7 +44,7 @@ func TestMain(m *testing.M) { // ### RainTree Unit Tests ### func TestRainTreeNetworkCompleteOneNodes(t *testing.T) { // val_1 - originatorNode := validatorId(1) + originatorNode := p2p_testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ originatorNode: {0, 0}, // val_1, the originator, does 0 network reads or writes } @@ -51,14 +55,13 @@ func TestRainTreeNetworkCompleteTwoNodes(t *testing.T) { // val_1 // └───────┐ // val_2 - originatorNode := validatorId(1) + originatorNode := p2p_testutil.NewServiceURL(1) // Per the diagram above, in the case of a 2 node network, the originator node (val_1) does a // single write to another node (val_2), also the // originator node and never performs any reads or writes during a RainTree broadcast. expectedCalls := TestNetworkSimulationConfig{ - // Attempt: I think Validator 1 is sending a message in a 2 (including self) node network - originatorNode: {0, 1}, // val_1 does a single network write (to val_2) - validatorId(2): {1, 0}, // val_2 does a single network read (from val_1) + // Attempt: I think Validator 1 is sending a message in a 2 (including self) node network originatorNode: {0, 1}, // val_1 does a single network write (to val_2) + p2p_testutil.NewServiceURL(2): {1, 0}, // val_2 does a single network read (from val_1) } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -67,11 +70,11 @@ func TestRainTreeNetworkCompleteThreeNodes(t *testing.T) { // val_1 // ┌───────┴────┬─────────┐ // val_2 val_1 val_3 - originatorNode := validatorId(1) + originatorNode := p2p_testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {0, 2}, // val_1 does two network writes (to val_2 and val_3) - validatorId(2): {1, 0}, // val_2 does a single network read (from val_1) - validatorId(3): {1, 0}, // val_2 does a single network read (from val_3) + originatorNode: {0, 2}, // val_1 does two network writes (to val_2 and val_3) + p2p_testutil.NewServiceURL(2): {1, 0}, // val_2 does a single network read (from val_1) + p2p_testutil.NewServiceURL(3): {1, 0}, // val_2 does a single network read (from val_3) } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -83,12 +86,12 @@ func TestRainTreeNetworkCompleteFourNodes(t *testing.T) { // val_2 val_1 val_3 // └───────┐ └───────┐ └───────┐ // val_3 val_2 val_4 - originatorNode := validatorId(1) + originatorNode := p2p_testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {0, 3}, // val_1 does 3 network writes (two to val_2 and 1 to val_3) - validatorId(2): {2, 1}, // val_2 does 2 network reads (both from val_1) and 1 network write (to val_3) - validatorId(3): {2, 1}, // val_2 does 2 network reads (from val_1 and val_2) and 1 network write (to val_4) - validatorId(4): {1, 0}, // val_2 does 1 network read (from val_3) + originatorNode: {0, 3}, // val_1 does 3 network writes (two to val_2 and 1 to val_3) + p2p_testutil.NewServiceURL(2): {2, 1}, // val_2 does 2 network reads (both from val_1) and 1 network write (to val_3) + p2p_testutil.NewServiceURL(3): {2, 1}, // val_2 does 2 network reads (from val_1 and val_2) and 1 network write (to val_4) + p2p_testutil.NewServiceURL(4): {1, 0}, // val_2 does 1 network read (from val_3) } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -99,17 +102,17 @@ func TestRainTreeNetworkCompleteNineNodes(t *testing.T) { // val_4 val_1 val_7 // ┌───────┴────┬─────────┐ ┌───────┴────┬─────────┐ ┌───────┴────┬─────────┐ // val_6 val_4 val_8 val_3 val_1 val_5 val_9 val_7 val_2 - originatorNode := validatorId(1) + originatorNode := p2p_testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {0, 4}, - validatorId(2): {1, 0}, - validatorId(3): {1, 0}, - validatorId(4): {1, 2}, - validatorId(5): {1, 0}, - validatorId(6): {1, 0}, - validatorId(7): {1, 2}, - validatorId(8): {1, 0}, - validatorId(9): {1, 0}, + originatorNode: {0, 4}, + p2p_testutil.NewServiceURL(2): {1, 0}, + p2p_testutil.NewServiceURL(3): {1, 0}, + p2p_testutil.NewServiceURL(4): {1, 2}, + p2p_testutil.NewServiceURL(5): {1, 0}, + p2p_testutil.NewServiceURL(6): {1, 0}, + p2p_testutil.NewServiceURL(7): {1, 2}, + p2p_testutil.NewServiceURL(8): {1, 0}, + p2p_testutil.NewServiceURL(9): {1, 0}, } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -123,20 +126,20 @@ func TestRainTreeNetworkCompleteNineNodes(t *testing.T) { // val_8 val_7 val_10 val_6 val_5 val_8 val_11 val_10 val_5 val_4 val_3 val_6 val_2 val_1 val_4 val_7 val_6 val_1 val_12 val_11 val_2 val_10 val_9 val_12 val_3 val_2 val_9 func TestRainTreeCompleteTwelveNodes(t *testing.T) { - originatorNode := validatorId(1) + originatorNode := p2p_testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {1, 6}, - validatorId(2): {3, 2}, - validatorId(3): {2, 2}, - validatorId(4): {2, 0}, - validatorId(5): {2, 4}, - validatorId(6): {3, 2}, - validatorId(7): {2, 2}, - validatorId(8): {2, 0}, - validatorId(9): {2, 4}, - validatorId(10): {3, 2}, - validatorId(11): {2, 2}, - validatorId(12): {2, 0}, + originatorNode: {1, 6}, + p2p_testutil.NewServiceURL(2): {3, 2}, + p2p_testutil.NewServiceURL(3): {2, 2}, + p2p_testutil.NewServiceURL(4): {2, 0}, + p2p_testutil.NewServiceURL(5): {2, 4}, + p2p_testutil.NewServiceURL(6): {3, 2}, + p2p_testutil.NewServiceURL(7): {2, 2}, + p2p_testutil.NewServiceURL(8): {2, 0}, + p2p_testutil.NewServiceURL(9): {2, 4}, + p2p_testutil.NewServiceURL(10): {3, 2}, + p2p_testutil.NewServiceURL(11): {2, 2}, + p2p_testutil.NewServiceURL(12): {2, 0}, } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -149,26 +152,26 @@ func TestRainTreeNetworkCompleteEighteenNodes(t *testing.T) { // val_11 val_7 val_15 val_5 val_1 val_9 val_17 val_13 val_3 // ┌────────┴─────┬───────────┐ ┌───────┴────┬──────────┐ ┌────────┴─────┬──────────┐ ┌───────┴────┬──────────┐ ┌───────┴────┬─────────┐ ┌────────┴────┬─────────┐ ┌───────┴─────┬──────────┐ ┌────────┴─────┬───────────┐ ┌───────┴────┬──────────┐ // val_13 val_11 val_16 val_9 val_7 val_12 val_17 val_15 val_8 val_7 val_5 val_10 val_3 val_1 val_6 val_11 val_9 val_2 val_1 val_17 val_4 val_15 val_13 val_18 val_5 val_3 val_14 - originatorNode := validatorId(1) + originatorNode := p2p_testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {1, 6}, - validatorId(2): {1, 0}, - validatorId(3): {2, 2}, - validatorId(4): {1, 0}, - validatorId(5): {2, 2}, - validatorId(6): {1, 0}, - validatorId(7): {2, 4}, - validatorId(8): {1, 0}, - validatorId(9): {2, 2}, - validatorId(10): {1, 0}, - validatorId(11): {2, 2}, - validatorId(12): {1, 0}, - validatorId(13): {2, 4}, - validatorId(14): {1, 0}, - validatorId(15): {2, 2}, - validatorId(16): {1, 0}, - validatorId(17): {2, 2}, - validatorId(18): {1, 0}, + originatorNode: {1, 6}, + p2p_testutil.NewServiceURL(2): {1, 0}, + p2p_testutil.NewServiceURL(3): {2, 2}, + p2p_testutil.NewServiceURL(4): {1, 0}, + p2p_testutil.NewServiceURL(5): {2, 2}, + p2p_testutil.NewServiceURL(6): {1, 0}, + p2p_testutil.NewServiceURL(7): {2, 4}, + p2p_testutil.NewServiceURL(8): {1, 0}, + p2p_testutil.NewServiceURL(9): {2, 2}, + p2p_testutil.NewServiceURL(10): {1, 0}, + p2p_testutil.NewServiceURL(11): {2, 2}, + p2p_testutil.NewServiceURL(12): {1, 0}, + p2p_testutil.NewServiceURL(13): {2, 4}, + p2p_testutil.NewServiceURL(14): {1, 0}, + p2p_testutil.NewServiceURL(15): {2, 2}, + p2p_testutil.NewServiceURL(16): {1, 0}, + p2p_testutil.NewServiceURL(17): {2, 2}, + p2p_testutil.NewServiceURL(18): {1, 0}, } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -181,35 +184,35 @@ func TestRainTreeNetworkCompleteTwentySevenNodes(t *testing.T) { // val_16 val_10 val_22 val_7 val_1 val_13 val_25 val_19 val_4 // ┌────────┴─────┬───────────┐ ┌────────┴─────┬───────────┐ ┌────────┴─────┬───────────┐ ┌────────┴────┬──────────┐ ┌───────┴────┬─────────┐ ┌────────┴─────┬──────────┐ ┌───────┴─────┬──────────┐ ┌────────┴─────┬───────────┐ ┌───────┴────┬──────────┐ // val_20 val_16 val_24 val_14 val_10 val_18 val_26 val_22 val_12 val_11 val_7 val_15 val_5 val_1 val_9 val_17 val_13 val_3 val_2 val_25 val_6 val_23 val_19 val_27 val_8 val_4 val_21 - originatorNode := validatorId(1) + originatorNode := p2p_testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {0, 6}, - validatorId(2): {1, 0}, - validatorId(3): {1, 0}, - validatorId(4): {1, 2}, - validatorId(5): {1, 0}, - validatorId(6): {1, 0}, - validatorId(7): {1, 2}, - validatorId(8): {1, 0}, - validatorId(9): {1, 0}, - validatorId(10): {1, 4}, - validatorId(11): {1, 0}, - validatorId(12): {1, 0}, - validatorId(13): {1, 2}, - validatorId(14): {1, 0}, - validatorId(15): {1, 0}, - validatorId(16): {1, 2}, - validatorId(17): {1, 0}, - validatorId(18): {1, 0}, - validatorId(19): {1, 4}, - validatorId(20): {1, 0}, - validatorId(21): {1, 0}, - validatorId(22): {1, 2}, - validatorId(23): {1, 0}, - validatorId(24): {1, 0}, - validatorId(25): {1, 2}, - validatorId(26): {1, 0}, - validatorId(27): {1, 0}, + originatorNode: {0, 6}, + p2p_testutil.NewServiceURL(2): {1, 0}, + p2p_testutil.NewServiceURL(3): {1, 0}, + p2p_testutil.NewServiceURL(4): {1, 2}, + p2p_testutil.NewServiceURL(5): {1, 0}, + p2p_testutil.NewServiceURL(6): {1, 0}, + p2p_testutil.NewServiceURL(7): {1, 2}, + p2p_testutil.NewServiceURL(8): {1, 0}, + p2p_testutil.NewServiceURL(9): {1, 0}, + p2p_testutil.NewServiceURL(10): {1, 4}, + p2p_testutil.NewServiceURL(11): {1, 0}, + p2p_testutil.NewServiceURL(12): {1, 0}, + p2p_testutil.NewServiceURL(13): {1, 2}, + p2p_testutil.NewServiceURL(14): {1, 0}, + p2p_testutil.NewServiceURL(15): {1, 0}, + p2p_testutil.NewServiceURL(16): {1, 2}, + p2p_testutil.NewServiceURL(17): {1, 0}, + p2p_testutil.NewServiceURL(18): {1, 0}, + p2p_testutil.NewServiceURL(19): {1, 4}, + p2p_testutil.NewServiceURL(20): {1, 0}, + p2p_testutil.NewServiceURL(21): {1, 0}, + p2p_testutil.NewServiceURL(22): {1, 2}, + p2p_testutil.NewServiceURL(23): {1, 0}, + p2p_testutil.NewServiceURL(24): {1, 0}, + p2p_testutil.NewServiceURL(25): {1, 2}, + p2p_testutil.NewServiceURL(26): {1, 0}, + p2p_testutil.NewServiceURL(27): {1, 0}, } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -224,24 +227,38 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te numValidators := len(networkSimulationConfig) runtimeConfigs := createMockRuntimeMgrs(t, numValidators) genesisMock := runtimeConfigs[0].GetGenesis() - busMocks := createMockBuses(t, runtimeConfigs) + + var wg sync.WaitGroup + //busMocks := createMockBuses(t, runtimeConfigs, &wg) + busEventHandlerFactory := func(t gocuke.TestingT, bus modules.Bus) testutil.BusEventHandler { + return func(data *messaging.PocketEnvelope) { + // `p2pModule#handleNetworkData()` calls `modules.Bus#PublishEventToBus()` + // assumes that P2P module is the only event producer running during the test + wg.Done() + } + } + + busMocks, p2pModules, _ := constructors.NewP2PModulesAndMocknet( + t, numValidators, + genesisMock, + busEventHandlerFactory, + ) valIds := make([]string, 0, numValidators) for valId := range networkSimulationConfig { valIds = append(valIds, valId) } + // TODO_THIS_COMMIT: need this? + // sort `valIds` in ascending order sort.Slice(valIds, func(i, j int) bool { iId := extractNumericId(valIds[i]) jId := extractNumericId(valIds[j]) return iId < jId }) - testutil.PrepareDNSMockFromServiceURLs(t, valIds) - // Create connection and bus mocks along with a shared WaitGroup to track the number of expected // reads and writes throughout the mocked local network - var wg sync.WaitGroup for i, valId := range valIds { expectedCall := networkSimulationConfig[valId] expectedReads := expectedCall.numNetworkReads @@ -252,23 +269,19 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te wg.Add(expectedReads) wg.Add(expectedWrites) - persistenceMock := preparePersistenceMock(t, busMocks[i], genesisMock) - consensusMock := prepareConsensusMock(t, busMocks[i]) + persistenceMock := persistence_testutil.BasePersistenceMock(t, busMocks[i], genesisMock) + consensusMock := consensus_testutil.PrepareConsensusMock(t, busMocks[i]) telemetryMock := prepareTelemetryMock(t, busMocks[i], valId, &wg, expectedWrites) - prepareBusMock(busMocks[i], persistenceMock, consensusMock, telemetryMock) + busMocks[i].EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() + busMocks[i].EXPECT().GetConsensusModule().Return(consensusMock).AnyTimes() + busMocks[i].EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() } - libp2pMockNet := mocknet.New() - defer func() { - err := libp2pMockNet.Close() - require.NoError(t, err) - }() - // Inject the connection and bus mocks into the P2P modules - p2pModules := createP2PModules(t, busMocks, libp2pMockNet) + //p2pModules := createP2PModules(t, busMocks, libp2pNetworkMock, valIds) - for serviceURL, p2pMod := range p2pModules { + for _, p2pMod := range p2pModules { err := p2pMod.Start() require.NoError(t, err) diff --git a/p2p/module_test.go b/p2p/module_test.go index 79cd17066..85e6e858a 100644 --- a/p2p/module_test.go +++ b/p2p/module_test.go @@ -1,7 +1,12 @@ -package p2p +package p2p_test import ( "fmt" + "github.com/pokt-network/pocket/internal/testutil" + p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" + "github.com/pokt-network/pocket/internal/testutil/persistence" + "github.com/pokt-network/pocket/internal/testutil/runtime" + "github.com/pokt-network/pocket/p2p" "strings" "testing" @@ -111,10 +116,11 @@ func Test_Create_configureBootstrapNodes(t *testing.T) { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) mockRuntimeMgr := mockModules.NewMockRuntimeMgr(ctrl) - mockBus := createMockBus(t, mockRuntimeMgr) + mockBus := testutil.BaseBusMock(t, mockRuntimeMgr) - genesisStateMock := createMockGenesisState(keys) - persistenceMock := preparePersistenceMock(t, mockBus, genesisStateMock) + serviceURLs := p2p_testutil.SequentialServiceURLs(t, len(keys)) + genesisStateMock := runtime_testutil.BaseGenesisStateMock(t, keys, serviceURLs) + persistenceMock := persistence_testutil.BasePersistenceMock(t, mockBus, genesisStateMock) mockBus.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() mockConsensusModule := mockModules.NewMockConsensusModule(ctrl) @@ -137,7 +143,7 @@ func Test_Create_configureBootstrapNodes(t *testing.T) { } host := newLibp2pMockNetHost(t, privKey, peer) - p2pMod, err := Create(mockBus, WithHostOption(host)) + p2pMod, err := p2p.Create(mockBus, p2p.WithHostOption(host)) if (err != nil) != tt.wantErr { t.Errorf("p2pModule.Create() error = %v, wantErr %v", err, tt.wantErr) } @@ -155,10 +161,10 @@ func TestP2pModule_WithHostOption_Restart(t *testing.T) { privKey := cryptoPocket.GetPrivKeySeed(1) mockRuntimeMgr := mockModules.NewMockRuntimeMgr(ctrl) - mockBus := createMockBus(t, mockRuntimeMgr) + mockBus := testutil.BaseBusMock(t, mockRuntimeMgr) - genesisStateMock := createMockGenesisState(nil) - persistenceMock := preparePersistenceMock(t, mockBus, genesisStateMock) + genesisStateMock := runtime_testutil.BaseGenesisStateMock(t, nil, nil) + persistenceMock := persistence_testutil.BasePersistenceMock(t, mockBus, genesisStateMock) mockBus.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() consensusModuleMock := mockModules.NewMockConsensusModule(ctrl) diff --git a/p2p/raintree/peers_manager_test.go b/p2p/raintree/peers_manager_test.go index 7fa01a3d3..742080088 100644 --- a/p2p/raintree/peers_manager_test.go +++ b/p2p/raintree/peers_manager_test.go @@ -356,5 +356,6 @@ func mockAlphabetValidatorServiceURLsDNS(t *testing.T) (done func()) { } } - return testutil.PrepareDNSMock(zones) + _, done = testutil.PrepareDNSMock(t, zones) + return done } diff --git a/p2p/transport_encryption_test.go b/p2p/transport_encryption_test.go index d95cb6496..407f18e09 100644 --- a/p2p/transport_encryption_test.go +++ b/p2p/transport_encryption_test.go @@ -3,6 +3,11 @@ package p2p import ( "context" "fmt" + "github.com/pokt-network/pocket/internal/testutil" + p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" + "github.com/pokt-network/pocket/internal/testutil/persistence" + "github.com/pokt-network/pocket/internal/testutil/runtime" + "github.com/pokt-network/pocket/internal/testutil/telemetry" "testing" "time" @@ -11,7 +16,6 @@ import ( "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" - "github.com/pokt-network/pocket/internal/testutil" "github.com/pokt-network/pocket/p2p/protocol" typesP2P "github.com/pokt-network/pocket/p2p/types" "github.com/pokt-network/pocket/p2p/utils" @@ -19,7 +23,6 @@ import ( "github.com/pokt-network/pocket/runtime/configs/types" "github.com/pokt-network/pocket/runtime/defaults" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" - "github.com/pokt-network/pocket/shared/modules" mockModules "github.com/pokt-network/pocket/shared/modules/mocks" ) @@ -45,27 +48,18 @@ func TestP2pModule_Insecure_Error(t *testing.T) { }, }).AnyTimes() - timeSeriesAgentMock := prepareNoopTimeSeriesAgentMock(t) - eventMetricsAgentMock := mockModules.NewMockEventMetricsAgent(ctrl) - eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + telemetryMock := telemetry_testutil.BaseTelemetryMock(t) - telemetryMock := mockModules.NewMockTelemetryModule(ctrl) - telemetryMock.EXPECT().GetTimeSeriesAgent().Return(timeSeriesAgentMock).AnyTimes() - telemetryMock.EXPECT().GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() - telemetryMock.EXPECT().GetModuleName().Return(modules.TelemetryModuleName).AnyTimes() - - busMock := createMockBus(t, runtimeMgrMock) + busMock := testutil.BaseBusMock(t, runtimeMgrMock) busMock.EXPECT().GetConsensusModule().Return(mockConsensusModule).AnyTimes() - busMock.EXPECT().GetRuntimeMgr().Return(runtimeMgrMock).AnyTimes() busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() - genesisStateMock := createMockGenesisState(keys[:1]) - persistenceMock := preparePersistenceMock(t, busMock, genesisStateMock) + keys := testutil.LoadLocalnetPrivateKeys(t, 1) + serviceURLs := p2p_testutil.SequentialServiceURLs(t, 1) + genesisStateMock := runtime_testutil.BaseGenesisStateMock(t, keys, serviceURLs) + persistenceMock := persistence_testutil.BasePersistenceMock(t, busMock, genesisStateMock) busMock.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() - telemetryMock.EXPECT().GetBus().Return(busMock).AnyTimes() - telemetryMock.EXPECT().SetBus(busMock).AnyTimes() - serviceURLs := make([]string, len(genesisStateMock.Validators)) for i, actor := range genesisStateMock.Validators { serviceURLs[i] = actor.ServiceUrl diff --git a/p2p/utils_test.go b/p2p/utils_test.go index 66466acb0..706377dc7 100644 --- a/p2p/utils_test.go +++ b/p2p/utils_test.go @@ -1,41 +1,29 @@ -package p2p +package p2p_test import ( - "fmt" - "log" - "net" + "github.com/pokt-network/pocket/internal/testutil" + "github.com/pokt-network/pocket/internal/testutil/runtime" + "github.com/pokt-network/pocket/internal/testutil/telemetry" + "github.com/pokt-network/pocket/shared/messaging" + "github.com/regen-network/gocuke" "sort" - "strconv" "sync" "testing" "time" "github.com/golang/mock/gomock" - libp2pCrypto "github.com/libp2p/go-libp2p/core/crypto" - libp2pPeer "github.com/libp2p/go-libp2p/core/peer" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" - "github.com/pokt-network/pocket/p2p/providers/current_height_provider" - "github.com/pokt-network/pocket/p2p/providers/peerstore_provider" - typesP2P "github.com/pokt-network/pocket/p2p/types" - "github.com/pokt-network/pocket/p2p/utils" - "github.com/pokt-network/pocket/runtime" - "github.com/pokt-network/pocket/runtime/configs" - "github.com/pokt-network/pocket/runtime/configs/types" - "github.com/pokt-network/pocket/runtime/defaults" - "github.com/pokt-network/pocket/runtime/genesis" - "github.com/pokt-network/pocket/runtime/test_artifacts" - coreTypes "github.com/pokt-network/pocket/shared/core/types" + "github.com/stretchr/testify/require" + + p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/modules" mockModules "github.com/pokt-network/pocket/shared/modules/mocks" - "github.com/pokt-network/pocket/telemetry" - "github.com/stretchr/testify/require" ) // ~~~~~~ RainTree Unit Test Configurations ~~~~~~ const ( - serviceURLFormat = "node%d.consensus:42069" eventsChannelSize = 10000 // Since we simulate up to a 27 node network, we will pre-generate a n >= 27 number of keys to avoid generation // every time. The genesis config seed start is set for deterministic key generation and 42 was chosen arbitrarily. @@ -75,12 +63,6 @@ type TestNetworkSimulationConfig map[string]struct { // node IDs the specific read or write is coming from or going to. } -// CLEANUP: This could (should?) be a codebase-wide shared test helper -// TECHDEBT: rename `validatorId()` to `serviceURL()` -func validatorId(i int) string { - return fmt.Sprintf(serviceURLFormat, i) -} - func waitForNetworkSimulationCompletion(t *testing.T, wg *sync.WaitGroup) { // Wait for all messages to be transmitted done := make(chan struct{}) @@ -102,179 +84,61 @@ func waitForNetworkSimulationCompletion(t *testing.T, wg *sync.WaitGroup) { // ~~~~~~ RainTree Unit Test Mocks ~~~~~~ // createP2PModules returns a map of configured p2pModules keyed by an incremental naming convention (eg: `val_1`, `val_2`, etc.) -func createP2PModules(t *testing.T, busMocks []*mockModules.MockBus, netMock mocknet.Mocknet) (p2pModules map[string]*p2pModule) { - peerIDs := setupMockNetPeers(t, netMock, len(busMocks)) +func createP2PModules(t *testing.T, busMocks []*mockModules.MockBus, netMock mocknet.Mocknet, serviceURLs []string) (p2pModules map[string]*p2pModule) { + t.Helper() + + require.GreaterOrEqualf(t, len(serviceURLs), len(busMocks), "number of bus mocks must be less than or equal to the number of service URLs") + peerIDs := p2p_testutil.SetupMockNetPeers(t, netMock, keys[:len(busMocks)], serviceURLs) p2pModules = make(map[string]*p2pModule, len(busMocks)) for i := range busMocks { host := netMock.Host(peerIDs[i]) p2pMod, err := Create(busMocks[i], WithHostOption(host)) require.NoError(t, err) - p2pModules[validatorId(i+1)] = p2pMod.(*p2pModule) + p2pModules[serviceURLs[i]] = p2pMod.(*p2pModule) } return } -func setupMockNetPeers(t *testing.T, netMock mocknet.Mocknet, numPeers int) (peerIDs []libp2pPeer.ID) { - // Add a libp2p peers/hosts to the `MockNet` with the keypairs corresponding - // to the genesis validators' keypairs - for i, privKey := range keys[:numPeers] { - peerInfo, err := utils.Libp2pAddrInfoFromPeer(&typesP2P.NetworkPeer{ - PublicKey: privKey.PublicKey(), - Address: privKey.Address(), - ServiceURL: validatorId(i + 1), - }) - require.NoError(t, err) - - libp2pPrivKey, err := libp2pCrypto.UnmarshalEd25519PrivateKey(privKey.Bytes()) - require.NoError(t, err) - - _, err = netMock.AddPeer(libp2pPrivKey, peerInfo.Addrs[0]) - require.NoError(t, err) - - peerIDs = append(peerIDs, peerInfo.ID) - } - - // Link all peers such that any may dial/connect to any other. - err := netMock.LinkAll() - require.NoError(t, err) - - return peerIDs -} - // createMockRuntimeMgrs creates `numValidators` instances of mocked `RuntimeMgr` that are essentially // representing the runtime environments of the validators that we will use in our tests func createMockRuntimeMgrs(t *testing.T, numValidators int) []modules.RuntimeMgr { - ctrl := gomock.NewController(t) mockRuntimeMgrs := make([]modules.RuntimeMgr, numValidators) valKeys := make([]cryptoPocket.PrivateKey, numValidators) copy(valKeys, keys[:numValidators]) - mockGenesisState := createMockGenesisState(valKeys) + mockGenesisState := runtime_testutil.GenesisWithSequentialServiceURLs(t, valKeys) for i := range mockRuntimeMgrs { - serviceURL := validatorId(i + 1) - hostname, portStr, err := net.SplitHostPort(serviceURL) - require.NoError(t, err) - - port, err := strconv.Atoi(portStr) - require.NoError(t, err) - - cfg := &configs.Config{ - RootDirectory: "", - PrivateKey: valKeys[i].String(), - P2P: &configs.P2PConfig{ - Hostname: hostname, - PrivateKey: valKeys[i].String(), - Port: uint32(port), - ConnectionType: types.ConnectionType_EmptyConnection, - MaxNonces: defaults.DefaultP2PMaxNonces, - }, - } - - mockRuntimeMgr := mockModules.NewMockRuntimeMgr(ctrl) - mockRuntimeMgr.EXPECT().GetConfig().Return(cfg).AnyTimes() - mockRuntimeMgr.EXPECT().GetGenesis().Return(mockGenesisState).AnyTimes() - mockRuntimeMgrs[i] = mockRuntimeMgr + mockRuntimeMgrs[i] = runtime_testutil.BaseRuntimeManagerMock( + t, valKeys[i], + p2p_testutil.NewServiceURL(i+1), + mockGenesisState, + ) } return mockRuntimeMgrs } -func createMockBuses(t *testing.T, runtimeMgrs []modules.RuntimeMgr) []*mockModules.MockBus { +func createMockBuses(t *testing.T, runtimeMgrs []modules.RuntimeMgr, wg *sync.WaitGroup) []*mockModules.MockBus { mockBuses := make([]*mockModules.MockBus, len(runtimeMgrs)) for i := range mockBuses { - mockBuses[i] = createMockBus(t, runtimeMgrs[i]) - } - return mockBuses -} - -func createMockBus(t *testing.T, runtimeMgr modules.RuntimeMgr) *mockModules.MockBus { - ctrl := gomock.NewController(t) - mockBus := mockModules.NewMockBus(ctrl) - mockBus.EXPECT().GetRuntimeMgr().Return(runtimeMgr).AnyTimes() - mockBus.EXPECT().RegisterModule(gomock.Any()).DoAndReturn(func(m modules.Module) { - m.SetBus(mockBus) - }).AnyTimes() - mockModulesRegistry := mockModules.NewMockModulesRegistry(ctrl) - mockModulesRegistry.EXPECT().GetModule(peerstore_provider.ModuleName).Return(nil, runtime.ErrModuleNotRegistered(peerstore_provider.ModuleName)).AnyTimes() - mockModulesRegistry.EXPECT().GetModule(current_height_provider.ModuleName).Return(nil, runtime.ErrModuleNotRegistered(current_height_provider.ModuleName)).AnyTimes() - mockBus.EXPECT().GetModulesRegistry().Return(mockModulesRegistry).AnyTimes() - mockBus.EXPECT().PublishEventToBus(gomock.Any()).AnyTimes() - return mockBus -} - -// createMockGenesisState configures and returns a mocked GenesisState -func createMockGenesisState(valKeys []cryptoPocket.PrivateKey) *genesis.GenesisState { - genesisState := new(genesis.GenesisState) - validators := make([]*coreTypes.Actor, len(valKeys)) - for i, valKey := range valKeys { - addr := valKey.Address().String() - mockActor := &coreTypes.Actor{ - ActorType: coreTypes.ActorType_ACTOR_TYPE_VAL, - Address: addr, - PublicKey: valKey.PublicKey().String(), - ServiceUrl: validatorId(i + 1), - StakedAmount: test_artifacts.DefaultStakeAmountString, - PausedHeight: int64(0), - UnstakingHeight: int64(0), - Output: addr, + handlerFactory := func(t gocuke.TestingT, bus modules.Bus) testutil.BusEventHandler { + return func(data *messaging.PocketEnvelope) { + wg.Done() + } } - validators[i] = mockActor + mockBuses[i] = testutil.BusMockWithEventHandler(t, runtimeMgrs[i], handlerFactory) } - genesisState.Validators = validators - - return genesisState -} - -// Bus Mock - needed to return the appropriate modules when accessed -func prepareBusMock(busMock *mockModules.MockBus, - persistenceMock *mockModules.MockPersistenceModule, - consensusMock *mockModules.MockConsensusModule, - telemetryMock *mockModules.MockTelemetryModule, -) { - busMock.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() - busMock.EXPECT().GetConsensusModule().Return(consensusMock).AnyTimes() - busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() -} - -// Consensus mock - only needed for validatorMap access -func prepareConsensusMock(t *testing.T, busMock *mockModules.MockBus) *mockModules.MockConsensusModule { - ctrl := gomock.NewController(t) - consensusMock := mockModules.NewMockConsensusModule(ctrl) - consensusMock.EXPECT().CurrentHeight().Return(uint64(1)).AnyTimes() - - consensusMock.EXPECT().GetBus().Return(busMock).AnyTimes() - consensusMock.EXPECT().SetBus(busMock).AnyTimes() - consensusMock.EXPECT().GetModuleName().Return(modules.ConsensusModuleName).AnyTimes() - busMock.RegisterModule(consensusMock) - - return consensusMock -} - -// Persistence mock - only needed for validatorMap access -func preparePersistenceMock(t *testing.T, busMock *mockModules.MockBus, genesisState *genesis.GenesisState) *mockModules.MockPersistenceModule { - ctrl := gomock.NewController(t) - - persistenceModuleMock := mockModules.NewMockPersistenceModule(ctrl) - readCtxMock := mockModules.NewMockPersistenceReadContext(ctrl) - - readCtxMock.EXPECT().GetAllValidators(gomock.Any()).Return(genesisState.GetValidators(), nil).AnyTimes() - persistenceModuleMock.EXPECT().NewReadContext(gomock.Any()).Return(readCtxMock, nil).AnyTimes() - readCtxMock.EXPECT().Release().AnyTimes() - - persistenceModuleMock.EXPECT().GetBus().Return(busMock).AnyTimes() - persistenceModuleMock.EXPECT().SetBus(busMock).AnyTimes() - persistenceModuleMock.EXPECT().GetModuleName().Return(modules.PersistenceModuleName).AnyTimes() - busMock.RegisterModule(persistenceModuleMock) - - return persistenceModuleMock + return mockBuses } +// TODO_THIS_COMMIT: refactor // Telemetry mock - Needed to help with proper counts for number of expected network writes func prepareTelemetryMock(t *testing.T, busMock *mockModules.MockBus, valId string, wg *sync.WaitGroup, expectedNumNetworkWrites int) *mockModules.MockTelemetryModule { ctrl := gomock.NewController(t) telemetryMock := mockModules.NewMockTelemetryModule(ctrl) - timeSeriesAgentMock := prepareNoopTimeSeriesAgentMock(t) - eventMetricsAgentMock := prepareEventMetricsAgentMock(t, valId, wg, expectedNumNetworkWrites) + timeSeriesAgentMock := telemetry_testutil.BaseTimeSeriesAgentMock(t) + // TODO_THIS_COMMIT: refactor + eventMetricsAgentMock := telemetry_testutil.PrepareEventMetricsAgentMock(t, valId, wg, expectedNumNetworkWrites) telemetryMock.EXPECT().GetTimeSeriesAgent().Return(timeSeriesAgentMock).AnyTimes() telemetryMock.EXPECT().GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() @@ -286,29 +150,3 @@ func prepareTelemetryMock(t *testing.T, busMock *mockModules.MockBus, valId stri return telemetryMock } - -// Noop mock - no specific business logic to tend to in the timeseries agent mock -func prepareNoopTimeSeriesAgentMock(t *testing.T) *mockModules.MockTimeSeriesAgent { - ctrl := gomock.NewController(t) - timeseriesAgentMock := mockModules.NewMockTimeSeriesAgent(ctrl) - - timeseriesAgentMock.EXPECT().CounterRegister(gomock.Any(), gomock.Any()).AnyTimes() - timeseriesAgentMock.EXPECT().CounterIncrement(gomock.Any()).AnyTimes() - - return timeseriesAgentMock -} - -// Events metric mock - Needed to help with proper counts for number of expected network writes -func prepareEventMetricsAgentMock(t *testing.T, valId string, wg *sync.WaitGroup, expectedNumNetworkWrites int) *mockModules.MockEventMetricsAgent { - ctrl := gomock.NewController(t) - eventMetricsAgentMock := mockModules.NewMockEventMetricsAgent(ctrl) - - eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() - eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Eq(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).Do(func(n, e any, l ...any) { - log.Printf("[valId: %s] Write\n", valId) - wg.Done() - }).Times(expectedNumNetworkWrites) - eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Not(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).AnyTimes() - - return eventMetricsAgentMock -} From 1b4ea5d44f8814de93d1540a24d1ca17c59acb81 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 11 May 2023 09:37:30 +0200 Subject: [PATCH 02/22] wip: checkpoint --- .../testutil/constructors/constructors.go | 40 +++++-------------- p2p/module_raintree_test.go | 14 +++---- p2p/module_test.go | 18 +++++---- p2p/testutil.go | 6 +++ p2p/utils_test.go | 11 +++-- 5 files changed, 39 insertions(+), 50 deletions(-) create mode 100644 p2p/testutil.go diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 6de6b7910..50b049884 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -1,26 +1,22 @@ package constructors import ( - "net" - - "github.com/golang/mock/gomock" libp2pHost "github.com/libp2p/go-libp2p/core/host" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + runtime_testutil "github.com/pokt-network/pocket/internal/testutil/runtime" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" "github.com/pokt-network/pocket/internal/testutil" p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" "github.com/pokt-network/pocket/p2p" - "github.com/pokt-network/pocket/runtime/configs" - "github.com/pokt-network/pocket/runtime/configs/types" "github.com/pokt-network/pocket/runtime/genesis" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/modules" mock_modules "github.com/pokt-network/pocket/shared/modules/mocks" ) -type peerIDString = string +type serviceURLStr = string // NewP2PMocknetModules returns a map of peer IDs to P2PModules using libp2p mocknet hosts. func NewP2PModulesAndMocknet( @@ -29,8 +25,8 @@ func NewP2PModulesAndMocknet( genesisState *genesis.GenesisState, busEventHandlerFactory testutil.BusEventHandlerFactory, ) ( - buses map[peerIDString]modules.Bus, - p2pModules map[peerIDString]modules.P2PModule, + buses map[serviceURLStr]*mock_modules.MockBus, + p2pModules map[serviceURLStr]modules.P2PModule, libp2pNetworkMock mocknet.Mocknet, ) { libp2pNetworkMock = mocknet.New() @@ -47,13 +43,12 @@ func NewP2PModulesAndMocknet( // CONSIDERATION: using an iterator/generator would prevent unintentional // serviceURL collisions serviceURLs := p2p_testutil.SequentialServiceURLs(t, count) - peerIDs := p2p_testutil.SetupMockNetPeers(t, libp2pNetworkMock, privKeys, serviceURLs) + _ = p2p_testutil.SetupMockNetPeers(t, libp2pNetworkMock, privKeys, serviceURLs) - for i, peerID := range peerIDs { + for i, serviceURL := range serviceURLs { // TECHDEBT: refactor host := libp2pNetworkMock.Hosts()[i] - peerIDStr := peerID.String() - buses[peerIDStr], p2pModules[peerIDStr] = NewP2PModuleWithHost( + buses[serviceURL], p2pModules[serviceURL] = NewP2PModuleWithHost( t, privKeys[i], serviceURLs[i], host, @@ -72,27 +67,10 @@ func NewP2PModuleWithHost( host libp2pHost.Host, genesisState *genesis.GenesisState, busEventHandlerFactory testutil.BusEventHandlerFactory, -) (modules.Bus, modules.P2PModule) { +) (*mock_modules.MockBus, modules.P2PModule) { t.Helper() - hostname, _, err := net.SplitHostPort(serviceURL) - require.NoError(t, err) - - // TODO_THIS_COMMIT: refactor to `BaseNodeMocks` or something - ctrl := gomock.NewController(t) - runtimeMgrMock := mock_modules.NewMockRuntimeMgr(ctrl) - runtimeMgrMock.EXPECT().GetConfig().Return(&configs.Config{ - P2P: &configs.P2PConfig{ - PrivateKey: privKey.String(), - Hostname: hostname, - //Port: 0, - ConnectionType: types.ConnectionType_TCPConnection, - MaxNonces: 100, - //IsClientOnly: false, - //BootstrapNodesCsv: "", - }, - }).AnyTimes() - + runtimeMgrMock := runtime_testutil.BaseRuntimeManagerMock(t, privKey, serviceURL, genesisState) busMock := testutil.BusMockWithEventHandler(t, runtimeMgrMock, busEventHandlerFactory) busMock.EXPECT().GetRuntimeMgr().Return(runtimeMgrMock).AnyTimes() diff --git a/p2p/module_raintree_test.go b/p2p/module_raintree_test.go index 085eacb65..4c53a6f79 100644 --- a/p2p/module_raintree_test.go +++ b/p2p/module_raintree_test.go @@ -259,7 +259,7 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te // Create connection and bus mocks along with a shared WaitGroup to track the number of expected // reads and writes throughout the mocked local network - for i, valId := range valIds { + for _, valId := range valIds { expectedCall := networkSimulationConfig[valId] expectedReads := expectedCall.numNetworkReads expectedWrites := expectedCall.numNetworkWrites @@ -269,13 +269,13 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te wg.Add(expectedReads) wg.Add(expectedWrites) - persistenceMock := persistence_testutil.BasePersistenceMock(t, busMocks[i], genesisMock) - consensusMock := consensus_testutil.PrepareConsensusMock(t, busMocks[i]) - telemetryMock := prepareTelemetryMock(t, busMocks[i], valId, &wg, expectedWrites) + persistenceMock := persistence_testutil.BasePersistenceMock(t, busMocks[valId], genesisMock) + consensusMock := consensus_testutil.PrepareConsensusMock(t, busMocks[valId]) + telemetryMock := prepareTelemetryMock(t, busMocks[valId], valId, &wg, expectedWrites) - busMocks[i].EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() - busMocks[i].EXPECT().GetConsensusModule().Return(consensusMock).AnyTimes() - busMocks[i].EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() + busMocks[valId].EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() + busMocks[valId].EXPECT().GetConsensusModule().Return(consensusMock).AnyTimes() + busMocks[valId].EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() } // Inject the connection and bus mocks into the P2P modules diff --git a/p2p/module_test.go b/p2p/module_test.go index 85e6e858a..69bedb1a9 100644 --- a/p2p/module_test.go +++ b/p2p/module_test.go @@ -1,12 +1,7 @@ -package p2p_test +package p2p import ( "fmt" - "github.com/pokt-network/pocket/internal/testutil" - p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" - "github.com/pokt-network/pocket/internal/testutil/persistence" - "github.com/pokt-network/pocket/internal/testutil/runtime" - "github.com/pokt-network/pocket/p2p" "strings" "testing" @@ -14,6 +9,12 @@ import ( libp2pCrypto "github.com/libp2p/go-libp2p/core/crypto" libp2pHost "github.com/libp2p/go-libp2p/core/host" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/pocket/internal/testutil" + p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" + "github.com/pokt-network/pocket/internal/testutil/persistence" + "github.com/pokt-network/pocket/internal/testutil/runtime" typesP2P "github.com/pokt-network/pocket/p2p/types" "github.com/pokt-network/pocket/p2p/utils" "github.com/pokt-network/pocket/runtime/configs" @@ -21,7 +22,6 @@ import ( cryptoPocket "github.com/pokt-network/pocket/shared/crypto" "github.com/pokt-network/pocket/shared/modules" mockModules "github.com/pokt-network/pocket/shared/modules/mocks" - "github.com/stretchr/testify/require" ) // TECHDEBT(#609): move & de-dup. @@ -112,6 +112,8 @@ func Test_Create_configureBootstrapNodes(t *testing.T) { }, } + keys := testutil.LoadLocalnetPrivateKeys(t, 10) + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) @@ -143,7 +145,7 @@ func Test_Create_configureBootstrapNodes(t *testing.T) { } host := newLibp2pMockNetHost(t, privKey, peer) - p2pMod, err := p2p.Create(mockBus, p2p.WithHostOption(host)) + p2pMod, err := Create(mockBus, WithHostOption(host)) if (err != nil) != tt.wantErr { t.Errorf("p2pModule.Create() error = %v, wantErr %v", err, tt.wantErr) } diff --git a/p2p/testutil.go b/p2p/testutil.go new file mode 100644 index 000000000..a030d8682 --- /dev/null +++ b/p2p/testutil.go @@ -0,0 +1,6 @@ +//go:build test + +package p2p + +// P2PModule exports the `p2pModule` type for use in tests +type P2PModule = p2pModule diff --git a/p2p/utils_test.go b/p2p/utils_test.go index 706377dc7..7de0f6429 100644 --- a/p2p/utils_test.go +++ b/p2p/utils_test.go @@ -1,9 +1,12 @@ +//go:build test + package p2p_test import ( "github.com/pokt-network/pocket/internal/testutil" "github.com/pokt-network/pocket/internal/testutil/runtime" "github.com/pokt-network/pocket/internal/testutil/telemetry" + "github.com/pokt-network/pocket/p2p" "github.com/pokt-network/pocket/shared/messaging" "github.com/regen-network/gocuke" "sort" @@ -84,18 +87,18 @@ func waitForNetworkSimulationCompletion(t *testing.T, wg *sync.WaitGroup) { // ~~~~~~ RainTree Unit Test Mocks ~~~~~~ // createP2PModules returns a map of configured p2pModules keyed by an incremental naming convention (eg: `val_1`, `val_2`, etc.) -func createP2PModules(t *testing.T, busMocks []*mockModules.MockBus, netMock mocknet.Mocknet, serviceURLs []string) (p2pModules map[string]*p2pModule) { +func createP2PModules(t *testing.T, busMocks []*mockModules.MockBus, netMock mocknet.Mocknet, serviceURLs []string) (p2pModules map[string]*p2p.P2PModule) { t.Helper() require.GreaterOrEqualf(t, len(serviceURLs), len(busMocks), "number of bus mocks must be less than or equal to the number of service URLs") peerIDs := p2p_testutil.SetupMockNetPeers(t, netMock, keys[:len(busMocks)], serviceURLs) - p2pModules = make(map[string]*p2pModule, len(busMocks)) + p2pModules = make(map[string]*p2p.P2PModule, len(busMocks)) for i := range busMocks { host := netMock.Host(peerIDs[i]) - p2pMod, err := Create(busMocks[i], WithHostOption(host)) + p2pMod, err := p2p.Create(busMocks[i], p2p.WithHostOption(host)) require.NoError(t, err) - p2pModules[serviceURLs[i]] = p2pMod.(*p2pModule) + p2pModules[serviceURLs[i]] = p2pMod.(*p2p.P2PModule) } return } From 906452dd13bbe4e20216c8406c43d13f1c6c28b7 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:01:20 +0200 Subject: [PATCH 03/22] wip: testutils --- .../testutil/constructors/constructors.go | 1 + internal/testutil/keys.go | 3 ++- internal/testutil/keys_test.go | 23 +++++++++++++++++++ internal/testutil/p2p/network.go | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 internal/testutil/keys_test.go diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 50b049884..699da383d 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -47,6 +47,7 @@ func NewP2PModulesAndMocknet( for i, serviceURL := range serviceURLs { // TECHDEBT: refactor + t.Logf("hosts: %v", libp2pNetworkMock.Hosts()) host := libp2pNetworkMock.Hosts()[i] buses[serviceURL], p2pModules[serviceURL] = NewP2PModuleWithHost( t, privKeys[i], diff --git a/internal/testutil/keys.go b/internal/testutil/keys.go index c9de34064..5c621fe11 100644 --- a/internal/testutil/keys.go +++ b/internal/testutil/keys.go @@ -29,7 +29,7 @@ func LoadLocalnetPrivateKeys(t require.TestingT, keyCount int) (privKeys []crypt scanner := bufio.NewScanner(privKeyManifest) scanner.Split(bufio.ScanLines) - for i, done := 0, false; i < keyCount || !done; i++ { + for i, done := 0, false; i < keyCount && !done; { done = !scanner.Scan() line := scanner.Text() matches := privKeyManifestKeyRegex.FindStringSubmatch(line) @@ -38,6 +38,7 @@ func LoadLocalnetPrivateKeys(t require.TestingT, keyCount int) (privKeys []crypt require.NoError(t, err) privKeys = append(privKeys, privKey) + i++ } } return privKeys diff --git a/internal/testutil/keys_test.go b/internal/testutil/keys_test.go new file mode 100644 index 000000000..fc423fb5e --- /dev/null +++ b/internal/testutil/keys_test.go @@ -0,0 +1,23 @@ +package testutil_test + +import ( + "testing" + + "github.com/pokt-network/pocket/internal/testutil" + "github.com/stretchr/testify/require" +) + +func TestLoadLocalnetPrivateKeys(t *testing.T) { + keyCount := 1000 + privKeys := testutil.LoadLocalnetPrivateKeys(t, keyCount) + + require.Lenf(t, privKeys, keyCount, "expected %d private keys; got %d", keyCount, len(privKeys)) + + // ensure each key is unique + seen := make(map[string]struct{}) + for _, privKey := range privKeys { + seen[privKey.String()] = struct{}{} + } + + require.Lenf(t, seen, keyCount, "expected %d unique private keys; got %d", keyCount, len(seen)) +} diff --git a/internal/testutil/p2p/network.go b/internal/testutil/p2p/network.go index 6ae35b1b9..67cd69d05 100644 --- a/internal/testutil/p2p/network.go +++ b/internal/testutil/p2p/network.go @@ -35,6 +35,8 @@ func SetupMockNetPeers( ) (peerIDs []peer.ID) { t.Helper() + // TODO_THIS_COMMIT: return these + // // MUST add mockdns before any libp2p host comes online. Otherwise, it will // error while attempting to resolve its own hostname. _, dnsSrvDone := testutil.PrepareDNSMockFromServiceURLs(t, serviceURLs) From 06ef34ecf4bab1904b330ab26afa83f07c7fa445 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 11 May 2023 14:39:14 +0200 Subject: [PATCH 04/22] wip: checkpoint --- .../testutil/constructors/constructors.go | 79 +++++++++++++++---- internal/testutil/mockdns.go | 48 ++++++----- internal/testutil/p2p/network.go | 31 +++++++- p2p/module_raintree_test.go | 2 +- p2p/raintree/peers_manager_test.go | 2 +- p2p/transport_encryption_test.go | 5 +- 6 files changed, 126 insertions(+), 41 deletions(-) diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 699da383d..11d468b12 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -3,12 +3,12 @@ package constructors import ( libp2pHost "github.com/libp2p/go-libp2p/core/host" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" - runtime_testutil "github.com/pokt-network/pocket/internal/testutil/runtime" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" "github.com/pokt-network/pocket/internal/testutil" p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" + runtime_testutil "github.com/pokt-network/pocket/internal/testutil/runtime" "github.com/pokt-network/pocket/p2p" "github.com/pokt-network/pocket/runtime/genesis" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" @@ -19,16 +19,20 @@ import ( type serviceURLStr = string // NewP2PMocknetModules returns a map of peer IDs to P2PModules using libp2p mocknet hosts. -func NewP2PModulesAndMocknet( +func NewBusesMocknetAndP2PModules( t gocuke.TestingT, count int, genesisState *genesis.GenesisState, busEventHandlerFactory testutil.BusEventHandlerFactory, ) ( buses map[serviceURLStr]*mock_modules.MockBus, - p2pModules map[serviceURLStr]modules.P2PModule, libp2pNetworkMock mocknet.Mocknet, + p2pModules map[serviceURLStr]modules.P2PModule, ) { + // TODO_THIS_COMMIT: refafactor + dnsSrv, dnsDone := testutil.MinimalDNSMock(t) + t.Cleanup(dnsDone) + libp2pNetworkMock = mocknet.New() // destroy mocknet on test cleanup t.Cleanup(func() { @@ -39,29 +43,50 @@ func NewP2PModulesAndMocknet( // CONSIDERATION: using an iterator/generator would prevent unintentional // ID collisions privKeys := testutil.LoadLocalnetPrivateKeys(t, count) + serviceURLs := p2p_testutil.SequentialServiceURLs(t, count) + for i, serviceURL := range serviceURLs { + if len(privKeys) <= i { + t.Logf("WARNING: not enough private keys for %d service URLs", len(serviceURLs)) + break + } + + privKey := privKeys[i] + busMock := NewBus(t, privKey, serviceURL, genesisState, busEventHandlerFactory) + host := p2p_testutil.NewMocknetHost(t, libp2pNetworkMock, privKey) + + // MUST register DNS before instantiating P2PModule + testutil.AddServiceURLZone(t, dnsSrv, serviceURL) + p2pModules[serviceURL] = NewP2PModuleWithHost(t, busMock, host) + } + return buses, libp2pNetworkMock, p2pModules +} + +// TODO_THIS_TEST: need this? +func NewP2PModules( + t gocuke.TestingT, + privKeys []cryptoPocket.PrivateKey, + busMock *mock_modules.MockBus, + libp2pNetworkMock mocknet.Mocknet, +) ( + p2pModules map[serviceURLStr]modules.P2PModule, +) { // CONSIDERATION: using an iterator/generator would prevent unintentional // serviceURL collisions - serviceURLs := p2p_testutil.SequentialServiceURLs(t, count) + serviceURLs := p2p_testutil.SequentialServiceURLs(t, len(privKeys)) _ = p2p_testutil.SetupMockNetPeers(t, libp2pNetworkMock, privKeys, serviceURLs) for i, serviceURL := range serviceURLs { - // TECHDEBT: refactor - t.Logf("hosts: %v", libp2pNetworkMock.Hosts()) host := libp2pNetworkMock.Hosts()[i] - buses[serviceURL], p2pModules[serviceURL] = NewP2PModuleWithHost( - t, privKeys[i], - serviceURLs[i], - host, - genesisState, - busEventHandlerFactory, - ) + // TECHDEBT: refactor + p2pModules[serviceURL] = NewP2PModuleWithHost(t, busMock, host) } - return buses, p2pModules, libp2pNetworkMock + return p2pModules } +// TODO_THIS_TEST: need this? // TODO_THIS_COMMIT: consider following create factory convention (?) -func NewP2PModuleWithHost( +func NewBusesAndP2PModuleWithHost( t gocuke.TestingT, privKey cryptoPocket.PrivateKey, serviceURL string, @@ -71,12 +96,34 @@ func NewP2PModuleWithHost( ) (*mock_modules.MockBus, modules.P2PModule) { t.Helper() + busMock := NewBus(t, privKey, serviceURL, genesisState, busEventHandlerFactory) + return busMock, NewP2PModuleWithHost(t, busMock, host) +} + +func NewBus( + t gocuke.TestingT, + privKey cryptoPocket.PrivateKey, + serviceURL string, + genesisState *genesis.GenesisState, + busEventHandlerFactory testutil.BusEventHandlerFactory, +) *mock_modules.MockBus { + t.Helper() + runtimeMgrMock := runtime_testutil.BaseRuntimeManagerMock(t, privKey, serviceURL, genesisState) busMock := testutil.BusMockWithEventHandler(t, runtimeMgrMock, busEventHandlerFactory) busMock.EXPECT().GetRuntimeMgr().Return(runtimeMgrMock).AnyTimes() + return busMock +} + +func NewP2PModuleWithHost( + t gocuke.TestingT, + busMock *mock_modules.MockBus, + host libp2pHost.Host, +) modules.P2PModule { + t.Helper() mod, err := p2p.Create(busMock, p2p.WithHostOption(host)) require.NoError(t, err) - return busMock, mod.(modules.P2PModule) + return mod.(modules.P2PModule) } diff --git a/internal/testutil/mockdns.go b/internal/testutil/mockdns.go index 019a97860..4d8cc674e 100644 --- a/internal/testutil/mockdns.go +++ b/internal/testutil/mockdns.go @@ -2,41 +2,51 @@ package testutil import ( "fmt" + "net" + "github.com/foxcpp/go-mockdns" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" - "net" - "net/url" ) -func PrepareDNSMockFromServiceURLs(t gocuke.TestingT, serviceURLs []string) (srv *mockdns.Server, done func()) { +func DNSMockFromServiceURLs(t gocuke.TestingT, serviceURLs []string) (srv *mockdns.Server, done func()) { t.Helper() - zones := make(map[string]mockdns.Zone) - for i, u := range serviceURLs { - // Perpend `scheme://` as serviceURLs are currently scheme-less. - // Required for parsing to produce useful results. - // (see: https://pkg.go.dev/net/url@go1.20.2#URL) - serviceURL, err := url.Parse(fmt.Sprintf("scheme://%s", u)) - require.NoError(t, err) + srv, done = MinimalDNSMock(t) + for _, serviceURL := range serviceURLs { + AddServiceURLZone(t, srv, serviceURL) + } + return srv, done +} - ipStr := fmt.Sprintf("10.0.0.%d", i+1) +func AddServiceURLZone(t gocuke.TestingT, srv *mockdns.Server, serviceURL string) { + t.Helper() - if i >= 254 { - panic(fmt.Sprintf("would generate invalid IPv4 address: %s", ipStr)) - } + // TODO_THIS_COMMIT: move & de-dup + hostname, _, err := net.SplitHostPort(serviceURL) + require.NoError(t, err) - zones[fmt.Sprintf("%s.", serviceURL.Hostname())] = mockdns.Zone{ - A: []string{ipStr}, - } + zone := mockdns.Zone{ + A: []string{"10.0.0.1"}, } - return PrepareDNSMock(t, zones) + err = srv.AddZone(fmt.Sprintf("%s.", hostname), zone) + require.NoError(t, err) } -func PrepareDNSMock(t gocuke.TestingT, zones map[string]mockdns.Zone) (srv *mockdns.Server, done func()) { +func MinimalDNSMock(t gocuke.TestingT) (srv *mockdns.Server, done func()) { t.Helper() + return BaseDNSMock(t, nil) +} + +func BaseDNSMock(t gocuke.TestingT, zones map[string]mockdns.Zone) (srv *mockdns.Server, done func()) { + t.Helper() + + if zones == nil { + zones = make(map[string]mockdns.Zone) + } + srv, _ = mockdns.NewServerWithLogger(zones, noopLogger{}, false) srv.PatchNet(net.DefaultResolver) return srv, func() { diff --git a/internal/testutil/p2p/network.go b/internal/testutil/p2p/network.go index 67cd69d05..1e4525046 100644 --- a/internal/testutil/p2p/network.go +++ b/internal/testutil/p2p/network.go @@ -3,9 +3,11 @@ package p2p_testutil import ( "fmt" "github.com/libp2p/go-libp2p/core/crypto" + libp2pHost "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" libp2pPeer "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/multiformats/go-multiaddr" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" @@ -15,6 +17,7 @@ import ( cryptoPocket "github.com/pokt-network/pocket/shared/crypto" ) +// TODO: remove if not needed func NewMocknetWithNPeers(t gocuke.TestingT, peerCount int) (mocknet.Mocknet, []string) { t.Helper() @@ -27,6 +30,25 @@ func NewMocknetWithNPeers(t gocuke.TestingT, peerCount int) (mocknet.Mocknet, [] return libp2pNetworkMock, serviceURLs } +func NewMocknetHost( + t gocuke.TestingT, + netMock mocknet.Mocknet, + privKey cryptoPocket.PrivateKey, +) libp2pHost.Host { + t.Helper() + + addrMock, err := multiaddr.NewMultiaddr("/ip4/10.0.0.1/tcp/0") + require.NoError(t, err) + + libp2pPrivKey, err := crypto.UnmarshalEd25519PrivateKey(privKey.Bytes()) + require.NoError(t, err) + + host, err := netMock.AddPeer(libp2pPrivKey, addrMock) + require.NoError(t, err) + + return host +} + func SetupMockNetPeers( t gocuke.TestingT, netMock mocknet.Mocknet, @@ -39,7 +61,7 @@ func SetupMockNetPeers( // // MUST add mockdns before any libp2p host comes online. Otherwise, it will // error while attempting to resolve its own hostname. - _, dnsSrvDone := testutil.PrepareDNSMockFromServiceURLs(t, serviceURLs) + _, dnsSrvDone := testutil.DNSMockFromServiceURLs(t, serviceURLs) t.Cleanup(dnsSrvDone) // Add a libp2p peers/hosts to the `MockNet` with the keypairs corresponding @@ -48,6 +70,7 @@ func SetupMockNetPeers( libp2pPrivKey, err := crypto.UnmarshalEd25519PrivateKey(privKeys[i].Bytes()) require.NoError(t, err) + // TODO_THIS_COMMIT: add mock DNS zone per peer instead of all at once _, err = netMock.AddPeer(libp2pPrivKey, peerInfo.Addrs[0]) require.NoError(t, err) @@ -92,7 +115,11 @@ func PeersFromPrivKeysAndServiceURLs( return peersInfo } -func peerFromPrivKeyAndServiceURL(t gocuke.TestingT, privKey cryptoPocket.PrivateKey, serviceURL string) libp2pPeer.AddrInfo { +func peerFromPrivKeyAndServiceURL( + t gocuke.TestingT, + privKey cryptoPocket.PrivateKey, + serviceURL string, +) libp2pPeer.AddrInfo { t.Helper() peerInfo, err := utils.Libp2pAddrInfoFromPeer(&types.NetworkPeer{ diff --git a/p2p/module_raintree_test.go b/p2p/module_raintree_test.go index 4c53a6f79..63ece3122 100644 --- a/p2p/module_raintree_test.go +++ b/p2p/module_raintree_test.go @@ -238,7 +238,7 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te } } - busMocks, p2pModules, _ := constructors.NewP2PModulesAndMocknet( + busMocks, _, p2pModules := constructors.NewBusesMocknetAndP2PModules( t, numValidators, genesisMock, busEventHandlerFactory, diff --git a/p2p/raintree/peers_manager_test.go b/p2p/raintree/peers_manager_test.go index 742080088..79e0f197c 100644 --- a/p2p/raintree/peers_manager_test.go +++ b/p2p/raintree/peers_manager_test.go @@ -356,6 +356,6 @@ func mockAlphabetValidatorServiceURLsDNS(t *testing.T) (done func()) { } } - _, done = testutil.PrepareDNSMock(t, zones) + _, done = testutil.BaseDNSMock(t, zones) return done } diff --git a/p2p/transport_encryption_test.go b/p2p/transport_encryption_test.go index 407f18e09..7b46d4d0d 100644 --- a/p2p/transport_encryption_test.go +++ b/p2p/transport_encryption_test.go @@ -1,4 +1,4 @@ -package p2p +package p2p_test import ( "context" @@ -8,6 +8,7 @@ import ( "github.com/pokt-network/pocket/internal/testutil/persistence" "github.com/pokt-network/pocket/internal/testutil/runtime" "github.com/pokt-network/pocket/internal/testutil/telemetry" + "github.com/pokt-network/pocket/p2p" "testing" "time" @@ -67,7 +68,7 @@ func TestP2pModule_Insecure_Error(t *testing.T) { dnsDone := testutil.PrepareDNSMockFromServiceURLs(t, serviceURLs) t.Cleanup(dnsDone) - p2pMod, err := Create(busMock) + p2pMod, err := p2p.Create(busMock) require.NoError(t, err) err = p2pMod.Start() From e7f057bae1afb1006932f26b2fb3e59058a51cd8 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 11 May 2023 22:33:08 +0200 Subject: [PATCH 05/22] wip: checkpoint --- internal/testutil/consensus/mocks.go | 5 +- .../testutil/constructors/constructors.go | 14 +++- internal/testutil/p2p/network.go | 1 + internal/testutil/runtime/genesis.go | 2 +- .../testutil/telemetry/event_metrics_agent.go | 19 ++++++ internal/testutil/telemetry/mocks.go | 15 +++-- p2p/module_raintree_test.go | 66 ++++++++++--------- p2p/transport_encryption_test.go | 4 +- p2p/utils_test.go | 28 ++++---- 9 files changed, 97 insertions(+), 57 deletions(-) diff --git a/internal/testutil/consensus/mocks.go b/internal/testutil/consensus/mocks.go index 64888cfcb..660bb0a38 100644 --- a/internal/testutil/consensus/mocks.go +++ b/internal/testutil/consensus/mocks.go @@ -1,16 +1,15 @@ package consensus_testutil import ( - "testing" - "github.com/golang/mock/gomock" + "github.com/regen-network/gocuke" "github.com/pokt-network/pocket/shared/modules" "github.com/pokt-network/pocket/shared/modules/mocks" ) // Consensus mock - only needed for validatorMap access -func PrepareConsensusMock(t *testing.T, busMock *mock_modules.MockBus) *mock_modules.MockConsensusModule { +func PrepareConsensusMock(t gocuke.TestingT, busMock *mock_modules.MockBus) *mock_modules.MockConsensusModule { ctrl := gomock.NewController(t) consensusMock := mock_modules.NewMockConsensusModule(ctrl) consensusMock.EXPECT().CurrentHeight().Return(uint64(1)).AnyTimes() diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 11d468b12..63975c874 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -3,6 +3,7 @@ package constructors import ( libp2pHost "github.com/libp2p/go-libp2p/core/host" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + consensus_testutil "github.com/pokt-network/pocket/internal/testutil/consensus" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" @@ -29,7 +30,7 @@ func NewBusesMocknetAndP2PModules( libp2pNetworkMock mocknet.Mocknet, p2pModules map[serviceURLStr]modules.P2PModule, ) { - // TODO_THIS_COMMIT: refafactor + // TODO_THIS_COMMIT: refactor dnsSrv, dnsDone := testutil.MinimalDNSMock(t) t.Cleanup(dnsDone) @@ -40,9 +41,13 @@ func NewBusesMocknetAndP2PModules( require.NoError(t, err) }) + buses = make(map[serviceURLStr]*mock_modules.MockBus) + p2pModules = make(map[serviceURLStr]modules.P2PModule) // CONSIDERATION: using an iterator/generator would prevent unintentional // ID collisions privKeys := testutil.LoadLocalnetPrivateKeys(t, count) + // CONSIDERATION: using an iterator/generator would prevent unintentional + // serviceURL collisions serviceURLs := p2p_testutil.SequentialServiceURLs(t, count) for i, serviceURL := range serviceURLs { if len(privKeys) <= i { @@ -52,11 +57,16 @@ func NewBusesMocknetAndP2PModules( privKey := privKeys[i] busMock := NewBus(t, privKey, serviceURL, genesisState, busEventHandlerFactory) - host := p2p_testutil.NewMocknetHost(t, libp2pNetworkMock, privKey) + buses[serviceURL] = busMock + + // TODO_THIS_COMMIT: refactor + consensusMock := consensus_testutil.PrepareConsensusMock(t, busMock) + busMock.EXPECT().GetConsensusModule().Return(consensusMock).AnyTimes() // MUST register DNS before instantiating P2PModule testutil.AddServiceURLZone(t, dnsSrv, serviceURL) + host := p2p_testutil.NewMocknetHost(t, libp2pNetworkMock, privKey) p2pModules[serviceURL] = NewP2PModuleWithHost(t, busMock, host) } return buses, libp2pNetworkMock, p2pModules diff --git a/internal/testutil/p2p/network.go b/internal/testutil/p2p/network.go index 1e4525046..5b1177525 100644 --- a/internal/testutil/p2p/network.go +++ b/internal/testutil/p2p/network.go @@ -37,6 +37,7 @@ func NewMocknetHost( ) libp2pHost.Host { t.Helper() + // TODO_THIS_COMMIT: move to const addrMock, err := multiaddr.NewMultiaddr("/ip4/10.0.0.1/tcp/0") require.NoError(t, err) diff --git a/internal/testutil/runtime/genesis.go b/internal/testutil/runtime/genesis.go index b1d30deb5..e7ea512ae 100644 --- a/internal/testutil/runtime/genesis.go +++ b/internal/testutil/runtime/genesis.go @@ -38,7 +38,7 @@ func GenesisWithSequentialServiceURLs(t gocuke.TestingT, valKeys []cryptoPocket. serviceURLs := make([]string, len(valKeys)) for i := range valKeys { - serviceURLs[i] = p2p_testutil.NewServiceURL(i) + serviceURLs[i] = p2p_testutil.NewServiceURL(i + 1) } return BaseGenesisStateMock(t, valKeys, serviceURLs) } diff --git a/internal/testutil/telemetry/event_metrics_agent.go b/internal/testutil/telemetry/event_metrics_agent.go index f100c994a..69c5d7035 100644 --- a/internal/testutil/telemetry/event_metrics_agent.go +++ b/internal/testutil/telemetry/event_metrics_agent.go @@ -36,3 +36,22 @@ func PrepareEventMetricsAgentMock(t *testing.T, valId string, wg *sync.WaitGroup return eventMetricsAgentMock } + +func EventMetricsAgentMockWithHandler( + t gocuke.TestingT, + label string, + // TODO_THIS_COMMIT: consider refactoring as a type + handler func(namespace, event_name string, labels ...any), + times int, +) *mock_modules.MockEventMetricsAgent { + ctrl := gomock.NewController(t) + eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) + + // TODO_THIS_COMMIT: scrutinize these & their order + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Eq(label), gomock.Any()).Do(handler).Times(times) + // TODO_THIS_COMMIT: is this really needed? + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Not(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).AnyTimes() + + return eventMetricsAgentMock +} diff --git a/internal/testutil/telemetry/mocks.go b/internal/testutil/telemetry/mocks.go index fa68c690b..e695a8343 100644 --- a/internal/testutil/telemetry/mocks.go +++ b/internal/testutil/telemetry/mocks.go @@ -8,7 +8,10 @@ import ( "github.com/pokt-network/pocket/shared/modules/mocks" ) -func MinimalTelemetryMock(t gocuke.TestingT) modules.TelemetryModule { +func MinimalTelemetryMock( + t gocuke.TestingT, + busMock *mock_modules.MockBus, +) modules.TelemetryModule { t.Helper() ctrl := gomock.NewController(t) @@ -18,15 +21,19 @@ func MinimalTelemetryMock(t gocuke.TestingT) modules.TelemetryModule { telemetryMock.EXPECT().SetBus(gomock.Any()).Return().AnyTimes() telemetryMock.EXPECT().GetModuleName().Return(modules.TelemetryModuleName).AnyTimes() + busMock.RegisterModule(telemetryMock) return telemetryMock } -func BaseTelemetryMock(t gocuke.TestingT) modules.TelemetryModule { +func BaseTelemetryMock( + t gocuke.TestingT, + busMock *mock_modules.MockBus, +) modules.TelemetryModule { t.Helper() - return WithTimeSeriesAgent(t, WithEventMetricsAgent(t, MinimalTelemetryMock(t))) + return WithTimeSeriesAgent(t, WithEventMetricsAgent(t, MinimalTelemetryMock(t, busMock))) } -func WithTimeSeriesAgent(t gocuke.TestingT, telemetryMod modules.TelemetryModule) modules.TelemetryModule { +func WithTimeSeriesAgent(t gocuke.TestingT, telemetryMod modules.TelemetryModule) *mock_modules.MockTelemetryModule { t.Helper() telemetryMock := telemetryMod.(*mock_modules.MockTelemetryModule) diff --git a/p2p/module_raintree_test.go b/p2p/module_raintree_test.go index 63ece3122..fad6f43ec 100644 --- a/p2p/module_raintree_test.go +++ b/p2p/module_raintree_test.go @@ -3,28 +3,26 @@ package p2p_test import ( - "github.com/pokt-network/pocket/internal/testutil" - "github.com/pokt-network/pocket/internal/testutil/constructors" - "github.com/pokt-network/pocket/internal/testutil/p2p" - "github.com/pokt-network/pocket/shared/messaging" - "github.com/pokt-network/pocket/shared/modules" - "github.com/regen-network/gocuke" "log" "os" "path/filepath" "regexp" - "sort" "strconv" "sync" "testing" + "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/anypb" - consensus_testutil "github.com/pokt-network/pocket/internal/testutil/consensus" + "github.com/pokt-network/pocket/internal/testutil" + "github.com/pokt-network/pocket/internal/testutil/constructors" + "github.com/pokt-network/pocket/internal/testutil/p2p" persistence_testutil "github.com/pokt-network/pocket/internal/testutil/persistence" "github.com/pokt-network/pocket/p2p/protocol" "github.com/pokt-network/pocket/p2p/raintree" + "github.com/pokt-network/pocket/shared/messaging" + "github.com/pokt-network/pocket/shared/modules" ) // TODO(#314): Add the tooling and instructions on how to generate unit tests in this file. @@ -232,6 +230,7 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te //busMocks := createMockBuses(t, runtimeConfigs, &wg) busEventHandlerFactory := func(t gocuke.TestingT, bus modules.Bus) testutil.BusEventHandler { return func(data *messaging.PocketEnvelope) { + // TODO: decide - is mutually exclusive w/ telemetry based wg.Done() below // `p2pModule#handleNetworkData()` calls `modules.Bus#PublishEventToBus()` // assumes that P2P module is the only event producer running during the test wg.Done() @@ -244,42 +243,47 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te busEventHandlerFactory, ) - valIds := make([]string, 0, numValidators) - for valId := range networkSimulationConfig { - valIds = append(valIds, valId) - } - - // TODO_THIS_COMMIT: need this? - // sort `valIds` in ascending order - sort.Slice(valIds, func(i, j int) bool { - iId := extractNumericId(valIds[i]) - jId := extractNumericId(valIds[j]) - return iId < jId - }) + //serviceURLs := make([]string, 0, numValidators) + //for valId := range networkSimulationConfig { + // serviceURLs = append(serviceURLs, valId) + //} + // + //// TODO_THIS_COMMIT: need this? + //// sort `serviceURLs` in ascending order + //sort.Slice(serviceURLs, func(i, j int) bool { + // iId := extractNumericId(serviceURLs[i]) + // jId := extractNumericId(serviceURLs[j]) + // return iId < jId + //}) // Create connection and bus mocks along with a shared WaitGroup to track the number of expected // reads and writes throughout the mocked local network - for _, valId := range valIds { - expectedCall := networkSimulationConfig[valId] + for serviceURL, busMock := range busMocks { + expectedCall := networkSimulationConfig[serviceURL] expectedReads := expectedCall.numNetworkReads expectedWrites := expectedCall.numNetworkWrites - log.Printf("[valId: %s] expected reads: %d\n", valId, expectedReads) - log.Printf("[valId: %s] expected writes: %d\n", valId, expectedWrites) + log.Printf("[serviceURL: %s] expected reads: %d\n", serviceURL, expectedReads) + log.Printf("[serviceURL: %s] expected writes: %d\n", serviceURL, expectedWrites) wg.Add(expectedReads) wg.Add(expectedWrites) - persistenceMock := persistence_testutil.BasePersistenceMock(t, busMocks[valId], genesisMock) - consensusMock := consensus_testutil.PrepareConsensusMock(t, busMocks[valId]) - telemetryMock := prepareTelemetryMock(t, busMocks[valId], valId, &wg, expectedWrites) + // TODO_THIS_COMMIT: + //if serviceURL == origNode { + // ... + //} + + persistenceMock := persistence_testutil.BasePersistenceMock(t, busMock, genesisMock) + //consensusMock := consensus_testutil.PrepareConsensusMock(t, busMocks[serviceURL]) + telemetryMock := prepareTelemetryMock(t, busMock, serviceURL, &wg, expectedWrites) - busMocks[valId].EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() - busMocks[valId].EXPECT().GetConsensusModule().Return(consensusMock).AnyTimes() - busMocks[valId].EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() + busMock.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() + //busMocks[serviceURL].EXPECT().GetConsensusModule().Return(consensusMock).AnyTimes() + busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() } // Inject the connection and bus mocks into the P2P modules - //p2pModules := createP2PModules(t, busMocks, libp2pNetworkMock, valIds) + //p2pModules := createP2PModules(t, busMocks, libp2pNetworkMock, serviceURLs) for _, p2pMod := range p2pModules { err := p2pMod.Start() diff --git a/p2p/transport_encryption_test.go b/p2p/transport_encryption_test.go index 7b46d4d0d..a5dd7f236 100644 --- a/p2p/transport_encryption_test.go +++ b/p2p/transport_encryption_test.go @@ -49,10 +49,10 @@ func TestP2pModule_Insecure_Error(t *testing.T) { }, }).AnyTimes() - telemetryMock := telemetry_testutil.BaseTelemetryMock(t) - busMock := testutil.BaseBusMock(t, runtimeMgrMock) busMock.EXPECT().GetConsensusModule().Return(mockConsensusModule).AnyTimes() + + telemetryMock := telemetry_testutil.BaseTelemetryMock(t, busMock) busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() keys := testutil.LoadLocalnetPrivateKeys(t, 1) diff --git a/p2p/utils_test.go b/p2p/utils_test.go index 7de0f6429..bf225bc75 100644 --- a/p2p/utils_test.go +++ b/p2p/utils_test.go @@ -8,13 +8,13 @@ import ( "github.com/pokt-network/pocket/internal/testutil/telemetry" "github.com/pokt-network/pocket/p2p" "github.com/pokt-network/pocket/shared/messaging" + "github.com/pokt-network/pocket/telemetry" "github.com/regen-network/gocuke" "sort" "sync" "testing" "time" - "github.com/golang/mock/gomock" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/stretchr/testify/require" @@ -133,23 +133,23 @@ func createMockBuses(t *testing.T, runtimeMgrs []modules.RuntimeMgr, wg *sync.Wa return mockBuses } -// TODO_THIS_COMMIT: refactor +// TODO_THIS_COMMIT: refactor / move // Telemetry mock - Needed to help with proper counts for number of expected network writes func prepareTelemetryMock(t *testing.T, busMock *mockModules.MockBus, valId string, wg *sync.WaitGroup, expectedNumNetworkWrites int) *mockModules.MockTelemetryModule { - ctrl := gomock.NewController(t) - telemetryMock := mockModules.NewMockTelemetryModule(ctrl) + telemetryMock := telemetry_testutil.WithTimeSeriesAgent(t, + telemetry_testutil.MinimalTelemetryMock(t, busMock), + ) + + eventMetricsAgentMock := telemetry_testutil.EventMetricsAgentMockWithHandler( + t, telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL, + func(namesapce, event_name string, labels ...any) { + t.Logf("[valId: %s] Write\n", valId) + wg.Done() + }, + expectedNumNetworkWrites, + ) - timeSeriesAgentMock := telemetry_testutil.BaseTimeSeriesAgentMock(t) - // TODO_THIS_COMMIT: refactor - eventMetricsAgentMock := telemetry_testutil.PrepareEventMetricsAgentMock(t, valId, wg, expectedNumNetworkWrites) - - telemetryMock.EXPECT().GetTimeSeriesAgent().Return(timeSeriesAgentMock).AnyTimes() telemetryMock.EXPECT().GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() - - telemetryMock.EXPECT().GetModuleName().Return(modules.TelemetryModuleName).AnyTimes() - telemetryMock.EXPECT().GetBus().Return(busMock).AnyTimes() - telemetryMock.EXPECT().SetBus(busMock).AnyTimes() busMock.RegisterModule(telemetryMock) - return telemetryMock } From 70a0fc34dacc7db25663867bef9452b21f12fc3c Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:02:56 +0200 Subject: [PATCH 06/22] wip: testutils --- internal/testutil/bus.go | 2 +- internal/testutil/consensus/mocks.go | 5 +++-- .../testutil/constructors/constructors.go | 19 ++++++++++++----- internal/testutil/mockdns.go | 21 +++++++++++-------- internal/testutil/p2p/network.go | 10 ++++----- internal/testutil/persistence/mocks.go | 18 ++++++++-------- internal/testutil/runtime/genesis.go | 6 +++--- internal/testutil/telemetry/mocks.go | 3 ++- 8 files changed, 49 insertions(+), 35 deletions(-) diff --git a/internal/testutil/bus.go b/internal/testutil/bus.go index 6a0ea6102..972965eca 100644 --- a/internal/testutil/bus.go +++ b/internal/testutil/bus.go @@ -13,7 +13,7 @@ import ( ) type BusEventHandler func(*messaging.PocketEnvelope) -type BusEventHandlerFactory func(t gocuke.TestingT, bus modules.Bus) BusEventHandler +type BusEventHandlerFactory func(t gocuke.TestingT, busMock *mock_modules.MockBus) BusEventHandler // MinimalBusMock returns a bus mock with a module registry and minimal // expectations registered to maximize re-usability. diff --git a/internal/testutil/consensus/mocks.go b/internal/testutil/consensus/mocks.go index 660bb0a38..51bdc3338 100644 --- a/internal/testutil/consensus/mocks.go +++ b/internal/testutil/consensus/mocks.go @@ -9,7 +9,7 @@ import ( ) // Consensus mock - only needed for validatorMap access -func PrepareConsensusMock(t gocuke.TestingT, busMock *mock_modules.MockBus) *mock_modules.MockConsensusModule { +func BaseConsensusMock(t gocuke.TestingT, busMock *mock_modules.MockBus) *mock_modules.MockConsensusModule { ctrl := gomock.NewController(t) consensusMock := mock_modules.NewMockConsensusModule(ctrl) consensusMock.EXPECT().CurrentHeight().Return(uint64(1)).AnyTimes() @@ -17,7 +17,8 @@ func PrepareConsensusMock(t gocuke.TestingT, busMock *mock_modules.MockBus) *moc consensusMock.EXPECT().GetBus().Return(busMock).AnyTimes() consensusMock.EXPECT().SetBus(busMock).AnyTimes() consensusMock.EXPECT().GetModuleName().Return(modules.ConsensusModuleName).AnyTimes() - busMock.RegisterModule(consensusMock) + busMock.EXPECT().GetConsensusModule().Return(consensusMock).AnyTimes() + //busMock.RegisterModule(consensusMock) return consensusMock } diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 63975c874..9f78c7448 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -4,6 +4,8 @@ import ( libp2pHost "github.com/libp2p/go-libp2p/core/host" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" consensus_testutil "github.com/pokt-network/pocket/internal/testutil/consensus" + persistence_testutil "github.com/pokt-network/pocket/internal/testutil/persistence" + telemetry_testutil "github.com/pokt-network/pocket/internal/testutil/telemetry" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" @@ -31,8 +33,7 @@ func NewBusesMocknetAndP2PModules( p2pModules map[serviceURLStr]modules.P2PModule, ) { // TODO_THIS_COMMIT: refactor - dnsSrv, dnsDone := testutil.MinimalDNSMock(t) - t.Cleanup(dnsDone) + dnsSrv := testutil.MinimalDNSMock(t) libp2pNetworkMock = mocknet.New() // destroy mocknet on test cleanup @@ -60,8 +61,9 @@ func NewBusesMocknetAndP2PModules( buses[serviceURL] = busMock // TODO_THIS_COMMIT: refactor - consensusMock := consensus_testutil.PrepareConsensusMock(t, busMock) - busMock.EXPECT().GetConsensusModule().Return(consensusMock).AnyTimes() + _ = consensus_testutil.BaseConsensusMock(t, busMock) + _ = persistence_testutil.BasePersistenceMock(t, busMock, genesisState) + _ = telemetry_testutil.BaseTelemetryMock(t, busMock) // MUST register DNS before instantiating P2PModule testutil.AddServiceURLZone(t, dnsSrv, serviceURL) @@ -69,6 +71,9 @@ func NewBusesMocknetAndP2PModules( host := p2p_testutil.NewMocknetHost(t, libp2pNetworkMock, privKey) p2pModules[serviceURL] = NewP2PModuleWithHost(t, busMock, host) } + err := libp2pNetworkMock.LinkAll() + require.NoError(t, err) + return buses, libp2pNetworkMock, p2pModules } @@ -119,7 +124,11 @@ func NewBus( ) *mock_modules.MockBus { t.Helper() - runtimeMgrMock := runtime_testutil.BaseRuntimeManagerMock(t, privKey, serviceURL, genesisState) + runtimeMgrMock := runtime_testutil.BaseRuntimeManagerMock( + t, privKey, + serviceURL, + genesisState, + ) busMock := testutil.BusMockWithEventHandler(t, runtimeMgrMock, busEventHandlerFactory) busMock.EXPECT().GetRuntimeMgr().Return(runtimeMgrMock).AnyTimes() return busMock diff --git a/internal/testutil/mockdns.go b/internal/testutil/mockdns.go index 4d8cc674e..2adc4ab74 100644 --- a/internal/testutil/mockdns.go +++ b/internal/testutil/mockdns.go @@ -9,14 +9,14 @@ import ( "github.com/stretchr/testify/require" ) -func DNSMockFromServiceURLs(t gocuke.TestingT, serviceURLs []string) (srv *mockdns.Server, done func()) { +func DNSMockFromServiceURLs(t gocuke.TestingT, serviceURLs []string) *mockdns.Server { t.Helper() - srv, done = MinimalDNSMock(t) + srv := MinimalDNSMock(t) for _, serviceURL := range serviceURLs { AddServiceURLZone(t, srv, serviceURL) } - return srv, done + return srv } func AddServiceURLZone(t gocuke.TestingT, srv *mockdns.Server, serviceURL string) { @@ -34,25 +34,28 @@ func AddServiceURLZone(t gocuke.TestingT, srv *mockdns.Server, serviceURL string require.NoError(t, err) } -func MinimalDNSMock(t gocuke.TestingT) (srv *mockdns.Server, done func()) { +func MinimalDNSMock(t gocuke.TestingT) *mockdns.Server { t.Helper() return BaseDNSMock(t, nil) } -func BaseDNSMock(t gocuke.TestingT, zones map[string]mockdns.Zone) (srv *mockdns.Server, done func()) { +func BaseDNSMock(t gocuke.TestingT, zones map[string]mockdns.Zone) *mockdns.Server { t.Helper() if zones == nil { zones = make(map[string]mockdns.Zone) } - srv, _ = mockdns.NewServerWithLogger(zones, noopLogger{}, false) + srv, _ := mockdns.NewServerWithLogger(zones, noopLogger{}, false) srv.PatchNet(net.DefaultResolver) - return srv, func() { - _ = srv.Close() + t.Cleanup(func() { + err := srv.Close() + require.NoError(t, err) mockdns.UnpatchNet(net.DefaultResolver) - } + }) + + return srv } // NB: default logging behavior is too noisy. diff --git a/internal/testutil/p2p/network.go b/internal/testutil/p2p/network.go index 5b1177525..77fdb9edb 100644 --- a/internal/testutil/p2p/network.go +++ b/internal/testutil/p2p/network.go @@ -8,6 +8,7 @@ import ( libp2pPeer "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/multiformats/go-multiaddr" + "github.com/pokt-network/pocket/runtime/defaults" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" @@ -32,19 +33,19 @@ func NewMocknetWithNPeers(t gocuke.TestingT, peerCount int) (mocknet.Mocknet, [] func NewMocknetHost( t gocuke.TestingT, - netMock mocknet.Mocknet, + libp2pNetworkMock mocknet.Mocknet, privKey cryptoPocket.PrivateKey, ) libp2pHost.Host { t.Helper() // TODO_THIS_COMMIT: move to const - addrMock, err := multiaddr.NewMultiaddr("/ip4/10.0.0.1/tcp/0") + addrMock, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/10.0.0.1/tcp/%d", defaults.DefaultP2PPort)) require.NoError(t, err) libp2pPrivKey, err := crypto.UnmarshalEd25519PrivateKey(privKey.Bytes()) require.NoError(t, err) - host, err := netMock.AddPeer(libp2pPrivKey, addrMock) + host, err := libp2pNetworkMock.AddPeer(libp2pPrivKey, addrMock) require.NoError(t, err) return host @@ -62,8 +63,7 @@ func SetupMockNetPeers( // // MUST add mockdns before any libp2p host comes online. Otherwise, it will // error while attempting to resolve its own hostname. - _, dnsSrvDone := testutil.DNSMockFromServiceURLs(t, serviceURLs) - t.Cleanup(dnsSrvDone) + _ = testutil.DNSMockFromServiceURLs(t, serviceURLs) // Add a libp2p peers/hosts to the `MockNet` with the keypairs corresponding // to the genesis validators' keypairs diff --git a/internal/testutil/persistence/mocks.go b/internal/testutil/persistence/mocks.go index 07702b867..f64c9bab1 100644 --- a/internal/testutil/persistence/mocks.go +++ b/internal/testutil/persistence/mocks.go @@ -2,21 +2,20 @@ package persistence_testutil import ( "fmt" - "github.com/pokt-network/pocket/persistence/types/mocks" - "github.com/pokt-network/pocket/shared/codec" - "github.com/pokt-network/pocket/shared/core/types" - "github.com/pokt-network/pocket/shared/utils" - "testing" - "github.com/golang/mock/gomock" + "github.com/regen-network/gocuke" + "github.com/pokt-network/pocket/persistence/types/mocks" "github.com/pokt-network/pocket/runtime/genesis" + "github.com/pokt-network/pocket/shared/codec" + "github.com/pokt-network/pocket/shared/core/types" "github.com/pokt-network/pocket/shared/modules" "github.com/pokt-network/pocket/shared/modules/mocks" + "github.com/pokt-network/pocket/shared/utils" ) // Persistence mock - only needed for validatorMap access -func BasePersistenceMock(t *testing.T, busMock *mock_modules.MockBus, genesisState *genesis.GenesisState) *mock_modules.MockPersistenceModule { +func BasePersistenceMock(t gocuke.TestingT, busMock *mock_modules.MockBus, genesisState *genesis.GenesisState) *mock_modules.MockPersistenceModule { ctrl := gomock.NewController(t) persistenceModuleMock := mock_modules.NewMockPersistenceModule(ctrl) @@ -29,13 +28,14 @@ func BasePersistenceMock(t *testing.T, busMock *mock_modules.MockBus, genesisSta persistenceModuleMock.EXPECT().GetBus().Return(busMock).AnyTimes() persistenceModuleMock.EXPECT().SetBus(busMock).AnyTimes() persistenceModuleMock.EXPECT().GetModuleName().Return(modules.PersistenceModuleName).AnyTimes() - busMock.RegisterModule(persistenceModuleMock) + busMock.EXPECT().GetPersistenceModule().Return(persistenceModuleMock).AnyTimes() + //busMock.RegisterModule(persistenceModuleMock) return persistenceModuleMock } // Creates a persistence module mock with mock implementations of some basic functionality -func PersistenceMockWithBlockStore(t *testing.T, _ modules.EventsChannel, bus modules.Bus) *mock_modules.MockPersistenceModule { +func PersistenceMockWithBlockStore(t gocuke.TestingT, _ modules.EventsChannel, bus modules.Bus) *mock_modules.MockPersistenceModule { ctrl := gomock.NewController(t) persistenceMock := mock_modules.NewMockPersistenceModule(ctrl) persistenceReadContextMock := mock_modules.NewMockPersistenceReadContext(ctrl) diff --git a/internal/testutil/runtime/genesis.go b/internal/testutil/runtime/genesis.go index e7ea512ae..b14aac47d 100644 --- a/internal/testutil/runtime/genesis.go +++ b/internal/testutil/runtime/genesis.go @@ -9,7 +9,7 @@ import ( "github.com/regen-network/gocuke" ) -func BaseGenesisStateMock(t gocuke.TestingT, valKeys []cryptoPocket.PrivateKey, serviceURLs []string) *genesis.GenesisState { +func BaseGenesisStateMock(t gocuke.TestingT, valKeys []cryptoPocket.PublicKey, serviceURLs []string) *genesis.GenesisState { t.Helper() genesisState := new(genesis.GenesisState) @@ -19,7 +19,7 @@ func BaseGenesisStateMock(t gocuke.TestingT, valKeys []cryptoPocket.PrivateKey, mockActor := &types.Actor{ ActorType: types.ActorType_ACTOR_TYPE_VAL, Address: addr, - PublicKey: valKey.PublicKey().String(), + PublicKey: valKey.String(), ServiceUrl: serviceURLs[i], StakedAmount: test_artifacts.DefaultStakeAmountString, PausedHeight: int64(0), @@ -33,7 +33,7 @@ func BaseGenesisStateMock(t gocuke.TestingT, valKeys []cryptoPocket.PrivateKey, return genesisState } -func GenesisWithSequentialServiceURLs(t gocuke.TestingT, valKeys []cryptoPocket.PrivateKey) *genesis.GenesisState { +func GenesisWithSequentialServiceURLs(t gocuke.TestingT, valKeys []cryptoPocket.PublicKey) *genesis.GenesisState { t.Helper() serviceURLs := make([]string, len(valKeys)) diff --git a/internal/testutil/telemetry/mocks.go b/internal/testutil/telemetry/mocks.go index e695a8343..795c73aed 100644 --- a/internal/testutil/telemetry/mocks.go +++ b/internal/testutil/telemetry/mocks.go @@ -20,8 +20,9 @@ func MinimalTelemetryMock( telemetryMock.EXPECT().Start().Return(nil).AnyTimes() telemetryMock.EXPECT().SetBus(gomock.Any()).Return().AnyTimes() telemetryMock.EXPECT().GetModuleName().Return(modules.TelemetryModuleName).AnyTimes() + busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() + //busMock.RegisterModule(telemetryMock) - busMock.RegisterModule(telemetryMock) return telemetryMock } From 430477b928d275d15c45ddd25e57416ce25d0d60 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:05:18 +0200 Subject: [PATCH 07/22] wip: utils/host --- p2p/utils/host.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/p2p/utils/host.go b/p2p/utils/host.go index e9c6e130b..b016bcc47 100644 --- a/p2p/utils/host.go +++ b/p2p/utils/host.go @@ -94,6 +94,17 @@ func Libp2pSendToPeer(host libp2pHost.Host, data []byte, peer typesP2P.Peer) err logger.Global.Debug().Err(err).Msg("logging resource scope stats") } + // TODO: remove me! + //pstore := host.Peerstore() + //for _, peerID := range pstore.Peers() { + // addr := pstore.Addrs(peerID)[0] + // logger.Global.Debug(). + // Str("peerID", peerID.String()). + // Str("addr", addr.String()). + // Msg("peerstore") + //} + // -- end TODO + stream, err := host.NewStream(ctx, peerInfo.ID, protocol.PoktProtocolID) if err != nil { return fmt.Errorf("opening stream: %w", err) From 86a067d5c0ff401078be3c0a0789b3fa0d340f84 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 16 May 2023 12:16:14 +0200 Subject: [PATCH 08/22] wip: checkpoint --- .../testutil/constructors/constructors.go | 11 +- .../testutil/telemetry/event_metrics_agent.go | 13 ++- internal/testutil/telemetry/mocks.go | 4 +- p2p/module_raintree_test.go | 100 ++++++++++++++++-- p2p/module_test.go | 10 +- p2p/raintree/peers_manager_test.go | 2 +- p2p/testutil.go | 7 ++ 7 files changed, 126 insertions(+), 21 deletions(-) diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 9f78c7448..094813ec3 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -63,7 +63,16 @@ func NewBusesMocknetAndP2PModules( // TODO_THIS_COMMIT: refactor _ = consensus_testutil.BaseConsensusMock(t, busMock) _ = persistence_testutil.BasePersistenceMock(t, busMock, genesisState) - _ = telemetry_testutil.BaseTelemetryMock(t, busMock) + _ = telemetry_testutil.WithTimeSeriesAgent( + t, telemetry_testutil.MinimalTelemetryMock(t, busMock), + ) + //_ = telemetry_testutil.BaseTelemetryMock(t, busMock) + //telemetryMock.GetEventMetricsAgent().(*mock_modules.MockEventMetricsAgent).EXPECT().EmitEvent( + // gomock.Any(), + // gomock.Any(), + // gomock.Any(), + // gomock.Any(), + //).AnyTimes() // MUST register DNS before instantiating P2PModule testutil.AddServiceURLZone(t, dnsSrv, serviceURL) diff --git a/internal/testutil/telemetry/event_metrics_agent.go b/internal/testutil/telemetry/event_metrics_agent.go index 69c5d7035..0b77fe482 100644 --- a/internal/testutil/telemetry/event_metrics_agent.go +++ b/internal/testutil/telemetry/event_metrics_agent.go @@ -17,6 +17,7 @@ func BaseEventMetricsAgentMock(t gocuke.TestingT) *mock_modules.MockEventMetrics ctrl := gomock.NewController(t) eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() return eventMetricsAgentMock } @@ -27,12 +28,16 @@ func PrepareEventMetricsAgentMock(t *testing.T, valId string, wg *sync.WaitGroup ctrl := gomock.NewController(t) eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) - eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + logEvent := func(n, e string, l ...any) { + t.Logf("n: %s, e: %s, l: %v\n", n, e, l) + } + + //eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Do(logEvent).AnyTimes() eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Eq(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).Do(func(n, e any, l ...any) { log.Printf("[valId: %s] Write\n", valId) wg.Done() - }).Times(expectedNumNetworkWrites) - eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Not(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).AnyTimes() + }).Do(logEvent).Times(expectedNumNetworkWrites) + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Not(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).Do(logEvent).AnyTimes() return eventMetricsAgentMock } @@ -41,7 +46,7 @@ func EventMetricsAgentMockWithHandler( t gocuke.TestingT, label string, // TODO_THIS_COMMIT: consider refactoring as a type - handler func(namespace, event_name string, labels ...any), + handler func(namespace, eventName string, labels ...any), times int, ) *mock_modules.MockEventMetricsAgent { ctrl := gomock.NewController(t) diff --git a/internal/testutil/telemetry/mocks.go b/internal/testutil/telemetry/mocks.go index 795c73aed..a369bcbd5 100644 --- a/internal/testutil/telemetry/mocks.go +++ b/internal/testutil/telemetry/mocks.go @@ -19,6 +19,8 @@ func MinimalTelemetryMock( telemetryMock.EXPECT().Start().Return(nil).AnyTimes() telemetryMock.EXPECT().SetBus(gomock.Any()).Return().AnyTimes() + // TODO_THIS_COMMIT: which one ^ v ? + //telemetryMock.EXPECT().SetBus(busMock).Return().AnyTimes() telemetryMock.EXPECT().GetModuleName().Return(modules.TelemetryModuleName).AnyTimes() busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() //busMock.RegisterModule(telemetryMock) @@ -39,10 +41,8 @@ func WithTimeSeriesAgent(t gocuke.TestingT, telemetryMod modules.TelemetryModule telemetryMock := telemetryMod.(*mock_modules.MockTelemetryModule) timeSeriesAgentMock := BaseTimeSeriesAgentMock(t) - eventMetricsAgentMock := BaseEventMetricsAgentMock(t) telemetryMock.EXPECT().GetTimeSeriesAgent().Return(timeSeriesAgentMock).AnyTimes() - telemetryMock.EXPECT().GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() return telemetryMock } diff --git a/p2p/module_raintree_test.go b/p2p/module_raintree_test.go index fad6f43ec..24bc2b6f1 100644 --- a/p2p/module_raintree_test.go +++ b/p2p/module_raintree_test.go @@ -3,6 +3,10 @@ package p2p_test import ( + runtime_testutil "github.com/pokt-network/pocket/internal/testutil/runtime" + telemetry_testutil "github.com/pokt-network/pocket/internal/testutil/telemetry" + cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + mock_modules "github.com/pokt-network/pocket/shared/modules/mocks" "log" "os" "path/filepath" @@ -22,7 +26,6 @@ import ( "github.com/pokt-network/pocket/p2p/protocol" "github.com/pokt-network/pocket/p2p/raintree" "github.com/pokt-network/pocket/shared/messaging" - "github.com/pokt-network/pocket/shared/modules" ) // TODO(#314): Add the tooling and instructions on how to generate unit tests in this file. @@ -223,26 +226,45 @@ func TestRainTreeNetworkCompleteTwentySevenNodes(t *testing.T) { func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig TestNetworkSimulationConfig) { // Configure & prepare test module numValidators := len(networkSimulationConfig) - runtimeConfigs := createMockRuntimeMgrs(t, numValidators) - genesisMock := runtimeConfigs[0].GetGenesis() + //runtimeConfigs := createMockRuntimeMgrs(t, numValidators) + //genesisState := runtimeConfigs[0].GetGenesis() + + privKeys := testutil.LoadLocalnetPrivateKeys(t, numValidators) + pubKeys := make([]cryptoPocket.PublicKey, len(privKeys)) + for i, privKey := range privKeys { + pubKeys[i] = privKey.PublicKey() + } + + genesisState := runtime_testutil.GenesisWithSequentialServiceURLs(t, pubKeys) var wg sync.WaitGroup //busMocks := createMockBuses(t, runtimeConfigs, &wg) - busEventHandlerFactory := func(t gocuke.TestingT, bus modules.Bus) testutil.BusEventHandler { + busEventHandlerFactory := func(t gocuke.TestingT, busMock *mock_modules.MockBus) testutil.BusEventHandler { return func(data *messaging.PocketEnvelope) { // TODO: decide - is mutually exclusive w/ telemetry based wg.Done() below // `p2pModule#handleNetworkData()` calls `modules.Bus#PublishEventToBus()` // assumes that P2P module is the only event producer running during the test + t.Log("bus event received") wg.Done() } } busMocks, _, p2pModules := constructors.NewBusesMocknetAndP2PModules( t, numValidators, - genesisMock, + genesisState, busEventHandlerFactory, ) + //for _, busMock := range busMocks { + // telemetryMock := busMock.GetTelemetryModule().(*mock_modules.MockTelemetryModule) + // telemetryMock.GetEventMetricsAgent().(*mock_modules.MockEventMetricsAgent).EXPECT().EmitEvent( + // gomock.Any(), + // gomock.Any(), + // gomock.Any(), + // gomock.Any(), + // ).AnyTimes() + //} + //serviceURLs := make([]string, 0, numValidators) //for valId := range networkSimulationConfig { // serviceURLs = append(serviceURLs, valId) @@ -273,13 +295,57 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te // ... //} - persistenceMock := persistence_testutil.BasePersistenceMock(t, busMock, genesisMock) - //consensusMock := consensus_testutil.PrepareConsensusMock(t, busMocks[serviceURL]) - telemetryMock := prepareTelemetryMock(t, busMock, serviceURL, &wg, expectedWrites) + // TODO_THIS_COMMIT: MOVE + //telemetryEventHandler := func(namespace, eventName string, labels ...any) { + // t.Log("telemetry event received") + // wg.Done() + //} - busMock.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() - //busMocks[serviceURL].EXPECT().GetConsensusModule().Return(consensusMock).AnyTimes() - busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() + //privKey, err := cryptoPocket.NewPrivateKey(busMock.GetRuntimeMgr().GetConfig().P2P.PrivateKey) + //require.NoError(t, err) + // + // TODO_THIS_COMMIT: move & de-dup + //libp2pPrivKey, err := libp2pCrypto.UnmarshalEd25519PrivateKey(privKey.Bytes()) + //require.NoError(t, err) + // + //libp2pPeerID, err := libp2pPeer.IDFromPrivateKey(libp2pPrivKey) + //require.NoError(t, err) + // END TODO + // + //sURL := strings.Clone(serviceURL) + //host := libp2pNetworkMock.Host(libp2pPeerID) + //host.SetStreamHandler(protocol.PoktProtocolID, func(stream libp2pNetwork.Stream) { + // t.Logf("[valID: %s] Read\n", sURL) + // p2pModules[serviceURL].(*p2p.P2PModule).HandleStream(stream) + // wg.Done() + //}) + + eventMetricsAgentMock := telemetry_testutil.PrepareEventMetricsAgentMock(t, serviceURL, &wg, expectedWrites) + busMock.GetTelemetryModule().(*mock_modules.MockTelemetryModule).EXPECT(). + GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() + + _ = persistence_testutil.BasePersistenceMock(t, busMock, genesisState) + //telemetryMock := prepareTelemetryMock(t, busMock, serviceURL, &wg, expectedWrites) + //_ = telemetry_testutil.BaseTelemetryMock(t, busMock) + //telemetryMock.GetEventMetricsAgent().(*mock_modules.MockEventMetricsAgent).EXPECT().EmitEvent( + // gomock.Any(), + // gomock.Any(), + // gomock.Eq(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), + // gomock.Any(), + // //).Do(telemetryEventHandler).Times(expectedWrites) + //).Do(telemetryEventHandler).AnyTimes() + ////telemetryMock.GetEventMetricsAgent().(*mock_modules.MockEventMetricsAgent).EXPECT().EmitEvent( + //// gomock.Eq("one"), + //// gomock.Eq("two"), + //// gomock.Eq("three"), + ////).Do(telemetryEventHandler).Times(expectedWrites) + ////telemetryMock. + //// GetEventMetricsAgent(). + //// EmitEvent( + //// "one", + //// "two", + //// "three", + //// ) } // Inject the connection and bus mocks into the P2P modules @@ -312,6 +378,18 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te p := &anypb.Any{} p2pMod := p2pModules[origNode] require.NoError(t, p2pMod.Broadcast(p)) + + //for _, busMock := range busMocks { + // busMock. + //busMocks[testutil.GetKeys(busMocks)[0]]. + // GetTelemetryModule(). + // GetEventMetricsAgent(). + // EmitEvent( + // "one", + // "two", + // "three", + // ) + //} } func extractNumericId(valId string) int64 { diff --git a/p2p/module_test.go b/p2p/module_test.go index 69bedb1a9..c2503f699 100644 --- a/p2p/module_test.go +++ b/p2p/module_test.go @@ -120,8 +120,14 @@ func Test_Create_configureBootstrapNodes(t *testing.T) { mockRuntimeMgr := mockModules.NewMockRuntimeMgr(ctrl) mockBus := testutil.BaseBusMock(t, mockRuntimeMgr) - serviceURLs := p2p_testutil.SequentialServiceURLs(t, len(keys)) - genesisStateMock := runtime_testutil.BaseGenesisStateMock(t, keys, serviceURLs) + // TODO_THIS_COMMIT: refactor + pubKeys := make([]cryptoPocket.PublicKey, len(keys)) + for i, privKey := range keys { + pubKeys[i] = privKey.PublicKey() + } + + serviceURLs := p2p_testutil.SequentialServiceURLs(t, len(pubKeys)) + genesisStateMock := runtime_testutil.BaseGenesisStateMock(t, pubKeys, serviceURLs) persistenceMock := persistence_testutil.BasePersistenceMock(t, mockBus, genesisStateMock) mockBus.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() diff --git a/p2p/raintree/peers_manager_test.go b/p2p/raintree/peers_manager_test.go index 79e0f197c..caca32f5b 100644 --- a/p2p/raintree/peers_manager_test.go +++ b/p2p/raintree/peers_manager_test.go @@ -356,6 +356,6 @@ func mockAlphabetValidatorServiceURLsDNS(t *testing.T) (done func()) { } } - _, done = testutil.BaseDNSMock(t, zones) + _ = testutil.BaseDNSMock(t, zones) return done } diff --git a/p2p/testutil.go b/p2p/testutil.go index a030d8682..b455024bf 100644 --- a/p2p/testutil.go +++ b/p2p/testutil.go @@ -2,5 +2,12 @@ package p2p +import libp2pNetwork "github.com/libp2p/go-libp2p/core/network" + // P2PModule exports the `p2pModule` type for use in tests type P2PModule = p2pModule + +// HandleStream exports the `handleStream` method for use in tests +func (m *p2pModule) HandleStream(stream libp2pNetwork.Stream) { + m.handleStream(stream) +} From 83e80e6c9d7d707d5f8052b8748ad4278f981e80 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 16 May 2023 12:34:51 +0200 Subject: [PATCH 09/22] wip: checkpoint --- .../testutil/constructors/constructors.go | 7 -- .../testutil/telemetry/event_metrics_agent.go | 8 +- p2p/module_raintree_test.go | 81 +++++-------------- p2p/testutil.go | 7 -- 4 files changed, 25 insertions(+), 78 deletions(-) diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 094813ec3..744acf85e 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -66,13 +66,6 @@ func NewBusesMocknetAndP2PModules( _ = telemetry_testutil.WithTimeSeriesAgent( t, telemetry_testutil.MinimalTelemetryMock(t, busMock), ) - //_ = telemetry_testutil.BaseTelemetryMock(t, busMock) - //telemetryMock.GetEventMetricsAgent().(*mock_modules.MockEventMetricsAgent).EXPECT().EmitEvent( - // gomock.Any(), - // gomock.Any(), - // gomock.Any(), - // gomock.Any(), - //).AnyTimes() // MUST register DNS before instantiating P2PModule testutil.AddServiceURLZone(t, dnsSrv, serviceURL) diff --git a/internal/testutil/telemetry/event_metrics_agent.go b/internal/testutil/telemetry/event_metrics_agent.go index 0b77fe482..ff665b0a1 100644 --- a/internal/testutil/telemetry/event_metrics_agent.go +++ b/internal/testutil/telemetry/event_metrics_agent.go @@ -1,7 +1,6 @@ package telemetry_testutil import ( - "log" "sync" "testing" @@ -28,13 +27,14 @@ func PrepareEventMetricsAgentMock(t *testing.T, valId string, wg *sync.WaitGroup ctrl := gomock.NewController(t) eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) + // TODO_THIS_COMMIT: remove logEvent := func(n, e string, l ...any) { - t.Logf("n: %s, e: %s, l: %v\n", n, e, l) + //t.Logf("n: %s, e: %s, l: %v\n", n, e, l) } - //eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Do(logEvent).AnyTimes() + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Do(logEvent).AnyTimes() eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Eq(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).Do(func(n, e any, l ...any) { - log.Printf("[valId: %s] Write\n", valId) + t.Logf("[valId: %s] Write", valId) wg.Done() }).Do(logEvent).Times(expectedNumNetworkWrites) eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Not(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).Do(logEvent).AnyTimes() diff --git a/p2p/module_raintree_test.go b/p2p/module_raintree_test.go index 24bc2b6f1..98a8d4297 100644 --- a/p2p/module_raintree_test.go +++ b/p2p/module_raintree_test.go @@ -6,6 +6,7 @@ import ( runtime_testutil "github.com/pokt-network/pocket/internal/testutil/runtime" telemetry_testutil "github.com/pokt-network/pocket/internal/testutil/telemetry" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/modules" mock_modules "github.com/pokt-network/pocket/shared/modules/mocks" "log" "os" @@ -23,8 +24,6 @@ import ( "github.com/pokt-network/pocket/internal/testutil/constructors" "github.com/pokt-network/pocket/internal/testutil/p2p" persistence_testutil "github.com/pokt-network/pocket/internal/testutil/persistence" - "github.com/pokt-network/pocket/p2p/protocol" - "github.com/pokt-network/pocket/p2p/raintree" "github.com/pokt-network/pocket/shared/messaging" ) @@ -237,19 +236,25 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te genesisState := runtime_testutil.GenesisWithSequentialServiceURLs(t, pubKeys) - var wg sync.WaitGroup + var ( + wg sync.WaitGroup + busMocks map[string]*mock_modules.MockBus + p2pModules map[string]modules.P2PModule + ) //busMocks := createMockBuses(t, runtimeConfigs, &wg) busEventHandlerFactory := func(t gocuke.TestingT, busMock *mock_modules.MockBus) testutil.BusEventHandler { return func(data *messaging.PocketEnvelope) { - // TODO: decide - is mutually exclusive w/ telemetry based wg.Done() below + p2pCfg := busMock.GetRuntimeMgr().GetConfig().P2P + // `p2pModule#handleNetworkData()` calls `modules.Bus#PublishEventToBus()` - // assumes that P2P module is the only event producer running during the test - t.Log("bus event received") + // assumes that P2P module is the only bus event producer running during + // the test. + t.Logf("[valId: %s:%d] Read", p2pCfg.Hostname, p2pCfg.Port) wg.Done() } } - busMocks, _, p2pModules := constructors.NewBusesMocknetAndP2PModules( + busMocks, _, p2pModules = constructors.NewBusesMocknetAndP2PModules( t, numValidators, genesisState, busEventHandlerFactory, @@ -301,25 +306,6 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te // wg.Done() //} - //privKey, err := cryptoPocket.NewPrivateKey(busMock.GetRuntimeMgr().GetConfig().P2P.PrivateKey) - //require.NoError(t, err) - // - // TODO_THIS_COMMIT: move & de-dup - //libp2pPrivKey, err := libp2pCrypto.UnmarshalEd25519PrivateKey(privKey.Bytes()) - //require.NoError(t, err) - // - //libp2pPeerID, err := libp2pPeer.IDFromPrivateKey(libp2pPrivKey) - //require.NoError(t, err) - // END TODO - // - //sURL := strings.Clone(serviceURL) - //host := libp2pNetworkMock.Host(libp2pPeerID) - //host.SetStreamHandler(protocol.PoktProtocolID, func(stream libp2pNetwork.Stream) { - // t.Logf("[valID: %s] Read\n", sURL) - // p2pModules[serviceURL].(*p2p.P2PModule).HandleStream(stream) - // wg.Done() - //}) - eventMetricsAgentMock := telemetry_testutil.PrepareEventMetricsAgentMock(t, serviceURL, &wg, expectedWrites) busMock.GetTelemetryModule().(*mock_modules.MockTelemetryModule).EXPECT(). GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() @@ -334,34 +320,21 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te // gomock.Any(), // //).Do(telemetryEventHandler).Times(expectedWrites) //).Do(telemetryEventHandler).AnyTimes() - ////telemetryMock.GetEventMetricsAgent().(*mock_modules.MockEventMetricsAgent).EXPECT().EmitEvent( - //// gomock.Eq("one"), - //// gomock.Eq("two"), - //// gomock.Eq("three"), - ////).Do(telemetryEventHandler).Times(expectedWrites) - ////telemetryMock. - //// GetEventMetricsAgent(). - //// EmitEvent( - //// "one", - //// "two", - //// "three", - //// ) } - // Inject the connection and bus mocks into the P2P modules - //p2pModules := createP2PModules(t, busMocks, libp2pNetworkMock, serviceURLs) - + // Start all p2p modules for _, p2pMod := range p2pModules { err := p2pMod.Start() require.NoError(t, err) - sURL := strings.Clone(serviceURL) - mod := *p2pMod - p2pMod.host.SetStreamHandler(protocol.PoktProtocolID, func(stream libp2pNetwork.Stream) { - log.Printf("[valID: %s] Read\n", sURL) - (&mod).router.(*raintree.RainTreeRouter).HandleStream(stream) - wg.Done() - }) + // TODO_THIS_COMMIT: decide where to `wg.Done()` + //sURL := strings.Clone(serviceURL) + //mod := *p2pMod + //p2pMod.host.SetStreamHandler(protocol.PoktProtocolID, func(stream libp2pNetwork.Stream) { + // log.Printf("[valID: %s] Read\n", sURL) + // (&mod).router.(*raintree.RainTreeRouter).HandleStream(stream) + // wg.Done() + //}) } // Wait for completion @@ -378,18 +351,6 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te p := &anypb.Any{} p2pMod := p2pModules[origNode] require.NoError(t, p2pMod.Broadcast(p)) - - //for _, busMock := range busMocks { - // busMock. - //busMocks[testutil.GetKeys(busMocks)[0]]. - // GetTelemetryModule(). - // GetEventMetricsAgent(). - // EmitEvent( - // "one", - // "two", - // "three", - // ) - //} } func extractNumericId(valId string) int64 { diff --git a/p2p/testutil.go b/p2p/testutil.go index b455024bf..a030d8682 100644 --- a/p2p/testutil.go +++ b/p2p/testutil.go @@ -2,12 +2,5 @@ package p2p -import libp2pNetwork "github.com/libp2p/go-libp2p/core/network" - // P2PModule exports the `p2pModule` type for use in tests type P2PModule = p2pModule - -// HandleStream exports the `handleStream` method for use in tests -func (m *p2pModule) HandleStream(stream libp2pNetwork.Stream) { - m.handleStream(stream) -} From e46f386af7b14584b2e6bbafe142c2764f47cf46 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:08:18 +0200 Subject: [PATCH 10/22] wip: testutils --- internal/testutil/constructors/constructors.go | 1 + internal/testutil/telemetry/event_metrics_agent.go | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 744acf85e..57990e03b 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -63,6 +63,7 @@ func NewBusesMocknetAndP2PModules( // TODO_THIS_COMMIT: refactor _ = consensus_testutil.BaseConsensusMock(t, busMock) _ = persistence_testutil.BasePersistenceMock(t, busMock, genesisState) + //_ = telemetry_testutil.BaseTelemetryMock(t, busMock) _ = telemetry_testutil.WithTimeSeriesAgent( t, telemetry_testutil.MinimalTelemetryMock(t, busMock), ) diff --git a/internal/testutil/telemetry/event_metrics_agent.go b/internal/testutil/telemetry/event_metrics_agent.go index ff665b0a1..4060ac4ae 100644 --- a/internal/testutil/telemetry/event_metrics_agent.go +++ b/internal/testutil/telemetry/event_metrics_agent.go @@ -1,11 +1,9 @@ package telemetry_testutil import ( - "sync" - "testing" - "github.com/golang/mock/gomock" "github.com/regen-network/gocuke" + "sync" "github.com/pokt-network/pocket/shared/modules/mocks" "github.com/pokt-network/pocket/telemetry" @@ -17,13 +15,18 @@ func BaseEventMetricsAgentMock(t gocuke.TestingT) *mock_modules.MockEventMetrics ctrl := gomock.NewController(t) eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + + // TODO_THIS_COMMIT: remove v -- may represent failure condition w/ reused nonces.. + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + // END TODO + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() return eventMetricsAgentMock } // TODO_THIS_COMMIT: refactor... // Events metric mock - Needed to help with proper counts for number of expected network writes -func PrepareEventMetricsAgentMock(t *testing.T, valId string, wg *sync.WaitGroup, expectedNumNetworkWrites int) *mock_modules.MockEventMetricsAgent { +func PrepareEventMetricsAgentMock(t gocuke.TestingT, valId string, wg *sync.WaitGroup, expectedNumNetworkWrites int) *mock_modules.MockEventMetricsAgent { ctrl := gomock.NewController(t) eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) @@ -56,7 +59,7 @@ func EventMetricsAgentMockWithHandler( eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Eq(label), gomock.Any()).Do(handler).Times(times) // TODO_THIS_COMMIT: is this really needed? - eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Not(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).AnyTimes() + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Not(label), gomock.Any()).AnyTimes() return eventMetricsAgentMock } From dc435633cf4f011c107c688c449bc6b6368914e7 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 22 May 2023 10:57:15 +0200 Subject: [PATCH 11/22] wip: checkpoint --- internal/testutil/persistence/mocks.go | 4 ++-- p2p/transport_encryption_test.go | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/internal/testutil/persistence/mocks.go b/internal/testutil/persistence/mocks.go index f64c9bab1..2e18385b6 100644 --- a/internal/testutil/persistence/mocks.go +++ b/internal/testutil/persistence/mocks.go @@ -5,7 +5,7 @@ import ( "github.com/golang/mock/gomock" "github.com/regen-network/gocuke" - "github.com/pokt-network/pocket/persistence/types/mocks" + persistence_mocks "github.com/pokt-network/pocket/persistence/types/mocks" "github.com/pokt-network/pocket/runtime/genesis" "github.com/pokt-network/pocket/shared/codec" "github.com/pokt-network/pocket/shared/core/types" @@ -47,7 +47,7 @@ func PersistenceMockWithBlockStore(t gocuke.TestingT, _ modules.EventsChannel, b persistenceMock.EXPECT().ReleaseWriteContext().Return(nil).AnyTimes() - blockStoreMock := mock_kvstore.NewMockKVStore(ctrl) + blockStoreMock := persistence_mocks.NewMockBlockStore(ctrl) blockStoreMock.EXPECT().Get(gomock.Any()).DoAndReturn(func(height []byte) ([]byte, error) { heightInt := utils.HeightFromBytes(height) diff --git a/p2p/transport_encryption_test.go b/p2p/transport_encryption_test.go index a5dd7f236..f2f2dbec7 100644 --- a/p2p/transport_encryption_test.go +++ b/p2p/transport_encryption_test.go @@ -61,12 +61,8 @@ func TestP2pModule_Insecure_Error(t *testing.T) { persistenceMock := persistence_testutil.BasePersistenceMock(t, busMock, genesisStateMock) busMock.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() - serviceURLs := make([]string, len(genesisStateMock.Validators)) - for i, actor := range genesisStateMock.Validators { - serviceURLs[i] = actor.ServiceUrl - } - dnsDone := testutil.PrepareDNSMockFromServiceURLs(t, serviceURLs) - t.Cleanup(dnsDone) + // mock DNS for service URL hostnames + _ = testutil.DNSMockFromServiceURLs(t, serviceURLs) p2pMod, err := p2p.Create(busMock) require.NoError(t, err) From 262a77095dc67e6afdc277d25b139cc4a2ff55ac Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:16:41 +0200 Subject: [PATCH 12/22] wip: testutils --- .../testutil/constructors/constructors.go | 12 ++- .../testutil/telemetry/event_metrics_agent.go | 51 ++++++++++- internal/testutil/telemetry/mocks.go | 19 +++-- p2p/utils_test.go | 84 ------------------- 4 files changed, 68 insertions(+), 98 deletions(-) diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 57990e03b..6c95ad422 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -63,10 +63,14 @@ func NewBusesMocknetAndP2PModules( // TODO_THIS_COMMIT: refactor _ = consensus_testutil.BaseConsensusMock(t, busMock) _ = persistence_testutil.BasePersistenceMock(t, busMock, genesisState) - //_ = telemetry_testutil.BaseTelemetryMock(t, busMock) - _ = telemetry_testutil.WithTimeSeriesAgent( - t, telemetry_testutil.MinimalTelemetryMock(t, busMock), - ) + + // -- option 1 + _ = telemetry_testutil.BaseTelemetryMock(t, busMock) + + // -- option 2 + //_ = telemetry_testutil.WithTimeSeriesAgent( + // t, telemetry_testutil.MinimalTelemetryMock(t, busMock), + //) // MUST register DNS before instantiating P2PModule testutil.AddServiceURLZone(t, dnsSrv, serviceURL) diff --git a/internal/testutil/telemetry/event_metrics_agent.go b/internal/testutil/telemetry/event_metrics_agent.go index 4060ac4ae..5de2987c0 100644 --- a/internal/testutil/telemetry/event_metrics_agent.go +++ b/internal/testutil/telemetry/event_metrics_agent.go @@ -9,11 +9,12 @@ import ( "github.com/pokt-network/pocket/telemetry" ) -func BaseEventMetricsAgentMock(t gocuke.TestingT) *mock_modules.MockEventMetricsAgent { +func WithP2PIntegrationEvents( + t gocuke.TestingT, + eventMetricsAgentMock *mock_modules.MockEventMetricsAgent, +) *mock_modules.MockEventMetricsAgent { t.Helper() - ctrl := gomock.NewController(t) - eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() // TODO_THIS_COMMIT: remove v -- may represent failure condition w/ reused nonces.. @@ -45,6 +46,29 @@ func PrepareEventMetricsAgentMock(t gocuke.TestingT, valId string, wg *sync.Wait return eventMetricsAgentMock } +func WhyEventMetricsAgentMock( + t gocuke.TestingT, + eventMetricsAgentMock *mock_modules.MockEventMetricsAgent, + valId string, + wg *sync.WaitGroup, + //handler func(namespace, eventName string, labels ...any), + expectedNumNetworkWrites int, +) *mock_modules.MockEventMetricsAgent { + // TODO_THIS_COMMIT: remove + logEvent := func(n, e string, l ...any) { + //t.Logf("n: %s, e: %s, l: %v\n", n, e, l) + } + + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Do(logEvent).AnyTimes() + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Eq(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).Do(func(n, e any, l ...any) { + t.Logf("[valId: %s] Write", valId) + wg.Done() + }).Do(logEvent).Times(expectedNumNetworkWrites) + eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Not(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).Do(logEvent).AnyTimes() + + return eventMetricsAgentMock +} + func EventMetricsAgentMockWithHandler( t gocuke.TestingT, label string, @@ -52,9 +76,30 @@ func EventMetricsAgentMockWithHandler( handler func(namespace, eventName string, labels ...any), times int, ) *mock_modules.MockEventMetricsAgent { + t.Helper() + ctrl := gomock.NewController(t) eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) + return WithEventMetricsHandler(t, eventMetricsAgentMock, label, handler, times) +} + +func WithEventMetricsHandler( + t gocuke.TestingT, + eventMetricsAgentMock *mock_modules.MockEventMetricsAgent, + label string, + handler func(namespace, eventName string, labels ...any), + times int, +) *mock_modules.MockEventMetricsAgent { + t.Helper() + + //eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Do(logEvent).AnyTimes() + //eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Eq(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).Do(func(n, e any, l ...any) { + // t.Logf("[valId: %s] Write", valId) + // wg.Done() + //}).Do(logEvent).Times(expectedNumNetworkWrites) + //eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Not(telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL), gomock.Any()).Do(logEvent).AnyTimes() + // TODO_THIS_COMMIT: scrutinize these & their order eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() eventMetricsAgentMock.EXPECT().EmitEvent(gomock.Any(), gomock.Any(), gomock.Eq(label), gomock.Any()).Do(handler).Times(times) diff --git a/internal/testutil/telemetry/mocks.go b/internal/testutil/telemetry/mocks.go index a369bcbd5..3271e9767 100644 --- a/internal/testutil/telemetry/mocks.go +++ b/internal/testutil/telemetry/mocks.go @@ -11,7 +11,7 @@ import ( func MinimalTelemetryMock( t gocuke.TestingT, busMock *mock_modules.MockBus, -) modules.TelemetryModule { +) *mock_modules.MockTelemetryModule { t.Helper() ctrl := gomock.NewController(t) @@ -31,26 +31,31 @@ func MinimalTelemetryMock( func BaseTelemetryMock( t gocuke.TestingT, busMock *mock_modules.MockBus, -) modules.TelemetryModule { +) *mock_modules.MockTelemetryModule { t.Helper() return WithTimeSeriesAgent(t, WithEventMetricsAgent(t, MinimalTelemetryMock(t, busMock))) } -func WithTimeSeriesAgent(t gocuke.TestingT, telemetryMod modules.TelemetryModule) *mock_modules.MockTelemetryModule { +func WithTimeSeriesAgent( + t gocuke.TestingT, + telemetryMock *mock_modules.MockTelemetryModule, +) *mock_modules.MockTelemetryModule { t.Helper() - telemetryMock := telemetryMod.(*mock_modules.MockTelemetryModule) timeSeriesAgentMock := BaseTimeSeriesAgentMock(t) telemetryMock.EXPECT().GetTimeSeriesAgent().Return(timeSeriesAgentMock).AnyTimes() return telemetryMock } -func WithEventMetricsAgent(t gocuke.TestingT, telemetryMod modules.TelemetryModule) modules.TelemetryModule { +func WithEventMetricsAgent( + t gocuke.TestingT, + telemetryMock *mock_modules.MockTelemetryModule, +) *mock_modules.MockTelemetryModule { t.Helper() - telemetryMock := telemetryMod.(*mock_modules.MockTelemetryModule) - eventMetricsAgentMock := BaseEventMetricsAgentMock(t) + ctrl := gomock.NewController(t) + eventMetricsAgentMock := mock_modules.NewMockEventMetricsAgent(ctrl) telemetryMock.EXPECT().GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() return telemetryMock diff --git a/p2p/utils_test.go b/p2p/utils_test.go index bf225bc75..57f5729d2 100644 --- a/p2p/utils_test.go +++ b/p2p/utils_test.go @@ -3,31 +3,17 @@ package p2p_test import ( - "github.com/pokt-network/pocket/internal/testutil" - "github.com/pokt-network/pocket/internal/testutil/runtime" - "github.com/pokt-network/pocket/internal/testutil/telemetry" - "github.com/pokt-network/pocket/p2p" - "github.com/pokt-network/pocket/shared/messaging" - "github.com/pokt-network/pocket/telemetry" - "github.com/regen-network/gocuke" "sort" "sync" "testing" "time" - mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" - "github.com/stretchr/testify/require" - - p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" - "github.com/pokt-network/pocket/shared/modules" - mockModules "github.com/pokt-network/pocket/shared/modules/mocks" ) // ~~~~~~ RainTree Unit Test Configurations ~~~~~~ const ( - eventsChannelSize = 10000 // Since we simulate up to a 27 node network, we will pre-generate a n >= 27 number of keys to avoid generation // every time. The genesis config seed start is set for deterministic key generation and 42 was chosen arbitrarily. genesisConfigSeedStart = 42 @@ -83,73 +69,3 @@ func waitForNetworkSimulationCompletion(t *testing.T, wg *sync.WaitGroup) { t.Fatal("Timeout waiting for message to be handled") } } - -// ~~~~~~ RainTree Unit Test Mocks ~~~~~~ - -// createP2PModules returns a map of configured p2pModules keyed by an incremental naming convention (eg: `val_1`, `val_2`, etc.) -func createP2PModules(t *testing.T, busMocks []*mockModules.MockBus, netMock mocknet.Mocknet, serviceURLs []string) (p2pModules map[string]*p2p.P2PModule) { - t.Helper() - - require.GreaterOrEqualf(t, len(serviceURLs), len(busMocks), "number of bus mocks must be less than or equal to the number of service URLs") - - peerIDs := p2p_testutil.SetupMockNetPeers(t, netMock, keys[:len(busMocks)], serviceURLs) - p2pModules = make(map[string]*p2p.P2PModule, len(busMocks)) - for i := range busMocks { - host := netMock.Host(peerIDs[i]) - p2pMod, err := p2p.Create(busMocks[i], p2p.WithHostOption(host)) - require.NoError(t, err) - p2pModules[serviceURLs[i]] = p2pMod.(*p2p.P2PModule) - } - return -} - -// createMockRuntimeMgrs creates `numValidators` instances of mocked `RuntimeMgr` that are essentially -// representing the runtime environments of the validators that we will use in our tests -func createMockRuntimeMgrs(t *testing.T, numValidators int) []modules.RuntimeMgr { - mockRuntimeMgrs := make([]modules.RuntimeMgr, numValidators) - valKeys := make([]cryptoPocket.PrivateKey, numValidators) - copy(valKeys, keys[:numValidators]) - mockGenesisState := runtime_testutil.GenesisWithSequentialServiceURLs(t, valKeys) - for i := range mockRuntimeMgrs { - mockRuntimeMgrs[i] = runtime_testutil.BaseRuntimeManagerMock( - t, valKeys[i], - p2p_testutil.NewServiceURL(i+1), - mockGenesisState, - ) - } - return mockRuntimeMgrs -} - -func createMockBuses(t *testing.T, runtimeMgrs []modules.RuntimeMgr, wg *sync.WaitGroup) []*mockModules.MockBus { - mockBuses := make([]*mockModules.MockBus, len(runtimeMgrs)) - for i := range mockBuses { - handlerFactory := func(t gocuke.TestingT, bus modules.Bus) testutil.BusEventHandler { - return func(data *messaging.PocketEnvelope) { - wg.Done() - } - } - mockBuses[i] = testutil.BusMockWithEventHandler(t, runtimeMgrs[i], handlerFactory) - } - return mockBuses -} - -// TODO_THIS_COMMIT: refactor / move -// Telemetry mock - Needed to help with proper counts for number of expected network writes -func prepareTelemetryMock(t *testing.T, busMock *mockModules.MockBus, valId string, wg *sync.WaitGroup, expectedNumNetworkWrites int) *mockModules.MockTelemetryModule { - telemetryMock := telemetry_testutil.WithTimeSeriesAgent(t, - telemetry_testutil.MinimalTelemetryMock(t, busMock), - ) - - eventMetricsAgentMock := telemetry_testutil.EventMetricsAgentMockWithHandler( - t, telemetry.P2P_RAINTREE_MESSAGE_EVENT_METRIC_SEND_LABEL, - func(namesapce, event_name string, labels ...any) { - t.Logf("[valId: %s] Write\n", valId) - wg.Done() - }, - expectedNumNetworkWrites, - ) - - telemetryMock.EXPECT().GetEventMetricsAgent().Return(eventMetricsAgentMock).AnyTimes() - busMock.RegisterModule(telemetryMock) - return telemetryMock -} From 0a27fadc6f2671cc009c220cbf14ea8eb77b62a6 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:22:21 +0200 Subject: [PATCH 13/22] wip: testutils --- internal/testutil/keys.go | 2 +- internal/testutil/telemetry/mocks.go | 27 ++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/internal/testutil/keys.go b/internal/testutil/keys.go index 5c621fe11..5f8b6accc 100644 --- a/internal/testutil/keys.go +++ b/internal/testutil/keys.go @@ -25,7 +25,7 @@ func LoadLocalnetPrivateKeys(t require.TestingT, keyCount int) (privKeys []crypt privKeys = make([]cryptoPocket.PrivateKey, 0, keyCount) - // scann through file & extract private keys + // scan through file & extract private keys scanner := bufio.NewScanner(privKeyManifest) scanner.Split(bufio.ScanLines) diff --git a/internal/testutil/telemetry/mocks.go b/internal/testutil/telemetry/mocks.go index 3271e9767..633d03129 100644 --- a/internal/testutil/telemetry/mocks.go +++ b/internal/testutil/telemetry/mocks.go @@ -2,6 +2,7 @@ package telemetry_testutil import ( "github.com/golang/mock/gomock" + "github.com/pokt-network/pocket/internal/testutil" "github.com/regen-network/gocuke" "github.com/pokt-network/pocket/shared/modules" @@ -17,13 +18,20 @@ func MinimalTelemetryMock( ctrl := gomock.NewController(t) telemetryMock := mock_modules.NewMockTelemetryModule(ctrl) + busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() + + return telemetryMock +} + +func BehavesLikeBaseTelemetryMock( + t gocuke.TestingT, + telemetryMock *mock_modules.MockTelemetryModule, +) *mock_modules.MockTelemetryModule { + t.Helper() + telemetryMock.EXPECT().Start().Return(nil).AnyTimes() telemetryMock.EXPECT().SetBus(gomock.Any()).Return().AnyTimes() - // TODO_THIS_COMMIT: which one ^ v ? - //telemetryMock.EXPECT().SetBus(busMock).Return().AnyTimes() telemetryMock.EXPECT().GetModuleName().Return(modules.TelemetryModuleName).AnyTimes() - busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() - //busMock.RegisterModule(telemetryMock) return telemetryMock } @@ -33,7 +41,16 @@ func BaseTelemetryMock( busMock *mock_modules.MockBus, ) *mock_modules.MockTelemetryModule { t.Helper() - return WithTimeSeriesAgent(t, WithEventMetricsAgent(t, MinimalTelemetryMock(t, busMock))) + + return testutil.PipeTwoToOne[ + gocuke.TestingT, + *mock_modules.MockTelemetryModule + ]( + t, MinimalTelemetryMock(t, busMock), + BehavesLikeBaseTelemetryMock, + WithEventMetricsAgent, + WithTimeSeriesAgent, + ) } func WithTimeSeriesAgent( From 7fc3c3d97eadba614a4d8a755926c4ed27e0d8f5 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:25:49 +0200 Subject: [PATCH 14/22] wip: testutils - refactor & add to generics --- internal/testutil/composition.go | 30 +++++++++++++++++++++++ internal/testutil/generics/composition.go | 30 +++++++++++++++++++++++ internal/testutil/{ => generics}/map.go | 0 internal/testutil/generics/proxy.go | 3 +++ 4 files changed, 63 insertions(+) create mode 100644 internal/testutil/composition.go create mode 100644 internal/testutil/generics/composition.go rename internal/testutil/{ => generics}/map.go (100%) create mode 100644 internal/testutil/generics/proxy.go diff --git a/internal/testutil/composition.go b/internal/testutil/composition.go new file mode 100644 index 000000000..5e4d66b0f --- /dev/null +++ b/internal/testutil/composition.go @@ -0,0 +1,30 @@ +package testutil + +// PipeTwoToOne threads two values of any type (T and U) through a pipeline of +// functions and returns the result of any type (U). Each function in the pipeline +// takes two arguments of type T and U, and returns a value of type U. +// +// Applies each function in the pipeline to the current value of U and the +// constant value of T, effectively "threading" the initial U value through the +// pipeline of functions. +// +// Does *not* mutate the original U value. Instead, it operates on a reference +// to U, ensuring that value types (non-pointer types) are not mutated. +// +// Returns the final value of U after it has been threaded through all the functions in the pipeline. +// +// Usage: +// +// result := PipeTwo(initialT, initialU, func1, func2, func3) +// +// In this example, initialT and initialU are the initial values of T and U, and func1, func2, and func3 +// are functions that take two arguments of type T and U and return a value of type U. +func PipeTwoToOne[T, U any](t T, u U, pipeline ...func(T, U) U) U { + // NB: don't mutate potential value type `u` (i.e. non-pointer) + uRef := u + for _, fn := range pipeline { + uRef = fn(t, uRef) + } + + return u +} diff --git a/internal/testutil/generics/composition.go b/internal/testutil/generics/composition.go new file mode 100644 index 000000000..5e4d66b0f --- /dev/null +++ b/internal/testutil/generics/composition.go @@ -0,0 +1,30 @@ +package testutil + +// PipeTwoToOne threads two values of any type (T and U) through a pipeline of +// functions and returns the result of any type (U). Each function in the pipeline +// takes two arguments of type T and U, and returns a value of type U. +// +// Applies each function in the pipeline to the current value of U and the +// constant value of T, effectively "threading" the initial U value through the +// pipeline of functions. +// +// Does *not* mutate the original U value. Instead, it operates on a reference +// to U, ensuring that value types (non-pointer types) are not mutated. +// +// Returns the final value of U after it has been threaded through all the functions in the pipeline. +// +// Usage: +// +// result := PipeTwo(initialT, initialU, func1, func2, func3) +// +// In this example, initialT and initialU are the initial values of T and U, and func1, func2, and func3 +// are functions that take two arguments of type T and U and return a value of type U. +func PipeTwoToOne[T, U any](t T, u U, pipeline ...func(T, U) U) U { + // NB: don't mutate potential value type `u` (i.e. non-pointer) + uRef := u + for _, fn := range pipeline { + uRef = fn(t, uRef) + } + + return u +} diff --git a/internal/testutil/map.go b/internal/testutil/generics/map.go similarity index 100% rename from internal/testutil/map.go rename to internal/testutil/generics/map.go diff --git a/internal/testutil/generics/proxy.go b/internal/testutil/generics/proxy.go new file mode 100644 index 000000000..8dd837735 --- /dev/null +++ b/internal/testutil/generics/proxy.go @@ -0,0 +1,3 @@ +package generics_testutil + +type ProxyFactory[T any] func(target T) (proxy T) From 02b6b1e9fb03844dc21179031242bfd74556f67b Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 11:28:54 +0200 Subject: [PATCH 15/22] wip: testutils --- .../testutil/constructors/constructors.go | 25 +++---------------- shared/messaging/proto/debug_message.proto | 4 +++ 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 6c95ad422..3fd96a39a 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -3,6 +3,7 @@ package constructors import ( libp2pHost "github.com/libp2p/go-libp2p/core/host" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/pokt-network/pocket/internal/testutil/bus" consensus_testutil "github.com/pokt-network/pocket/internal/testutil/consensus" persistence_testutil "github.com/pokt-network/pocket/internal/testutil/persistence" telemetry_testutil "github.com/pokt-network/pocket/internal/testutil/telemetry" @@ -11,7 +12,6 @@ import ( "github.com/pokt-network/pocket/internal/testutil" p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" - runtime_testutil "github.com/pokt-network/pocket/internal/testutil/runtime" "github.com/pokt-network/pocket/p2p" "github.com/pokt-network/pocket/runtime/genesis" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" @@ -57,7 +57,7 @@ func NewBusesMocknetAndP2PModules( } privKey := privKeys[i] - busMock := NewBus(t, privKey, serviceURL, genesisState, busEventHandlerFactory) + busMock := bus_testutil.NewBus(t, privKey, serviceURL, genesisState, busEventHandlerFactory) buses[serviceURL] = busMock // TODO_THIS_COMMIT: refactor @@ -118,29 +118,10 @@ func NewBusesAndP2PModuleWithHost( ) (*mock_modules.MockBus, modules.P2PModule) { t.Helper() - busMock := NewBus(t, privKey, serviceURL, genesisState, busEventHandlerFactory) + busMock := bus_testutil.NewBus(t, privKey, serviceURL, genesisState, busEventHandlerFactory) return busMock, NewP2PModuleWithHost(t, busMock, host) } -func NewBus( - t gocuke.TestingT, - privKey cryptoPocket.PrivateKey, - serviceURL string, - genesisState *genesis.GenesisState, - busEventHandlerFactory testutil.BusEventHandlerFactory, -) *mock_modules.MockBus { - t.Helper() - - runtimeMgrMock := runtime_testutil.BaseRuntimeManagerMock( - t, privKey, - serviceURL, - genesisState, - ) - busMock := testutil.BusMockWithEventHandler(t, runtimeMgrMock, busEventHandlerFactory) - busMock.EXPECT().GetRuntimeMgr().Return(runtimeMgrMock).AnyTimes() - return busMock -} - func NewP2PModuleWithHost( t gocuke.TestingT, busMock *mock_modules.MockBus, diff --git a/shared/messaging/proto/debug_message.proto b/shared/messaging/proto/debug_message.proto index 7ce079afa..7e42f7ddd 100644 --- a/shared/messaging/proto/debug_message.proto +++ b/shared/messaging/proto/debug_message.proto @@ -30,6 +30,10 @@ message DebugMessage { google.protobuf.Any message = 3; } +message DebugStringMessage { + string value = 1; +} + // NB: See https://en.wikipedia.org/wiki/Routing for more info on routing and delivery schemes. enum DebugMessageRoutingType { DEBUG_MESSAGE_TYPE_UNKNOWN = 0; From f0aee7207feb37acbb97789dc69db04448568fe5 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:31:46 +0200 Subject: [PATCH 16/22] wip: testutils --- internal/testutil/bus.go | 7 +- .../testutil/constructors/constructors.go | 135 +++++++------- internal/testutil/module.go | 41 +++++ internal/testutil/network.go | 73 ++++++++ internal/testutil/p2p/network.go | 49 ++---- internal/testutil/runtime/genesis.go | 28 ++- p2p/module_raintree_test.go | 165 +++++++++--------- p2p/module_test.go | 3 +- p2p/transport_encryption_test.go | 11 +- 9 files changed, 322 insertions(+), 190 deletions(-) create mode 100644 internal/testutil/module.go create mode 100644 internal/testutil/network.go diff --git a/internal/testutil/bus.go b/internal/testutil/bus.go index 972965eca..1f83597a3 100644 --- a/internal/testutil/bus.go +++ b/internal/testutil/bus.go @@ -75,8 +75,11 @@ func WithBusEventHandler( ) *mock_modules.MockBus { t.Helper() - handler := handlerFactory(t, busMock) - busMock.EXPECT().PublishEventToBus(gomock.Any()).Do(handler).AnyTimes() + if handlerFactory != nil { + handler := handlerFactory(t, busMock) + busMock.EXPECT().PublishEventToBus(gomock.Any()).Do(handler).AnyTimes() + } + return busMock } diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 3fd96a39a..5491c981a 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -1,6 +1,7 @@ package constructors import ( + "github.com/foxcpp/go-mockdns" libp2pHost "github.com/libp2p/go-libp2p/core/host" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/pokt-network/pocket/internal/testutil/bus" @@ -25,6 +26,7 @@ type serviceURLStr = string func NewBusesMocknetAndP2PModules( t gocuke.TestingT, count int, + dnsSrv *mockdns.Server, genesisState *genesis.GenesisState, busEventHandlerFactory testutil.BusEventHandlerFactory, ) ( @@ -32,78 +34,92 @@ func NewBusesMocknetAndP2PModules( libp2pNetworkMock mocknet.Mocknet, p2pModules map[serviceURLStr]modules.P2PModule, ) { - // TODO_THIS_COMMIT: refactor - dnsSrv := testutil.MinimalDNSMock(t) - - libp2pNetworkMock = mocknet.New() - // destroy mocknet on test cleanup - t.Cleanup(func() { - err := libp2pNetworkMock.Close() - require.NoError(t, err) - }) - - buses = make(map[serviceURLStr]*mock_modules.MockBus) - p2pModules = make(map[serviceURLStr]modules.P2PModule) - // CONSIDERATION: using an iterator/generator would prevent unintentional - // ID collisions - privKeys := testutil.LoadLocalnetPrivateKeys(t, count) - // CONSIDERATION: using an iterator/generator would prevent unintentional - // serviceURL collisions - serviceURLs := p2p_testutil.SequentialServiceURLs(t, count) - for i, serviceURL := range serviceURLs { - if len(privKeys) <= i { - t.Logf("WARNING: not enough private keys for %d service URLs", len(serviceURLs)) - break - } - - privKey := privKeys[i] - busMock := bus_testutil.NewBus(t, privKey, serviceURL, genesisState, busEventHandlerFactory) - buses[serviceURL] = busMock - - // TODO_THIS_COMMIT: refactor - _ = consensus_testutil.BaseConsensusMock(t, busMock) - _ = persistence_testutil.BasePersistenceMock(t, busMock, genesisState) - - // -- option 1 - _ = telemetry_testutil.BaseTelemetryMock(t, busMock) - - // -- option 2 - //_ = telemetry_testutil.WithTimeSeriesAgent( - // t, telemetry_testutil.MinimalTelemetryMock(t, busMock), - //) - - // MUST register DNS before instantiating P2PModule - testutil.AddServiceURLZone(t, dnsSrv, serviceURL) - - host := p2p_testutil.NewMocknetHost(t, libp2pNetworkMock, privKey) - p2pModules[serviceURL] = NewP2PModuleWithHost(t, busMock, host) - } + libp2pNetworkMock = p2p_testutil.NewLibp2pNetworkMock(t) + serviceURLKeyMap := testutil.SequentialServiceURLPrivKeyMap(t, count) + + buses, p2pModules = NewBusesAndP2PModules( + t, busEventHandlerFactory, + dnsSrv, + genesisState, + libp2pNetworkMock, + serviceURLKeyMap, + ) err := libp2pNetworkMock.LinkAll() require.NoError(t, err) return buses, libp2pNetworkMock, p2pModules } -// TODO_THIS_TEST: need this? -func NewP2PModules( +// TODO_THIS_COMMIT: rename / move, if possible +func NewP2PModule( t gocuke.TestingT, - privKeys []cryptoPocket.PrivateKey, + // TODO_THIS_COMMIT: get these from the bus instead + serviceURL string, + privKey cryptoPocket.PrivateKey, + // -- busMock *mock_modules.MockBus, + genesisState *genesis.GenesisState, + dnsSrv *mockdns.Server, + libp2pNetworkMock mocknet.Mocknet, + // TODO_THIS_COMMIT: consider *p2p.P2PModule instead +) modules.P2PModule { + _ = consensus_testutil.BaseConsensusMock(t, busMock) + _ = persistence_testutil.BasePersistenceMock(t, busMock, genesisState) + + // -- option 1 + _ = telemetry_testutil.BaseTelemetryMock(t, busMock) + + // -- option 2 + //_ = telemetry_testutil.WithTimeSeriesAgent( + // t, telemetry_testutil.MinimalTelemetryMock(t, busMock), + //) + + // MUST register DNS before instantiating P2PModule + testutil.AddServiceURLZone(t, dnsSrv, serviceURL) + + host := testutil.NewMocknetHost(t, libp2pNetworkMock, privKey) + return NewP2PModuleWithHost(t, busMock, host) +} + +// TODO_THIS_TEST: need this? +func NewBusesAndP2PModules( + t gocuke.TestingT, + busEventHandlerFactory testutil.BusEventHandlerFactory, + dnsSrv *mockdns.Server, + genesisState *genesis.GenesisState, libp2pNetworkMock mocknet.Mocknet, + serviceURLKeyMap map[serviceURLStr]cryptoPocket.PrivateKey, ) ( + busMocks map[serviceURLStr]*mock_modules.MockBus, + // TODO_THIS_COMMIT: consider *p2p.P2PModule instead p2pModules map[serviceURLStr]modules.P2PModule, ) { - // CONSIDERATION: using an iterator/generator would prevent unintentional - // serviceURL collisions - serviceURLs := p2p_testutil.SequentialServiceURLs(t, len(privKeys)) - _ = p2p_testutil.SetupMockNetPeers(t, libp2pNetworkMock, privKeys, serviceURLs) - - for i, serviceURL := range serviceURLs { - host := libp2pNetworkMock.Hosts()[i] - // TECHDEBT: refactor - p2pModules[serviceURL] = NewP2PModuleWithHost(t, busMock, host) + busMocks = make(map[serviceURLStr]*mock_modules.MockBus) + p2pModules = make(map[serviceURLStr]modules.P2PModule) + + for serviceURL, privKey := range serviceURLKeyMap { + busMock := bus_testutil.NewBus( + t, privKey, + serviceURL, + genesisState, + busEventHandlerFactory, + ) + busMocks[serviceURL] = busMock + + p2pModules[serviceURL] = NewP2PModule( + t, serviceURL, + // TODO_THIS_COMMIT: send via busMock instead + privKey, + busMock, + // TODO_THIS_COMMIT: send via busMock instead + genesisState, + // TODO_THIS_COMMIT: send via busMock instead (?) + dnsSrv, + // TODO_THIS_COMMIT: send via busMock instead (?) + libp2pNetworkMock, + ) } - return p2pModules + return busMocks, p2pModules } // TODO_THIS_TEST: need this? @@ -122,6 +138,7 @@ func NewBusesAndP2PModuleWithHost( return busMock, NewP2PModuleWithHost(t, busMock, host) } +// TODO_THIS_COMMIT: rename; consider returning *p2p.P2PModule instead func NewP2PModuleWithHost( t gocuke.TestingT, busMock *mock_modules.MockBus, diff --git a/internal/testutil/module.go b/internal/testutil/module.go new file mode 100644 index 000000000..a59710b02 --- /dev/null +++ b/internal/testutil/module.go @@ -0,0 +1,41 @@ +package testutil + +import ( + "github.com/foxcpp/go-mockdns" + mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/pokt-network/pocket/runtime/genesis" + "github.com/pokt-network/pocket/shared/modules" + "github.com/pokt-network/pocket/shared/modules/base_modules" +) + +// TODO_THIS_COMMIT: is this helpful? +const TestModuleName = "testModule" + +var ( + _ modules.Module = &TestModule{} + _ modules.ModuleFactoryWithOptions = &TestModule{} +) + +type TestModule struct { + base_modules.IntegratableModule + base_modules.InterruptableModule + + DNS *mockdns.Server + Genesis *genesis.GenesisState + Libp2pNetworkMock mocknet.Mocknet +} + +func (m *TestModule) GetModuleName() string { + return TestModuleName +} + +func (m *TestModule) Create( + bus modules.Bus, + opts ...modules.ModuleOption, +) (modules.Module, error) { + panic("implement me") +} + +func (m *TestModule) GetDNS() *mockdns.Server { + return m.DNS +} diff --git a/internal/testutil/network.go b/internal/testutil/network.go new file mode 100644 index 000000000..1403dca46 --- /dev/null +++ b/internal/testutil/network.go @@ -0,0 +1,73 @@ +package testutil + +import ( + "fmt" + + crypto2 "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/multiformats/go-multiaddr" + "github.com/regen-network/gocuke" + "github.com/stretchr/testify/require" + + "github.com/pokt-network/pocket/runtime/defaults" + "github.com/pokt-network/pocket/shared/crypto" +) + +const ServiceURLFormat = "node%d.consensus:42069" + +func NewMocknetHost( + t gocuke.TestingT, + libp2pNetworkMock mocknet.Mocknet, + privKey crypto.PrivateKey, +) host.Host { + t.Helper() + + // TODO_THIS_COMMIT: move to const + addrMock, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/10.0.0.1/tcp/%d", defaults.DefaultP2PPort)) + require.NoError(t, err) + + libp2pPrivKey, err := crypto2.UnmarshalEd25519PrivateKey(privKey.Bytes()) + require.NoError(t, err) + + host, err := libp2pNetworkMock.AddPeer(libp2pPrivKey, addrMock) + require.NoError(t, err) + + return host +} + +func SequentialServiceURLPrivKeyMap(t gocuke.TestingT, count int) map[string]crypto.PrivateKey { + t.Helper() + + // CONSIDERATION: using an iterator/generator would prevent unintentional + // ID collisions + privKeys := LoadLocalnetPrivateKeys(t, count) + // CONSIDERATION: using an iterator/generator would prevent unintentional + // serviceURL collisions + serviceURLs := SequentialServiceURLs(t, count) + + require.GreaterOrEqualf(t, len(privKeys), len(serviceURLs), "not enough private keys for service URLs") + + serviceURLKeysMap := make(map[string]crypto.PrivateKey, len(serviceURLs)) + + for i, serviceURL := range serviceURLs { + serviceURLKeysMap[serviceURL] = privKeys[i] + } + return serviceURLKeysMap +} + +// CONSIDERATION: serviceURLs are only unique within their respective slice; +// consider building an iterator/generator instead. +func SequentialServiceURLs(t gocuke.TestingT, count int) (serviceURLs []string) { + t.Helper() + + for i := 0; i < count; i++ { + serviceURLs = append(serviceURLs, NewServiceURL(i+1)) + } + return serviceURLs +} + +// TECHDEBT: rename `validatorId()` to `serviceURL()` +func NewServiceURL(i int) string { + return fmt.Sprintf(ServiceURLFormat, i) +} diff --git a/internal/testutil/p2p/network.go b/internal/testutil/p2p/network.go index 77fdb9edb..23196a6c8 100644 --- a/internal/testutil/p2p/network.go +++ b/internal/testutil/p2p/network.go @@ -1,14 +1,10 @@ package p2p_testutil import ( - "fmt" "github.com/libp2p/go-libp2p/core/crypto" - libp2pHost "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" libp2pPeer "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/net/mock" - "github.com/multiformats/go-multiaddr" - "github.com/pokt-network/pocket/runtime/defaults" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" @@ -25,30 +21,23 @@ func NewMocknetWithNPeers(t gocuke.TestingT, peerCount int) (mocknet.Mocknet, [] // load pre-generated validator keypairs libp2pNetworkMock := mocknet.New() privKeys := testutil.LoadLocalnetPrivateKeys(t, peerCount) - serviceURLs := SequentialServiceURLs(t, peerCount) + serviceURLs := testutil.SequentialServiceURLs(t, peerCount) _ = SetupMockNetPeers(t, libp2pNetworkMock, privKeys, serviceURLs) return libp2pNetworkMock, serviceURLs } -func NewMocknetHost( - t gocuke.TestingT, - libp2pNetworkMock mocknet.Mocknet, - privKey cryptoPocket.PrivateKey, -) libp2pHost.Host { +func NewLibp2pNetworkMock(t gocuke.TestingT) mocknet.Mocknet { t.Helper() - // TODO_THIS_COMMIT: move to const - addrMock, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/10.0.0.1/tcp/%d", defaults.DefaultP2PPort)) - require.NoError(t, err) - - libp2pPrivKey, err := crypto.UnmarshalEd25519PrivateKey(privKey.Bytes()) - require.NoError(t, err) - - host, err := libp2pNetworkMock.AddPeer(libp2pPrivKey, addrMock) - require.NoError(t, err) + libp2pNetworkMock := mocknet.New() + // destroy mocknet on test cleanup + t.Cleanup(func() { + err := libp2pNetworkMock.Close() + require.NoError(t, err) + }) - return host + return libp2pNetworkMock } func SetupMockNetPeers( @@ -85,17 +74,6 @@ func SetupMockNetPeers( return peerIDs } -// CONSIDERATION: serviceURLs are only unique within their respective slice; -// consider building an iterator/generator instead. -func SequentialServiceURLs(t gocuke.TestingT, count int) (serviceURLs []string) { - t.Helper() - - for i := 0; i < count; i++ { - serviceURLs = append(serviceURLs, NewServiceURL(i+1)) - } - return serviceURLs -} - func PeersFromPrivKeysAndServiceURLs( t gocuke.TestingT, privKeys []cryptoPocket.PrivateKey, @@ -110,7 +88,7 @@ func PeersFromPrivKeysAndServiceURLs( } for i, privKey := range privKeys[:maxCount] { - peerInfo := peerFromPrivKeyAndServiceURL(t, privKey, NewServiceURL(i+1)) + peerInfo := peerFromPrivKeyAndServiceURL(t, privKey, testutil.NewServiceURL(i+1)) peersInfo = append(peersInfo, peerInfo) } return peersInfo @@ -132,10 +110,3 @@ func peerFromPrivKeyAndServiceURL( return peerInfo } - -const ServiceURLFormat = "node%d.consensus:42069" - -// TECHDEBT: rename `validatorId()` to `serviceURL()` -func NewServiceURL(i int) string { - return fmt.Sprintf(ServiceURLFormat, i) -} diff --git a/internal/testutil/runtime/genesis.go b/internal/testutil/runtime/genesis.go index b14aac47d..47da6caed 100644 --- a/internal/testutil/runtime/genesis.go +++ b/internal/testutil/runtime/genesis.go @@ -1,7 +1,7 @@ package runtime_testutil import ( - "github.com/pokt-network/pocket/internal/testutil/p2p" + "github.com/pokt-network/pocket/internal/testutil" "github.com/pokt-network/pocket/runtime/genesis" "github.com/pokt-network/pocket/runtime/test_artifacts" "github.com/pokt-network/pocket/shared/core/types" @@ -33,12 +33,36 @@ func BaseGenesisStateMock(t gocuke.TestingT, valKeys []cryptoPocket.PublicKey, s return genesisState } +func BaseGenesisStateMockFromServiceURLKeyMap(t gocuke.TestingT, serviceURLKeyMap map[string]cryptoPocket.PrivateKey) *genesis.GenesisState { + t.Helper() + + var validators []*types.Actor + genesisState := new(genesis.GenesisState) + for serviceURL, privKey := range serviceURLKeyMap { + addr := privKey.Address().String() + mockValidator := &types.Actor{ + ActorType: types.ActorType_ACTOR_TYPE_VAL, + Address: addr, + PublicKey: privKey.PublicKey().String(), + ServiceUrl: serviceURL, + StakedAmount: test_artifacts.DefaultStakeAmountString, + PausedHeight: int64(0), + UnstakingHeight: int64(0), + Output: addr, + } + validators = append(validators, mockValidator) + } + genesisState.Validators = validators + + return genesisState +} + func GenesisWithSequentialServiceURLs(t gocuke.TestingT, valKeys []cryptoPocket.PublicKey) *genesis.GenesisState { t.Helper() serviceURLs := make([]string, len(valKeys)) for i := range valKeys { - serviceURLs[i] = p2p_testutil.NewServiceURL(i + 1) + serviceURLs[i] = testutil.NewServiceURL(i + 1) } return BaseGenesisStateMock(t, valKeys, serviceURLs) } diff --git a/p2p/module_raintree_test.go b/p2p/module_raintree_test.go index 98a8d4297..e8058a672 100644 --- a/p2p/module_raintree_test.go +++ b/p2p/module_raintree_test.go @@ -22,7 +22,6 @@ import ( "github.com/pokt-network/pocket/internal/testutil" "github.com/pokt-network/pocket/internal/testutil/constructors" - "github.com/pokt-network/pocket/internal/testutil/p2p" persistence_testutil "github.com/pokt-network/pocket/internal/testutil/persistence" "github.com/pokt-network/pocket/shared/messaging" ) @@ -44,7 +43,7 @@ func TestMain(m *testing.M) { // ### RainTree Unit Tests ### func TestRainTreeNetworkCompleteOneNodes(t *testing.T) { // val_1 - originatorNode := p2p_testutil.NewServiceURL(1) + originatorNode := testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ originatorNode: {0, 0}, // val_1, the originator, does 0 network reads or writes } @@ -55,13 +54,13 @@ func TestRainTreeNetworkCompleteTwoNodes(t *testing.T) { // val_1 // └───────┐ // val_2 - originatorNode := p2p_testutil.NewServiceURL(1) + originatorNode := testutil.NewServiceURL(1) // Per the diagram above, in the case of a 2 node network, the originator node (val_1) does a // single write to another node (val_2), also the // originator node and never performs any reads or writes during a RainTree broadcast. expectedCalls := TestNetworkSimulationConfig{ // Attempt: I think Validator 1 is sending a message in a 2 (including self) node network originatorNode: {0, 1}, // val_1 does a single network write (to val_2) - p2p_testutil.NewServiceURL(2): {1, 0}, // val_2 does a single network read (from val_1) + testutil.NewServiceURL(2): {1, 0}, // val_2 does a single network read (from val_1) } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -70,11 +69,11 @@ func TestRainTreeNetworkCompleteThreeNodes(t *testing.T) { // val_1 // ┌───────┴────┬─────────┐ // val_2 val_1 val_3 - originatorNode := p2p_testutil.NewServiceURL(1) + originatorNode := testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {0, 2}, // val_1 does two network writes (to val_2 and val_3) - p2p_testutil.NewServiceURL(2): {1, 0}, // val_2 does a single network read (from val_1) - p2p_testutil.NewServiceURL(3): {1, 0}, // val_2 does a single network read (from val_3) + originatorNode: {0, 2}, // val_1 does two network writes (to val_2 and val_3) + testutil.NewServiceURL(2): {1, 0}, // val_2 does a single network read (from val_1) + testutil.NewServiceURL(3): {1, 0}, // val_2 does a single network read (from val_3) } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -86,12 +85,12 @@ func TestRainTreeNetworkCompleteFourNodes(t *testing.T) { // val_2 val_1 val_3 // └───────┐ └───────┐ └───────┐ // val_3 val_2 val_4 - originatorNode := p2p_testutil.NewServiceURL(1) + originatorNode := testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {0, 3}, // val_1 does 3 network writes (two to val_2 and 1 to val_3) - p2p_testutil.NewServiceURL(2): {2, 1}, // val_2 does 2 network reads (both from val_1) and 1 network write (to val_3) - p2p_testutil.NewServiceURL(3): {2, 1}, // val_2 does 2 network reads (from val_1 and val_2) and 1 network write (to val_4) - p2p_testutil.NewServiceURL(4): {1, 0}, // val_2 does 1 network read (from val_3) + originatorNode: {0, 3}, // val_1 does 3 network writes (two to val_2 and 1 to val_3) + testutil.NewServiceURL(2): {2, 1}, // val_2 does 2 network reads (both from val_1) and 1 network write (to val_3) + testutil.NewServiceURL(3): {2, 1}, // val_2 does 2 network reads (from val_1 and val_2) and 1 network write (to val_4) + testutil.NewServiceURL(4): {1, 0}, // val_2 does 1 network read (from val_3) } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -102,17 +101,17 @@ func TestRainTreeNetworkCompleteNineNodes(t *testing.T) { // val_4 val_1 val_7 // ┌───────┴────┬─────────┐ ┌───────┴────┬─────────┐ ┌───────┴────┬─────────┐ // val_6 val_4 val_8 val_3 val_1 val_5 val_9 val_7 val_2 - originatorNode := p2p_testutil.NewServiceURL(1) + originatorNode := testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {0, 4}, - p2p_testutil.NewServiceURL(2): {1, 0}, - p2p_testutil.NewServiceURL(3): {1, 0}, - p2p_testutil.NewServiceURL(4): {1, 2}, - p2p_testutil.NewServiceURL(5): {1, 0}, - p2p_testutil.NewServiceURL(6): {1, 0}, - p2p_testutil.NewServiceURL(7): {1, 2}, - p2p_testutil.NewServiceURL(8): {1, 0}, - p2p_testutil.NewServiceURL(9): {1, 0}, + originatorNode: {0, 4}, + testutil.NewServiceURL(2): {1, 0}, + testutil.NewServiceURL(3): {1, 0}, + testutil.NewServiceURL(4): {1, 2}, + testutil.NewServiceURL(5): {1, 0}, + testutil.NewServiceURL(6): {1, 0}, + testutil.NewServiceURL(7): {1, 2}, + testutil.NewServiceURL(8): {1, 0}, + testutil.NewServiceURL(9): {1, 0}, } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -126,20 +125,20 @@ func TestRainTreeNetworkCompleteNineNodes(t *testing.T) { // val_8 val_7 val_10 val_6 val_5 val_8 val_11 val_10 val_5 val_4 val_3 val_6 val_2 val_1 val_4 val_7 val_6 val_1 val_12 val_11 val_2 val_10 val_9 val_12 val_3 val_2 val_9 func TestRainTreeCompleteTwelveNodes(t *testing.T) { - originatorNode := p2p_testutil.NewServiceURL(1) + originatorNode := testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {1, 6}, - p2p_testutil.NewServiceURL(2): {3, 2}, - p2p_testutil.NewServiceURL(3): {2, 2}, - p2p_testutil.NewServiceURL(4): {2, 0}, - p2p_testutil.NewServiceURL(5): {2, 4}, - p2p_testutil.NewServiceURL(6): {3, 2}, - p2p_testutil.NewServiceURL(7): {2, 2}, - p2p_testutil.NewServiceURL(8): {2, 0}, - p2p_testutil.NewServiceURL(9): {2, 4}, - p2p_testutil.NewServiceURL(10): {3, 2}, - p2p_testutil.NewServiceURL(11): {2, 2}, - p2p_testutil.NewServiceURL(12): {2, 0}, + originatorNode: {1, 6}, + testutil.NewServiceURL(2): {3, 2}, + testutil.NewServiceURL(3): {2, 2}, + testutil.NewServiceURL(4): {2, 0}, + testutil.NewServiceURL(5): {2, 4}, + testutil.NewServiceURL(6): {3, 2}, + testutil.NewServiceURL(7): {2, 2}, + testutil.NewServiceURL(8): {2, 0}, + testutil.NewServiceURL(9): {2, 4}, + testutil.NewServiceURL(10): {3, 2}, + testutil.NewServiceURL(11): {2, 2}, + testutil.NewServiceURL(12): {2, 0}, } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -152,26 +151,26 @@ func TestRainTreeNetworkCompleteEighteenNodes(t *testing.T) { // val_11 val_7 val_15 val_5 val_1 val_9 val_17 val_13 val_3 // ┌────────┴─────┬───────────┐ ┌───────┴────┬──────────┐ ┌────────┴─────┬──────────┐ ┌───────┴────┬──────────┐ ┌───────┴────┬─────────┐ ┌────────┴────┬─────────┐ ┌───────┴─────┬──────────┐ ┌────────┴─────┬───────────┐ ┌───────┴────┬──────────┐ // val_13 val_11 val_16 val_9 val_7 val_12 val_17 val_15 val_8 val_7 val_5 val_10 val_3 val_1 val_6 val_11 val_9 val_2 val_1 val_17 val_4 val_15 val_13 val_18 val_5 val_3 val_14 - originatorNode := p2p_testutil.NewServiceURL(1) + originatorNode := testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {1, 6}, - p2p_testutil.NewServiceURL(2): {1, 0}, - p2p_testutil.NewServiceURL(3): {2, 2}, - p2p_testutil.NewServiceURL(4): {1, 0}, - p2p_testutil.NewServiceURL(5): {2, 2}, - p2p_testutil.NewServiceURL(6): {1, 0}, - p2p_testutil.NewServiceURL(7): {2, 4}, - p2p_testutil.NewServiceURL(8): {1, 0}, - p2p_testutil.NewServiceURL(9): {2, 2}, - p2p_testutil.NewServiceURL(10): {1, 0}, - p2p_testutil.NewServiceURL(11): {2, 2}, - p2p_testutil.NewServiceURL(12): {1, 0}, - p2p_testutil.NewServiceURL(13): {2, 4}, - p2p_testutil.NewServiceURL(14): {1, 0}, - p2p_testutil.NewServiceURL(15): {2, 2}, - p2p_testutil.NewServiceURL(16): {1, 0}, - p2p_testutil.NewServiceURL(17): {2, 2}, - p2p_testutil.NewServiceURL(18): {1, 0}, + originatorNode: {1, 6}, + testutil.NewServiceURL(2): {1, 0}, + testutil.NewServiceURL(3): {2, 2}, + testutil.NewServiceURL(4): {1, 0}, + testutil.NewServiceURL(5): {2, 2}, + testutil.NewServiceURL(6): {1, 0}, + testutil.NewServiceURL(7): {2, 4}, + testutil.NewServiceURL(8): {1, 0}, + testutil.NewServiceURL(9): {2, 2}, + testutil.NewServiceURL(10): {1, 0}, + testutil.NewServiceURL(11): {2, 2}, + testutil.NewServiceURL(12): {1, 0}, + testutil.NewServiceURL(13): {2, 4}, + testutil.NewServiceURL(14): {1, 0}, + testutil.NewServiceURL(15): {2, 2}, + testutil.NewServiceURL(16): {1, 0}, + testutil.NewServiceURL(17): {2, 2}, + testutil.NewServiceURL(18): {1, 0}, } testRainTreeCalls(t, originatorNode, expectedCalls) } @@ -184,35 +183,35 @@ func TestRainTreeNetworkCompleteTwentySevenNodes(t *testing.T) { // val_16 val_10 val_22 val_7 val_1 val_13 val_25 val_19 val_4 // ┌────────┴─────┬───────────┐ ┌────────┴─────┬───────────┐ ┌────────┴─────┬───────────┐ ┌────────┴────┬──────────┐ ┌───────┴────┬─────────┐ ┌────────┴─────┬──────────┐ ┌───────┴─────┬──────────┐ ┌────────┴─────┬───────────┐ ┌───────┴────┬──────────┐ // val_20 val_16 val_24 val_14 val_10 val_18 val_26 val_22 val_12 val_11 val_7 val_15 val_5 val_1 val_9 val_17 val_13 val_3 val_2 val_25 val_6 val_23 val_19 val_27 val_8 val_4 val_21 - originatorNode := p2p_testutil.NewServiceURL(1) + originatorNode := testutil.NewServiceURL(1) expectedCalls := TestNetworkSimulationConfig{ - originatorNode: {0, 6}, - p2p_testutil.NewServiceURL(2): {1, 0}, - p2p_testutil.NewServiceURL(3): {1, 0}, - p2p_testutil.NewServiceURL(4): {1, 2}, - p2p_testutil.NewServiceURL(5): {1, 0}, - p2p_testutil.NewServiceURL(6): {1, 0}, - p2p_testutil.NewServiceURL(7): {1, 2}, - p2p_testutil.NewServiceURL(8): {1, 0}, - p2p_testutil.NewServiceURL(9): {1, 0}, - p2p_testutil.NewServiceURL(10): {1, 4}, - p2p_testutil.NewServiceURL(11): {1, 0}, - p2p_testutil.NewServiceURL(12): {1, 0}, - p2p_testutil.NewServiceURL(13): {1, 2}, - p2p_testutil.NewServiceURL(14): {1, 0}, - p2p_testutil.NewServiceURL(15): {1, 0}, - p2p_testutil.NewServiceURL(16): {1, 2}, - p2p_testutil.NewServiceURL(17): {1, 0}, - p2p_testutil.NewServiceURL(18): {1, 0}, - p2p_testutil.NewServiceURL(19): {1, 4}, - p2p_testutil.NewServiceURL(20): {1, 0}, - p2p_testutil.NewServiceURL(21): {1, 0}, - p2p_testutil.NewServiceURL(22): {1, 2}, - p2p_testutil.NewServiceURL(23): {1, 0}, - p2p_testutil.NewServiceURL(24): {1, 0}, - p2p_testutil.NewServiceURL(25): {1, 2}, - p2p_testutil.NewServiceURL(26): {1, 0}, - p2p_testutil.NewServiceURL(27): {1, 0}, + originatorNode: {0, 6}, + testutil.NewServiceURL(2): {1, 0}, + testutil.NewServiceURL(3): {1, 0}, + testutil.NewServiceURL(4): {1, 2}, + testutil.NewServiceURL(5): {1, 0}, + testutil.NewServiceURL(6): {1, 0}, + testutil.NewServiceURL(7): {1, 2}, + testutil.NewServiceURL(8): {1, 0}, + testutil.NewServiceURL(9): {1, 0}, + testutil.NewServiceURL(10): {1, 4}, + testutil.NewServiceURL(11): {1, 0}, + testutil.NewServiceURL(12): {1, 0}, + testutil.NewServiceURL(13): {1, 2}, + testutil.NewServiceURL(14): {1, 0}, + testutil.NewServiceURL(15): {1, 0}, + testutil.NewServiceURL(16): {1, 2}, + testutil.NewServiceURL(17): {1, 0}, + testutil.NewServiceURL(18): {1, 0}, + testutil.NewServiceURL(19): {1, 4}, + testutil.NewServiceURL(20): {1, 0}, + testutil.NewServiceURL(21): {1, 0}, + testutil.NewServiceURL(22): {1, 2}, + testutil.NewServiceURL(23): {1, 0}, + testutil.NewServiceURL(24): {1, 0}, + testutil.NewServiceURL(25): {1, 2}, + testutil.NewServiceURL(26): {1, 0}, + testutil.NewServiceURL(27): {1, 0}, } testRainTreeCalls(t, originatorNode, expectedCalls) } diff --git a/p2p/module_test.go b/p2p/module_test.go index c2503f699..d39c9f097 100644 --- a/p2p/module_test.go +++ b/p2p/module_test.go @@ -12,7 +12,6 @@ import ( "github.com/stretchr/testify/require" "github.com/pokt-network/pocket/internal/testutil" - p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" "github.com/pokt-network/pocket/internal/testutil/persistence" "github.com/pokt-network/pocket/internal/testutil/runtime" typesP2P "github.com/pokt-network/pocket/p2p/types" @@ -126,7 +125,7 @@ func Test_Create_configureBootstrapNodes(t *testing.T) { pubKeys[i] = privKey.PublicKey() } - serviceURLs := p2p_testutil.SequentialServiceURLs(t, len(pubKeys)) + serviceURLs := testutil.SequentialServiceURLs(t, len(pubKeys)) genesisStateMock := runtime_testutil.BaseGenesisStateMock(t, pubKeys, serviceURLs) persistenceMock := persistence_testutil.BasePersistenceMock(t, mockBus, genesisStateMock) mockBus.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() diff --git a/p2p/transport_encryption_test.go b/p2p/transport_encryption_test.go index f2f2dbec7..86e3c0f1d 100644 --- a/p2p/transport_encryption_test.go +++ b/p2p/transport_encryption_test.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "github.com/pokt-network/pocket/internal/testutil" - p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" "github.com/pokt-network/pocket/internal/testutil/persistence" "github.com/pokt-network/pocket/internal/testutil/runtime" "github.com/pokt-network/pocket/internal/testutil/telemetry" @@ -56,8 +55,14 @@ func TestP2pModule_Insecure_Error(t *testing.T) { busMock.EXPECT().GetTelemetryModule().Return(telemetryMock).AnyTimes() keys := testutil.LoadLocalnetPrivateKeys(t, 1) - serviceURLs := p2p_testutil.SequentialServiceURLs(t, 1) - genesisStateMock := runtime_testutil.BaseGenesisStateMock(t, keys, serviceURLs) + + // TODO_THIS_COMMIT: refactor + pubKeys := make([]cryptoPocket.PublicKey, len(keys)) + for i, privKey := range keys { + pubKeys[i] = privKey.PublicKey() + } + serviceURLs := testutil.SequentialServiceURLs(t, len(pubKeys)) + genesisStateMock := runtime_testutil.BaseGenesisStateMock(t, pubKeys, serviceURLs) persistenceMock := persistence_testutil.BasePersistenceMock(t, busMock, genesisStateMock) busMock.EXPECT().GetPersistenceModule().Return(persistenceMock).AnyTimes() From d0acc92476211936b6b1682d20a25dabd1ba42fe Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:34:10 +0200 Subject: [PATCH 17/22] wip: testutils --- .../testutil/constructors/constructors.go | 27 +++++++---------- internal/testutil/network.go | 29 +++++++++++++++++++ 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 5491c981a..19175f8bd 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -10,6 +10,8 @@ import ( telemetry_testutil "github.com/pokt-network/pocket/internal/testutil/telemetry" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" + "net" + "strconv" "github.com/pokt-network/pocket/internal/testutil" p2p_testutil "github.com/pokt-network/pocket/internal/testutil/p2p" @@ -53,16 +55,13 @@ func NewBusesMocknetAndP2PModules( // TODO_THIS_COMMIT: rename / move, if possible func NewP2PModule( t gocuke.TestingT, - // TODO_THIS_COMMIT: get these from the bus instead - serviceURL string, - privKey cryptoPocket.PrivateKey, - // -- busMock *mock_modules.MockBus, - genesisState *genesis.GenesisState, dnsSrv *mockdns.Server, libp2pNetworkMock mocknet.Mocknet, // TODO_THIS_COMMIT: consider *p2p.P2PModule instead ) modules.P2PModule { + genesisState := busMock.GetRuntimeMgr().GetGenesis() + _ = consensus_testutil.BaseConsensusMock(t, busMock) _ = persistence_testutil.BasePersistenceMock(t, busMock, genesisState) @@ -74,6 +73,11 @@ func NewP2PModule( // t, telemetry_testutil.MinimalTelemetryMock(t, busMock), //) + p2pCfg := busMock.GetRuntimeMgr().GetConfig().P2P + serviceURL := net.JoinHostPort(p2pCfg.Hostname, strconv.Itoa(int(p2pCfg.Port))) + privKey, err := cryptoPocket.NewPrivateKey(p2pCfg.PrivateKey) + require.NoError(t, err) + // MUST register DNS before instantiating P2PModule testutil.AddServiceURLZone(t, dnsSrv, serviceURL) @@ -106,18 +110,7 @@ func NewBusesAndP2PModules( ) busMocks[serviceURL] = busMock - p2pModules[serviceURL] = NewP2PModule( - t, serviceURL, - // TODO_THIS_COMMIT: send via busMock instead - privKey, - busMock, - // TODO_THIS_COMMIT: send via busMock instead - genesisState, - // TODO_THIS_COMMIT: send via busMock instead (?) - dnsSrv, - // TODO_THIS_COMMIT: send via busMock instead (?) - libp2pNetworkMock, - ) + p2pModules[serviceURL] = NewP2PModule(t, busMock, dnsSrv, libp2pNetworkMock) } return busMocks, p2pModules } diff --git a/internal/testutil/network.go b/internal/testutil/network.go index 1403dca46..e59dd2ab0 100644 --- a/internal/testutil/network.go +++ b/internal/testutil/network.go @@ -2,6 +2,7 @@ package testutil import ( "fmt" + "github.com/libp2p/go-libp2p/core/network" crypto2 "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/host" @@ -71,3 +72,31 @@ func SequentialServiceURLs(t gocuke.TestingT, count int) (serviceURLs []string) func NewServiceURL(i int) string { return fmt.Sprintf(ServiceURLFormat, i) } + +// TODO_THIS_COMMIT: move +func NewDebugNotifee(t gocuke.TestingT) network.Notifiee { + t.Helper() + + return &network.NotifyBundle{ + ConnectedF: func(_ network.Network, conn network.Conn) { + t.Logf("connected: local: %s; remote: %s", + conn.LocalPeer().String(), + conn.RemotePeer().String(), + ) + //bootstrapPeerIDCh <- conn.RemotePeer().String() + //bootstrapWaitgroup.Done() + }, + DisconnectedF: func(_ network.Network, conn network.Conn) { + t.Logf("disconnected: local: %s; remote: %s", + conn.LocalPeer().String(), + conn.RemotePeer().String(), + ) + }, + ListenF: func(_ network.Network, addr multiaddr.Multiaddr) { + t.Logf("listening: %s", addr.String()) + }, + ListenCloseF: func(_ network.Network, addr multiaddr.Multiaddr) { + t.Logf("closed: %s", addr.String()) + }, + } +} From 7f699101855e045396d8915a4e1f6b5160d6318c Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:34:43 +0200 Subject: [PATCH 18/22] wip: testutils --- .../testutil/constructors/constructors.go | 14 ++++++++++++-- internal/testutil/network.go | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/internal/testutil/constructors/constructors.go b/internal/testutil/constructors/constructors.go index 19175f8bd..2d6e7900f 100644 --- a/internal/testutil/constructors/constructors.go +++ b/internal/testutil/constructors/constructors.go @@ -3,6 +3,7 @@ package constructors import ( "github.com/foxcpp/go-mockdns" libp2pHost "github.com/libp2p/go-libp2p/core/host" + libp2pNetwork "github.com/libp2p/go-libp2p/core/network" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/pokt-network/pocket/internal/testutil/bus" consensus_testutil "github.com/pokt-network/pocket/internal/testutil/consensus" @@ -31,6 +32,7 @@ func NewBusesMocknetAndP2PModules( dnsSrv *mockdns.Server, genesisState *genesis.GenesisState, busEventHandlerFactory testutil.BusEventHandlerFactory, + notifiee libp2pNetwork.Notifiee, ) ( buses map[serviceURLStr]*mock_modules.MockBus, libp2pNetworkMock mocknet.Mocknet, @@ -45,6 +47,7 @@ func NewBusesMocknetAndP2PModules( genesisState, libp2pNetworkMock, serviceURLKeyMap, + notifiee, ) err := libp2pNetworkMock.LinkAll() require.NoError(t, err) @@ -58,6 +61,7 @@ func NewP2PModule( busMock *mock_modules.MockBus, dnsSrv *mockdns.Server, libp2pNetworkMock mocknet.Mocknet, + notifiee libp2pNetwork.Notifiee, // TODO_THIS_COMMIT: consider *p2p.P2PModule instead ) modules.P2PModule { genesisState := busMock.GetRuntimeMgr().GetGenesis() @@ -81,7 +85,7 @@ func NewP2PModule( // MUST register DNS before instantiating P2PModule testutil.AddServiceURLZone(t, dnsSrv, serviceURL) - host := testutil.NewMocknetHost(t, libp2pNetworkMock, privKey) + host := testutil.NewMocknetHost(t, libp2pNetworkMock, privKey, notifiee) return NewP2PModuleWithHost(t, busMock, host) } @@ -93,6 +97,7 @@ func NewBusesAndP2PModules( genesisState *genesis.GenesisState, libp2pNetworkMock mocknet.Mocknet, serviceURLKeyMap map[serviceURLStr]cryptoPocket.PrivateKey, + notifiee libp2pNetwork.Notifiee, ) ( busMocks map[serviceURLStr]*mock_modules.MockBus, // TODO_THIS_COMMIT: consider *p2p.P2PModule instead @@ -110,7 +115,12 @@ func NewBusesAndP2PModules( ) busMocks[serviceURL] = busMock - p2pModules[serviceURL] = NewP2PModule(t, busMock, dnsSrv, libp2pNetworkMock) + p2pModules[serviceURL] = NewP2PModule( + t, busMock, + dnsSrv, + libp2pNetworkMock, + notifiee, + ) } return busMocks, p2pModules } diff --git a/internal/testutil/network.go b/internal/testutil/network.go index e59dd2ab0..f7943156d 100644 --- a/internal/testutil/network.go +++ b/internal/testutil/network.go @@ -2,10 +2,10 @@ package testutil import ( "fmt" - "github.com/libp2p/go-libp2p/core/network" crypto2 "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/host" + libp2pNetwork "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/multiformats/go-multiaddr" "github.com/regen-network/gocuke" @@ -21,6 +21,7 @@ func NewMocknetHost( t gocuke.TestingT, libp2pNetworkMock mocknet.Mocknet, privKey crypto.PrivateKey, + notifiee libp2pNetwork.Notifiee, ) host.Host { t.Helper() @@ -34,6 +35,10 @@ func NewMocknetHost( host, err := libp2pNetworkMock.AddPeer(libp2pPrivKey, addrMock) require.NoError(t, err) + if notifiee != nil { + host.Network().Notify(notifiee) + } + return host } @@ -74,11 +79,11 @@ func NewServiceURL(i int) string { } // TODO_THIS_COMMIT: move -func NewDebugNotifee(t gocuke.TestingT) network.Notifiee { +func NewDebugNotifee(t gocuke.TestingT) libp2pNetwork.Notifiee { t.Helper() - return &network.NotifyBundle{ - ConnectedF: func(_ network.Network, conn network.Conn) { + return &libp2pNetwork.NotifyBundle{ + ConnectedF: func(_ libp2pNetwork.Network, conn libp2pNetwork.Conn) { t.Logf("connected: local: %s; remote: %s", conn.LocalPeer().String(), conn.RemotePeer().String(), @@ -86,16 +91,16 @@ func NewDebugNotifee(t gocuke.TestingT) network.Notifiee { //bootstrapPeerIDCh <- conn.RemotePeer().String() //bootstrapWaitgroup.Done() }, - DisconnectedF: func(_ network.Network, conn network.Conn) { + DisconnectedF: func(_ libp2pNetwork.Network, conn libp2pNetwork.Conn) { t.Logf("disconnected: local: %s; remote: %s", conn.LocalPeer().String(), conn.RemotePeer().String(), ) }, - ListenF: func(_ network.Network, addr multiaddr.Multiaddr) { + ListenF: func(_ libp2pNetwork.Network, addr multiaddr.Multiaddr) { t.Logf("listening: %s", addr.String()) }, - ListenCloseF: func(_ network.Network, addr multiaddr.Multiaddr) { + ListenCloseF: func(_ libp2pNetwork.Network, addr multiaddr.Multiaddr) { t.Logf("closed: %s", addr.String()) }, } From 2e4f26a8b50bcaec3a89c419bba0bda50a713b45 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:37:09 +0200 Subject: [PATCH 19/22] wip: testutils - p2p module test refactor --- p2p/module_raintree_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/p2p/module_raintree_test.go b/p2p/module_raintree_test.go index e8058a672..c67c6fb34 100644 --- a/p2p/module_raintree_test.go +++ b/p2p/module_raintree_test.go @@ -222,6 +222,8 @@ func TestRainTreeNetworkCompleteTwentySevenNodes(t *testing.T) { // 1. It creates and configures a "real" P2P module where all the other components of the node are mocked. // 2. It then triggers a single message and waits for all of the expected messages transmission to complete before announcing failure. func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig TestNetworkSimulationConfig) { + dnsSrv := testutil.MinimalDNSMock(t) + // Configure & prepare test module numValidators := len(networkSimulationConfig) //runtimeConfigs := createMockRuntimeMgrs(t, numValidators) @@ -255,8 +257,10 @@ func testRainTreeCalls(t *testing.T, origNode string, networkSimulationConfig Te busMocks, _, p2pModules = constructors.NewBusesMocknetAndP2PModules( t, numValidators, + dnsSrv, genesisState, busEventHandlerFactory, + nil, ) //for _, busMock := range busMocks { From f956fcc2a85b4d4902445637e942ce58d0e01d59 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 12:37:50 +0200 Subject: [PATCH 20/22] wip: testutils --- internal/testutil/network.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/testutil/network.go b/internal/testutil/network.go index f7943156d..a86d5a866 100644 --- a/internal/testutil/network.go +++ b/internal/testutil/network.go @@ -88,8 +88,6 @@ func NewDebugNotifee(t gocuke.TestingT) libp2pNetwork.Notifiee { conn.LocalPeer().String(), conn.RemotePeer().String(), ) - //bootstrapPeerIDCh <- conn.RemotePeer().String() - //bootstrapWaitgroup.Done() }, DisconnectedF: func(_ libp2pNetwork.Network, conn libp2pNetwork.Conn) { t.Logf("disconnected: local: %s; remote: %s", From b7203cb5ca68d3af28febba59bb39a57e4a501cd Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 09:07:15 +0200 Subject: [PATCH 21/22] wip: testutils --- internal/testutil/p2p/network.go | 28 +++++++ p2p/background/router_test.go | 124 ++++++++++++++++++++----------- 2 files changed, 109 insertions(+), 43 deletions(-) diff --git a/internal/testutil/p2p/network.go b/internal/testutil/p2p/network.go index 23196a6c8..2fd47f150 100644 --- a/internal/testutil/p2p/network.go +++ b/internal/testutil/p2p/network.go @@ -1,17 +1,22 @@ package p2p_testutil import ( + "testing" + "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" libp2pPeer "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" "github.com/pokt-network/pocket/internal/testutil" "github.com/pokt-network/pocket/p2p/types" "github.com/pokt-network/pocket/p2p/utils" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/messaging" ) // TODO: remove if not needed @@ -110,3 +115,26 @@ func peerFromPrivKeyAndServiceURL( return peerInfo } + +func NewTestPoktEnvelopeBz(t *testing.T, msg string) []byte { + debugMsg := NewDebugStringMessage(t, msg) + + poktEnvelope, err := messaging.PackMessage(debugMsg) + require.NoError(t, err) + + poktEnvelopeBz, err := proto.Marshal(poktEnvelope) + require.NoError(t, err) + + return poktEnvelopeBz +} + +func NewDebugStringMessage(t gocuke.TestingT, msg string) *messaging.DebugMessage { + debugStringMsg, err := anypb.New(&messaging.DebugStringMessage{Value: msg}) + require.NoError(t, err) + + return &messaging.DebugMessage{ + Action: messaging.DebugMessageAction_DEBUG_ACTION_UNKNOWN, + Type: messaging.DebugMessageRoutingType_DEBUG_MESSAGE_TYPE_BROADCAST, + Message: debugStringMsg, + } +} diff --git a/p2p/background/router_test.go b/p2p/background/router_test.go index a1a0fe40b..6b3219d12 100644 --- a/p2p/background/router_test.go +++ b/p2p/background/router_test.go @@ -14,7 +14,11 @@ import ( libp2pPeer "github.com/libp2p/go-libp2p/core/peer" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/multiformats/go-multiaddr" - "github.com/pokt-network/pocket/internal/testutil" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + "github.com/pokt-network/pocket/internal/testutil/generics" + "github.com/pokt-network/pocket/internal/testutil/p2p" "github.com/pokt-network/pocket/p2p/config" typesP2P "github.com/pokt-network/pocket/p2p/types" mock_types "github.com/pokt-network/pocket/p2p/types/mocks" @@ -22,16 +26,28 @@ import ( "github.com/pokt-network/pocket/runtime/configs" "github.com/pokt-network/pocket/runtime/defaults" cryptoPocket "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/messaging" mockModules "github.com/pokt-network/pocket/shared/modules/mocks" - "github.com/stretchr/testify/require" ) // https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2 -const testIP6ServiceURL = "[2a00:1450:4005:802::2004]:8080" +const ( + testIP6ServiceURL = "[2a00:1450:4005:802::2004]:8080" + numPeers = 4 + testMsg = "test messsage" + testTimeoutDuration = time.Second * 2 +) // TECHDEBT(#609): move & de-dup. var testLocalServiceURL = fmt.Sprintf("127.0.0.1:%d", defaults.DefaultP2PPort) +func TestBackgroundRouter_InvalidConfig(t *testing.T) { + t.Skip("pending") + //busMock := bus_testutil.NewBus(t) + // + //router, err := NewBackgroundRouter() +} + func TestBackgroundRouter_AddPeer(t *testing.T) { testRouter := newTestRouter(t, nil) libp2pPStore := testRouter.host.Peerstore() @@ -115,19 +131,15 @@ func TestBackgroundRouter_RemovePeer(t *testing.T) { } func TestBackgroundRouter_Broadcast(t *testing.T) { - const ( - numPeers = 4 - testMsg = "test messsage" - testTimeoutDuration = time.Second * 5 - ) - var ( ctx = context.Background() // mutex preventing concurrent writes to `seenMessages` - seenMessagesMutext sync.Mutex + seenMessagesMutex sync.Mutex // map used as a set to collect IDs of peers which have received a message seenMessages = make(map[string]struct{}) bootstrapWaitgroup = sync.WaitGroup{} + bootstrapPeerIDCh = make(chan string) + bootstrapPeerIDs = make(map[string]struct{}) broadcastWaitgroup = sync.WaitGroup{} broadcastDone = make(chan struct{}, 1) testTimeout = time.After(testTimeoutDuration) @@ -148,9 +160,31 @@ func TestBackgroundRouter_Broadcast(t *testing.T) { testHosts = append(testHosts, host) expectedPeerIDs[i] = host.ID().String() rtr := newRouterWithSelfPeerAndHost(t, selfPeer, host) - go readSubscription(t, ctx, &broadcastWaitgroup, rtr, &seenMessagesMutext, seenMessages) + rtr.HandlerProxy(t, func(origHandler typesP2P.RouterHandler) typesP2P.RouterHandler { + return func(data []byte) error { + seenMessagesMutex.Lock() + broadcastWaitgroup.Done() + seenMessages[rtr.host.ID().String()] = struct{}{} + seenMessagesMutex.Unlock() + + return origHandler(data) + } + }) } + // concurrently update the set of bootstrapped peer IDs as they connect + go func() { + for { + peerIDStr := <-bootstrapPeerIDCh + if _, ok := bootstrapPeerIDs[peerIDStr]; ok { + // already connected to this peer during bootstrapping + continue + } + bootstrapPeerIDs[peerIDStr] = struct{}{} + bootstrapWaitgroup.Done() + } + }() + // bootstrap off of arbitrary testHost privKey, selfPeer := newTestPeer(t) @@ -166,9 +200,14 @@ func TestBackgroundRouter_Broadcast(t *testing.T) { // setup notifee/notify BEFORE bootstrapping notifee := &libp2pNetwork.NotifyBundle{ - ConnectedF: func(_ libp2pNetwork.Network, _ libp2pNetwork.Conn) { + ConnectedF: func(_ libp2pNetwork.Network, conn libp2pNetwork.Conn) { t.Logf("connected!") - bootstrapWaitgroup.Done() + t.Logf("local PeerID %s; remote PeerID: %s", + conn.LocalPeer().String(), + conn.RemotePeer().String(), + ) + bootstrapPeerIDCh <- conn.RemotePeer().String() + //bootstrapWaitgroup.Done() }, } testRouter.host.Network().Notify(notifee) @@ -189,7 +228,8 @@ func TestBackgroundRouter_Broadcast(t *testing.T) { // broadcast message t.Log("broadcasting...") - err := testRouter.Broadcast([]byte(testMsg)) + testPoktEnvelopeBz := p2p_testutil.NewTestPoktEnvelopeBz(t, testMsg) + err = testRouter.Broadcast(testPoktEnvelopeBz) require.NoError(t, err) // wait for broadcast to be received by all peers @@ -200,6 +240,7 @@ func TestBackgroundRouter_Broadcast(t *testing.T) { // waitgroup broadcastDone or timeout select { case <-testTimeout: + seenMessagesMutex.Lock() t.Fatalf( "timed out waiting for all expected messages: got %d; wanted %d", len(seenMessages), @@ -208,7 +249,10 @@ func TestBackgroundRouter_Broadcast(t *testing.T) { case <-broadcastDone: } - actualPeerIDs = testutil.GetKeys[string](seenMessages) + seenMessagesMutex.Lock() + defer seenMessagesMutex.Unlock() + + actualPeerIDs = generics_testutil.GetKeys[string](seenMessages) require.ElementsMatchf(t, expectedPeerIDs, actualPeerIDs, "peerIDs don't match") } @@ -284,11 +328,33 @@ func newRouterWithSelfPeerAndHost(t *testing.T, selfPeer typesP2P.Peer, host lib err := pstore.AddPeer(selfPeer) require.NoError(t, err) + handler := func(poktEnvelopeBz []byte) error { + poktEnvelope := &messaging.PocketEnvelope{} + err := proto.Unmarshal(poktEnvelopeBz, poktEnvelope) + require.NoError(t, err) + + require.NotEmpty(t, poktEnvelope.Nonce) + require.NotEmpty(t, poktEnvelope.Content) + + debugMsg := &messaging.DebugMessage{} + err = poktEnvelope.Content.UnmarshalTo(debugMsg) + require.NoError(t, err) + + debugStringMsg := &messaging.DebugStringMessage{} + err = debugMsg.Message.UnmarshalTo(debugStringMsg) + require.NoError(t, err) + + require.Equal(t, testMsg, debugStringMsg.Value, "debug string messages don't match") + + return nil + } + router, err := NewBackgroundRouter(busMock, &config.BackgroundConfig{ Addr: selfPeer.GetAddress(), PeerstoreProvider: pstoreProviderMock, CurrentHeightProvider: consensusMock, Host: host, + Handler: handler, }) require.NoError(t, err) @@ -345,31 +411,3 @@ func newTestHost(t *testing.T, mockNet mocknet.Mocknet, privKey cryptoPocket.Pri // construct mock host return newMockNetHostFromPeer(t, mockNet, privKey, peer) } - -func readSubscription( - t *testing.T, - ctx context.Context, - broadcastWaitGroup *sync.WaitGroup, - rtr *backgroundRouter, - mu *sync.Mutex, - seenMsgs map[string]struct{}, -) { - t.Helper() - - for { - if err := ctx.Err(); err != nil { - if err != context.Canceled || err != context.DeadlineExceeded { - require.NoError(t, err) - } - return - } - - _, err := rtr.subscription.Next(ctx) - require.NoError(t, err) - - mu.Lock() - broadcastWaitGroup.Done() - seenMsgs[rtr.host.ID().String()] = struct{}{} - mu.Unlock() - } -} From cb4bf216d5ad4cbd3c24efb032723c1f5ed6d0c5 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 1 Jun 2023 13:26:08 +0200 Subject: [PATCH 22/22] wip: testutils --- internal/testutil/bus/bus.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 internal/testutil/bus/bus.go diff --git a/internal/testutil/bus/bus.go b/internal/testutil/bus/bus.go new file mode 100644 index 000000000..f83e27735 --- /dev/null +++ b/internal/testutil/bus/bus.go @@ -0,0 +1,30 @@ +package bus_testutil + +import ( + "github.com/regen-network/gocuke" + + "github.com/pokt-network/pocket/internal/testutil" + "github.com/pokt-network/pocket/internal/testutil/runtime" + "github.com/pokt-network/pocket/runtime/genesis" + "github.com/pokt-network/pocket/shared/crypto" + "github.com/pokt-network/pocket/shared/modules/mocks" +) + +func NewBus( + t gocuke.TestingT, + privKey crypto.PrivateKey, + serviceURL string, + genesisState *genesis.GenesisState, + busEventHandlerFactory testutil.BusEventHandlerFactory, +) *mock_modules.MockBus { + t.Helper() + + runtimeMgrMock := runtime_testutil.BaseRuntimeManagerMock( + t, privKey, + serviceURL, + genesisState, + ) + busMock := testutil.BusMockWithEventHandler(t, runtimeMgrMock, busEventHandlerFactory) + busMock.EXPECT().GetRuntimeMgr().Return(runtimeMgrMock).AnyTimes() + return busMock +}