diff --git a/x-pack/plugins/canvas/server/routes/shareables/download.test.ts b/x-pack/plugins/canvas/server/routes/shareables/download.test.ts new file mode 100644 index 0000000000000..be4765217d7aa --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/shareables/download.test.ts @@ -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; + + beforeEach(() => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + 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"`); + }); +}); diff --git a/x-pack/plugins/canvas/server/routes/shareables/download.ts b/x-pack/plugins/canvas/server/routes/shareables/download.ts index 9d4a06c2e351b..08bec1e4881ae 100644 --- a/x-pack/plugins/canvas/server/routes/shareables/download.ts +++ b/x-pack/plugins/canvas/server/routes/shareables/download.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import fs from 'fs'; +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'; @@ -16,12 +16,14 @@ export function initializeDownloadShareableWorkpadRoute(deps: RouteInitializerDe path: API_ROUTE_SHAREABLE_RUNTIME_DOWNLOAD, validate: false, }, - async (context, request, response) => { + 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 = fs.readFileSync(SHAREABLE_RUNTIME_FILE); + const file = readFileSync(SHAREABLE_RUNTIME_FILE); return response.ok({ headers: { 'content-type': 'application/octet-stream' }, body: file, diff --git a/x-pack/plugins/canvas/server/routes/shareables/mock_shareable_workpad.json b/x-pack/plugins/canvas/server/routes/shareables/mock_shareable_workpad.json new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/x-pack/plugins/canvas/server/routes/shareables/zip.test.ts b/x-pack/plugins/canvas/server/routes/shareables/zip.test.ts new file mode 100644 index 0000000000000..edb59694a7400 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/shareables/zip.test.ts @@ -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; + + beforeEach(() => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + 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(); + }); +}); diff --git a/x-pack/plugins/canvas/server/routes/shareables/zip.ts b/x-pack/plugins/canvas/server/routes/shareables/zip.ts index cc83f663aa97a..e25b96cce96ff 100644 --- a/x-pack/plugins/canvas/server/routes/shareables/zip.ts +++ b/x-pack/plugins/canvas/server/routes/shareables/zip.ts @@ -21,7 +21,7 @@ export function initializeZipShareableWorkpadRoute(deps: RouteInitializerDeps) { path: API_ROUTE_SHAREABLE_ZIP, validate: { body: RenderedWorkpadSchema }, }, - async (context, request, response) => { + async (_context, request, response) => { const workpad = request.body; const archive = archiver('zip'); archive.append(JSON.stringify(workpad), { name: 'workpad.json' });