Skip to content

Commit

Permalink
[E2E] Test REST Relays (#611)
Browse files Browse the repository at this point in the history
Co-authored-by: Dmitry K. <[email protected]>
Co-authored-by: Daniel Olshansky <[email protected]>
  • Loading branch information
3 people authored Jun 19, 2024
1 parent 0aa062c commit 11a60b6
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 13 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,8 @@ localnet_regenesis: check_yq warn_message_acc_initialize_pubkeys ## Regenerate t
@cp -r ${HOME}/.poktroll/keyring-test $(POKTROLLD_HOME)
@cp -r ${HOME}/.poktroll/config $(POKTROLLD_HOME)/

.PHONY: send_relay_sovereign_app
send_relay_sovereign_app: # Send a relay through the AppGateServer as a sovereign application
.PHONY: send_relay_sovereign_app_JSONRPC
send_relay_sovereign_app_JSONRPC: # Send a JSONRPC relay through the AppGateServer as a sovereign application
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
$(APPGATE_SERVER)/anvil
Expand Down
10 changes: 7 additions & 3 deletions e2e/tests/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package e2e

import (
"context"
"encoding/json"
"flag"
"fmt"
"log"
Expand Down Expand Up @@ -379,12 +380,12 @@ func (s *suite) TheSessionForApplicationAndServiceContainsTheSupplier(appName st
s.Fatalf("session for app %s and service %s does not contain supplier %s", appName, serviceId, supplierName)
}

func (s *suite) TheApplicationSendsTheSupplierARequestForServiceWithData(appName, supplierName, serviceId, requestData string) {
func (s *suite) TheApplicationSendsTheSupplierARequestForServiceWithPathAndData(appName, supplierName, serviceId, path, requestData string) {
// TODO_HACK: We need to support a non self_signing LocalNet AppGateServer
// that allows any application to send a relay in LocalNet and our E2E Tests.
require.Equal(s, "app1", appName, "TODO_HACK: The LocalNet AppGateServer is self_signing and only supports app1.")

res, err := s.pocketd.RunCurl(appGateServerUrl, serviceId, requestData)
res, err := s.pocketd.RunCurl(appGateServerUrl, serviceId, path, requestData)
require.NoError(s, err, "error sending relay request from app %q to supplier %q for service %q", appName, supplierName, serviceId)

relayKey := relayReferenceKey(appName, supplierName)
Expand All @@ -399,7 +400,10 @@ func (s *suite) TheApplicationReceivesASuccessfulRelayResponseSignedBy(appName s
relayKey := relayReferenceKey(appName, supplierName)
stdout, ok := s.scenarioState[relayKey]
require.Truef(s, ok, "no relay response found for %s", relayKey)
require.Contains(s, stdout, `"result":"0x`)

var jsonContent json.RawMessage
err := json.Unmarshal([]byte(stdout.(string)), &jsonContent)
require.NoError(s, err, `Expected valid JSON, got: %s`, stdout)
}

// TODO_TECHDEBT: Factor out the common logic between this step and waitForTxResultEvent.
Expand Down
16 changes: 11 additions & 5 deletions e2e/tests/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type commandResult struct {
type PocketClient interface {
RunCommand(args ...string) (*commandResult, error)
RunCommandOnHost(rpcUrl string, args ...string) (*commandResult, error)
RunCurl(rpcUrl, service, data string, args ...string) (*commandResult, error)
RunCurl(rpcUrl, service, path, data string, args ...string) (*commandResult, error)
}

// Ensure that pocketdBin struct fulfills PocketClient
Expand Down Expand Up @@ -94,11 +94,11 @@ func (p *pocketdBin) RunCommandOnHostWithRetry(rpcUrl string, numRetries uint8,
}

// RunCurl runs a curl command on the local machine
func (p *pocketdBin) RunCurl(rpcUrl, service, data string, args ...string) (*commandResult, error) {
func (p *pocketdBin) RunCurl(rpcUrl, service, path, data string, args ...string) (*commandResult, error) {
if rpcUrl == "" {
rpcUrl = defaultAppGateServerURL
}
return p.runCurlPostCmd(rpcUrl, service, data, args...)
return p.runCurlPostCmd(rpcUrl, service, path, data, args...)
}

// runPocketCmd is a helper to run a command using the local pocketd binary with the flags provided
Expand Down Expand Up @@ -134,9 +134,15 @@ func (p *pocketdBin) runPocketCmd(args ...string) (*commandResult, error) {
}

// runCurlPostCmd is a helper to run a command using the local pocketd binary with the flags provided
func (p *pocketdBin) runCurlPostCmd(rpcUrl string, service string, data string, args ...string) (*commandResult, error) {
func (p *pocketdBin) runCurlPostCmd(rpcUrl, service, path, data string, args ...string) (*commandResult, error) {
dataStr := fmt.Sprintf("%s", data)
urlStr := fmt.Sprintf("%s/%s", rpcUrl, service)
// Ensure that if a path is provided, it starts with a "/".
// This is required for RESTful APIs that use a path to identify resources.
// For JSON-RPC APIs, the resource path should be empty, so empty paths are allowed.
if len(path) > 0 && path[0] != '/' {
path = "/" + path
}
urlStr := fmt.Sprintf("%s/%s%s", rpcUrl, service, path)
base := []string{
"-v", // verbose output
"-sS", // silent with error
Expand Down
12 changes: 10 additions & 2 deletions e2e/tests/relay.feature
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
Feature: Relay Namespace

# NB: `make acc_initialize_pubkeys` must have been executed before this test is run
Scenario: App can send relay to Supplier
Scenario: App can send a JSON-RPC relay to Supplier
Given the user has the pocketd binary installed
And the application "app1" is staked for service "anvil"
And the supplier "supplier1" is staked for service "anvil"
And the session for application "app1" and service "anvil" contains the supplier "supplier1"
When the application "app1" sends the supplier "supplier1" a request for service "anvil" with data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
When the application "app1" sends the supplier "supplier1" a request for service "anvil" with path "" and data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
Then the application "app1" receives a successful relay response signed by "supplier1"

Scenario: App can send a REST relay to Supplier
Given the user has the pocketd binary installed
And the application "app1" is staked for service "ollama"
And the supplier "supplier1" is staked for service "ollama"
And the session for application "app1" and service "ollama" contains the supplier "supplier1"
When the application "app1" sends the supplier "supplier1" a request for service "ollama" with path "/api/chat" and data '{"model": "qwen:0.5b", "stream": false, "messages": [{"role": "user", "content":"count from 1 to 10"}]}'
Then the application "app1" receives a successful relay response signed by "supplier1"
And a "tokenomics" module "ClaimSettled" event is broadcasted

Expand Down
4 changes: 3 additions & 1 deletion e2e/tests/session_steps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const (
// testServiceId is the service ID used for testing purposes that is
// expected to be available in LocalNet.
testServiceId = "anvil"
// defaultJSONPRCPath is the default path used for sending JSON-RPC relay requests.
defaultJSONPRCPath = ""

// txSenderEventSubscriptionQueryFmt is the format string which yields the
// cosmos-sdk event subscription "query" string for a given sender address.
Expand Down Expand Up @@ -192,7 +194,7 @@ func (s *suite) sendRelaysForSession(

for i := 0; i < relayLimit; i++ {
s.Logf("Sending relay %d \n", i)
s.TheApplicationSendsTheSupplierARequestForServiceWithData(appName, supplierName, serviceId, data)
s.TheApplicationSendsTheSupplierARequestForServiceWithPathAndData(appName, supplierName, serviceId, defaultJSONPRCPath, data)
s.TheApplicationReceivesASuccessfulRelayResponseSignedBy(appName, supplierName)
}
}
Expand Down

0 comments on commit 11a60b6

Please sign in to comment.