Skip to content

Commit

Permalink
Some more tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
q-uint committed Apr 24, 2024
1 parent fcf0e46 commit 3ff65dc
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 76 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ jobs:
- uses: actions/setup-go@v4
with:
go-version: '1.21.0'
- uses: aviate-labs/[email protected].0
- uses: aviate-labs/[email protected].1
with:
dfx-version: 0.18.0
pocketic-version: 3.0.1
- run: mv ic/testdata/networks.json $HOME/.config/dfx/networks.json
- run: make test
30 changes: 19 additions & 11 deletions agent.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package agent

import (
"crypto/rand"
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"math/rand"
"net/url"
"reflect"
"time"
Expand Down Expand Up @@ -54,6 +54,14 @@ func effectiveCanisterID(canisterID principal.Principal, args []any) principal.P
return canisterID
}

func newNonce() ([]byte, error) {
/* Read 10 bytes of random data, which is smaller than the max allowed by the IC (32 bytes)
* and should still be enough from a practical point of view. */
nonce := make([]byte, 10)
_, err := rand.Read(nonce)
return nonce, err
}

func uint64FromBytes(raw []byte) uint64 {
switch len(raw) {
case 1:
Expand Down Expand Up @@ -126,14 +134,18 @@ func (a Agent) Call(canisterID principal.Principal, methodName string, args []an
// Default to the empty Candid argument list.
rawArgs = []byte{'D', 'I', 'D', 'L', 0, 0}
}
nonce, err := newNonce()
if err != nil {
return err
}
requestID, data, err := a.sign(Request{
Type: RequestTypeCall,
Sender: a.Sender(),
CanisterID: canisterID,
MethodName: methodName,
Arguments: rawArgs,
IngressExpiry: a.expiryDate(),
Nonce: newNonce(),
Nonce: nonce,
})
if err != nil {
return err
Expand Down Expand Up @@ -226,14 +238,6 @@ func (a Agent) GetRootKey() []byte {
return a.rootKey
}

func newNonce() []byte {
/* Read 10 bytes of random data, which is smaller than the max allowed by the IC (32 bytes)
* and should still be enough from a practical point of view. */
nonce := make([]byte, 10)
rand.Read(nonce)
return nonce
}

func (a Agent) Query(canisterID principal.Principal, methodName string, args []any, values []any) error {
rawArgs, err := idl.Marshal(args)
if err != nil {
Expand All @@ -243,14 +247,18 @@ func (a Agent) Query(canisterID principal.Principal, methodName string, args []a
// Default to the empty Candid argument list.
rawArgs = []byte{'D', 'I', 'D', 'L', 0, 0}
}
nonce, err := newNonce()
if err != nil {
return err
}
_, data, err := a.sign(Request{
Type: RequestTypeQuery,
Sender: a.Sender(),
CanisterID: canisterID,
MethodName: methodName,
Arguments: rawArgs,
IngressExpiry: a.expiryDate(),
Nonce: newNonce(),
Nonce: nonce,
})
if err != nil {
return err
Expand Down
55 changes: 55 additions & 0 deletions pocketic/agent_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Package pocketic provides a client for the "hello" canister.
// Do NOT edit this file. It was automatically generated by https://github.com/aviate-labs/agent-go.
package pocketic_test

import (
"github.com/aviate-labs/agent-go"

"github.com/aviate-labs/agent-go/principal"
)

// Agent is a client for the "hello" canister.
type Agent struct {
a *agent.Agent
canisterId principal.Principal
}

// NewAgent creates a new agent for the "hello" canister.
func NewAgent(canisterId principal.Principal, config agent.Config) (*Agent, error) {
a, err := agent.New(config)
if err != nil {
return nil, err
}
return &Agent{
a: a,
canisterId: canisterId,
}, nil
}

// HelloQuery calls the "helloQuery" method on the "hello" canister.
func (a Agent) HelloQuery(arg0 string) (*string, error) {
var r0 string
if err := a.a.Query(
a.canisterId,
"helloQuery",
[]any{arg0},
[]any{&r0},
); err != nil {
return nil, err
}
return &r0, nil
}

// HelloUpdate calls the "helloUpdate" method on the "hello" canister.
func (a Agent) HelloUpdate(arg0 string) (*string, error) {
var r0 string
if err := a.a.Call(
a.canisterId,
"helloUpdate",
[]any{arg0},
[]any{&r0},
); err != nil {
return nil, err
}
return &r0, nil
}
61 changes: 39 additions & 22 deletions pocketic/pocketic.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ import (
"fmt"
"github.com/aviate-labs/agent-go/candid/idl"
"github.com/aviate-labs/agent-go/principal"
"io"
"time"
)

var DefaultSubnetConfig = ExtendedSubnetConfigSet{
NNS: &SubnetSpec{
var (
DefaultSubnetSpec = SubnetSpec{
StateConfig: NewSubnetStateConfig{},
InstructionConfig: ProductionSubnetInstructionConfig{},
DtsFlag: false,
},
}
}
DefaultSubnetConfig = ExtendedSubnetConfigSet{
NNS: &DefaultSubnetSpec,
}
)

// BenchmarkingSubnetInstructionConfig uses very high instruction limits useful for asymptotic canister benchmarking.
type BenchmarkingSubnetInstructionConfig struct{}
Expand Down Expand Up @@ -78,13 +82,27 @@ type EffectiveSubnetID struct {
SubnetID string `json:"SubnetId"`
}

type ExtendedSubnetConfigSet struct {
Application []SubnetSpec `json:"application"`
Bitcoin *SubnetSpec `json:"bitcoin,omitempty"`
Fiduciary *SubnetSpec `json:"fiduciary,omitempty"`
II *SubnetSpec `json:"ii,omitempty"`
NNS *SubnetSpec `json:"nns,omitempty"`
SNS *SubnetSpec `json:"sns,omitempty"`
System []SubnetSpec `json:"system"`
}

// FromPathSubnetStateConfig load existing subnet state from the given path. The path must be on a filesystem
// accessible to the server process.
type FromPathSubnetStateConfig struct {
Path string
SubnetID RawSubnetID
}

func (c FromPathSubnetStateConfig) MarshalJSON() ([]byte, error) {
return json.Marshal([]any{c.Path, c.SubnetID})
}

func (c FromPathSubnetStateConfig) UnmarshalJSON(bytes []byte) error {
var v []json.RawMessage
if err := json.Unmarshal(bytes, &v); err != nil {
Expand All @@ -99,10 +117,6 @@ func (c FromPathSubnetStateConfig) UnmarshalJSON(bytes []byte) error {
return json.Unmarshal(v[1], &c.SubnetID)
}

func (c FromPathSubnetStateConfig) MarshalJSON() ([]byte, error) {
return json.Marshal([]any{c.Path, c.SubnetID})
}

func (FromPathSubnetStateConfig) stateConfig() {}

type NNSConfig struct {
Expand Down Expand Up @@ -185,7 +199,7 @@ func (pic PocketIC) CanisterExits(canisterID principal.Principal) bool {
return err == nil
}

func (pic PocketIC) CreateAndInstallCanister(wasmModule []byte, arg []byte, subnetPID *principal.Principal) (*principal.Principal, error) {
func (pic PocketIC) CreateAndInstallCanister(wasmModule io.Reader, arg []byte, subnetPID *principal.Principal) (*principal.Principal, error) {
canisterID, err := pic.CreateCanister(CreateCanisterArgs{}, subnetPID)
if err != nil {
return nil, err
Expand Down Expand Up @@ -239,6 +253,15 @@ func (pic PocketIC) GetCycleBalance(canisterID principal.Principal) (int, error)
return body.Cycles, nil
}

// GetHost returns the host of the PocketIC instance.
func (pic PocketIC) GetHost() string {
return fmt.Sprintf(
"%s/instances/%d",
pic.server.URL(),
pic.instanceID,
)
}

// GetRootKey returns the root key of the PocketIC instance.
func (pic PocketIC) GetRootKey() ([]byte, error) {
var nnsPID principal.Principal
Expand Down Expand Up @@ -296,7 +319,11 @@ func (pic PocketIC) GetTime() (*time.Time, error) {
return &t, nil
}

func (pic PocketIC) InstallCode(canisterID principal.Principal, wasmModule []byte, arg []byte) error {
func (pic PocketIC) InstallCode(canisterID principal.Principal, wasmModuleReader io.Reader, arg []byte) error {
wasmModule, err := io.ReadAll(wasmModuleReader)
if err != nil {
return err
}
payload, err := idl.Marshal([]any{installCodeArgs{
WasmModule: wasmModule,
CanisterID: canisterID,
Expand Down Expand Up @@ -432,29 +459,19 @@ func (r *RawSubnetID) UnmarshalJSON(bytes []byte) error {
return nil
}

type ExtendedSubnetConfigSet struct {
Application []SubnetSpec `json:"application"`
Bitcoin *SubnetSpec `json:"bitcoin,omitempty"`
Fiduciary *SubnetSpec `json:"fiduciary,omitempty"`
II *SubnetSpec `json:"ii,omitempty"`
NNS *SubnetSpec `json:"nns,omitempty"`
SNS *SubnetSpec `json:"sns,omitempty"`
System []SubnetSpec `json:"system"`
}

type RejectError string

func (e RejectError) Error() string {
return string(e)
}

type ReplyError struct {
Code int `json:"code"`
Code string `json:"code"`
Description string `json:"description"`
}

func (e ReplyError) Error() string {
return fmt.Sprintf("code: %d, description: %s", e.Code, e.Description)
return fmt.Sprintf("code: %s, description: %s", e.Code, e.Description)
}

type SubnetInstructionConfig interface {
Expand Down
42 changes: 39 additions & 3 deletions pocketic/pocketic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package pocketic_test
import (
"bytes"
"fmt"
"github.com/aviate-labs/agent-go"
"github.com/aviate-labs/agent-go/pocketic"
"github.com/aviate-labs/agent-go/principal"
"net/url"
"os"
"os/exec"
"strings"
Expand Down Expand Up @@ -33,7 +35,7 @@ func TestPocketIC(t *testing.T) {
if err := mocCmd.Run(); err != nil {
t.Skip(err)
}
helloWasm, err := os.ReadFile("testdata/main.wasm")
helloWasm, err := os.Open("testdata/main.wasm")
if err != nil {
t.Skip(err)
}
Expand All @@ -55,10 +57,44 @@ func TestPocketIC(t *testing.T) {
if helloWorld != "Hello, there!" {
t.Errorf("hello world is %s, expected Hello, there!", helloWorld)
}

host, err := url.Parse(s.GetHost())
if err != nil {
t.Fatal(err)
}
a, err := NewAgent(*canisterID, agent.Config{
FetchRootKey: true,
ClientConfig: &agent.ClientConfig{
Host: host,
},
})
if err != nil {
t.Fatal(err)
}
t.Run("Agent QueryCall", func(t *testing.T) {
resp, err := a.HelloQuery("world")
if err != nil {
t.Fatal(err)
}
if *resp != "Hello, world!" {
t.Errorf("resp is %s, expected Hello, world!", *resp)
}
})
t.Run("Agent UpdateCall", func(t *testing.T) {
t.Skip("PocketIC does not advance automatically, so the time is not updated.")

resp, err := a.HelloUpdate("there")
if err != nil {
t.Fatal(err)
}
if *resp != "Hello, there!" {
t.Errorf("resp is %s, expected Hello, there!", *resp)
}
})
}

func TestPocketIC_CreateAndInstallCanister(t *testing.T) {
if _, err := s.CreateAndInstallCanister(wasmModule, nil, nil); err != nil {
if _, err := s.CreateAndInstallCanister(bytes.NewReader(wasmModule), nil, nil); err != nil {
t.Fatal(err)
}
}
Expand Down Expand Up @@ -103,7 +139,7 @@ func TestPocketIC_CreateCanister(t *testing.T) {
}, nil); err == nil {
t.Error("expected error")
}
if err := s.InstallCode(cID, wasmModule, nil); err != nil {
if err := s.InstallCode(cID, bytes.NewReader(wasmModule), nil); err != nil {
t.Fatal(err)
}
}
Expand Down
Loading

0 comments on commit 3ff65dc

Please sign in to comment.