This repository has been archived by the owner on Jun 3, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* WIP [masternode controller] * Masternode.spec.ts * Masternode.controller.e2e.ts * Cleanup and CI fixes * Code governace fix and minor fixes * clean up and improvements * Minor fixes * Minor fixes * Fix ci failure * Implemented quested advise on PR * Minor fixes * Minor fixes * updated masternode tests to use genesis masternodes * Improved code better testing naming * Apply suggestions from code review * Added more tests assertations Co-authored-by: Fuxing Loh <[email protected]>
- Loading branch information
Showing
8 changed files
with
427 additions
and
1 deletion.
There are no files selected for viewing
120 changes: 120 additions & 0 deletions
120
packages/whale-api-client/__tests__/api/masternode.test.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,120 @@ | ||
import { MasterNodeRegTestContainer } from '@defichain/testcontainers' | ||
import { StubWhaleApiClient } from '../stub.client' | ||
import { StubService } from '../stub.service' | ||
import { WhaleApiClient, WhaleApiException } from '../../src' | ||
|
||
let container: MasterNodeRegTestContainer | ||
let service: StubService | ||
let client: WhaleApiClient | ||
|
||
beforeAll(async () => { | ||
container = new MasterNodeRegTestContainer() | ||
service = new StubService(container) | ||
client = new StubWhaleApiClient(service) | ||
|
||
await container.start() | ||
await container.waitForReady() | ||
await service.start() | ||
}) | ||
|
||
afterAll(async () => { | ||
try { | ||
await service.stop() | ||
} finally { | ||
await container.stop() | ||
} | ||
}) | ||
|
||
describe('list', () => { | ||
it('should list masternodes', async () => { | ||
const data = await client.masternodes.list() | ||
expect(Object.keys(data[0]).length).toStrictEqual(7) | ||
expect(data.hasNext).toStrictEqual(false) | ||
expect(data.nextToken).toStrictEqual(undefined) | ||
|
||
expect(data[0]).toStrictEqual({ | ||
id: '03280abd3d3ae8dc294c1a572cd7912c3c3e53044943eac62c2f6c4687c87f10', | ||
state: 'ENABLED', | ||
mintedBlocks: 0, | ||
owner: { address: 'bcrt1qyeuu9rvq8a67j86pzvh5897afdmdjpyankp4mu' }, | ||
operator: { address: 'bcrt1qurwyhta75n2g75u2u5nds9p6w9v62y8wr40d2r' }, | ||
creation: { height: 0 }, | ||
resign: { | ||
tx: '0000000000000000000000000000000000000000000000000000000000000000', | ||
height: -1 | ||
} | ||
}) | ||
}) | ||
|
||
it('should list masternodes with pagination', async () => { | ||
const first = await client.masternodes.list(4) | ||
expect(first.length).toStrictEqual(4) | ||
expect(first.hasNext).toStrictEqual(true) | ||
expect(first.nextToken).toStrictEqual(first[3].id) | ||
|
||
const next = await client.paginate(first) | ||
expect(next.length).toStrictEqual(4) | ||
expect(next.hasNext).toStrictEqual(true) | ||
expect(next.nextToken).toStrictEqual(next[3].id) | ||
|
||
const last = await client.paginate(next) | ||
expect(last.length).toStrictEqual(0) | ||
expect(last.hasNext).toStrictEqual(false) | ||
expect(last.nextToken).toStrictEqual(undefined) | ||
}) | ||
}) | ||
|
||
describe('get', () => { | ||
it('should get masternode', async () => { | ||
// get a masternode from list | ||
const masternode = (await client.masternodes.list(1))[0] | ||
|
||
const data = await client.masternodes.get(masternode.id) | ||
expect(Object.keys(data).length).toStrictEqual(7) | ||
expect(data).toStrictEqual({ | ||
id: masternode.id, | ||
state: masternode.state, | ||
mintedBlocks: masternode.mintedBlocks, | ||
owner: { address: masternode.owner.address }, | ||
operator: { address: masternode.operator.address }, | ||
creation: { height: masternode.creation.height }, | ||
resign: { | ||
tx: masternode.resign.tx, | ||
height: masternode.resign.height | ||
} | ||
}) | ||
}) | ||
|
||
it('should fail due to non-existent masternode', async () => { | ||
expect.assertions(2) | ||
const id = '8d4d987dee688e400a0cdc899386f243250d3656d802231755ab4d28178c9816' | ||
try { | ||
await client.masternodes.get(id) | ||
} catch (err) { | ||
expect(err).toBeInstanceOf(WhaleApiException) | ||
expect(err.error).toStrictEqual({ | ||
code: 404, | ||
type: 'NotFound', | ||
at: expect.any(Number), | ||
message: 'Unable to find masternode', | ||
url: `/v0/regtest/masternodes/${id}` | ||
}) | ||
} | ||
}) | ||
|
||
it('should fail and throw an error with malformed id', async () => { | ||
expect.assertions(2) | ||
try { | ||
await client.masternodes.get('sdh183') | ||
} catch (err) { | ||
expect(err).toBeInstanceOf(WhaleApiException) | ||
expect(err.error).toStrictEqual({ | ||
code: 400, | ||
type: 'BadRequest', | ||
at: expect.any(Number), | ||
message: "RpcApiError: 'masternode id must be of length 64 (not 6, for 'sdh183')', code: -8, method: getmasternode", | ||
url: '/v0/regtest/masternodes/sdh183' | ||
}) | ||
} | ||
}) | ||
}) |
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,66 @@ | ||
import { WhaleApiClient } from '../whale.api.client' | ||
import { ApiPagedResponse } from '../whale.api.response' | ||
|
||
/** | ||
* DeFi whale endpoint for masternode related services. | ||
*/ | ||
export class Masternodes { | ||
constructor (private readonly client: WhaleApiClient) { | ||
} | ||
|
||
/** | ||
* Get list of masternodes. | ||
* | ||
* @param {number} size masternodes size to query | ||
* @param {string} next set of masternodes to get | ||
* @return {Promise<ApiPagedResponse<MasternodeData>>} | ||
*/ | ||
async list (size: number = 30, next?: string): Promise<ApiPagedResponse<MasternodeData>> { | ||
return await this.client.requestList('GET', 'masternodes', size, next) | ||
} | ||
|
||
/** | ||
* Get information about a masternode with given id. | ||
* | ||
* @param {string} id masternode id to get | ||
* @return {Promise<MasternodeData>} | ||
*/ | ||
async get (id: string): Promise<MasternodeData> { | ||
return await this.client.requestData('GET', `masternodes/${id}`) | ||
} | ||
} | ||
|
||
/** | ||
* Masternode data | ||
*/ | ||
export interface MasternodeData { | ||
id: string | ||
state: MasternodeState | ||
mintedBlocks: number | ||
owner: { | ||
address: string | ||
} | ||
operator: { | ||
address: string | ||
} | ||
creation: { | ||
height: number | ||
} | ||
resign: { | ||
tx: string | ||
height: number | ||
} | ||
} | ||
|
||
/** | ||
* Masternode state | ||
*/ | ||
export enum MasternodeState { | ||
PRE_ENABLED = 'PRE_ENABLED', | ||
ENABLED = 'ENABLED', | ||
PRE_RESIGNED = 'PRE_RESIGNED', | ||
RESIGNED = 'RESIGNED', | ||
PRE_BANNED = 'PRE_BANNED', | ||
BANNED = 'BANNED', | ||
UNKNOWN = 'UNKNOWN' | ||
} |
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
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,73 @@ | ||
import { MasterNodeRegTestContainer } from '@defichain/testcontainers' | ||
import { NestFastifyApplication } from '@nestjs/platform-fastify' | ||
import { createTestingApp, stopTestingApp } from '@src/e2e.module' | ||
import { NotFoundException } from '@nestjs/common' | ||
import { MasternodesController } from '@src/module.api/masternode.controller' | ||
|
||
const container = new MasterNodeRegTestContainer() | ||
let app: NestFastifyApplication | ||
let controller: MasternodesController | ||
|
||
beforeAll(async () => { | ||
await container.start() | ||
await container.waitForReady() | ||
|
||
app = await createTestingApp(container) | ||
controller = app.get(MasternodesController) | ||
}) | ||
|
||
afterAll(async () => { | ||
await stopTestingApp(container, app) | ||
}) | ||
|
||
describe('list', () => { | ||
it('should list masternodes', async () => { | ||
const result = await controller.list({ size: 4 }) | ||
expect(result.data.length).toStrictEqual(4) | ||
expect(Object.keys(result.data[0]).length).toStrictEqual(7) | ||
}) | ||
|
||
it('should list masternodes with pagination', async () => { | ||
const first = await controller.list({ size: 4 }) | ||
expect(first.data.length).toStrictEqual(4) | ||
|
||
const next = await controller.list({ | ||
size: 4, | ||
next: first.page?.next | ||
}) | ||
expect(next.data.length).toStrictEqual(4) | ||
expect(next.page?.next).toStrictEqual(next.data[3].id) | ||
|
||
const last = await controller.list({ | ||
size: 4, | ||
next: next.page?.next | ||
}) | ||
expect(last.data.length).toStrictEqual(0) | ||
expect(last.page).toStrictEqual(undefined) | ||
}) | ||
}) | ||
|
||
describe('get', () => { | ||
it('should get a masternode with id', async () => { | ||
// get a masternode from list | ||
const masternode = (await controller.list({ size: 1 })).data[0] | ||
|
||
const result = await controller.get(masternode.id) | ||
expect(Object.keys(result).length).toStrictEqual(7) | ||
expect(result).toStrictEqual(masternode) | ||
}) | ||
|
||
it('should fail due to non-existent masternode', async () => { | ||
expect.assertions(2) | ||
try { | ||
await controller.get('8d4d987dee688e400a0cdc899386f243250d3656d802231755ab4d28178c9816') | ||
} catch (err) { | ||
expect(err).toBeInstanceOf(NotFoundException) | ||
expect(err.response).toStrictEqual({ | ||
statusCode: 404, | ||
message: 'Unable to find masternode', | ||
error: 'Not Found' | ||
}) | ||
} | ||
}) | ||
}) |
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,84 @@ | ||
import { Test, TestingModule } from '@nestjs/testing' | ||
import { MasterNodeRegTestContainer } from '@defichain/testcontainers' | ||
import { JsonRpcClient } from '@defichain/jellyfish-api-jsonrpc' | ||
import { MasternodesController } from '@src/module.api/masternode.controller' | ||
import { CacheModule, NotFoundException } from '@nestjs/common' | ||
import { DeFiDCache } from './cache/defid.cache' | ||
|
||
const container = new MasterNodeRegTestContainer() | ||
let controller: MasternodesController | ||
|
||
beforeAll(async () => { | ||
await container.start() | ||
await container.waitForReady() | ||
const client = new JsonRpcClient(await container.getCachedRpcUrl()) | ||
|
||
const app: TestingModule = await Test.createTestingModule({ | ||
imports: [ | ||
CacheModule.register() | ||
], | ||
controllers: [MasternodesController], | ||
providers: [ | ||
{ provide: JsonRpcClient, useValue: client }, | ||
DeFiDCache | ||
] | ||
}).compile() | ||
|
||
controller = app.get(MasternodesController) | ||
}) | ||
|
||
afterAll(async () => { | ||
await container.stop() | ||
}) | ||
|
||
describe('list', () => { | ||
it('should list masternodes', async () => { | ||
const result = await controller.list({ size: 4 }) | ||
expect(result.data.length).toStrictEqual(4) | ||
expect(Object.keys(result.data[0]).length).toStrictEqual(7) | ||
}) | ||
|
||
it('should list masternodes with pagination', async () => { | ||
const first = await controller.list({ size: 4 }) | ||
expect(first.data.length).toStrictEqual(4) | ||
|
||
const next = await controller.list({ | ||
size: 4, | ||
next: first.page?.next | ||
}) | ||
expect(next.data.length).toStrictEqual(4) | ||
expect(next.page?.next).toStrictEqual(next.data[3].id) | ||
|
||
const last = await controller.list({ | ||
size: 4, | ||
next: next.page?.next | ||
}) | ||
expect(last.data.length).toStrictEqual(0) | ||
expect(last.page).toStrictEqual(undefined) | ||
}) | ||
}) | ||
|
||
describe('get', () => { | ||
it('should get a masternode with id', async () => { | ||
// get a masternode from list | ||
const masternode = (await controller.list({ size: 1 })).data[0] | ||
|
||
const result = await controller.get(masternode.id) | ||
expect(Object.keys(result).length).toStrictEqual(7) | ||
expect(result).toStrictEqual(masternode) | ||
}) | ||
|
||
it('should fail due to non-existent masternode', async () => { | ||
expect.assertions(2) | ||
try { | ||
await controller.get('8d4d987dee688e400a0cdc899386f243250d3656d802231755ab4d28178c9816') | ||
} catch (err) { | ||
expect(err).toBeInstanceOf(NotFoundException) | ||
expect(err.response).toStrictEqual({ | ||
statusCode: 404, | ||
message: 'Unable to find masternode', | ||
error: 'Not Found' | ||
}) | ||
} | ||
}) | ||
}) |
Oops, something went wrong.