Skip to content

Commit

Permalink
testcontainers for defichain js ecosystem (#39)
Browse files Browse the repository at this point in the history
* removed main/test net workflow

* testcontainers for defichain js ecosystem

* check in .idea code styles

* automatically pull docker image for testing

* cleanup code debt

* added escape-hatch, unable to find open handles

* added DeFiDRpcError for easier downstream error surfacing
  • Loading branch information
fuxingloh authored Mar 8, 2021
1 parent 76623bb commit bf9b3c6
Show file tree
Hide file tree
Showing 22 changed files with 1,038 additions and 65 deletions.
50 changes: 2 additions & 48 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# Shift-left testing to mitigation upstream risk
name: CI

on:
Expand All @@ -9,7 +8,7 @@ on:

jobs:
build:
name: Build
name: Build & Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -21,50 +20,5 @@ jobs:
- run: npm run build
- run: npm run standard

- run: npx --no-install jest --ci --coverage
- run: npx --no-install jest --ci --coverage --forceExit
- run: npx codecov

reg-net:
name: RegNet
runs-on: ubuntu-latest
needs: [ build ]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '15'

# TODO(fuxingloh): reg net testing
- run: |
echo "::error::not yet implemented"
exit 1
test-net:
name: TestNet
runs-on: ubuntu-latest
needs: [ build ]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '15'

# TODO(fuxingloh): test net testing
- run: |
echo "::error::not yet implemented"
exit 1
main-net:
name: MainNet
runs-on: ubuntu-latest
needs: [ reg-net, test-net ]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '15'

# TODO(fuxingloh): main net testing?
- run: |
echo "::error::not yet implemented"
exit 1
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
.idea/*
!.idea/inspectionProfiles/
!.idea/dictionaries/
!.idea/codeStyles/
!.idea/vcs.xml
!.idea/modules.xml
!.idea/*.iml
!.idea/README.md

# Yarn
.yarn/*
Expand Down
21 changes: 21 additions & 0 deletions .idea/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions .idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 56 additions & 2 deletions .idea/dictionaries/fuxing.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,29 @@ npm install
### Testing

`jest.config.js` is set up at the root project level as well as at each sub module. You can run jest at root to test all
modules or individually at each sub module. If you use IntelliJ IDEA, you can right click any file to test it
individually and have it reported to the IDE.
modules or individually at each sub module. By default, only regtest chain are used for normal testing. If you use
IntelliJ IDEA, you can right click any file to test it individually and have it reported to the IDE.

Docker is required to run the tests as [`@defichain/testcontainers`](./packages/testcontainers) will automatically spin
up `regtest` instances for testing.
up `regtest` instances for testing. The number of containers it will spin up concurrently is dependent on your
jest `--maxConcurrency` count.

Coverage is collected at merge with `codecov`; more testing 🚀 less 🐛 = 😎
Coverage is collected at pr merge with `codecov`; more testing 🚀 less 🐛 = 😎

```shell
jest
```

### Publishing

`"version": "0.0.0"` is used because publishing will be done automatically
by [GitHub releases](https://github.com/DeFiCh/jellyfish/releases) with connected workflows. On
release `types: [ published, prereleased ]`, GitHub Action will automatically build all packages in this repo and
publish it into npm.

* release are tagged as `@latest`
* prerelease are tagged as `@next` (please use this cautiously)

### IntelliJ IDEA

IntelliJ IDEA is the IDE of choice for writing and maintaining this library. IntelliJ's files are included for
Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
projects: [
'<rootDir>/packages/*'
]
],
testTimeout: 240000
}
15 changes: 14 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"size-limit": "^4.9.2",
"ts-jest": "^26.5.2",
"ts-standard": "^10.0.0",
"typescript": "^4.2.2"
"typescript": "^4.2.2",
"wait-for-expect": "^3.0.2"
},
"lint-staged": {
"*.{ts,js}": [
Expand Down
114 changes: 113 additions & 1 deletion packages/testcontainers/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,115 @@
# @defichain/testcontainers


Similar to [testcontainers](https://www.testcontainers.org/) in the Java ecosystem, this package provides a lightweight,
throwaway instances of `regtest`, `testnet` or `mainnet` provisioned automatically in Docker container.
`@defichain/testcontainers` encapsulate on top of `defi/defichain:v1.x` and directly interface with the Docker REST API.

With `@defichain/testcontainers`, it allows the JS developers to:

1. End-to-end test their application without hassle of setting up the toolchain
2. Run parallel tests as port number and container are dynamically generated on demand
3. Supercharge our CI workflow; run locally, anywhere or CI (as long as it has Docker installed)
4. Supercharge your `@defichain/jellyfish` implementation with 100% day 1 compatibility (mono repo!)
5. Bring quality and reliability to dApps on the DeFiChain JS ecosystem

## Usage Example

Install as dev only as you don't need this in production. **Please don't use this in production!**

```shell
npm i -D @defichain/testcontainers
```

Use your favourite jest runner and start building dApps!

### Basic `RegTestContainer` setup

```js
import { RegTestDocker } from '@defichain/testcontainers'
import { getClient } from 'somewhere'

describe('reg test', () => {
const node = new RegTestDocker()

beforeEach(async () => {
await node.start({
user: 'foo',
password: 'bar',
})
await node.ready()
})

afterEach(async () => {
await node.stop()
})

it('should getmintinginfo and chain should be regtest', async () => {
const url = await node.getRpcUrl()
const client = getClient(url)
const result = await client.call('getmintinginfo', [])
expect(result.chain).toBe('regtest')
})
})
```

### `MasterNodeRegTestContainer` with auto-minting

```js
import { MasterNodeRegTestContainer } from '@defichain/testcontainers'
import waitForExpect from "wait-for-expect";

describe('master node pos minting', () => {
const container = new MasterNodeRegTestContainer()

beforeEach(async () => {
await container.start()
await container.waitForReady()
})

afterEach(async () => {
await container.stop()
})

it('should wait until coinbase maturity with spendable balance', async () => {
await container.generate(100)

await waitForExpect(async () => {
const info = await container.getMintingInfo()
expect(info.blocks).toBeGreaterThan(100)
})

// perform utxostoaccount rpc
const address = await container.getNewAddress()
const payload: { [key: string]: string } = {}
payload[address] = "100@0"
await container.call("utxostoaccount", [payload])
})
})
```

### Endpoint?

```js
const container = new MasterNodeRegTestContainer()
const rpcURL = await container.getCachedRpcUrl()

// they are dynmaically assigned to host, you can run multiple concurrent tests!
const port = await container.getPort('8555/tcp')
```

### Included `container.call('method', [])` for convenience RPC calls

```js
const container = new MasterNodeRegTestContainer()
await container.start()
await container.waitForReady()

// raw universal calls
const { blocks } = await container.call('getmintinginfo')
const address = await container.call('getnewaddress', ['label', 'legacy'])

// basic included types
const count = await container.getBlockCount()
const info = await container.getMintingInfo()
const newAddress = await container.getNewAddress()
```
Loading

0 comments on commit bf9b3c6

Please sign in to comment.