Skip to content

Commit

Permalink
chore(whale/sanity-testing): port over tests from whale ci newman (#1433
Browse files Browse the repository at this point in the history
)

* 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
  • Loading branch information
eli-lim authored May 23, 2022
1 parent bcbb8bc commit c78a3e4
Show file tree
Hide file tree
Showing 4 changed files with 247 additions and 8 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
224 changes: 218 additions & 6 deletions apps/whale/__sanity__/WhaleSanityContainer.sanity.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
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<void> {
await whale.blockchain.waitForWalletCoinbaseMaturity()
await whale.blockchain.waitForWalletBalanceGTE(100)

// TODO(kodemon/eli-lim): Create tokens, pool pairs, etc. to sanity test the endpoints
}

await mockRealisticState()

await waitForExpect(async () => {
Expand All @@ -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: {
Expand All @@ -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<string>('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)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -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<Response> {
return await this.fetch(rpcEndpoint, {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
method: method,
params: params
})
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down

0 comments on commit c78a3e4

Please sign in to comment.