-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Qa wrappers #19
base: master
Are you sure you want to change the base?
Qa wrappers #19
Changes from all commits
80670e5
8ccbabd
18840fa
8a3f6cf
74bb730
b166398
3a6cce2
3223548
d973e45
b81b437
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# Testlibs for Go-Waku Bindings | ||
|
||
`testlibs` is a dedicated testing framework for the [Go-Waku Bindings](https://github.com/waku-org/waku-go-bindings). It provides an organized structure for writing and executing tests to validate the behavior of Waku nodes and their associated functionalities. | ||
|
||
## Overview | ||
|
||
The primary goal of `testlibs` is to simplify and enhance the testing process for Go-Waku Bindings by offering: | ||
|
||
- **Test Wrappers**: High-level abstractions for managing Waku nodes, including operations like starting, stopping, and destroying nodes. | ||
- **Peer Management**: Tools for validating peer-to-peer connections, such as connecting, disconnecting, and verifying connected peers. | ||
- **Relay Protocol Testing**: Functions to test relay features like subscribing and unsubscribing to pubsub topics and checking relay peer connections. | ||
- **Utility Functions**: Logging and helper functions to streamline debugging and test execution. | ||
## Key Components | ||
|
||
### 1. Wrappers | ||
|
||
The `wrapper` files define abstractions around the `WakuNode` to streamline node management and interaction during testing. Key functionalities include: | ||
|
||
- **Node Lifecycle Management**: | ||
- `Wrappers_StartWakuNode`: Starts a Waku node with a custom or default configuration. | ||
- `Wrappers_Stop`: Stops the Waku node gracefully. | ||
- `Wrappers_Destroy`: Cleans up and destroys the Waku node. | ||
- `Wrappers_StopAndDestroy`: Combines stop and destroy operations for efficient cleanup. | ||
|
||
- **Peer Management**: | ||
- `Wrappers_ConnectPeer`: Simplifies connecting nodes by taking a `WakuNode` instance instead of a `peerID`, constructing the `peerID` and connection details internally. | ||
- `Wrappers_DisconnectPeer`: Disconnects a Waku node from a target peer with validation and error handling. | ||
- `Wrappers_GetConnectedPeers`: Retrieves a list of peers connected to the Waku node. | ||
- `Wrappers_GetNumConnectedRelayPeers`: Returns the number of relay peers connected for a specific pubsub topic. | ||
|
||
- **Relay Subscription**: | ||
- `Wrappers_RelaySubscribe`: Subscribes the Waku node to a given pubsub topic, ensuring subscription and verifying peer connections. | ||
- `Wrappers_RelayUnsubscribe`: Unsubscribes from a specific pubsub topic and validates the unsubscription process. | ||
|
||
--- | ||
|
||
### 2. Utilities | ||
|
||
The `utilities` package provides helper functions and constants to facilitate testing. Key highlights include: | ||
|
||
- **Default Configuration**: | ||
- `DefaultWakuConfig`: Provides a baseline Waku node configuration with sensible defaults for testing purposes. | ||
|
||
- **Logging Support**: | ||
- Centralized logging via `zap` for debugging during tests. | ||
- Debug-level messages are used extensively to trace the flow and identify issues. | ||
|
||
- **Port Management**: | ||
- `GenerateUniquePort`: Dynamically allocates unique ports for Waku nodes during tests to avoid conflicts. | ||
|
||
- **Timeout and Error Handling**: | ||
- Constants for peer connection timeouts. | ||
- Enhanced error messaging for debugging failures in Waku node operations. | ||
|
||
--- | ||
|
||
### 3. Test Files | ||
|
||
#### Relay Tests (`relay_test.go`) | ||
- **Highlights**: | ||
- Tests the behavior of the relay protocol. | ||
- Example: `TestRelaySubscribeToDefaultTopic` validates subscription to the default pubsub topic and ensures connected relay peers increase. | ||
|
||
#### Peer Connection Tests (`Peers_connection_test.go`) | ||
- **Highlights**: | ||
- Simplifies peer connectivity testing using the wrappers. | ||
- Example: `TestConnectMultipleNodesToSingleNode` verifies multiple nodes can connect to a single node efficiently. | ||
|
||
#### Basic Node Tests (`Nodes_basic_test.go`) | ||
- **Highlights**: | ||
- Validates fundamental node lifecycle management using wrapper APIs. | ||
- Example: `TestBasicWakuNodes` covers node creation, startup, and cleanup using `Wrappers_StartWakuNode` and `Wrappers_StopAndDestroy`. | ||
|
||
## Purpose | ||
|
||
This framework is designed to ensure the reliability and robustness of the Go-Waku Bindings, which enable Go applications to interface with the Waku protocol. With `testlibs`, developers can simulate various conditions, verify expected behaviors, and maintain confidence in their implementations. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,282 @@ | ||
package testlibs | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
|
||
"github.com/libp2p/go-libp2p/core/peer" | ||
|
||
utilities "github.com/waku-org/waku-go-bindings/testlibs/utilities" | ||
"github.com/waku-org/waku-go-bindings/waku" | ||
"go.uber.org/zap" | ||
) | ||
|
||
type WakuNodeWrapper struct { | ||
*waku.WakuNode | ||
} | ||
|
||
// This function create waku node from config and start it | ||
func Wrappers_StartWakuNode(customCfg *waku.WakuConfig, logger *zap.Logger) (*WakuNodeWrapper, error) { | ||
|
||
var nodeCfg waku.WakuConfig | ||
|
||
if customCfg == nil { | ||
nodeCfg = *utilities.DefaultWakuConfig | ||
} else { | ||
nodeCfg = *customCfg | ||
} | ||
|
||
nodeCfg.Discv5UdpPort = utilities.GenerateUniquePort() | ||
nodeCfg.TcpPort = utilities.GenerateUniquePort() | ||
|
||
utilities.Debug("Create node with default config") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe this log is misleading? because if |
||
node, err := waku.NewWakuNode(&nodeCfg, logger) | ||
if err != nil { | ||
utilities.Error("Can't create node") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we add the error in the log? something like
|
||
return nil, err | ||
} | ||
|
||
utilities.Debug("Attempting to start WakuNode") | ||
wrapper := &WakuNodeWrapper{WakuNode: node} | ||
if err := utilities.CheckWakuNodeNull(logger, wrapper.WakuNode); err != nil { | ||
utilities.Error("Failed to start WakuNode", zap.Error(err)) | ||
return nil, err | ||
} | ||
|
||
err = wrapper.WakuNode.Start() | ||
if err != nil { | ||
utilities.Error("Failed to start WakuNode", zap.Error(err)) | ||
return nil, err | ||
} | ||
utilities.Debug("Successfully started WakuNode") | ||
|
||
return wrapper, nil | ||
} | ||
|
||
// Stops the WakuNode. | ||
func (node *WakuNodeWrapper) Wrappers_Stop() error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As this is a method of Same for all the methods of |
||
if err := utilities.CheckWakuNodeNull(nil, node.WakuNode); err != nil { | ||
utilities.Error("Failed to stop WakuNode", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Attempting to stop WakuNode") | ||
err := node.WakuNode.Stop() | ||
if err != nil { | ||
utilities.Error("Failed to stop WakuNode", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Successfully stopped WakuNode") | ||
return nil | ||
} | ||
|
||
// Destroys the WakuNode. | ||
func (node *WakuNodeWrapper) Wrappers_Destroy() error { | ||
if err := utilities.CheckWakuNodeNull(nil, node.WakuNode); err != nil { | ||
utilities.Error("Failed to destroy WakuNode", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Attempting to destroy WakuNode") | ||
err := node.WakuNode.Destroy() | ||
if err != nil { | ||
utilities.Error("Failed to destroy WakuNode", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Successfully destroyed WakuNode") | ||
return nil | ||
} | ||
|
||
func (wrapper *WakuNodeWrapper) Wrappers_StopAndDestroy() error { | ||
if err := utilities.CheckWakuNodeNull(nil, wrapper.WakuNode); err != nil { | ||
utilities.Error("Failed to stop or destroy WakuNode", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Attempting to stop WakuNode") | ||
err := wrapper.Stop() | ||
if err != nil { | ||
utilities.Error("Failed to stop WakuNode", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Attempting to destroy WakuNode") | ||
err = wrapper.Destroy() | ||
if err != nil { | ||
utilities.Error("Failed to destroy WakuNode", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Successfully stopped and destroyed WakuNode") | ||
return nil | ||
} | ||
|
||
func (wrapper *WakuNodeWrapper) Wrappers_GetConnectedPeers() ([]peer.ID, error) { | ||
if err := utilities.CheckWakuNodeNull(nil, wrapper.WakuNode); err != nil { | ||
utilities.Error("Cannot proceed; node is nil", zap.Error(err)) | ||
return nil, err | ||
} | ||
|
||
peerID, err := wrapper.WakuNode.PeerID() | ||
if err != nil { | ||
utilities.Error("Failed to get PeerID of node", zap.Error(err)) | ||
return nil, err | ||
} | ||
|
||
utilities.Debug("Getting number of connected peers to node", zap.String("node", peerID.String())) | ||
|
||
peers, err := wrapper.WakuNode.GetConnectedPeers() | ||
if err != nil { | ||
utilities.Error("Failed to get connected peers", zap.Error(err)) | ||
return nil, err | ||
} | ||
|
||
utilities.Debug("Successfully fetched connected peers", | ||
zap.Int("count", len(peers)), | ||
) | ||
return peers, nil | ||
} | ||
|
||
func (wrapper *WakuNodeWrapper) Wrappers_GetNumConnectedRelayPeers(optPubsubTopic ...string) (int, error) { | ||
utilities.Debug("Wrappers_GetNumConnectedRelayPeers called") | ||
|
||
if err := utilities.CheckWakuNodeNull(nil, wrapper.WakuNode); err != nil { | ||
utilities.Error("Cannot proceed; node is nil", zap.Error(err)) | ||
return 0, err | ||
} | ||
|
||
numPeers, err := wrapper.WakuNode.GetNumConnectedRelayPeers(optPubsubTopic...) | ||
if err != nil { | ||
utilities.Error("Failed to get number of connected relay peers", zap.Error(err)) | ||
return 0, err | ||
} | ||
|
||
utilities.Debug("Successfully fetched number of connected relay peers", | ||
zap.Int("count", numPeers), | ||
) | ||
return numPeers, nil | ||
} | ||
|
||
func (wrapper *WakuNodeWrapper) Wrappers_ConnectPeer(targetNode *WakuNodeWrapper) error { | ||
|
||
utilities.Debug("Connect node to peer") | ||
if err := utilities.CheckWakuNodeNull(nil, wrapper.WakuNode); err != nil { | ||
utilities.Error("Cannot call Connect; caller node is nil", zap.Error(err)) | ||
return err | ||
} | ||
if err := utilities.CheckWakuNodeNull(nil, targetNode.WakuNode); err != nil { | ||
utilities.Error("Cannot connect; target node is nil", zap.Error(err)) | ||
return err | ||
} | ||
|
||
targetPeerID, err := targetNode.WakuNode.PeerID() | ||
if err != nil { | ||
utilities.Error("Failed to get PeerID of target node", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Get connected peers before attempting to connect") | ||
|
||
connectedPeersBefore, err := wrapper.Wrappers_GetConnectedPeers() | ||
if err != nil { | ||
utilities.Debug("Could not fetch connected peers before connecting (might be none yet)", zap.Error(err)) | ||
} else { | ||
utilities.Debug("Connected peers before connecting", zap.Int("count", len(connectedPeersBefore))) | ||
} | ||
|
||
utilities.Debug("Attempt to connect to the target node") | ||
ctx, cancel := context.WithTimeout(context.Background(), utilities.ConnectPeerTimeout) | ||
defer cancel() | ||
|
||
targetAddr, err := targetNode.WakuNode.ListenAddresses() | ||
if err != nil || len(targetAddr) == 0 { | ||
utilities.Error("Failed to get listen addresses for target node", zap.Error(err)) | ||
return errors.New("target node has no listen addresses") | ||
} | ||
|
||
utilities.Debug("Connecting to peer", zap.String("address", targetAddr[0].String())) | ||
err = wrapper.WakuNode.Connect(ctx, targetAddr[0]) | ||
if err != nil { | ||
utilities.Error("Failed to connect to peer", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Get connected peers after attempting to connect") | ||
connectedPeersAfter, err := wrapper.Wrappers_GetConnectedPeers() | ||
if err != nil { | ||
utilities.Error("Failed to get connected peers after connecting", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Connected peers after connecting", zap.Int("count", len(connectedPeersAfter))) | ||
|
||
utilities.Debug("Check if the target peer is now connected") | ||
isConnected := false | ||
for _, peerID := range connectedPeersAfter { | ||
if peerID == targetPeerID { | ||
isConnected = true | ||
break | ||
} | ||
} | ||
|
||
if !isConnected { | ||
err := errors.New("failed to connect; target peer is not in connected peers list") | ||
utilities.Error("Connect operation failed", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Successfully connected to target peer", zap.String("targetPeerID", targetPeerID.String())) | ||
return nil | ||
} | ||
|
||
func (wrapper *WakuNodeWrapper) Wrappers_DisconnectPeer(target *WakuNodeWrapper) error { | ||
|
||
if err := utilities.CheckWakuNodeNull(nil, wrapper.WakuNode); err != nil { | ||
utilities.Error("Cannot call Disconnect; caller node is nil", zap.Error(err)) | ||
return err | ||
} | ||
if err := utilities.CheckWakuNodeNull(nil, target.WakuNode); err != nil { | ||
utilities.Error("Cannot disconnect; target node is nil", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Check if nodes are peers first") | ||
|
||
peerID, err := target.WakuNode.PeerID() | ||
if err != nil { | ||
utilities.Error("Failed to get PeerID of target node", zap.Error(err)) | ||
return err | ||
} | ||
|
||
connectedPeers, err := wrapper.Wrappers_GetConnectedPeers() | ||
if err != nil { | ||
utilities.Error("Failed to get connected peers", zap.Error(err)) | ||
return err | ||
} | ||
|
||
isPeer := false | ||
for _, connectedPeerID := range connectedPeers { | ||
if connectedPeerID == peerID { | ||
isPeer = true | ||
break | ||
} | ||
} | ||
|
||
if !isPeer { | ||
err = errors.New("nodes are not connected as peers") | ||
utilities.Error("Cannot disconnect; nodes are not peers", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Nodes are peers.. attempting to disconnect") | ||
err = wrapper.WakuNode.DisconnectPeerByID(peerID) | ||
if err != nil { | ||
utilities.Error("Failed to disconnect peer", zap.Error(err)) | ||
return err | ||
} | ||
|
||
utilities.Debug("Successfully disconnected peer", zap.String("peerID", peerID.String())) | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you should add the Key Components section from PR description here as well, what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right. since the Key Components contain more details it's better to include it in the README file too
Done