From c78a3e4707351e28eeb96af7f2af36db0490a412 Mon Sep 17 00:00:00 2001 From: Eli <31790206+eli-lim@users.noreply.github.com> Date: Mon, 23 May 2022 12:06:17 +0800 Subject: [PATCH] chore(whale/sanity-testing): port over tests from whale ci newman (#1433) * chore(whale/sanity-testing): port over tests from whale ci newman * chore(whale/sanity-testing): include WhaleApiClient sanity testcases * chore(sanity-testing): add sanity test workflow * chore(whale/sanity-testing): increase startup timeout to 5m * fix(whale/sanity-testing): change host.docker.internal to be compatible with linux - https://stackoverflow.com/questions/48546124/what-is-linux-equivalent-of-host-docker-internal --- .github/workflows/ci.yml | 14 ++ .../__sanity__/WhaleSanityContainer.sanity.ts | 224 +++++++++++++++++- .../AppContainer/WhaleSanityContainer.ts | 15 +- .../src/containers/AppContainer/index.ts | 2 +- 4 files changed, 247 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9aa32d38c2..57d1987457 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,6 +49,20 @@ jobs: with: fail_ci_if_error: true + docker-sanity: + needs: [ build, lint ] + name: Docker Sanity Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b + - uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048 + with: + node-version: '16' + cache: 'npm' + + - run: npm ci + - run: npm run sanity + lint: name: Lint runs-on: ubuntu-latest diff --git a/apps/whale/__sanity__/WhaleSanityContainer.sanity.ts b/apps/whale/__sanity__/WhaleSanityContainer.sanity.ts index ca6451650e..2568b28966 100644 --- a/apps/whale/__sanity__/WhaleSanityContainer.sanity.ts +++ b/apps/whale/__sanity__/WhaleSanityContainer.sanity.ts @@ -1,14 +1,17 @@ import { WhaleSanityContainer } from '@defichain/testcontainers' +import { WhaleApiClient } from '@defichain/whale-api-client' import waitForExpect from 'wait-for-expect' const whale = new WhaleSanityContainer() - -// TODO(kodemon/eli-lim): -// would it make sense to use WhaleApiClient for sanity tests, -// instead of raw http requests? +let client: WhaleApiClient beforeAll(async () => { await whale.start() + client = new WhaleApiClient({ + url: await whale.getUrl(), + version: 'v0.0', + network: 'regtest' + }) async function mockRealisticState (): Promise { await whale.blockchain.waitForWalletCoinbaseMaturity() @@ -16,6 +19,7 @@ beforeAll(async () => { // TODO(kodemon/eli-lim): Create tokens, pool pairs, etc. to sanity test the endpoints } + await mockRealisticState() await waitForExpect(async () => { @@ -32,7 +36,7 @@ afterAll(async () => { describe('/_actuator', () => { describe('/_actuator/probes/liveness', () => { - test('Status in JSON body is ok', async () => { + it('should return "ok" status', async () => { const response = await whale.get('/_actuator/probes/liveness') expect(await response.json()).toStrictEqual({ details: { @@ -51,9 +55,217 @@ describe('/_actuator', () => { }) describe('/_actuator/probes/readiness', () => { - test('Status code is 503', async () => { + it('should have status code 503 as defid has no peers', async () => { const response = await whale.get('/_actuator/probes/readiness') expect(response.status).toStrictEqual(503) + expect(await response.json()).toStrictEqual({ + details: { + defid: { + blocks: expect.any(Number), + headers: expect.any(Number), + initialBlockDownload: false, + peers: 0, + status: 'down' + }, + model: { + count: { + defid: expect.any(Number), + index: expect.any(Number) + }, + status: 'up' + } + }, + error: { + defid: { + blocks: expect.any(Number), + headers: expect.any(Number), + initialBlockDownload: false, + peers: 0, + status: 'down' + } + }, + info: { + model: { + count: { + defid: expect.any(Number), + index: expect.any(Number) + }, + status: 'up' + } + }, + status: 'error' + }) + }) + }) +}) + +describe('/rpc/getblockchaininfo', () => { + const expected = { + bestblockhash: expect.stringMatching(/[0-f]{64}/), + blocks: 101, + chain: 'regtest', + chainwork: '00000000000000000000000000000000000000000000000000000000000000cc', + difficulty: expect.any(Number), + headers: 101, + initialblockdownload: false, + mediantime: expect.any(Number), + pruned: false, + size_on_disk: expect.any(Number), + softforks: expect.any(Object), + verificationprogress: 1, + warnings: '' + } + + it('should return correct data - request via raw http', async () => { + const response = await whale.call('/v0.0/regtest/rpc', 'getblockchaininfo') + + expect(response.status).toStrictEqual(201) + expect(await response.json()).toStrictEqual({ + error: null, + id: null, + result: expected }) }) + + it('should return correct data - request via WhaleApiClient', async () => { + const info = await client.rpc.call('getblockchaininfo', [], 'number') + expect(info).toStrictEqual(expected) + }) +}) + +describe('/rpc/getblockhash', () => { + const expected = 'd744db74fb70ed42767ae028a129365fb4d7de54ba1b6575fb047490554f8a7b' + + it('should return correct data - request via raw http', async () => { + const response = await whale.call('/v0.0/regtest/rpc', 'getblockhash', [0]) + + expect(response.status).toStrictEqual(201) + expect(await response.json()).toStrictEqual({ + error: null, + id: null, + result: expected + }) + }) + + it('should return correct data - request via WhaleApiClient', async () => { + const hash = await client.rpc.call('getblockhash', [0], 'number') + expect(hash).toStrictEqual(expected) + }) +}) + +describe('/rpc/getblock', () => { + const expected = { + bits: '207fffff', + chainwork: '0000000000000000000000000000000000000000000000000000000000000002', + confirmations: 102, + difficulty: 4.656542373906925e-10, + hash: 'd744db74fb70ed42767ae028a129365fb4d7de54ba1b6575fb047490554f8a7b', + height: 0, + mediantime: 1579045065, + merkleroot: '5615dbbb379da893dd694e02d25a7955e1b7471db55f42bbd82b5d3f5bdb8d38', + mintedBlocks: 0, + nTx: 9, + nextblockhash: 'e9e8b4a016f31e4f292da95076be91314904481c681d4b643b14e49d127e3e2e', + nonutxo: [ + { + AnchorReward: 0.2, + IncentiveFunding: 20 + } + ], + size: 1424, + stakeModifier: '0000000000000000000000000000000000000000000000000000000000000000', + strippedsize: 1424, + time: 1579045065, + tx: expect.any(Array), + version: 1, + versionHex: '00000001', + weight: 5696 + } + + it('should return correct data - request via raw http', async () => { + const response = await whale.call( + '/v0.0/regtest/rpc', + 'getblock', + ['d744db74fb70ed42767ae028a129365fb4d7de54ba1b6575fb047490554f8a7b', 2] + ) + expect(response.status).toStrictEqual(201) + expect(await response.json()).toStrictEqual({ + error: null, + id: null, + result: expected + }) + }) + + it('should return correct data - request via WhaleApiClient', async () => { + const block = await client.rpc.call( + 'getblock', + [ + 'd744db74fb70ed42767ae028a129365fb4d7de54ba1b6575fb047490554f8a7b', + 2 + ], + 'number' + ) + expect(block).toStrictEqual(expected) + }) +}) + +describe('/tokens', () => { + const expected = [ + { + creation: { + height: 0, + tx: '0000000000000000000000000000000000000000000000000000000000000000' + }, + decimal: 8, + destruction: { + height: -1, + tx: '0000000000000000000000000000000000000000000000000000000000000000' + }, + displaySymbol: 'DFI', + finalized: true, + id: '0', + isDAT: true, + isLPS: false, + isLoanToken: false, + limit: '0', + mintable: false, + minted: '0', + name: 'Default Defi token', + symbol: 'DFI', + symbolKey: 'DFI', + tradeable: true + } + ] + + it('should return correct data - request via raw http', async () => { + const response = await whale.get('/v0.0/regtest/tokens') + + expect(response.status).toStrictEqual(200) + expect(await response.json()).toStrictEqual({ + data: expected + }) + }) + + it('should return correct data - request via WhaleApiClient', async () => { + const tokens = await client.tokens.list() + expect([...tokens]).toStrictEqual(expected) + }) +}) + +describe('/poolpairs', () => { + const expected: any[] = [] + + it('should return correct data - request via raw http', async () => { + const response = await whale.get('/v0.0/regtest/poolpairs') + expect(response.status).toStrictEqual(200) + + expect(await response.json()).toStrictEqual({ + data: expected + }) + }) + + it('should return correct data - request via WhaleApiClient', async () => { + const poolpairs = await client.poolpairs.list() + expect([...poolpairs]).toStrictEqual(expected) + }) }) diff --git a/packages/testcontainers/src/containers/AppContainer/WhaleSanityContainer.ts b/packages/testcontainers/src/containers/AppContainer/WhaleSanityContainer.ts index 74dce180c7..0b5285a95e 100644 --- a/packages/testcontainers/src/containers/AppContainer/WhaleSanityContainer.ts +++ b/packages/testcontainers/src/containers/AppContainer/WhaleSanityContainer.ts @@ -46,6 +46,19 @@ export class WhaleSanityContainer extends AppContainer { await waitForCondition(async () => { const res = await this.get('/_actuator/probes/liveness') return res.status === 200 - }, 30_000) // 30s + }, 300_000) // 5m + } + + public async call (rpcEndpoint: string, method: string, params?: any): Promise { + return await this.fetch(rpcEndpoint, { + method: 'POST', + headers: { + 'content-type': 'application/json' + }, + body: JSON.stringify({ + method: method, + params: params + }) + }) } } diff --git a/packages/testcontainers/src/containers/AppContainer/index.ts b/packages/testcontainers/src/containers/AppContainer/index.ts index 7221cc3731..15a81c0d7e 100644 --- a/packages/testcontainers/src/containers/AppContainer/index.ts +++ b/packages/testcontainers/src/containers/AppContainer/index.ts @@ -44,7 +44,7 @@ export abstract class AppContainer extends DockerContainer { }> { await this.blockchain.start() - const hostRegTestIp = 'host.docker.internal' // TODO(eli-lim): Works on linux? + const hostRegTestIp = '172.17.0.1' // host.docker.internal equivalent for MacOS and Linux const hostRegTestPort = await this.blockchain.getPort('19554/tcp') return { hostRegTestIp, hostRegTestPort }