-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(apps): add sanity testing containers (#1314)
* add sanity base * add draft test for fetching * fix(sanity-testing): Point defid url to correct bridge with regtest credentials * fix(sanity-testing): Add APP to buildargs - Build with tar to rely only on Dockerfile, reduce maintenance burden - Add logging to image building step * minor reorganization * set up port forwarding * fix(sanity-testing): wait for whale to start listening on its container port * chore(sanity-testing): add sanity tests (mapped from whale postman_collection.json) * polish and document solution * remove initial test being added to follow up PR * extract port randomizer Move port randomizer code into a readable method and link the source contributor from stackoverflow. * fix image check logic * build images before running tests * remove console log * chore: update package-lock.json * chore(sanity-testing): rename SanityContainer to AppContainer * chore(sanity-testing): remove redundant inclusion * chore(sanity-testing): remove redundant new line at start of file * chore(sanity-testing): increase sanity tests timeout to 5 mins * chore(sanity-testing): change container name generation to use uuidv4 Co-authored-by: Eli <[email protected]> Co-authored-by: Eli <[email protected]>
- Loading branch information
1 parent
252fa2b
commit bcbb8bc
Showing
11 changed files
with
322 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { WhaleSanityContainer } from '@defichain/testcontainers' | ||
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? | ||
|
||
beforeAll(async () => { | ||
await whale.start() | ||
|
||
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 () => { | ||
const response = await whale.get('/_actuator/probes/readiness') | ||
const json = await response.json() | ||
expect(json.details.model.status).toStrictEqual('up') | ||
expect(json.details.defid.blocks).toBeGreaterThanOrEqual(100) | ||
}, 60_000) | ||
}) | ||
|
||
afterAll(async () => { | ||
await whale.stop() | ||
}) | ||
|
||
describe('/_actuator', () => { | ||
describe('/_actuator/probes/liveness', () => { | ||
test('Status in JSON body is ok', async () => { | ||
const response = await whale.get('/_actuator/probes/liveness') | ||
expect(await response.json()).toStrictEqual({ | ||
details: { | ||
defid: { status: 'up' }, | ||
model: { status: 'up' } | ||
}, | ||
error: {}, | ||
info: { | ||
defid: { status: 'up' }, | ||
model: { status: 'up' } | ||
}, | ||
status: 'ok' | ||
}) | ||
expect(response.status).toStrictEqual(200) | ||
}) | ||
}) | ||
|
||
describe('/_actuator/probes/readiness', () => { | ||
test('Status code is 503', async () => { | ||
const response = await whale.get('/_actuator/probes/readiness') | ||
expect(response.status).toStrictEqual(503) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const config = require('./jest.config.js') | ||
|
||
module.exports = { | ||
...config, | ||
testRegex: '((\\.|/)(sanity))\\.ts$', | ||
testPathIgnorePatterns: [], | ||
globalSetup: './jest.sanity.setup.js', | ||
testTimeout: 300000 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
const Dockerode = require('dockerode') | ||
const path = require('path') | ||
const { pack } = require('tar-fs') | ||
|
||
const apps = ['whale'] | ||
|
||
module.exports = async function () { | ||
console.log('\nPreloading sanity images, this may take a while...') | ||
await Promise.all(apps.map(build)) | ||
} | ||
|
||
/** | ||
* Builds a new image with a :sanity tag that can be pulled into unit tests and | ||
* run on the current state of the code base. These steps are required to | ||
* ensure that we are sanity testing against the current code state and not | ||
* pre-built solutions which is tested seperately during our standard unit | ||
* tests. | ||
* | ||
* @remarks Images are built with tar | ||
* @see https://github.com/apocas/dockerode/issues/432 | ||
*/ | ||
async function build (app) { | ||
console.log(`Building '${app}:sanity' image`) | ||
const docker = new Dockerode() | ||
const image = pack(path.resolve(__dirname)) | ||
const stream = await docker.buildImage(image, { | ||
t: `${app}:sanity`, | ||
buildargs: { | ||
APP: app | ||
} | ||
}) | ||
await new Promise((resolve, reject) => { | ||
docker.modem.followProgress(stream, (err, res) => (err != null) ? reject(err) : resolve(res)) | ||
}) | ||
console.log(`Finished '${app}:sanity' image`) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
packages/testcontainers/src/containers/AppContainer/WhaleSanityContainer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { MasterNodeRegTestContainer } from '../RegTestContainer/Masternode' | ||
import { AppContainer } from '.' | ||
import { waitForCondition } from '../../utils' | ||
|
||
export class WhaleSanityContainer extends AppContainer { | ||
constructor (port?: number, blockchain?: MasterNodeRegTestContainer) { | ||
super('whale', port, blockchain) | ||
} | ||
|
||
/** | ||
* Start the whale container by initiating a build procedure, instantiate the | ||
* underlying blockchain node, and create a container instance to send sanity | ||
* requests to. | ||
* | ||
* We provide the blockchain node ip and port to the internal whale configuration | ||
* which links it to the node allowing it to hit the chain with RPC requests. | ||
* | ||
* @remarks | ||
* | ||
* The method performs a wait for condition to ensure the container is ready | ||
* before the start method is considered resolved. Otherwise the unit tests | ||
* will run before the container is ready which can result in various network | ||
* or request errors. | ||
*/ | ||
public async start (): Promise<void> { | ||
const { hostRegTestIp, hostRegTestPort } = await this.startMasterNode() | ||
|
||
this.container = await this.docker.createContainer({ | ||
name: this.name, | ||
Image: this.image, | ||
Tty: true, | ||
Env: [ | ||
`WHALE_DEFID_URL=http://testcontainers-user:testcontainers-password@${hostRegTestIp}:${hostRegTestPort}`, | ||
'WHALE_NETWORK=regtest', | ||
'WHALE_DATABASE_PROVIDER=memory' | ||
], | ||
ExposedPorts: { '3000/tcp': {} }, | ||
HostConfig: { | ||
PortBindings: { '3000/tcp': [{ HostPort: this.port.toString() }] }, | ||
PublishAllPorts: true | ||
} | ||
}) | ||
|
||
await this.container.start() | ||
|
||
await waitForCondition(async () => { | ||
const res = await this.get('/_actuator/probes/liveness') | ||
return res.status === 200 | ||
}, 30_000) // 30s | ||
} | ||
} |
Oops, something went wrong.