Skip to content

Commit

Permalink
feat(core-manager): implement log.archived action (#3714)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastijankuzner authored May 20, 2020
1 parent 36a607a commit 10e8217
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 6 deletions.
43 changes: 43 additions & 0 deletions __tests__/unit/core-manager/actions/log-archived.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import "jest-extended";

import { Container } from "@packages/core-kernel";
import { Action } from "@packages/core-manager/src/actions/log-archived";
import { Sandbox } from "@packages/core-test-framework";

let sandbox: Sandbox;
let action: Action;

const mockFilesystem = {
files: jest
.fn()
.mockResolvedValue([
`${process.env.HOME}/.pm2/logs/ark-core-out.log`,
`${process.env.HOME}/.pm2/logs/ark-core-error.log`,
]),

size: jest.fn().mockResolvedValue(1024),
};

beforeEach(() => {
sandbox = new Sandbox();

sandbox.app.bind(Container.Identifiers.ApplicationVersion).toConstantValue("dummyVersion");
sandbox.app.bind(Container.Identifiers.FilesystemService).toConstantValue(mockFilesystem);

action = sandbox.app.resolve(Action);
});

describe("Info:CoreVersion", () => {
it("should have name", () => {
expect(action.name).toEqual("log.archived");
});

it("should return file info", async () => {
const result = await action.execute({});

expect(result).toBeArray();
expect(result[0].size).toBe(1);
expect(result[0].name).toBeString();
expect(result[0].downloadLink).toBeString();
});
});
85 changes: 85 additions & 0 deletions __tests__/unit/core-manager/server/routes/log-achived.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import "jest-extended";

import { Container } from "@packages/core-kernel";
import { ActionReader } from "@packages/core-manager/src/action-reader";
import { Actions } from "@packages/core-manager/src/contracts";
import { defaults } from "@packages/core-manager/src/defaults";
import { Identifiers } from "@packages/core-manager/src/ioc";
import Handlers from "@packages/core-manager/src/server/handlers";
import { PluginFactory } from "@packages/core-manager/src/server/plugins/plugin-factory";
import { Server } from "@packages/core-manager/src/server/server";
import { Argon2id, SimpleTokenValidator } from "@packages/core-manager/src/server/validators";
import { Sandbox } from "@packages/core-test-framework";

let sandbox: Sandbox;
let server: Server;

const logger = {
info: jest.fn(),
notice: jest.fn(),
error: jest.fn(),
};

let pluginsConfiguration;

const mockFilesystem = {
get: jest.fn().mockResolvedValue(Buffer.from("file_content")),
};

beforeEach(() => {
const actionReader: Partial<ActionReader> = {
discoverActions(): Actions.Method[] {
return [];
},
};

pluginsConfiguration = { ...defaults.plugins };

pluginsConfiguration.basicAuthentication.enabled = false;
pluginsConfiguration.tokenAuthentication.enabled = false;

sandbox = new Sandbox();

sandbox.app.bind(Identifiers.HTTP).to(Server).inSingletonScope();
sandbox.app.bind(Identifiers.ActionReader).toConstantValue(actionReader);
sandbox.app.bind(Identifiers.PluginFactory).to(PluginFactory).inSingletonScope();
sandbox.app.bind(Identifiers.BasicCredentialsValidator).to(Argon2id).inSingletonScope();
sandbox.app.bind(Identifiers.TokenValidator).to(SimpleTokenValidator).inSingletonScope();

sandbox.app.bind(Container.Identifiers.LogService).toConstantValue(logger);
sandbox.app.bind(Container.Identifiers.FilesystemService).toConstantValue(mockFilesystem);
sandbox.app.bind(Container.Identifiers.PluginConfiguration).toConstantValue({
get: jest.fn().mockReturnValue(pluginsConfiguration),
});

sandbox.app.terminate = jest.fn();

server = sandbox.app.get<Server>(Identifiers.HTTP);
});

afterEach(async () => {
await server.dispose();
jest.clearAllMocks();
jest.restoreAllMocks();
});

describe("LogArchived", () => {
it("should be ok", async () => {
await server.initialize("serverName", {});

await server.register({
plugin: Handlers,
});

await server.boot();

const injectOptions = {
method: "GET",
url: "/log/archived/ark-core-out.log",
};

const response = await server.inject(injectOptions);

expect(response.result).toEqual("file_content");
});
});
13 changes: 7 additions & 6 deletions __tests__/unit/core-manager/service-provider.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import "jest-extended";

import { Application, Container, Providers } from "@packages/core-kernel";
import { ServiceProvider } from "@packages/core-manager/src/service-provider";
import { Identifiers } from "@packages/core-manager/src/ioc";
import { defaults } from "@packages/core-manager/src/defaults";
import { Identifiers } from "@packages/core-manager/src/ioc";
import { ServiceProvider } from "@packages/core-manager/src/service-provider";
import path from "path";

let app: Application;
Expand All @@ -26,6 +26,7 @@ beforeEach(() => {

app.bind(Container.Identifiers.LogService).toConstantValue(logger);
app.bind(Container.Identifiers.PluginConfiguration).to(Providers.PluginConfiguration).inSingletonScope();
app.bind(Container.Identifiers.FilesystemService).toConstantValue({});

defaults.server.https.tls.key = path.resolve(__dirname, "./__fixtures__/key.pem");
defaults.server.https.tls.cert = path.resolve(__dirname, "./__fixtures__/server.crt");
Expand All @@ -39,15 +40,15 @@ describe("ServiceProvider", () => {
});

it("should register", async () => {
let usedDefaults = { ...defaults };
const usedDefaults = { ...defaults };

setPluginConfiguration(app, serviceProvider, usedDefaults);

await expect(serviceProvider.register()).toResolve();
});

it("should boot and dispose HTTP server", async () => {
let usedDefaults = { ...defaults };
const usedDefaults = { ...defaults };

usedDefaults.server.http.enabled = true;

Expand All @@ -64,7 +65,7 @@ describe("ServiceProvider", () => {
});

it("should boot and dispose HTTPS server", async () => {
let usedDefaults = { ...defaults };
const usedDefaults = { ...defaults };

usedDefaults.server.http.enabled = false;
usedDefaults.server.https.enabled = "enabled";
Expand All @@ -82,7 +83,7 @@ describe("ServiceProvider", () => {
});

it("should dispose with HTTP and HTTPS server", async () => {
let usedDefaults = { ...defaults };
const usedDefaults = { ...defaults };

usedDefaults.server.http.enabled = true;
usedDefaults.server.https.enabled = "enabled";
Expand Down
29 changes: 29 additions & 0 deletions packages/core-manager/src/actions/log-archived.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Container, Contracts } from "@arkecosystem/core-kernel";
import { basename } from "path";

import { Actions } from "../contracts";

@Container.injectable()
export class Action implements Actions.Action {
public name = "log.archived";

@Container.inject(Container.Identifiers.FilesystemService)
private readonly filesystem!: Contracts.Kernel.Filesystem;

public async execute(params: object): Promise<any> {
return Promise.all((await this.getArchivedLogs()).map((x) => this.getArchiveInfo(x)));
}

private async getArchiveInfo(path: string): Promise<any> {
return {
name: basename(path),
size: Math.round((await this.filesystem.size(path)) / 1024),
downloadLink: `/log/archived/${basename(path)}`,
};
}

private async getArchivedLogs(): Promise<string[]> {
const logsPath = `${process.env.HOME}/.pm2/logs`;
return this.filesystem.files(logsPath);
}
}
21 changes: 21 additions & 0 deletions packages/core-manager/src/server/controllers/log-archived.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Container, Contracts } from "@arkecosystem/core-kernel";
import Hapi from "@hapi/hapi";
import { join } from "path";

@Container.injectable()
export class LogArchivedController {
@Container.inject(Container.Identifiers.FilesystemService)
private readonly filesystem!: Contracts.Kernel.Filesystem;

public async file(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const logsPath = `${process.env.HOME}/.pm2/logs`;
const fileName = request.params.id;

const file = await this.filesystem.get(join(logsPath, fileName));

return h
.response(file)
.header("Content-Type", "text/plain")
.header("Content-Disposition", "attachment; filename= " + fileName);
}
}
15 changes: 15 additions & 0 deletions packages/core-manager/src/server/handlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Hapi from "@hapi/hapi";

import * as LogArchived from "./routes/log-archived";

export = {
async register(server: Hapi.Server): Promise<void> {
const handlers = [LogArchived];

for (const handler of handlers) {
handler.register(server);
}
},
name: "Manager API",
version: "1.0.0",
};
22 changes: 22 additions & 0 deletions packages/core-manager/src/server/routes/log-archived.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Hapi from "@hapi/hapi";
import Joi from "@hapi/joi";

import { LogArchivedController } from "../controllers/log-archived";

export const register = (server: Hapi.Server): void => {
const controller = server.app.app.resolve(LogArchivedController);
server.bind(controller);

server.route({
method: "GET",
path: "/log/archived/{id}",
handler: controller.file,
options: {
validate: {
params: Joi.object({
id: Joi.string().required(),
}),
},
},
});
};
5 changes: 5 additions & 0 deletions packages/core-manager/src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@ export class Server {
public async initialize(name: string, serverOptions: Types.JsonObject): Promise<void> {
this.name = name;
this.server = new HapiServer(this.getServerOptions(serverOptions));
this.server.app.app = this.app;

await this.server.register(this.pluginFactory.preparePlugins());
}

public async register(plugins: any | any[]): Promise<void> {
return this.server.register(plugins);
}

public async inject(options: string | ServerInjectOptions): Promise<ServerInjectResponse> {
return this.server.inject(options);
}
Expand Down
5 changes: 5 additions & 0 deletions packages/core-manager/src/service-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Identifiers } from "./ioc";
import { PluginFactory } from "./server/plugins";
import { Server } from "./server/server";
import { Argon2id, SimpleTokenValidator } from "./server/validators";
import Handlers from "./server/handlers";

export class ServiceProvider extends Providers.ServiceProvider {
public async register(): Promise<void> {
Expand Down Expand Up @@ -67,5 +68,9 @@ export class ServiceProvider extends Providers.ServiceProvider {
},
},
});

await server.register({
plugin: Handlers,
});
}
}

0 comments on commit 10e8217

Please sign in to comment.