diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..2e720df --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // example of how to debug and step through a system test feature using IDE + // need to have a running instance of quickstart:soroban-dev for rpc url + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Dapp Test", + "type": "go", + "request": "launch", + "host": "127.0.0.1", + "mode": "test", + "program": "${workspaceFolder}/features/dapp_develop/dapp_develop_test.go", + "cwd": "${workspaceFolder}", + "env": { + "SorobanExamplesGitHash": "v0.7.0", + "SorobanExamplesRepoURL": "https://github.com/stellar/soroban-examples.git", + "TargetNetworkPassPhrase": "Standalone Network ; February 2017", + "TargetNetworkSecretKey": "SC5O7VZUXDJ6JBDSZ74DSERXL7W3Y5LTOAMRF7RQRL3TAGAPS7LUVG3L", + "TargetNetworkPublicKey": "GBZXN7PIRZGNMHGA7MUUUF4GWPY5AYPV6LY4UV2GL6VJGIQRXFDNMADI", + "TargetNetworkRPCURL":"http://localhost:8000/soroban/rpc", + "LocalCore": "true", + "VerboseOutput": "true", + "FeaturePath": "./features/dapp_develop" + }, + }, + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ba78e04..9dafa18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # System Test Releases +#### Pending + +* new scenario for testing diagnostic events retrieval from cli and js. [system-test, #49](https://github.com/stellar/system-test/pull/49) #### 1.0.10 diff --git a/Dockerfile b/Dockerfile index ed9f2f8..90b4b15 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ ARG QUICKSTART_IMAGE_REF=stellar/quickstart:soroban-dev ARG SOROBAN_CLI_IMAGE_REF=stellar/system-test-soroban-cli:dev -FROM golang:1.19 as go +FROM golang:1.20 as go RUN ["mkdir", "-p", "/test"] RUN ["mkdir", "-p", "/test/bin"] @@ -54,6 +54,10 @@ RUN groupadd --gid $USER_GID $USERNAME \ RUN ["mkdir", "-p", "/home/tester"] USER tester WORKDIR /home/tester +RUN mkdir -p ~/.ssh +RUN chmod 700 ~/.ssh +RUN echo "HOST *" > ~/.ssh/config +RUN echo "StrictHostKeyChecking no" >> ~/.ssh/config # Install Node.js RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash @@ -68,7 +72,7 @@ RUN npm i -g ts-node ARG JS_SOROBAN_CLIENT_NPM_VERSION ADD package*.json /home/tester/ RUN npm ci && npm install "soroban-client@${JS_SOROBAN_CLIENT_NPM_VERSION}" -ADD invoke.ts /home/tester/bin/ +ADD *.ts /home/tester/bin/ RUN ["sudo", "chmod", "+x", "/home/tester/bin/invoke.ts"] FROM base as build diff --git a/README.md b/README.md index 9287f77..178c60a 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ The default target network for system tests is a new/empty instance of standalon `--TargetNetworkTestAccountPublic "{your test account key pair info}"` Debug mode, the docker container will exit with error code when any pre-setup or test fails to pass, -you can enable DEBUG_MODE flag, and the container will stay running, prompting you for enter key before shutting down, make sure you invoke docker with `-it` so the prompt will reach your command line. While container is kept running, you can shell into it via `docker exec -it ` and view log files of core, rpc, horizon all of which are located in container at `/var/log/supervisor`. +you can enable DEBUG_MODE flag, and the container will stay running, prompting you for enter key before shutting down, make sure you invoke docker with `-it` so the prompt will reach your command line. While container is kept running, you can shell into it via `docker exec -it ` and view log files of services in the stack such as core, rpc located in container at `/var/log/supervisor`. `--DebugMode=true` @@ -133,19 +133,19 @@ The docker run follows standard exit code conventions, so if all tests pass in t ### Development mode and running tests directly from checked out system-test repo. -This approach allows to run the tests from source code directly on host as go tests, no docker image. -Tests will use `soroban` cli tool from the host path. You need to set `TargetNetworkRPCURL` to a running instance of soroban rpc. +This approach allows to run the tests from source code directly on host as go tests, no docker image is used. #### Prerequisites: 1. go 1.18 or above - https://go.dev/doc/install 2. rust toolchain(cargo and rustc), install the version per testing requirements or stable, - use rustup - https://www.rust-lang.org/tools/install - 3. target network stack for the tests to execute against - need a soroban-rpc instance. You can use an existing/running instance if reachable or can use the quickstart image `stellar/quickstart:soroban-dev` from dockerhub to run the latest stable target network stack locally, or build quickstart with specific versions of core, horizon and soroban rpc first [following these instructions](https://github.com/stellar/quickstart#building-custom-images) and run `stellar/quickstart:dev` locally. + 3. `soroban`, compile or install via cargo crate a version of soroban cli onto your machine and accessible from PATH. + 4. target network stack for the tests to access soroban-rpc instance. You can use an existing/running instance if reachable or can use the quickstart image `stellar/quickstart:soroban-dev` from dockerhub to run the latest stable target network stack locally, or build quickstart with specific versions of core, horizon and soroban rpc first [following these instructions](https://github.com/stellar/quickstart#building-custom-images) and run `stellar/quickstart:dev` locally. ``` docker run --rm -it -p 8000:8000 --name stellar stellar/quickstart:dev --standalone --enable-soroban-rpc --enable-core-artificially-accelerate-time-for-testing ``` - 4. locally checkout stellar/system-test GH repo and go into top folder - `git clone https://github.com/stellar/system-test.git;cd system-test` - 5. compile or install via cargo crate a version of soroban cli onto your machine and accessible from PATH. + 5. locally checkout stellar/system-test GH repo and go into top folder - `git clone https://github.com/stellar/system-test.git;cd system-test` + #### Running tests ``` @@ -168,3 +168,8 @@ This example uses a feature/scenario filter also to limit which tests are run. * the verbose output of BDD scenerio results for tests is dependent on go's testing verbose output rules, need to specify -v and a directory with single package, if multiple packages detected on directory location, then go won't print verbose output for each package, i.e. you wont see the BDD scenerio summaries printed, just the standard one liner for summary of package pass/fail status. +#### Debugging tests + +Have provided a debug config [launch.json](.vscode/launch.json) for example reference on how to run a test with the go/dlv debugger to step through, etc. + + diff --git a/e2e.go b/e2e.go index dcf0d0d..8919ec8 100644 --- a/e2e.go +++ b/e2e.go @@ -27,6 +27,10 @@ type E2EConfig struct { TargetNetworkPassPhrase string TargetNetworkSecretKey string TargetNetworkPublicKey string + // if true, means the core is running in same container as tests + LocalCore bool + // the relative feature file path + FeaturePath string } const ( @@ -77,12 +81,29 @@ type RPCLedgerEntryResponse struct { Error *RPCError `json:"error,omitempty"` } +type LatestLedgerResult struct { + // Hash of the latest ledger as a hex-encoded string + Hash string `json:"id"` + // Stellar Core protocol version associated with the ledger. + ProtocolVersion uint32 `json:"protocolVersion,string"` + // Sequence number of the latest ledger. + Sequence uint32 `json:"sequence"` +} + +type RPCLatestLedgerResponse struct { + Result LatestLedgerResult `json:"result"` + Error *RPCError `json:"error,omitempty"` +} + const TestTmpDirectory = "test_tmp_workspace" func InitEnvironment() (*E2EConfig, error) { var flagConfig = &E2EConfig{} var err error + if flagConfig.FeaturePath, err = getEnv("FeaturePath"); err != nil { + return nil, err + } if flagConfig.SorobanExamplesGitHash, err = getEnv("SorobanExamplesGitHash"); err != nil { return nil, err } @@ -104,6 +125,9 @@ func InitEnvironment() (*E2EConfig, error) { if verboseOutput, err := getEnv("VerboseOutput"); err == nil { flagConfig.VerboseOutput, _ = strconv.ParseBool(verboseOutput) } + if LocalCore, err := getEnv("LocalCore"); err == nil { + flagConfig.LocalCore, _ = strconv.ParseBool(LocalCore) + } return flagConfig, nil } @@ -180,6 +204,32 @@ func (a *Asserter) Errorf(format string, args ...interface{}) { a.Err = fmt.Errorf(format, args...) } +func QueryNetworkState(e2eConfig *E2EConfig) (LatestLedgerResult, error) { + getLatestLedger := []byte(`{ + "jsonrpc": "2.0", + "id": 10235, + "method": "getLatestLedger" + }`) + + resp, err := http.Post(e2eConfig.TargetNetworkRPCURL, "application/json", bytes.NewBuffer(getLatestLedger)) + if err != nil { + return LatestLedgerResult{}, fmt.Errorf("soroban rpc get latest ledger had error %e", err) + } + + var rpcResponse RPCLatestLedgerResponse + decoder := json.NewDecoder(resp.Body) + err = decoder.Decode(&rpcResponse) + if err != nil { + return LatestLedgerResult{}, fmt.Errorf("soroban rpc get latest ledger, not able to parse response, %v, %e", resp, err) + } + if rpcResponse.Error != nil { + return LatestLedgerResult{}, fmt.Errorf("soroban rpc get latest ledger, error on response, %v, %e", resp, err) + } + + return rpcResponse.Result, nil + +} + func QueryAccount(e2eConfig *E2EConfig, publicKey string) (*AccountInfo, error) { decoded, err := strkey.Decode(strkey.VersionByteAccountID, publicKey) if err != nil { diff --git a/events.ts b/events.ts new file mode 100755 index 0000000..0958c70 --- /dev/null +++ b/events.ts @@ -0,0 +1,47 @@ +#!/usr/bin/env ts-node-script + +import { ArgumentParser } from 'argparse'; +import * as SorobanClient from 'soroban-client'; +const xdr = SorobanClient.xdr; + +async function main() { + const parser = new ArgumentParser({ description: 'Get contract events' }) + parser.add_argument('--id', { dest: 'contractId', required: true, help: 'Contract ID' }); + parser.add_argument('--rpc-url', { dest: 'rpcUrl', required: true, help: 'RPC URL' }); + parser.add_argument('--size', { dest: 'size', required: true, help: 'Max Number of events to fetch' }); + parser.add_argument('--ledgerFrom', { dest: 'ledgerFrom', help: 'Ledget Start' }); + + const { + contractId, + rpcUrl, + size, + ledgerFrom, + } = parser.parse_args() as Record; + + const server = new SorobanClient.Server(rpcUrl, { allowHttp: true }); + + let filters: SorobanClient.SorobanRpc.EventFilter[] = []; + + if (contractId != null) { + filters.push({ + contractIds: [ contractId ] + }); + } + + let response = await server + .getEvents({ + startLedger: Number(ledgerFrom), + filters: filters, + limit: Number(size)}); + + if (!response.events) { + throw new Error(`No events in response: ${JSON.stringify(response)}`); + } + + console.log(JSON.stringify(response.events)); +} + +main().catch(err => { + console.error(JSON.stringify(err)); + throw err; +}); diff --git a/features/dapp_develop/cli.go b/features/dapp_develop/cli.go index 3228814..aefd787 100644 --- a/features/dapp_develop/cli.go +++ b/features/dapp_develop/cli.go @@ -1,6 +1,7 @@ package dapp_develop import ( + "encoding/json" "fmt" "strings" @@ -11,7 +12,7 @@ import ( // return the fn response as a serialized string // uses secret-key and network-passphrase directly on command -func invokeContractFromCliTool(deployedContractId, contractName, functionName, param1 string, e2eConfig *e2e.E2EConfig) (string, error) { +func invokeContractFromCliTool(deployedContractId, contractName, functionName, functionParams string, e2eConfig *e2e.E2EConfig) (string, error) { args := []string{ "contract", "invoke", @@ -23,8 +24,8 @@ func invokeContractFromCliTool(deployedContractId, contractName, functionName, p functionName, } - if param1 != "" { - args = append(args, param1) + if functionParams != "" { + args = append(args, functionParams) } envCmd := cmd.NewCmd("soroban", args...) @@ -74,3 +75,46 @@ func invokeContractFromCliToolWithConfig(deployedContractId, contractName, funct return stdOut, nil } + +func getEventsFromCliTool(ledgerFrom uint32, deployedContractId string, size uint32, e2eConfig *e2e.E2EConfig) ([]map[string]interface{}, error) { + + args := []string{ + "events", + "--start-ledger", fmt.Sprint(ledgerFrom), + "--count", fmt.Sprint(size), + "--id", deployedContractId, + "--rpc-url", e2eConfig.TargetNetworkRPCURL, + "--network-passphrase", e2eConfig.TargetNetworkPassPhrase, + "--output", "json", + } + + envCmd := cmd.NewCmd("soroban", args...) + + status, stdOutLines, err := e2e.RunCommand(envCmd, e2eConfig) + var jsonEvents []map[string]interface{} + var stdOutLinesTrimmed []string + + if status != 0 || err != nil { + return jsonEvents, fmt.Errorf("soroban cli get events had error %v, %v", status, err) + } + + if len(stdOutLines) > 0 { + // some output was produced to console by the cli events command, + // it could represent a correct or bad result, but need to remove the last line of it regardless + // because if it's correct results will have a last line of 'Latest Ledger: xxxx', which needs to be removed to + // parse the rest as valid json, + stdOutLinesTrimmed = stdOutLines[:len(stdOutLines)-1] + } + + // put commas between any json event objects if more than one found + stdOutEventsValidJson := strings.ReplaceAll(strings.Join(stdOutLinesTrimmed, "\n"), `\n}\n{\n`, `\n}\n,\n{\n`) + // wrap the json objects in json array brackets + stdOutEventsValidJson = "[" + stdOutEventsValidJson + "]" + + err = json.Unmarshal([]byte(stdOutEventsValidJson), &jsonEvents) + if err != nil { + return jsonEvents, fmt.Errorf("soroban cli get events console output %v was not parseable as event json, %e", strings.Join(stdOutLines, "\n"), err) + } + + return jsonEvents, nil +} diff --git a/features/dapp_develop/dapp_develop.feature b/features/dapp_develop/dapp_develop.feature index 8116cf0..94770e7 100644 --- a/features/dapp_develop/dapp_develop.feature +++ b/features/dapp_develop/dapp_develop.feature @@ -1,15 +1,17 @@ Feature: DApp Contract Development + + Scenario Outline: DApp developer compiles, installs, deploys and invokes a contract -Given I used cargo to compile example contract + Given I used cargo to compile example contract And I used rpc to verify my account is on the network And I used cli to install contract on network using my secret key And I used cli to deploy contract by installed hash using my secret key - When I invoke function on with request parameter from using my secret key - Then the result should be + When I invoke function on with request parameters from tool using my secret key + Then The result should be Examples: - | Tool | ContractExampleSubPath | ContractName | ContractCompiledFileName | FunctionName | Param1 | Result | + | Tool | ContractExampleSubPath | ContractName | ContractCompiledFileName | FunctionName | FunctionParams | Result | | NODEJS | hello_world | soroban-hello-world-contract | soroban_hello_world_contract.wasm | hello | Aloha | ["Hello","Aloha"] | | CLI | hello_world | soroban-hello-world-contract | soroban_hello_world_contract.wasm | hello | --to=Aloha | ["Hello","Aloha"] | | NODEJS | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 | @@ -17,18 +19,21 @@ Given I used cargo to compile example contract Scenario Outline: DApp developer compiles, deploys and invokes a contract - Given I used cargo to compile example contract + Given I am using an rpc instance that has captive core config, ENABLE_SOROBAN_DIAGNOSTIC_EVENTS=true + And I used cargo to compile example contract And I used rpc to verify my account is on the network + And I used rpc to get network latest ledger And I used cli to deploy contract using my secret key - When I invoke function on with request parameter from using my secret key - Then the result should be + When I invoke function on with request parameters from tool using my secret key + Then The result should be + And The result should be to receive contract events and diagnostic events for from Examples: - | Tool | ContractExampleSubPath | ContractName | ContractCompiledFileName | FunctionName | Param1 | Result | - | NODEJS | hello_world | soroban-hello-world-contract | soroban_hello_world_contract.wasm | hello | Aloha | ["Hello","Aloha"] | - | CLI | hello_world | soroban-hello-world-contract | soroban_hello_world_contract.wasm | hello | --to=Aloha | ["Hello","Aloha"] | - | NODEJS | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 | - | CLI | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 | + | Tool | ContractExampleSubPath | ContractName | ContractCompiledFileName | FunctionName | FunctionParams | Result | EventCount | DiagEventCount | + | NODEJS | hello_world | soroban-hello-world-contract | soroban_hello_world_contract.wasm | hello | Aloha | ["Hello","Aloha"] | 0 | 1 | + | CLI | hello_world | soroban-hello-world-contract | soroban_hello_world_contract.wasm | hello | --to=Aloha | ["Hello","Aloha"] | 0 | 1 | + | NODEJS | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 | 0 | 1 | + | CLI | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 | 0 | 1 | Scenario Outline: DApp developer uses config states, compiles, deploys and invokes contract with authorizations @@ -38,9 +43,9 @@ Scenario Outline: DApp developer uses config states, compiles, deploys and invok And I used cli to add Network Config for rpc and standalone And I used cli to add Identity for my secret key And I used cli to add Identity for tester secret key - And I used cli to deploy contract using my Identity and Network Config - When I invoke function on with request parameters from using tester Identity as invoker and Network Config - Then the result should be + And I used cli to deploy contract using Identity and Network Config + When I invoke function on with request parameters from tool using Identity as invoker and Network Config + Then The result should be Examples: | Tool | ContractExampleSubPath | ContractName | ContractCompiledFileName | FunctionName | FunctionParams | RootIdentityName | TesterIdentityName | NetworkConfigName | Result | diff --git a/features/dapp_develop/dapp_develop_test.go b/features/dapp_develop/dapp_develop_test.go index 02d5a66..eba6b06 100644 --- a/features/dapp_develop/dapp_develop_test.go +++ b/features/dapp_develop/dapp_develop_test.go @@ -16,7 +16,8 @@ import ( "github.com/stellar/go/keypair" "github.com/stellar/go/txnbuild" - "github.com/stellar/system-test" + "github.com/stellar/go/xdr" + e2e "github.com/stellar/system-test" "github.com/stretchr/testify/assert" ) @@ -37,6 +38,9 @@ type testConfig struct { TesterAccountPublicKey string TesterAccountPrivateKey string Identities map[string]string + ContractEvents []xdr.DiagnosticEvent + DiagnosticEvents []xdr.DiagnosticEvent + InitialNetworkState e2e.LatestLedgerResult } func TestDappDevelop(t *testing.T) { @@ -48,7 +52,7 @@ func TestDappDevelop(t *testing.T) { opts := &godog.Options{ Format: "pretty", - Paths: []string{"dapp_develop.feature"}, + Paths: []string{e2eConfig.FeaturePath + "/dapp_develop.feature"}, Output: colors.Colored(os.Stdout), StopOnFailure: true, TestingT: t, @@ -110,33 +114,29 @@ func installContractStep(ctx context.Context, compiledContractFileName string) e return nil } -func invokeNonAuthContractStep(ctx context.Context, functionName string, contractName string, param1 string, tool string) error { +func invokeContractStep(ctx context.Context, functionName string, contractName string, parameters string, tool string) error { - testConfig := ctx.Value(e2e.TestConfigContextKey).(*testConfig) - - var err error - if testConfig.ContractFunctionResponse, err = invokeContract(testConfig.DeployedContractId, contractName, functionName, param1, tool, testConfig.E2EConfig); err != nil { - return err - } - - return nil + return invokeContractStepWithConfig(ctx, functionName, contractName, parameters, tool, "", "") } -func invokeInvokerAuthContractStep(ctx context.Context, functionName string, contractName string, parameters string, tool string, identity string, networkConfig string) error { +func invokeContractStepWithConfig(ctx context.Context, functionName string, contractName string, parameters string, tool string, identity string, networkConfig string) error { + testConfig := ctx.Value(e2e.TestConfigContextKey).(*testConfig) + var err error - invokerPubKey, has := testConfig.Identities[identity] - if !has { - return fmt.Errorf("invocation of invoker auth contract could not proceed, no public key for identity %v", identity) - } + if identity != "" { + invokerPubKey, has := testConfig.Identities[identity] + if !has { + return fmt.Errorf("invocation of contract with config could not proceed, no public key for identity config name %v", identity) + } + parameters = strings.Replace(parameters, "", invokerPubKey, 1) + testConfig.ContractFunctionResponse, err = invokeContractWithConfig(testConfig.DeployedContractId, contractName, functionName, parameters, tool, identity, networkConfig, testConfig.E2EConfig) - parameters = strings.Replace(parameters, "", invokerPubKey, 1) - var err error - if testConfig.ContractFunctionResponse, err = invokeContractWithConfig(testConfig.DeployedContractId, contractName, functionName, parameters, tool, identity, networkConfig, testConfig.E2EConfig); err != nil { - return err + } else { + testConfig.ContractFunctionResponse, err = invokeContract(testConfig.DeployedContractId, contractName, functionName, parameters, tool, testConfig.E2EConfig) } - return nil + return err } func createNetworkConfigStep(ctx context.Context, configName string) error { @@ -175,6 +175,20 @@ func newTestConfig(e2eConfig *e2e.E2EConfig) *testConfig { } } +func getNetworkStep(ctx context.Context) error { + + testConfig := ctx.Value(e2e.TestConfigContextKey).(*testConfig) + + network, err := e2e.QueryNetworkState(testConfig.E2EConfig) + + if err != nil { + return fmt.Errorf("soroban network latest ledger retrieval had error %e", err) + } + + testConfig.InitialNetworkState = network + return nil +} + func theResultShouldBeStep(ctx context.Context, expectedResult string) error { testConfig := ctx.Value(e2e.TestConfigContextKey).(*testConfig) @@ -183,6 +197,44 @@ func theResultShouldBeStep(ctx context.Context, expectedResult string) error { return t.Err } +func noOpStep(ctx context.Context) error { + return nil +} + +func theContractEventsShouldBeStep(ctx context.Context, expectedContractEventsCount int, expectedContractDiagEventsCount int, contractName string, tool string) error { + testConfig := ctx.Value(e2e.TestConfigContextKey).(*testConfig) + + jsonResults, err := getEvents(testConfig.InitialNetworkState.Sequence, testConfig.DeployedContractId, tool, 10, testConfig.E2EConfig) + + if err != nil { + return err + } + + var contractEventsCount int + var diagEventsCount int + + for _, v := range jsonResults { + if v["type"] == "diagnostic" { + diagEventsCount++ + } else { + contractEventsCount++ + } + } + + var t e2e.Asserter + assert.Equal(&t, expectedContractEventsCount, contractEventsCount, "Expected %v contract events for %v using %v but got %v", expectedContractEventsCount, contractName, tool, contractEventsCount) + if t.Err != nil { + return t.Err + } + + if testConfig.E2EConfig.LocalCore { + assert.Equal(&t, expectedContractDiagEventsCount, diagEventsCount, "Expected %v diagnostic events for %v using %v but got %v", expectedContractDiagEventsCount, contractName, tool, diagEventsCount) + } else { + fmt.Fprintf(os.Stdout, "Skipping assertion of diagnostic events, network under test is not local standalone, can't enable diagnostic events in that case.") + } + return t.Err +} + func queryAccountStep(ctx context.Context) error { testConfig := ctx.Value(e2e.TestConfigContextKey).(*testConfig) @@ -255,7 +307,7 @@ func createTesterAccountStep(ctx context.Context) error { } func initializeScenario(scenarioCtx *godog.ScenarioContext) { - scenarioCtx.Before(func(ctx context.Context, scenario *godog.Scenario) (context.Context, error) { + scenarioCtx.Before(func(ctx context.Context, _ *godog.Scenario) (context.Context, error) { e2eConfig := ctx.Value(e2e.TestConfigContextKey).(*e2e.E2EConfig) @@ -278,27 +330,22 @@ func initializeScenario(scenarioCtx *godog.ScenarioContext) { testConfig.TestWorkingDir = e2e.TestTmpDirectory ctx = context.WithValue(ctx, e2e.TestConfigContextKey, testConfig) + scenarioCtx.Step(`^I am using an rpc instance that has captive core config, ENABLE_SOROBAN_DIAGNOSTIC_EVENTS=true$`, noOpStep) scenarioCtx.Step(`^I used cargo to compile example contract ([\S|\s]+)$`, compileContractStep) scenarioCtx.Step(`^I used rpc to verify my account is on the network`, queryAccountStep) - - switch scenario.Name { - case "DApp developer compiles, installs, deploys and invokes a contract": - scenarioCtx.Step(`^I used cli to install contract ([\S|\s]+) on network using my secret key$`, installContractStep) - scenarioCtx.Step(`^I used cli to deploy contract ([\S|\s]+) by installed hash using my secret key$`, deployContractStep) - scenarioCtx.Step(`^I invoke function ([\S|\s]+) on ([\S|\s]+) with request parameter ([\S|\s]*) from ([\S|\s]+) using my secret key$`, invokeNonAuthContractStep) - case "DApp developer compiles, deploys and invokes a contract": - scenarioCtx.Step(`^I used cli to deploy contract ([\S|\s]+) using my secret key$`, deployContractStep) - scenarioCtx.Step(`^I invoke function ([\S|\s]+) on ([\S|\s]+) with request parameter ([\S|\s]*) from ([\S|\s]+) using my secret key$`, invokeNonAuthContractStep) - case "DApp developer uses config states, compiles, deploys and invokes contract with authorizations": - scenarioCtx.Step(`^I used rpc to submit transaction to create tester account on the network$`, createTesterAccountStep) - scenarioCtx.Step(`^I used cli to add Network Config ([\S|\s]+) for rpc and standalone$`, createNetworkConfigStep) - scenarioCtx.Step(`^I used cli to add Identity ([\S|\s]+) for my secret key$`, createMyIdentityStep) - scenarioCtx.Step(`^I used cli to add Identity ([\S|\s]+) for tester secret key$`, createTestAccountIdentityStep) - scenarioCtx.Step(`^I used cli to deploy contract ([\S|\s]+) using my Identity ([\S|\s]+) and Network Config ([\S|\s]+)$`, deployContractUsingConfigParamsStep) - scenarioCtx.Step(`^I invoke function ([\S|\s]+) on ([\S|\s]+) with request parameters ([\S|\s]*) from ([\S|\s]+) using tester Identity ([\S|\s]+) as invoker and Network Config ([\S|\s]+)$`, invokeInvokerAuthContractStep) - } - - scenarioCtx.Step(`^the result should be (\S+)$`, theResultShouldBeStep) + scenarioCtx.Step(`^I used rpc to get network latest ledger$`, getNetworkStep) + scenarioCtx.Step(`^I used rpc to submit transaction to create tester account on the network$`, createTesterAccountStep) + scenarioCtx.Step(`^I used cli to add Network Config ([\S|\s]+) for rpc and standalone$`, createNetworkConfigStep) + scenarioCtx.Step(`^I used cli to add Identity ([\S|\s]+) for my secret key$`, createMyIdentityStep) + scenarioCtx.Step(`^I used cli to deploy contract ([\S|\s]+) using Identity ([\S|\s]+) and Network Config ([\S|\s]+)$`, deployContractUsingConfigParamsStep) + scenarioCtx.Step(`^I used cli to install contract ([\S|\s]+) on network using my secret key$`, installContractStep) + scenarioCtx.Step(`^I used cli to deploy contract ([\S|\s]+) by installed hash using my secret key$`, deployContractStep) + scenarioCtx.Step(`^I used cli to deploy contract ([\S|\s]+) using my secret key$`, deployContractStep) + scenarioCtx.Step(`^I used cli to add Identity ([\S|\s]+) for tester secret key$`, createTestAccountIdentityStep) + scenarioCtx.Step(`^I invoke function ([\S|\s]+) on ([\S|\s]+) with request parameters ([\S|\s]*) from tool ([\S|\s]+) using Identity ([\S|\s]+) as invoker and Network Config ([\S|\s]+)$`, invokeContractStepWithConfig) + scenarioCtx.Step(`^I invoke function ([\S|\s]+) on ([\S|\s]+) with request parameters ([\S|\s]*) from tool ([\S|\s]+) using my secret key$`, invokeContractStep) + scenarioCtx.Step(`^The result should be (\S+)$`, theResultShouldBeStep) + scenarioCtx.Step(`^The result should be to receive ([\S|\s]+) contract events and ([\S|\s]+) diagnostic events for ([\S|\s]+) from ([\S|\s]+)$`, theContractEventsShouldBeStep) return ctx, nil }) diff --git a/features/dapp_develop/main.go b/features/dapp_develop/main.go index 01becae..248052c 100644 --- a/features/dapp_develop/main.go +++ b/features/dapp_develop/main.go @@ -138,7 +138,7 @@ func createNetworkConfig(configName string, rpcUrl string, networkPassphrase str // uses 'expect' cli tool program, to forward the secret to the tty that cli wait for input func createIdentityConfig(identityName string, secretKey string, e2eConfig *e2e.E2EConfig) error { envCmd := cmd.NewCmd("expect", - "soroban_config.exp", + e2eConfig.FeaturePath+"/soroban_config.exp", identityName, secretKey) @@ -153,15 +153,15 @@ func createIdentityConfig(identityName string, secretKey string, e2eConfig *e2e. // returns the contract fn invocation response payload as a serialized string // uses secret-key and network-passphrase directly on command -func invokeContract(deployedContractId string, contractName string, functionName string, param1 string, tool string, e2eConfig *e2e.E2EConfig) (string, error) { +func invokeContract(deployedContractId string, contractName string, functionName string, functionParams string, tool string, e2eConfig *e2e.E2EConfig) (string, error) { var response string var err error switch tool { case "CLI": - response, err = invokeContractFromCliTool(deployedContractId, contractName, functionName, param1, e2eConfig) + response, err = invokeContractFromCliTool(deployedContractId, contractName, functionName, functionParams, e2eConfig) case "NODEJS": - response, err = invokeContractFromNodeJSTool(deployedContractId, contractName, functionName, param1, e2eConfig) + response, err = invokeContractFromNodeJSTool(deployedContractId, contractName, functionName, functionParams, e2eConfig) default: err = fmt.Errorf("%s tool not supported for invoke yet", tool) } @@ -193,3 +193,27 @@ func invokeContractWithConfig(deployedContractId string, contractName string, fu return response, nil } + +// returns all events as json array +// ledgerFrom - required, starting point +// deployedContractId - optional, the id of contract to filter events for or nil +// tool - required, which tool to use to get events +func getEvents(ledgerFrom uint32, deployedContractId string, tool string, size uint32, e2eConfig *e2e.E2EConfig) ([]map[string]interface{}, error) { + var response []map[string]interface{} + var err error + + switch tool { + case "CLI": + response, err = getEventsFromCliTool(ledgerFrom, deployedContractId, size, e2eConfig) + case "NODEJS": + response, err = getEventsFromNodeJSTool(ledgerFrom, deployedContractId, size, e2eConfig) + default: + err = fmt.Errorf("%s tool not supported for events retrieval yet", tool) + } + + if err != nil { + return nil, err + } + + return response, nil +} diff --git a/features/dapp_develop/nodejs.go b/features/dapp_develop/nodejs.go index 82aaf6c..5fb8349 100644 --- a/features/dapp_develop/nodejs.go +++ b/features/dapp_develop/nodejs.go @@ -1,6 +1,7 @@ package dapp_develop import ( + "encoding/json" "fmt" "strings" @@ -11,16 +12,16 @@ import ( // return the fn response as a serialized string // uses secret-key and network-passphrase directly on command -func invokeContractFromNodeJSTool(deployedContractId, contractName, functionName, param1 string, e2eConfig *e2e.E2EConfig) (string, error) { +func invokeContractFromNodeJSTool(deployedContractId, contractName, functionName string, functionParams string, e2eConfig *e2e.E2EConfig) (string, error) { args := []string{ "--id", deployedContractId, "--rpc-url", e2eConfig.TargetNetworkRPCURL, "--source", e2eConfig.TargetNetworkSecretKey, "--network-passphrase", e2eConfig.TargetNetworkPassPhrase, - "--", functionName, + "function", "--name", functionName, } - if param1 != "" { - args = append(args, "--param1", param1) + if functionParams != "" { + args = append(args, "--params", functionParams) } envCmd := cmd.NewCmd("./invoke.ts", args...) status, stdOutLines, err := e2e.RunCommand(envCmd, e2eConfig) @@ -41,3 +42,33 @@ func invokeContractFromNodeJSTool(deployedContractId, contractName, functionName func invokeContractFromNodeJSToolWithConfig(deployedContractId, contractName, functionName, parameters, identity, networkConfig string, e2eConfig *e2e.E2EConfig) (string, error) { return "", fmt.Errorf("invoke with named identity not supported for NODEJS tool") } + +func getEventsFromNodeJSTool(ledgerFrom uint32, deployedContractId string, size uint32, e2eConfig *e2e.E2EConfig) ([]map[string]interface{}, error) { + args := []string{ + "--id", deployedContractId, + "--rpc-url", e2eConfig.TargetNetworkRPCURL, + "--size", fmt.Sprint(size), + "--ledgerFrom", fmt.Sprint(ledgerFrom), + } + + envCmd := cmd.NewCmd("./events.ts", args...) + status, stdOutLines, err := e2e.RunCommand(envCmd, e2eConfig) + + var jsonEvents []map[string]interface{} + + if status != 0 || err != nil { + return jsonEvents, fmt.Errorf("soroban js client get events had error %v, %v", status, err) + } + + stdOutEvents := strings.TrimSpace(strings.Join(stdOutLines, "\n")) + if stdOutEvents == "" { + return jsonEvents, fmt.Errorf("soroban js client get events did not emit successful console response") + } + + err = json.Unmarshal([]byte(stdOutEvents), &jsonEvents) + if err != nil { + return jsonEvents, fmt.Errorf("soroban js client get events response output %v was not parseable as event json, %v", stdOutEvents, err) + } + + return jsonEvents, nil +} diff --git a/go.mod b/go.mod index 8fcd7e6..742ff96 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,11 @@ module github.com/stellar/system-test -go 1.18 +go 1.20 require ( github.com/cucumber/godog v0.12.5 github.com/go-cmd/cmd v1.4.1 - github.com/pkg/errors v0.8.1 - github.com/stellar/go v0.0.0-20230216182126-bc7f94cc35b6 + github.com/stellar/go v0.0.0-20230410132830-a9de2a21d17b github.com/stretchr/testify v1.7.1 ) diff --git a/go.sum b/go.sum index 5feb0ee..413d605 100644 --- a/go.sum +++ b/go.sum @@ -155,7 +155,6 @@ github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -194,8 +193,10 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/stellar/go v0.0.0-20230216182126-bc7f94cc35b6 h1:K94rhFNz3zKCTkRXyU5EQxRuui4PPAI1HmweVOv4pvQ= -github.com/stellar/go v0.0.0-20230216182126-bc7f94cc35b6/go.mod h1:VQE2/C8c5lqHVMbtN1SvFHSqZ7pKKXdrexU2lRT2QGk= +github.com/stellar/go v0.0.0-20230329163815-bbc53ae8a051 h1:g6whOXc5Iaz3s31iE6ibEcpjG0RPLM+CbIo1033T34c= +github.com/stellar/go v0.0.0-20230329163815-bbc53ae8a051/go.mod h1:QXwuKmYVvqQZlByv0EeNb0Rgog9AP+eMmARcdt3h2rI= +github.com/stellar/go v0.0.0-20230410132830-a9de2a21d17b h1:dgLmJicMZtOBbuAUZ9ggkmay5fFC4LNmjQXDbBjZmXc= +github.com/stellar/go v0.0.0-20230410132830-a9de2a21d17b/go.mod h1:QXwuKmYVvqQZlByv0EeNb0Rgog9AP+eMmARcdt3h2rI= github.com/stellar/go-xdr v0.0.0-20211103144802-8017fc4bdfee h1:fbVs0xmXpBvVS4GBeiRmAE3Le70ofAqFMch1GTiq/e8= github.com/stellar/go-xdr v0.0.0-20211103144802-8017fc4bdfee/go.mod h1:yoxyU/M8nl9LKeWIoBrbDPQ7Cy+4jxRcWcOayZ4BMps= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/invoke.ts b/invoke.ts index 9a020ce..6bdf9a9 100755 --- a/invoke.ts +++ b/invoke.ts @@ -7,18 +7,19 @@ const xdr = SorobanClient.xdr; async function main() { const parser = new ArgumentParser({ description: 'Invoke a contract function' }) + const subparsers = parser.add_subparsers(); parser.add_argument('--id', { dest: 'contractId', required: true, help: 'Contract ID' }); parser.add_argument('--rpc-url', { dest: 'rpcUrl', required: true, help: 'RPC URL' }); parser.add_argument('--source', { dest: 'source', required: true, help: 'Secret key' }); parser.add_argument('--network-passphrase', { dest: 'networkPassphrase', required: true, help: 'Network passphrase' }); - const subparsers = parser.add_subparsers(); - const functionSubparser = subparsers.add_parser('functionName', { help: 'Function name' }); - functionSubparser.add_argument('--param1', { dest: 'param1', help: 'Param 1' }); + const functionParamParser = subparsers.add_parser('function', { help: 'Function' }); + functionParamParser.add_argument('--name', { dest: 'functionName', help: 'Function Name' }); + functionParamParser.add_argument('--params', { dest: 'functionParams', help: 'Function Params, comma separated' }) const { contractId, rpcUrl, - param1, + functionParams, networkPassphrase, source, functionName, @@ -30,10 +31,14 @@ async function main() { const account = secretKey.publicKey(); const sourceAccount = await server.getAccount(account); - // Some hacky param-parsing. Generated Typescript bindings would be better - // here. But those don't exist yet as I'm writing this. - const params = param1 ? [xdr.ScVal.scvSymbol(param1)] : []; - + // Some hacky param-parsing as csv. Generated Typescript bindings would be better. + const params: SorobanClient.xdr.ScVal[] = []; + if (functionParams) { + functionParams.split(",").forEach((param) => { + params.push(xdr.ScVal.scvSymbol(param)); + }); + } + const txn = await server.prepareTransaction( new SorobanClient.TransactionBuilder(sourceAccount, { fee: "100", @@ -69,9 +74,8 @@ async function main() { const scval = result.result().results()[0].tr().invokeHostFunctionResult().success(); // Hacky result parsing. We should have some helpers from the - // js-stellar-base, or the generated Typescript bindings. But we don't yet as - // I'm writing this. - let parsed = null; + // js-stellar-base, or the generated Typescript bindings. + let parsed: number | object | null = null; switch (scval.switch()) { case xdr.ScValType.scvU32(): { parsed = scval.u32(); diff --git a/package-lock.json b/package-lock.json index e6f10c3..40a45f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,53 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" - }, "@types/argparse": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-2.0.10.tgz", @@ -80,21 +33,6 @@ "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.19.tgz", "integrity": "sha512-FDJNkyhmKLw7uEvTxx5tSXfPeQpO0iy73Ry+PmYZJvQy0QIWX8a7kJ4kLWRf+EbTPJEPDSgPXHaM7pzr5lmvCg==" }, - "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==" - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -140,16 +78,6 @@ "buffer": "^5.1.0" } }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" - }, "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -189,11 +117,6 @@ "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==" }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, "node-gyp-build": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", @@ -224,7 +147,7 @@ } }, "soroban-client": { - "version": "git+https://github.com/stellar/js-soroban-client.git#0537663dc2757b9571bb77c10fc8894e97223cf6", + "version": "git+https://github.com/stellar/js-soroban-client.git#1e9c3fbe2587be4816a6668226f1e50e4828974b", "from": "git+https://github.com/stellar/js-soroban-client.git#main", "requires": { "@types/eventsource": "^1.1.2", @@ -234,7 +157,7 @@ "axios": "0.25.0", "es6-promise": "^4.2.4", "lodash": "4.17.21", - "stellar-base": "8.2.2-soroban.11", + "stellar-base": "8.2.2-soroban.12", "urijs": "^1.19.1" }, "dependencies": { @@ -246,9 +169,9 @@ } }, "stellar-base": { - "version": "8.2.2-soroban.11", - "resolved": "https://registry.npmjs.org/stellar-base/-/stellar-base-8.2.2-soroban.11.tgz", - "integrity": "sha512-pizPJj/4Vg75n4slk3L66pzJS1+bCXsWWG7GgYiuNmzl2bKwY7cS/87PypBEDUx7msOF/ZEocGg9kJ7sU6wupg==", + "version": "8.2.2-soroban.12", + "resolved": "https://registry.npmjs.org/stellar-base/-/stellar-base-8.2.2-soroban.12.tgz", + "integrity": "sha512-bQQxRFA2GXoNsr2ZFN+eK9Du1hSu0+t983tHRMI3nyWlLgZInKg7B9ZFa4UjLbLYpxQ4mE1EYupk3bulqNA91A==", "requires": { "base32.js": "^0.1.0", "bignumber.js": "^4.0.0", @@ -260,26 +183,6 @@ "tweetnacl": "^1.0.3" } }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - } - }, "tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", @@ -299,16 +202,6 @@ "version": "1.19.11", "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" } } } diff --git a/package.json b/package.json index 6ec36a7..7ee33b1 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "dependencies": { "argparse": "^2.0.1", "soroban-client": "git+https://github.com/stellar/js-soroban-client.git#main", - "ts-node": "^10.9.1", "tslib": "^2.5.0", "typescript": "^4.9.5" }, diff --git a/start b/start index 56809ee..6007307 100755 --- a/start +++ b/start @@ -14,6 +14,7 @@ TARGET_NETWORK_SECRET_KEY="SC5O7VZUXDJ6JBDSZ74DSERXL7W3Y5LTOAMRF7RQRL3TAGAPS7LUV TARGET_NETWORK_PUBLIC_KEY="GBZXN7PIRZGNMHGA7MUUUF4GWPY5AYPV6LY4UV2GL6VJGIQRXFDNMADI" TARGET_NETWORK_RPC_URL= QUICKSTART_LOG_FILE=/var/log/system-test-quickstart.log +LOCAL_CORE=false # example filter for all combos of one scenario outline: ^TestDappDevelop$/^DApp developer compiles, deploys and invokes a contract.*$ # each row in example data for a scenario outline is postfixed with '#01', '#02', example: @@ -21,6 +22,9 @@ QUICKSTART_LOG_FILE=/var/log/system-test-quickstart.log TEST_FILTER="" VERBOSE_OUTPUT=false CANCELLED=false +# the relative path to runtime directory on image that feature files will be found at +# these files are aggregated into this directory by Dockerfile +FEATURE_PATH=. function print_screen_output() { echo "$1" @@ -36,7 +40,8 @@ printout() { trap finish EXIT function finish { - if [ $? -ne 0 ] && [ "$VERBOSE_OUTPUT" != "true" ]; then + if [ -z "$TARGET_NETWORK_RPC_URL" ] && [ $? -ne 0 ] && [ "$VERBOSE_OUTPUT" != "true" ]; then + # dump the local server logs if they were running in container. echo "" >&2 echo "" >&2 echo "dumping system log output $QUICKSTART_LOG_FILE ..." >&2 @@ -68,6 +73,7 @@ function main() { if [ -z "$TARGET_NETWORK_RPC_URL" ]; then TARGET_NETWORK_RPC_URL=http://localhost:8000/soroban/rpc + LOCAL_CORE=true print_screen_output "starting target stack on $TARGET_NETWORK with following server versions:" print_screen_output " CORE VERSION=$(stellar-core version 2>/dev/null || echo "n/a")" print_screen_output " HORIZON VERSION=$(stellar-horizon version 2>/dev/null || echo "n/a")" @@ -75,16 +81,17 @@ function main() { if [ "$TARGET_NETWORK" = "standalone" ]; then ARTIFICIAL_ACCELERATE=--enable-core-artificially-accelerate-time-for-testing - fi + ENABLE_SOROBAN_DIAGNOSTIC_EVENTS=--enable-soroban-diagnostic-events + fi if [ "$VERBOSE_OUTPUT" = "true" ]; then # redirects all quickstart output to console during test execution - /start --$TARGET_NETWORK --enable-soroban-rpc $ARTIFICIAL_ACCELERATE --logs 2>&1 & + /start --$TARGET_NETWORK --enable-soroban-rpc $ARTIFICIAL_ACCELERATE $ENABLE_SOROBAN_DIAGNOSTIC_EVENTS --logs 2>&1 & else # don't show any quickstart output on console during test execution # all quickstart output is redirected(buffering disabled) to log file, which will be dumped to # console if tests fail. - stdbuf -o0 -e0 /start --$TARGET_NETWORK --enable-soroban-rpc $ARTIFICIAL_ACCELERATE --logs >> $QUICKSTART_LOG_FILE 2>&1 & + stdbuf -o0 -e0 /start --$TARGET_NETWORK --enable-soroban-rpc $ARTIFICIAL_ACCELERATE $ENABLE_SOROBAN_DIAGNOSTIC_EVENTS --logs >> $QUICKSTART_LOG_FILE 2>&1 & fi fi @@ -111,6 +118,8 @@ function main() { export TargetNetworkPublicKey=${TARGET_NETWORK_PUBLIC_KEY} export TargetNetworkRPCURL=${TARGET_NETWORK_RPC_URL} export VerboseOutput=${VERBOSE_OUTPUT} + export LocalCore=${LOCAL_CORE} + export FeaturePath=${FEATURE_PATH} for file in ./*; do