Skip to content

Commit

Permalink
Added Auth Next Scenario Test (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
sreuland authored Mar 1, 2023
1 parent 1d2d06a commit ad8df03
Show file tree
Hide file tree
Showing 9 changed files with 665 additions and 196 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# System Test Releases

#### pending

* Auth Next Test coverage with new scenario 'DApp developer uses config states, compiles, deploys and invokes contract with authorizations'

#### 1.0.5

Expand Down
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@ ADD features ./features
# build each feature folder with go test module.
# compiles each feature to a binary to be executed,
# and copies the .feature file with it for runtime.
RUN go test -c -o ./bin/dapp_develop_test ./features/dapp_develop/...
RUN go test -c -o ./bin/dapp_develop_test.bin ./features/dapp_develop/...
ADD features/dapp_develop/dapp_develop.feature ./bin
# copy over a dapp develop test specific file, used for expect/tty usage
ADD features/dapp_develop/soroban_config.exp ./bin

FROM $SOROBAN_CLI_IMAGE_REF as soroban-cli

FROM $QUICKSTART_IMAGE_REF as base
ARG RUST_TOOLCHAIN_VERSION

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y build-essential && apt-get clean
RUN apt-get update && apt-get install -y build-essential expect && apt-get clean

# Install Rust
RUN ["mkdir", "-p", "/rust"]
Expand Down
203 changes: 200 additions & 3 deletions e2e.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
package e2e

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"strconv"
"time"

"github.com/go-cmd/cmd"
"github.com/stellar/go/strkey"
"github.com/stellar/go/txnbuild"
"github.com/stellar/go/xdr"
)

