Skip to content

Commit

Permalink
wip: test: separate fixture docs; more test fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
egasimus committed Oct 19, 2023
1 parent 1805efa commit 5d22aac
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 234 deletions.
2 changes: 1 addition & 1 deletion ensuite
Submodule ensuite updated 1 files
+1 −1 ensuite.d.ts
162 changes: 81 additions & 81 deletions fadroma.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import * as assert from 'node:assert'
import { into, intoArray, intoRecord } from '@fadroma/agent'
import {
Template, Contract, Client, Deployment, Builder, Uploader, into, intoArray, intoRecord
} from '@fadroma/agent'
import Project from '@hackbg/fadroma'
import type { Agent } from '@fadroma/agent'

import { testEntrypoint, testSuite } from '@hackbg/ensuite'

export default testEntrypoint(import.meta.url, {

'agent': testSuite('./agent/agent.test'),
Expand Down Expand Up @@ -46,7 +52,7 @@ export async function testCollections () {

export async function testProject () {
const { default: Project } = await import('@hackbg/fadroma')
const { tmpDir } = await import('./fixtures/Fixtures.ts.md')
const { tmpDir } = await import('./fixtures/fixtures')

const root = tmpDir()

Expand Down Expand Up @@ -77,66 +83,65 @@ export async function testProject () {
}

export async function testDeployment () {
assert.deepEqual(
Object.keys(deployment.snapshot.contracts),
['kv1', 'kv2']
)
// in your project's api.ts:

import { Deployment } from '@fadroma/agent'

// you would load snapshots as JSON, e.g.:
// const testnet = await (await fetch('./testnet_v4.json')).json()
export const mainnet = deployment.snapshot
export const testnet = deployment.snapshot

// and create instances of your deployment with preloaded
// "address books" of contracts. for example here we restore
// a different snapshot depending on whether we're passed a
// mainnet or testnet connection.
class DeploymentC extends Deployment {
kv1 = this.contract({ crate: 'examples/kv', name: 'kv1', initMsg: {} })
kv2 = this.contract({ crate: 'examples/kv', name: 'kv2', initMsg: {} })

static connect = (agent: Agent) => {
if (agent?.chain?.isMainnet) return new this({ ...mainnet, agent })
if (agent?.chain?.isTestnet) return new this({ ...testnet, agent })
return new this({ agent })
}
assert.deepEqual(
Object.keys(deployment.snapshot.contracts),
['kv1', 'kv2']
)
// you would load snapshots as JSON, e.g.:
// const testnet = await (await fetch('./testnet_v4.json')).json()
export const mainnet = deployment.snapshot
export const testnet = deployment.snapshot

const mainnetAgent: any = { chain: { isMainnet: true } } // mock
const testnetAgent: any = { chain: { isTestnet: true } } // mock
const onMainnet = DeploymentC.connect(mainnetAgent)
const onTestnet = DeploymentC.connect(testnetAgent)

assert(onMainnet.isMainnet)
assert(onTestnet.isTestnet)
assert.deepEqual(Object.keys(onMainnet.contracts), ['kv1', 'kv2'])
assert.deepEqual(Object.keys(onTestnet.contracts), ['kv1', 'kv2'])

const kv1 = DeploymentC.connect(mainnetAgent).kv1.expect()
assert(kv1 instanceof Client)

const kv2 = DeploymentC.connect(testnetAgent).kv2.expect()
assert(kv2 instanceof Client)
// simplest chain-side migration is to just call default deploy,
// which should reuse kv1 and kv2 and only deploy kv3.
deployment = await DeploymentD.upgrade(deployment).deploy()

deployment = await getDeployment(Deployment4).deploy()
assert(deployment.t instanceof Template)

assert([
deployment.a,
...Object.values(deployment.b)
...Object.values(deployment.c)
].every(
c=>(c instanceof Contract) && (c.expect() instanceof Client)
))
}
const mainnetAgent = { chain: { isMainnet: true } } // mock
const testnetAgent = { chain: { isTestnet: true } } // mock

const onMainnet = DeploymentC.connect(mainnetAgent)

const onTestnet = DeploymentC.connect(testnetAgent)

assert(onMainnet.isMainnet)
assert(onTestnet.isTestnet)
assert.deepEqual(Object.keys(onMainnet.contracts), ['kv1', 'kv2'])
assert.deepEqual(Object.keys(onTestnet.contracts), ['kv1', 'kv2'])

const kv1 = DeploymentC.connect(mainnetAgent).kv1.expect()
assert(kv1 instanceof Client)

const kv2 = DeploymentC.connect(testnetAgent).kv2.expect()
assert(kv2 instanceof Client)
// in your project's api.ts:

import { Deployment } from '@fadroma/agent'

class DeploymentD extends DeploymentC {
kv3 = this.contract({ crate: 'examples/kv', name: 'kv3', initMsg: {} })
export async function testBuild () {
const deployment = new Deployment4()
assert(deployment.t.builder instanceof Builder)
assert.equal(deployment.t.builder, deployment.builder)
await deployment.t.built
// -or-
await deployment.t.build()
}

// simplest client-side migration is to just instantiate
// a new deployment with the data from the old deployment.
static upgrade = (previous: DeploymentC) =>
new this({ ...previous })
export async function testUpload () {
const deployment = new Deployment4()
assert(deployment.t.uploader instanceof Uploader)
assert.equal(deployment.t.uploader, deployment.uploader)
await deployment.t.uploaded
// -or-
await deployment.t.upload()
}

// simplest chain-side migration is to just call default deploy,
// which should reuse kv1 and kv2 and only deploy kv3.
deployment = await DeploymentD.upgrade(deployment).deploy()
class Deployment4 extends Deployment {

t = this.template({ crate: 'examples/kv' })
Expand All @@ -156,32 +161,27 @@ class Deployment4 extends Deployment {
})

}
deployment = await getDeployment(Deployment4).deploy()
assert(deployment.t instanceof Template)

assert([
deployment.a,
...Object.values(deployment.b)
...Object.values(deployment.c)
].every(
c=>(c instanceof Contract) && (c.expect() instanceof Client)
))
}

export async function testBuild () {
import { Builder } from '@fadroma/agent'
assert(deployment.t.builder instanceof Builder)
assert.equal(deployment.t.builder, deployment.builder)
await deployment.t.built
// -or-
await deployment.t.build()
// and create instances of your deployment with preloaded
// "address books" of contracts. for example here we restore
// a different snapshot depending on whether we're passed a
// mainnet or testnet connection.
class DeploymentC extends Deployment {
kv1 = this.contract({ crate: 'examples/kv', name: 'kv1', initMsg: {} })
kv2 = this.contract({ crate: 'examples/kv', name: 'kv2', initMsg: {} })

static connect = (agent: Agent) => {
if (agent?.chain?.isMainnet) return new this({ ...mainnet, agent })
if (agent?.chain?.isTestnet) return new this({ ...testnet, agent })
return new this({ agent })
}
}

export async function testUpload () {
import { Uploader } from '@fadroma/agent'
assert(deployment.t.uploader instanceof Uploader)
assert.equal(deployment.t.uploader, deployment.uploader)
await deployment.t.uploaded
// -or-
await deployment.t.upload()
class DeploymentD extends DeploymentC {
kv3 = this.contract({ crate: 'examples/kv', name: 'kv3', initMsg: {} })

// simplest client-side migration is to just instantiate
// a new deployment with the data from the old deployment.
static upgrade = (previous: DeploymentC) =>
new this({ ...previous })
}
19 changes: 19 additions & 0 deletions fixtures/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Fixtures

* Files with a fixed content that are used in the test suites.
* TODO use `fetch` instead of Node FS API

## Example mnemonics

## Example contracts

* **Echo contract** (build with `pnpm rs:build:example examples/echo`).
Parrots back the data sent by the client, in order to validate
reading/writing and serializing/deserializing the input/output messages.
* **KV contract** (build with `pnpm rs:build:example examples/kv`).
Exposes the key/value storage API available to contracts,
in order to validate reading/writing and serializing/deserializing stored values.

## Mocks

### Mock agent
58 changes: 12 additions & 46 deletions fixtures/Fixtures.ts.md → fixtures/fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,22 @@
# Fixtures

* Files with a fixed content that are used in the test suites.
* TODO use `fetch` instead of Node FS API

```typescript
import { withTmpDir } from '@hackbg/file'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { readFileSync } from 'node:fs'

import $, { BinaryFile } from '@hackbg/file'
import { Console, bold } from '@fadroma/agent'
import $ from '@hackbg/file'
```
import { StubAgent as Agent, StubChain as Chain, Uploader, Contract, Client } from '@fadroma/agent'

```typescript
export const here = dirname(fileURLToPath(import.meta.url))
export const workspace = resolve(here)
export const fixture = x => resolve(here, x)
export const log = new Console('Fadroma Testing')

export const nullWasm = readFileSync(fixture('null.wasm'))
```

## Example mnemonics

```typescript
export const mnemonics = [
'canoe argue shrimp bundle drip neglect odor ribbon method spice stick pilot produce actual recycle deposit year crawl praise royal enlist option scene spy',
'bounce orphan vicious end identify universe excess miss random bench coconut curious chuckle fitness clean space damp bicycle legend quick hood sphere blur thing'
]
```

## Example contracts

* **Echo contract** (build with `pnpm rs:build:example examples/echo`).
Parrots back the data sent by the client, in order to validate
reading/writing and serializing/deserializing the input/output messages.
* **KV contract** (build with `pnpm rs:build:example examples/kv`).
Exposes the key/value storage API available to contracts,
in order to validate reading/writing and serializing/deserializing stored values.

```typescript
import $, { BinaryFile } from '@hackbg/file'
import { readFileSync } from 'fs'

export const examples = {
}
Expand All @@ -60,24 +35,19 @@ example('Empty', 'empty.wasm', 'e3b0c44298fc1c149afbf4c89
example('KV', '[email protected]', '16dea8b55237085f24af980bbd408f1d6893384996e90e0ce2c6fc3432692a0d')
example('Echo', '[email protected]', 'a4983efece1306aa897651fff74cae18436fc3280fc430d11a4997519659b6fd')
example('Legacy', '[email protected]', 'a5d58b42e686d9f5f8443eb055a3ac45018de2d1722985c5f77bad344fc00c3b')
```

## Mocks

### Mock agent
class MockChain extends Chain {
uploads = new class MockUploader extends Uploader {
resolve = () => `/tmp/fadroma-test-upload-${Math.floor(Math.random()*1000000)}`
make = () => new class MockFile {
resolve = () => `/tmp/fadroma-test-upload-${Math.floor(Math.random()*1000000)}`
}
}
}

```typescript
import { Agent, Chain, Uploader, Contract, Client } from '@fadroma/agent'
export const mockAgent = () => new class MockAgent extends Agent {

chain = new (class MockChain extends Chain {
uploads = new class MockUploader extends Uploader {
resolve = () => `/tmp/fadroma-test-upload-${Math.floor(Math.random()*1000000)}`
make = () => new class MockFile {
resolve = () => `/tmp/fadroma-test-upload-${Math.floor(Math.random()*1000000)}`
}
}
})('mock')
chain = new MockChain('mock')

async upload () { return {} }

Expand All @@ -99,13 +69,9 @@ export const mockAgent = () => new class MockAgent extends Agent {
}

}
```

```typescript
import { withTmpDir } from '@hackbg/file'
export const tmpDir = () => {
let x
withTmpDir(dir=>x=dir)
return x
}
```
Loading

0 comments on commit 5d22aac

Please sign in to comment.