Skip to content

Commit

Permalink
chore(core-forger): implements service provider schema (#4282)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastijankuzner authored Jan 26, 2021
1 parent 6d86afc commit 39caa0b
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 2 deletions.
154 changes: 152 additions & 2 deletions __tests__/unit/core-forger/service-provider.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { ServiceProvider } from "@packages/core-forger/src/service-provider";
import "jest-extended";

import { AnySchema } from "@hapi/joi";
import { DelegateFactory } from "@packages/core-forger/src/delegate-factory";
import { Container, Application, Providers } from "@packages/core-kernel";
import { ServiceProvider } from "@packages/core-forger/src/service-provider";
import { Application, Container, Providers } from "@packages/core-kernel";
import { Pm2ProcessActionsService } from "@packages/core-kernel/src/services/process-actions/drivers/pm2";

describe("ServiceProvider", () => {
Expand Down Expand Up @@ -132,4 +135,151 @@ describe("ServiceProvider", () => {
expect(bootWhenResultSecrets).toBeTrue();
});
});

describe("configSchema", () => {
beforeEach(() => {
serviceProvider = app.resolve<ServiceProvider>(ServiceProvider);

for (const key of Object.keys(process.env)) {
if (key === "CORE_P2P_PORT") {
delete process.env[key];
}
}
});

it("should validate schema using defaults", async () => {
jest.resetModules();
const result = (serviceProvider.configSchema() as AnySchema).validate(
(await import("@packages/core-forger/src/defaults")).defaults,
);

expect(result.error).toBeUndefined();

expect(result.value.hosts).toBeArray();
expect(result.value.hosts.length).toBeGreaterThanOrEqual(1);
result.value.hosts.forEach((item) => {
expect(item.hostname).toBeString();
expect(item.port).toBeNumber();
});

expect(result.value.tracker).toBeBoolean();

expect(result.value.bip38).toBeUndefined();
expect(result.value.password).toBeUndefined();
});

describe("process.env.CORE_P2P_PORT", () => {
it("should parse process.env.CORE_API_PORT", async () => {
process.env.CORE_P2P_PORT = "5000";

jest.resetModules();
const result = (serviceProvider.configSchema() as AnySchema).validate(
(await import("@packages/core-forger/src/defaults")).defaults,
);

expect(result.error).toBeUndefined();
expect(result.value.hosts[0].port).toEqual(5000);
});

it("should throw if process.env.CORE_API_PORT is not number", async () => {
process.env.CORE_P2P_PORT = "false";

jest.resetModules();
const result = (serviceProvider.configSchema() as AnySchema).validate(
(await import("@packages/core-forger/src/defaults")).defaults,
);

expect(result.error).toBeDefined();
expect(result.error!.message).toEqual('"hosts[0].port" must be a number');
});
});

describe("schema restrictions", () => {
let defaults;

beforeEach(async () => {
jest.resetModules();
defaults = (await import("@packages/core-forger/src/defaults")).defaults;
});

it("hosts is required && must be array", async () => {
defaults.hosts = false;
let result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual('"hosts" must be an array');

delete defaults.hosts;
result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual('"hosts" is required');
});

it("hosts.hostname is required && is ipv4 or ipv6 string", async () => {
defaults.hosts = [{ hostname: false }];
let result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual('"hosts[0].hostname" must be a string');

defaults.hosts = [{ hostname: "not an IP" }];
result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual(
'"hosts[0].hostname" must be a valid ip address of one of the following versions [ipv4, ipv6] with a optional CIDR',
);

defaults.hosts = [{}];
result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual('"hosts[0].hostname" is required');
});

it("hosts.port is required && is number", async () => {
defaults.hosts = [{ hostname: "127.0.0.1", port: false }];
let result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual('"hosts[0].port" must be a number');

defaults.hosts = [{ hostname: "127.0.0.1" }];
result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual('"hosts[0].port" is required');
});

it("tracker is required && is boolean", async () => {
defaults.tracker = 123;
let result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual('"tracker" must be a boolean');

delete defaults.tracker;
result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual('"tracker" is required');
});

it("bip38 is optional && is string", async () => {
defaults.bip38 = false;
let result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual('"bip38" must be a string');

delete defaults.bip38;
result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error).toBeUndefined();
});

it("password is optional && is string", async () => {
defaults.password = false;
let result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error!.message).toEqual('"password" must be a string');

delete defaults.password;
result = (serviceProvider.configSchema() as AnySchema).validate(defaults);

expect(result.error).toBeUndefined();
});
});
});
});
1 change: 1 addition & 0 deletions packages/core-forger/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@arkecosystem/core-p2p": "^3.0.0-next.20",
"@arkecosystem/crypto": "^3.0.0-next.20",
"@hapi/hapi": "^20.0.3",
"joi": "^17.3.0",
"node-forge": "^0.9.1",
"otplib": "^12.0.0",
"wif": "^2.0.6"
Expand Down
21 changes: 21 additions & 0 deletions packages/core-forger/src/service-provider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Container, Contracts, Enums, Providers, Services } from "@arkecosystem/core-kernel";
import Joi from "joi";

import { ForgeNewBlockAction, IsForgingAllowedAction } from "./actions";
import { DelegateFactory } from "./delegate-factory";
Expand Down Expand Up @@ -65,6 +66,26 @@ export class ServiceProvider extends Providers.ServiceProvider {
return true;
}

public configSchema(): object {
return Joi.object({
hosts: Joi.array()
.items(
Joi.object({
hostname: Joi.string()
.ip({
version: ["ipv4", "ipv6"],
})
.required(),
port: Joi.number().required(),
}),
)
.required(),
tracker: Joi.bool().required(),
bip38: Joi.string(),
password: Joi.string(),
});
}

private registerActions(): void {
this.app
.get<Services.Triggers.Triggers>(Container.Identifiers.TriggerService)
Expand Down

0 comments on commit 39caa0b

Please sign in to comment.