Skip to content

Commit

Permalink
added PersistentMNRegTestContainer (#173)
Browse files Browse the repository at this point in the history
  • Loading branch information
fuxingloh authored Apr 29, 2021
1 parent 8f3903d commit 34856ea
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { PersistentMNRegTestContainer } from '../../../src'
import waitForExpect from 'wait-for-expect'

beforeEach(async () => {
try {
await new PersistentMNRegTestContainer().stop()
} catch (ignored) {
}
})

afterEach(async () => {
try {
await new PersistentMNRegTestContainer().stop()
} catch (ignored) {
}
})

it('should start and mint coins', async () => {
const container = new PersistentMNRegTestContainer()
await container.start()
await container.waitForReady()

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

it('should always use the same persistent container', async () => {
let container = new PersistentMNRegTestContainer()
await container.start()
await container.waitForReady()

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

container = new PersistentMNRegTestContainer()
await container.start()
await container.waitForReady()

const info = await container.getMintingInfo()
expect(info.blocks).toBeGreaterThan(3)
})
30 changes: 15 additions & 15 deletions packages/testcontainers/src/chains/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,6 @@ export interface StartOptions {
password?: string
}

const defaultStartOptions = {
user: 'testcontainers-user',
password: 'testcontainers-password'
}

/**
* Generate a name for a new docker container with network type and random number
*/
function generateName (network: Network): string {
const rand = Math.floor(Math.random() * 10000000)
return `${DeFiDContainer.PREFIX}-${network}-${rand}`
}

/**
* Clean up stale nodes are nodes that are running for 1 hour
*/
Expand Down Expand Up @@ -94,6 +81,11 @@ export abstract class DeFiDContainer {
public static readonly PREFIX = 'defichain-testcontainers-'
public static readonly image = 'defi/defichain:1.6.3'

public static readonly DefaultStartOptions = {
user: 'testcontainers-user',
password: 'testcontainers-password'
}

protected readonly docker: Dockerode
protected readonly network: Network

Expand Down Expand Up @@ -137,9 +129,9 @@ export abstract class DeFiDContainer {
*/
async start (startOptions: StartOptions = {}): Promise<void> {
await pullImage(this.docker)
this.startOptions = Object.assign(defaultStartOptions, startOptions)
this.startOptions = Object.assign(DeFiDContainer.DefaultStartOptions, startOptions)
this.container = await this.docker.createContainer({
name: generateName(this.network),
name: this.generateName(),
Image: DeFiDContainer.image,
Tty: true,
Cmd: this.getCmd(this.startOptions),
Expand All @@ -150,6 +142,14 @@ export abstract class DeFiDContainer {
await this.container.start()
}

/**
* Generate a name for a new docker container with network type and random number
*/
generateName (): string {
const rand = Math.floor(Math.random() * 10000000)
return `${DeFiDContainer.PREFIX}-${this.network}-${rand}`
}

/**
* Get host machine port
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,11 @@ export class MasterNodeRegTestContainer extends RegTestContainer {
/**
* This will automatically import the necessary private key for master to mint tokens
*/
async waitForReady (timeout: number = 15000): Promise<void> {
await super.waitForReady(timeout)
async start (startOptions: StartOptions = {}): Promise<void> {
await super.start(startOptions)

// Wait for ready and setup for auto mint
await super.waitForReady(25000)

// import keys for master node
await this.call('importprivkey', [
Expand Down Expand Up @@ -79,7 +82,6 @@ export class MasterNodeRegTestContainer extends RegTestContainer {
// restart and wait for ready
await this.container?.stop()
await this.container?.start()
await super.waitForReady(timeout)
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { MasterNodeRegTestContainer } from './masternode'
import { DeFiDContainer, StartOptions } from '../container'
import Dockerode, { ContainerInfo } from 'dockerode'

async function getContainerInfoByName (docker: Dockerode, name: string): Promise<ContainerInfo | undefined> {
return await new Promise((resolve, reject) => {
const opts = { limit: 1, filters: `{"name": ["${name}"]}` }
docker.listContainers(opts, function (err, containers) {
if (err === null && containers !== undefined) {
resolve(containers[0])
} else {
reject(err)
}
})
})
}

/**
* PersistentMNRegTestContainer container is a RegTest container with MasterNode minting preconfigured.
* The container configuration is persistent and can be used consistently.
* If you do not stop the container, the same container can be used for all tests.
* However, you must be cognizant of race conditions.
*
* This container should not be used for finished work, it merely a dev tool to speed up test-driven development.
* Once you are done with your dev work, you should swap this out for MasterNodeRegTestContainer.
*/
export class PersistentMNRegTestContainer extends MasterNodeRegTestContainer {
/**
* Init the required container instances for start/stop operation
*/
async init (): Promise<void> {
const info = await getContainerInfoByName(this.docker, this.generateName())
this.container = info?.Id !== undefined ? this.docker.getContainer(info.Id) : undefined
}

/**
* This will only start a persistent container if it's not yet already started.
* @see {generateName()} for the name of container
*/
async start (startOptions: StartOptions = {}): Promise<void> {
this.startOptions = Object.assign(DeFiDContainer.DefaultStartOptions, startOptions)

try {
await this.init()
this.requireContainer()
await this.waitForReady(3000)
} catch (e) {
// Attempt clean up before starting
await super.stop()
await super.start(startOptions)
}
}

/**
* @return {string} name of persistent container that is always consistent.
*/
generateName (): string {
return `${DeFiDContainer.PREFIX}-${this.network}-persistent`
}

async stop (): Promise<void> {
await this.init()
await super.stop()
}
}
1 change: 1 addition & 0 deletions packages/testcontainers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './chains/main_net_container'
export * from './chains/test_net_container'
export * from './chains/reg_test_container/index'
export * from './chains/reg_test_container/masternode'
export * from './chains/reg_test_container/persistent'

0 comments on commit 34856ea

Please sign in to comment.