Skip to content

Commit

Permalink
[Canvas] Migrate Shareable Routes to NP (#56053)
Browse files Browse the repository at this point in the history
* Migrated shareables routes to NP

* Added tests
  • Loading branch information
cqliu1 authored Jan 31, 2020
1 parent c2a6e75 commit 8d54fa8
Show file tree
Hide file tree
Showing 11 changed files with 298 additions and 89 deletions.
3 changes: 0 additions & 3 deletions x-pack/legacy/plugins/canvas/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@
*/

import { CoreSetup, PluginsSetup } from './shim';
import { routes } from './routes';
import { functions } from '../canvas_plugin_src/functions/server';
import { loadSampleData } from './sample_data';

export class Plugin {
public setup(core: CoreSetup, plugins: PluginsSetup) {
routes(core);

plugins.interpreter.register({ serverFunctions: functions });

core.injectUiAppVars('canvas', async () => {
Expand Down
12 changes: 0 additions & 12 deletions x-pack/legacy/plugins/canvas/server/routes/index.ts

This file was deleted.

72 changes: 0 additions & 72 deletions x-pack/legacy/plugins/canvas/server/routes/shareables.ts

This file was deleted.

6 changes: 4 additions & 2 deletions x-pack/plugins/canvas/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
*/

import { IRouter, Logger } from 'src/core/server';
import { initWorkpadRoutes } from './workpad';
import { initCustomElementsRoutes } from './custom_elements';
import { initESFieldsRoutes } from './es_fields';
import { initShareablesRoutes } from './shareables';
import { initWorkpadRoutes } from './workpad';

export interface RouteInitializerDeps {
router: IRouter;
logger: Logger;
}

export function initRoutes(deps: RouteInitializerDeps) {
initWorkpadRoutes(deps);
initCustomElementsRoutes(deps);
initESFieldsRoutes(deps);
initShareablesRoutes(deps);
initWorkpadRoutes(deps);
}
55 changes: 55 additions & 0 deletions x-pack/plugins/canvas/server/routes/shareables/download.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

jest.mock('fs');

import fs from 'fs';
import {
IRouter,
kibanaResponseFactory,
RequestHandlerContext,
RequestHandler,
} from 'src/core/server';
import { httpServiceMock, httpServerMock, loggingServiceMock } from 'src/core/server/mocks';
import { initializeDownloadShareableWorkpadRoute } from './download';

const mockRouteContext = {} as RequestHandlerContext;
const path = `api/canvas/workpad/find`;
const mockRuntime = 'Canvas shareable runtime';

describe('Download Canvas shareables runtime', () => {
let routeHandler: RequestHandler<any, any, any>;

beforeEach(() => {
const httpService = httpServiceMock.createSetupContract();
const router = httpService.createRouter('') as jest.Mocked<IRouter>;
initializeDownloadShareableWorkpadRoute({
router,
logger: loggingServiceMock.create().get(),
});

routeHandler = router.get.mock.calls[0][1];
});

afterAll(() => {
jest.restoreAllMocks();
});

it(`returns 200 with canvas shareables runtime`, async () => {
const request = httpServerMock.createKibanaRequest({
method: 'get',
path,
});

const readFileSyncMock = fs.readFileSync as jest.Mock;
readFileSyncMock.mockReturnValueOnce(mockRuntime);

const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory);

expect(response.status).toBe(200);
expect(response.payload).toMatchInlineSnapshot(`"Canvas shareable runtime"`);
});
});
33 changes: 33 additions & 0 deletions x-pack/plugins/canvas/server/routes/shareables/download.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { readFileSync } from 'fs';
import { SHAREABLE_RUNTIME_FILE } from '../../../../../legacy/plugins/canvas/shareable_runtime/constants';
import { RouteInitializerDeps } from '../';
import { API_ROUTE_SHAREABLE_RUNTIME_DOWNLOAD } from '../../../../../legacy/plugins/canvas/common/lib/constants';

export function initializeDownloadShareableWorkpadRoute(deps: RouteInitializerDeps) {
const { router } = deps;
router.get(
{
path: API_ROUTE_SHAREABLE_RUNTIME_DOWNLOAD,
validate: false,
},
async (_context, _request, response) => {
// TODO: check if this is still an issue on cloud after migrating to NP
//
// The option setting is not for typical use. We're using it here to avoid
// problems in Cloud environments. See elastic/kibana#47405.
// @ts-ignore No type for inert Hapi handler
// const file = handler.file(SHAREABLE_RUNTIME_FILE, { confine: false });
const file = readFileSync(SHAREABLE_RUNTIME_FILE);
return response.ok({
headers: { 'content-type': 'application/octet-stream' },
body: file,
});
}
);
}
14 changes: 14 additions & 0 deletions x-pack/plugins/canvas/server/routes/shareables/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { RouteInitializerDeps } from '../';
import { initializeZipShareableWorkpadRoute } from './zip';
import { initializeDownloadShareableWorkpadRoute } from './download';

export function initShareablesRoutes(deps: RouteInitializerDeps) {
initializeDownloadShareableWorkpadRoute(deps);
initializeZipShareableWorkpadRoute(deps);
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { schema } from '@kbn/config-schema';

export const PositionSchema = schema.object({
angle: schema.number(),
height: schema.number(),
left: schema.number(),
parent: schema.nullable(schema.string()),
top: schema.number(),
width: schema.number(),
});

export const ContainerStyleSchema = schema.object({
type: schema.maybe(schema.string()),
border: schema.maybe(schema.string()),
borderRadius: schema.maybe(schema.string()),
padding: schema.maybe(schema.string()),
backgroundColor: schema.maybe(schema.string()),
backgroundImage: schema.maybe(schema.string()),
backgroundSize: schema.maybe(schema.string()),
backgroundRepeat: schema.maybe(schema.string()),
opacity: schema.maybe(schema.number()),
overflow: schema.maybe(schema.string()),
});

export const RenderableSchema = schema.object({
error: schema.nullable(schema.string()),
state: schema.string(),
value: schema.object({
as: schema.string(),
containerStyle: ContainerStyleSchema,
css: schema.maybe(schema.string()),
type: schema.string(),
value: schema.any(),
}),
});

export const RenderedWorkpadElementSchema = schema.object({
expressionRenderable: RenderableSchema,
id: schema.string(),
position: PositionSchema,
});

export const RenderedWorkpadPageSchema = schema.object({
id: schema.string(),
elements: schema.arrayOf(RenderedWorkpadElementSchema),
groups: schema.maybe(schema.arrayOf(schema.arrayOf(RenderedWorkpadElementSchema))),
style: schema.recordOf(schema.string(), schema.string()),
transition: schema.maybe(
schema.oneOf([
schema.object({}),
schema.object({
name: schema.string(),
}),
])
),
});

export const RenderedWorkpadSchema = schema.object({
'@created': schema.maybe(schema.string()),
'@timestamp': schema.maybe(schema.string()),
assets: schema.maybe(schema.recordOf(schema.string(), RenderedWorkpadPageSchema)),
colors: schema.arrayOf(schema.string()),
css: schema.string(),
height: schema.number(),
id: schema.string(),
isWriteable: schema.maybe(schema.boolean()),
name: schema.string(),
page: schema.number(),
pages: schema.arrayOf(RenderedWorkpadPageSchema),
width: schema.number(),
});
78 changes: 78 additions & 0 deletions x-pack/plugins/canvas/server/routes/shareables/zip.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

jest.mock('archiver');

const archiver = require('archiver') as jest.Mock;
import {
IRouter,
kibanaResponseFactory,
RequestHandlerContext,
RequestHandler,
} from 'src/core/server';
import { httpServiceMock, httpServerMock, loggingServiceMock } from 'src/core/server/mocks';
import { initializeZipShareableWorkpadRoute } from './zip';
import { API_ROUTE_SHAREABLE_ZIP } from '../../../../../legacy/plugins/canvas/common/lib';
import {
SHAREABLE_RUNTIME_FILE,
SHAREABLE_RUNTIME_SRC,
SHAREABLE_RUNTIME_NAME,
} from '../../../../../legacy/plugins/canvas/shareable_runtime/constants';

const mockRouteContext = {} as RequestHandlerContext;
const mockWorkpad = {};
const routePath = API_ROUTE_SHAREABLE_ZIP;

describe('Zips Canvas shareables runtime together with workpad', () => {
let routeHandler: RequestHandler<any, any, any>;

beforeEach(() => {
const httpService = httpServiceMock.createSetupContract();
const router = httpService.createRouter('') as jest.Mocked<IRouter>;
initializeZipShareableWorkpadRoute({
router,
logger: loggingServiceMock.create().get(),
});

routeHandler = router.post.mock.calls[0][1];
});

afterAll(() => {
jest.restoreAllMocks();
});

it(`returns 200 with zip file with runtime and workpad`, async () => {
const request = httpServerMock.createKibanaRequest({
method: 'get',
path: routePath,
body: mockWorkpad,
});

const mockArchive = {
append: jest.fn(),
file: jest.fn(),
finalize: jest.fn(),
};

archiver.mockReturnValueOnce(mockArchive);

const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory);

expect(response.status).toBe(200);
expect(response.payload).toBe(mockArchive);
expect(mockArchive.append).toHaveBeenCalledWith(JSON.stringify(mockWorkpad), {
name: 'workpad.json',
});
expect(mockArchive.file).toHaveBeenCalledTimes(2);
expect(mockArchive.file).nthCalledWith(1, `${SHAREABLE_RUNTIME_SRC}/template.html`, {
name: 'index.html',
});
expect(mockArchive.file).nthCalledWith(2, SHAREABLE_RUNTIME_FILE, {
name: `${SHAREABLE_RUNTIME_NAME}.js`,
});
expect(mockArchive.finalize).toBeCalled();
});
});
Loading

0 comments on commit 8d54fa8

Please sign in to comment.