type E2EConfig struct {
// e2e settings
SorobanExamplesGitHash string
SorobanExamplesRepoURL string
VerboseOutput bool
SorobanExamplesGitHash string
SorobanExamplesRepoURL string
VerboseOutput bool

// target network that test will use
TargetNetworkRPCURL string
Expand All @@ -21,6 +28,54 @@ type E2EConfig struct {
TargetNetworkPublicKey string
}

const (
TX_SUCCESS = "SUCCESS"
TX_PENDING = "PENDING"
)

type RPCError struct {
Code string `json:"code"`
Message string `json:"message"`
Data string `json:"data"`
}

type AccountInfo struct {
ID string `json:"id"`
Sequence int64 `json:"sequence,string"`
}

type TransactionResponse struct {
ID string `json:"id"`
Status string `json:"status"`
}

type RPCTransactionResponse struct {
Result TransactionResponse `json:"result"`
Error *RPCError `json:"error,omitempty"`
}

type TransactionStatusResponse struct {
ID string `json:"id"`
Status string `json:"status"`
EnvelopeXdr string `json:"envelopeXdr,omitempty"`
ResultXdr string `json:"resultXdr,omitempty"`
ResultMetaXdr string `json:"resultMetaXdr,omitempty"`
}

type RPCTransactionStatusResponse struct {
Result TransactionStatusResponse `json:"result"`
Error *RPCError `json:"error,omitempty"`
}

type LedgerEntryResult struct {
XDR string `json:"xdr"`
}

type RPCLedgerEntryResponse struct {
Result LedgerEntryResult `json:"result"`
Error *RPCError `json:"error,omitempty"`
}

const TestTmpDirectory = "test_tmp_workspace"

func InitEnvironment() (*E2EConfig, error) {
Expand Down Expand Up @@ -116,6 +171,148 @@ func (a *Asserter) Errorf(format string, args ...interface{}) {
a.Err = fmt.Errorf(format, args...)
}

func QueryAccount(e2eConfig *E2EConfig, publicKey string) (*AccountInfo, error) {
decoded, err := strkey.Decode(strkey.VersionByteAccountID, publicKey)
if err != nil {
return nil, fmt.Errorf("invalid account address: %v", err)
}
var key xdr.Uint256
copy(key[:], decoded)
keyXdr, err := xdr.LedgerKey{
Type: xdr.LedgerEntryTypeAccount,
Account: &xdr.LedgerKeyAccount{
AccountId: xdr.AccountId(xdr.PublicKey{
Type: xdr.PublicKeyTypePublicKeyTypeEd25519,
Ed25519: &key,
}),
},
}.MarshalBinaryBase64()
if err != nil {
return nil, fmt.Errorf("error encoding account ledger key xdr: %v", err)
}

getAccountRequest := []byte(`{
"jsonrpc": "2.0",
"id": 10235,
"method": "getLedgerEntry",
"params": {
"key": "` + keyXdr + `"
}
}`)

resp, err := http.Post(e2eConfig.TargetNetworkRPCURL, "application/json", bytes.NewBuffer(getAccountRequest))
if err != nil {
return nil, fmt.Errorf("soroban rpc get account had error %e", err)
}

var rpcResponse RPCLedgerEntryResponse
decoder := json.NewDecoder(resp.Body)
err = decoder.Decode(&rpcResponse)
if err != nil {
return nil, fmt.Errorf("soroban rpc get account, not able to parse ledger entry response, %v, %e", resp, err)
}
if rpcResponse.Error != nil {
return nil, fmt.Errorf("soroban rpc get account, error on ledger entry response, %v, %e", resp, err)
}

var entry xdr.LedgerEntryData
err = xdr.SafeUnmarshalBase64(rpcResponse.Result.XDR, &entry)
if err != nil {
return nil, fmt.Errorf("soroban rpc get account, not able to parse XDR from ledger entry response, %v, %e", rpcResponse.Result.XDR, err)
}

return &AccountInfo{ID: entry.Account.AccountId.Address(), Sequence: int64(entry.Account.SeqNum)}, nil
}

func QueryTxStatus(e2eConfig *E2EConfig, txHashId string) (*TransactionStatusResponse, error) {
getTxStatusRequest := []byte(`{
"jsonrpc": "2.0",
"id": 10235,
"method": "getTransaction",
"params": {
"hash": "` + txHashId + `"
}
}`)

resp, err := http.Post(e2eConfig.TargetNetworkRPCURL, "application/json", bytes.NewBuffer(getTxStatusRequest))
if err != nil {
return nil, fmt.Errorf("soroban rpc get tx status had error %e", err)
}

var rpcResponse RPCTransactionStatusResponse
decoder := json.NewDecoder(resp.Body)
err = decoder.Decode(&rpcResponse)

if err != nil {
return nil, fmt.Errorf("soroban rpc get tx status, not able to parse response, %v, %e", resp.Body, err)
}

if rpcResponse.Error != nil {
return nil, fmt.Errorf("soroban rpc get tx status, got error response, %v", rpcResponse)
}

return &rpcResponse.Result, nil
}

func TxSub(e2eConfig *E2EConfig, tx *txnbuild.Transaction) (*TransactionStatusResponse, error) {
b64, err := tx.Base64()
if err != nil {
return nil, fmt.Errorf("soroban rpc tx sub, not able to serialize tx, %v, %e", tx, err)
}

txsubRequest := []byte(`{
"jsonrpc": "2.0",
"id": 10235,
"method": "sendTransaction",
"params": {
"transaction": "` + b64 + `"
}
}`)

resp, err := http.Post(e2eConfig.TargetNetworkRPCURL, "application/json", bytes.NewBuffer(txsubRequest))
if err != nil {
return nil, fmt.Errorf("soroban rpc tx sub had error %e", err)
}

var rpcResponse RPCTransactionResponse
decoder := json.NewDecoder(resp.Body)

err = decoder.Decode(&rpcResponse)
if err != nil {
return nil, fmt.Errorf("soroban rpc tx sub, not able to parse response, %v, %e", resp.Body, err)
}

if rpcResponse.Error != nil {
return nil, fmt.Errorf("soroban rpc tx sub, got bad submission response, %v", rpcResponse)
}

txHashId, err := tx.HashHex(e2eConfig.TargetNetworkPassPhrase)
if err != nil {
return nil, fmt.Errorf("soroban rpc tx sub, not able to generate tx hash id, %v, %e", tx, err)
}

start := time.Now().Unix()
for x := range time.NewTicker(3 * time.Second).C {
if x.Unix()-start > 30 {
break
}

transactionStatusResponse, err := QueryTxStatus(e2eConfig, txHashId)
if err != nil {
return nil, fmt.Errorf("soroban rpc tx sub, unable to call tx status check, %v, %e", rpcResponse, err)
}

if transactionStatusResponse.Status == TX_SUCCESS {
return transactionStatusResponse, nil
}
if transactionStatusResponse.Status != TX_PENDING {
return nil, fmt.Errorf("soroban rpc tx sub, got bad response on tx status check, %v, %v", rpcResponse, transactionStatusResponse)
}
}

return nil, fmt.Errorf("soroban rpc tx sub, timeout after 30 seconds on tx status check, %v", rpcResponse)
}

func getEnv(key string) (string, error) {
if value, ok := os.LookupEnv(key); ok {
return value, nil
Expand Down
39 changes: 28 additions & 11 deletions features/dapp_develop/dapp_develop.feature
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
Feature: DApp Contract Development

Scenario Outline: DApp developer compiles, installs, deploys and invokes a contract
Given I used cli to compile example contract <ContractExampleSubPath>
Given I used cargo to compile example contract <ContractExampleSubPath>
And I used rpc to verify my account is on the network
And I used cli to install contract <ContractCompiledFileName> on ledger using my account to network
And I used cli to deploy contract <ContractCompiledFileName> by installed hash using my account to network
When I invoke function <FunctionName> on <ContractName> with request parameter <Param1> from <Tool>
And I used cli to install contract <ContractCompiledFileName> on network using my secret key
And I used cli to deploy contract <ContractCompiledFileName> by installed hash using my secret key
When I invoke function <FunctionName> on <ContractName> with request parameter <Param1> from <Tool> using my secret key
Then the result should be <Result>

Examples:
| Tool | ContractExampleSubPath | ContractName | ContractCompiledFileName |FunctionName | Param1 | Result |
| Tool | ContractExampleSubPath | ContractName | ContractCompiledFileName | FunctionName | Param1 | Result |
# | JSSDK | hello_world | soroban-hello-world-contract | soroban_hello_world_contract.wasm | hello | --to=Aloha | ["Hello","Aloha"] |
| CLI | hello_world | soroban-hello-world-contract | soroban_hello_world_contract.wasm | hello | --to=Aloha | ["Hello","Aloha"] |
# | JSSDK | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 |
| CLI | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 |
# | JSSDK | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 |
| CLI | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 |


Scenario Outline: DApp developer compiles, deploys and invokes a contract
Given I used cli to compile example contract <ContractExampleSubPath>
Given I used cargo to compile example contract <ContractExampleSubPath>
And I used rpc to verify my account is on the network
And I used cli to deploy contract <ContractCompiledFileName> using my account to network
When I invoke function <FunctionName> on <ContractName> with request parameter <Param1> from <Tool>
And I used cli to deploy contract <ContractCompiledFileName> using my secret key
When I invoke function <FunctionName> on <ContractName> with request parameter <Param1> from <Tool> using my secret key
Then the result should be <Result>

Examples:
| Tool | ContractExampleSubPath | ContractName | ContractCompiledFileName |FunctionName | Param1 | Result |
| Tool | ContractExampleSubPath | ContractName | ContractCompiledFileName | FunctionName | Param1 | Result |
# | JSSDK | hello_world | soroban-hello-world-contract | soroban_hello_world_contract.wasm | hello | --to=Aloha | ["Hello","Aloha"] |
| CLI | hello_world | soroban-hello-world-contract | soroban_hello_world_contract.wasm | hello | --to=Aloha | ["Hello","Aloha"] |
# | JSSDK | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 |
| CLI | increment | soroban-increment-contract | soroban_increment_contract.wasm | increment | | 1 |


Scenario Outline: DApp developer uses config states, compiles, deploys and invokes contract with authorizations
Given I used cargo to compile example contract <ContractExampleSubPath>
And I used rpc to verify my account is on the network
And I used rpc to submit transaction to create tester account on the network
And I used cli to add Network Config <NetworkConfigName> for rpc and standalone
And I used cli to add Identity <RootIdentityName> for my secret key
And I used cli to add Identity <TesterIdentityName> for tester secret key
And I used cli to deploy contract <ContractCompiledFileName> using my Identity <RootIdentityName> and Network Config <NetworkConfigName>
When I invoke function <FunctionName> on <ContractName> with request parameters <FunctionParams> from <Tool> using tester Identity <TesterIdentityName> as invoker and Network Config <NetworkConfigName>
Then the result should be <Result>

Examples:
| Tool | ContractExampleSubPath | ContractName | ContractCompiledFileName | FunctionName | FunctionParams | RootIdentityName | TesterIdentityName | NetworkConfigName | Result |
# | JSSDK | auth | soroban-auth-contract | soroban_auth_contract.wasm | increment | --user <tester_identity_pub_key> --value 2 | r1 | t1 | standalone | 2 |
| CLI | auth | soroban-auth-contract | soroban_auth_contract.wasm | increment | --user <tester_identity_pub_key> --value 2 | r1 | t1 | standalone | 2 |
Loading

0 comments on commit ad8df03

Please sign in to comment.