mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
parent
7930a3f045
commit
5d59537338
2 changed files with 567 additions and 47 deletions
|
@ -63,29 +63,10 @@ export function workpad(server) {
|
|||
);
|
||||
}
|
||||
|
||||
function updateWorkpad(req) {
|
||||
const savedObjectsClient = req.getSavedObjectsClient();
|
||||
const { id } = req.params;
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
return savedObjectsClient.get(CANVAS_TYPE, id).then(workpad => {
|
||||
// TODO: Using create with force over-write because of version conflict issues with update
|
||||
return savedObjectsClient.create(
|
||||
CANVAS_TYPE,
|
||||
{
|
||||
...req.payload,
|
||||
'@timestamp': now,
|
||||
'@created': workpad.attributes['@created'],
|
||||
},
|
||||
{ overwrite: true, id }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function updateWorkpadAssets(req) {
|
||||
function updateWorkpad(req, newPayload) {
|
||||
const savedObjectsClient = req.getSavedObjectsClient();
|
||||
const { id } = req.params;
|
||||
const payload = newPayload ? newPayload : req.payload;
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
|
@ -95,30 +76,9 @@ export function workpad(server) {
|
|||
CANVAS_TYPE,
|
||||
{
|
||||
...workpad.attributes,
|
||||
assets: req.payload,
|
||||
'@timestamp': now,
|
||||
'@created': workpad.attributes['@created'],
|
||||
},
|
||||
{ overwrite: true, id }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function updateWorkpadStructures(req) {
|
||||
const savedObjectsClient = req.getSavedObjectsClient();
|
||||
const { id } = req.params;
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
return savedObjectsClient.get(CANVAS_TYPE, id).then(workpad => {
|
||||
// TODO: Using create with force over-write because of version conflict issues with update
|
||||
return savedObjectsClient.create(
|
||||
CANVAS_TYPE,
|
||||
{
|
||||
...workpad.attributes, // retain preexisting assets and prop order (or maybe better to call out the `assets` prop?)
|
||||
...req.payload,
|
||||
'@timestamp': now,
|
||||
'@created': workpad.attributes['@created'],
|
||||
...payload,
|
||||
'@timestamp': now, // always update the modified time
|
||||
'@created': workpad.attributes['@created'], // ensure created is not modified
|
||||
},
|
||||
{ overwrite: true, id }
|
||||
);
|
||||
|
@ -194,7 +154,8 @@ export function workpad(server) {
|
|||
path: `${routePrefixAssets}/{id}`,
|
||||
config: { payload: { allow: 'application/json', maxBytes: 26214400 } }, // 25MB payload limit
|
||||
handler: function(request) {
|
||||
return updateWorkpadAssets(request)
|
||||
const payload = { assets: request.payload };
|
||||
return updateWorkpad(request, payload)
|
||||
.then(() => ({ ok: true }))
|
||||
.catch(formatResponse);
|
||||
},
|
||||
|
@ -206,7 +167,7 @@ export function workpad(server) {
|
|||
path: `${routePrefixStructures}/{id}`,
|
||||
config: { payload: { allow: 'application/json', maxBytes: 26214400 } }, // 25MB payload limit
|
||||
handler: function(request) {
|
||||
return updateWorkpadStructures(request)
|
||||
return updateWorkpad(request)
|
||||
.then(() => ({ ok: true }))
|
||||
.catch(formatResponse);
|
||||
},
|
||||
|
|
559
x-pack/plugins/canvas/server/routes/workpad.test.js
Normal file
559
x-pack/plugins/canvas/server/routes/workpad.test.js
Normal file
|
@ -0,0 +1,559 @@
|
|||
/*
|
||||
* 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 Hapi from 'hapi';
|
||||
import {
|
||||
CANVAS_TYPE,
|
||||
API_ROUTE_WORKPAD,
|
||||
API_ROUTE_WORKPAD_ASSETS,
|
||||
API_ROUTE_WORKPAD_STRUCTURES,
|
||||
} from '../../common/lib/constants';
|
||||
import { workpad } from './workpad';
|
||||
|
||||
const routePrefix = API_ROUTE_WORKPAD;
|
||||
const routePrefixAssets = API_ROUTE_WORKPAD_ASSETS;
|
||||
const routePrefixStructures = API_ROUTE_WORKPAD_STRUCTURES;
|
||||
|
||||
jest.mock('uuid/v4', () => jest.fn().mockReturnValue('123abc'));
|
||||
|
||||
describe(`${CANVAS_TYPE} API`, () => {
|
||||
const savedObjectsClient = {
|
||||
get: jest.fn(),
|
||||
create: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
find: jest.fn(),
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
savedObjectsClient.get.mockReset();
|
||||
savedObjectsClient.create.mockReset();
|
||||
savedObjectsClient.delete.mockReset();
|
||||
savedObjectsClient.find.mockReset();
|
||||
});
|
||||
|
||||
// Mock toISOString function of all Date types
|
||||
global.Date = class Date extends global.Date {
|
||||
toISOString() {
|
||||
return '2019-02-12T21:01:22.479Z';
|
||||
}
|
||||
};
|
||||
|
||||
// Setup mock server
|
||||
const mockServer = new Hapi.Server({ debug: false, port: 0 });
|
||||
mockServer.plugins = {
|
||||
elasticsearch: {
|
||||
getCluster: () => ({
|
||||
errors: {
|
||||
// formatResponse will fail without objects here
|
||||
'400': Error,
|
||||
'401': Error,
|
||||
'403': Error,
|
||||
'404': Error,
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
mockServer.ext('onRequest', (req, h) => {
|
||||
req.getSavedObjectsClient = () => savedObjectsClient;
|
||||
return h.continue;
|
||||
});
|
||||
workpad(mockServer);
|
||||
|
||||
describe(`GET ${routePrefix}/{id}`, () => {
|
||||
test('returns successful response', async () => {
|
||||
const request = {
|
||||
method: 'GET',
|
||||
url: `${routePrefix}/123`,
|
||||
};
|
||||
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
id: '123',
|
||||
attributes: { foo: true, id: '123' },
|
||||
});
|
||||
|
||||
const { payload, statusCode } = await mockServer.inject(request);
|
||||
const response = JSON.parse(payload);
|
||||
|
||||
expect(statusCode).toBe(200);
|
||||
expect(response).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"foo": true,
|
||||
"id": "123",
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.get).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"canvas-workpad",
|
||||
"123",
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`POST ${routePrefix}`, () => {
|
||||
test('returns successful response without id in payload', async () => {
|
||||
const request = {
|
||||
method: 'POST',
|
||||
url: routePrefix,
|
||||
payload: {
|
||||
foo: true,
|
||||
},
|
||||
};
|
||||
|
||||
savedObjectsClient.create.mockResolvedValueOnce({});
|
||||
|
||||
const { payload, statusCode } = await mockServer.inject(request);
|
||||
const response = JSON.parse(payload);
|
||||
|
||||
expect(statusCode).toBe(200);
|
||||
expect(response).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ok": true,
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.create).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"canvas-workpad",
|
||||
Object {
|
||||
"@created": "2019-02-12T21:01:22.479Z",
|
||||
"@timestamp": "2019-02-12T21:01:22.479Z",
|
||||
"foo": true,
|
||||
},
|
||||
Object {
|
||||
"id": "workpad-123abc",
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('returns successful response with id in payload', async () => {
|
||||
const request = {
|
||||
method: 'POST',
|
||||
url: routePrefix,
|
||||
payload: {
|
||||
id: '123',
|
||||
foo: true,
|
||||
},
|
||||
};
|
||||
|
||||
savedObjectsClient.create.mockResolvedValueOnce({});
|
||||
|
||||
const { payload, statusCode } = await mockServer.inject(request);
|
||||
const response = JSON.parse(payload);
|
||||
|
||||
expect(statusCode).toBe(200);
|
||||
expect(response).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ok": true,
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.create).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"canvas-workpad",
|
||||
Object {
|
||||
"@created": "2019-02-12T21:01:22.479Z",
|
||||
"@timestamp": "2019-02-12T21:01:22.479Z",
|
||||
"foo": true,
|
||||
"id": "123",
|
||||
},
|
||||
Object {
|
||||
"id": "123",
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`PUT ${routePrefix}/{id}`, () => {
|
||||
test('formats successful response', async () => {
|
||||
const request = {
|
||||
method: 'PUT',
|
||||
url: `${routePrefix}/123`,
|
||||
payload: {
|
||||
id: '234',
|
||||
foo: true,
|
||||
},
|
||||
};
|
||||
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
attributes: {
|
||||
'@created': new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
savedObjectsClient.create.mockResolvedValueOnce({});
|
||||
|
||||
const { payload, statusCode } = await mockServer.inject(request);
|
||||
const response = JSON.parse(payload);
|
||||
|
||||
expect(statusCode).toBe(200);
|
||||
expect(response).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ok": true,
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.get).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"canvas-workpad",
|
||||
"123",
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.create).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"canvas-workpad",
|
||||
Object {
|
||||
"@created": "2019-02-12T21:01:22.479Z",
|
||||
"@timestamp": "2019-02-12T21:01:22.479Z",
|
||||
"foo": true,
|
||||
"id": "234",
|
||||
},
|
||||
Object {
|
||||
"id": "123",
|
||||
"overwrite": true,
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`DELETE ${routePrefix}/{id}`, () => {
|
||||
test('formats successful response', async () => {
|
||||
const request = {
|
||||
method: 'DELETE',
|
||||
url: `${routePrefix}/123`,
|
||||
};
|
||||
|
||||
savedObjectsClient.delete.mockResolvedValueOnce({});
|
||||
|
||||
const { payload, statusCode } = await mockServer.inject(request);
|
||||
const response = JSON.parse(payload);
|
||||
|
||||
expect(statusCode).toBe(200);
|
||||
expect(response).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ok": true,
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.delete).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"canvas-workpad",
|
||||
"123",
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`GET ${routePrefix}/find`, () => {
|
||||
test('formats successful response', async () => {
|
||||
const request = {
|
||||
method: 'GET',
|
||||
url: `${routePrefix}/find?name=abc&page=2&perPage=10`,
|
||||
};
|
||||
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
saved_objects: [
|
||||
{
|
||||
id: '123',
|
||||
attributes: {
|
||||
foo: true,
|
||||
id: '123',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { payload, statusCode } = await mockServer.inject(request);
|
||||
const response = JSON.parse(payload);
|
||||
|
||||
expect(statusCode).toBe(200);
|
||||
expect(response).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"workpads": Array [
|
||||
Object {
|
||||
"foo": true,
|
||||
"id": "123",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"fields": Array [
|
||||
"id",
|
||||
"name",
|
||||
"@created",
|
||||
"@timestamp",
|
||||
],
|
||||
"page": "2",
|
||||
"perPage": "10",
|
||||
"search": "abc* | abc",
|
||||
"searchFields": Array [
|
||||
"name",
|
||||
],
|
||||
"sortField": "@timestamp",
|
||||
"sortOrder": "desc",
|
||||
"type": "canvas-workpad",
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`PUT ${routePrefixAssets}/{id}`, () => {
|
||||
test('only updates assets', async () => {
|
||||
const request = {
|
||||
method: 'PUT',
|
||||
url: `${routePrefixAssets}/123`,
|
||||
payload: {
|
||||
'asset-123': {
|
||||
id: 'asset-123',
|
||||
'@created': '2019-02-14T00:00:00.000Z',
|
||||
type: 'dataurl',
|
||||
value: 'mockbase64data',
|
||||
},
|
||||
'asset-456': {
|
||||
id: 'asset-456',
|
||||
'@created': '2019-02-15T00:00:00.000Z',
|
||||
type: 'dataurl',
|
||||
value: 'mockbase64data',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// provide some existing workpad data to check that it's preserved
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
attributes: {
|
||||
'@created': new Date().toISOString(),
|
||||
name: 'fake workpad',
|
||||
},
|
||||
});
|
||||
savedObjectsClient.create.mockResolvedValueOnce({});
|
||||
|
||||
const { payload, statusCode } = await mockServer.inject(request);
|
||||
const response = JSON.parse(payload);
|
||||
|
||||
expect(statusCode).toBe(200);
|
||||
expect(response).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ok": true,
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.get).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"canvas-workpad",
|
||||
"123",
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.create).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"canvas-workpad",
|
||||
Object {
|
||||
"@created": "2019-02-12T21:01:22.479Z",
|
||||
"@timestamp": "2019-02-12T21:01:22.479Z",
|
||||
"assets": Object {
|
||||
"asset-123": Object {
|
||||
"@created": "2019-02-14T00:00:00.000Z",
|
||||
"id": "asset-123",
|
||||
"type": "dataurl",
|
||||
"value": "mockbase64data",
|
||||
},
|
||||
"asset-456": Object {
|
||||
"@created": "2019-02-15T00:00:00.000Z",
|
||||
"id": "asset-456",
|
||||
"type": "dataurl",
|
||||
"value": "mockbase64data",
|
||||
},
|
||||
},
|
||||
"name": "fake workpad",
|
||||
},
|
||||
Object {
|
||||
"id": "123",
|
||||
"overwrite": true,
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`PUT ${routePrefixStructures}/{id}`, () => {
|
||||
test('only updates workpad', async () => {
|
||||
const request = {
|
||||
method: 'PUT',
|
||||
url: `${routePrefixStructures}/123`,
|
||||
payload: {
|
||||
name: 'renamed workpad',
|
||||
css: '.canvasPage { color: LavenderBlush; }',
|
||||
},
|
||||
};
|
||||
|
||||
// provide some existing asset data and a name to replace
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
attributes: {
|
||||
'@created': new Date().toISOString(),
|
||||
name: 'fake workpad',
|
||||
assets: {
|
||||
'asset-123': {
|
||||
id: 'asset-123',
|
||||
'@created': '2019-02-14T00:00:00.000Z',
|
||||
type: 'dataurl',
|
||||
value: 'mockbase64data',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
savedObjectsClient.create.mockResolvedValueOnce({});
|
||||
|
||||
const { payload, statusCode } = await mockServer.inject(request);
|
||||
const response = JSON.parse(payload);
|
||||
|
||||
expect(statusCode).toBe(200);
|
||||
expect(response).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ok": true,
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.get).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"canvas-workpad",
|
||||
"123",
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(savedObjectsClient.create).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"canvas-workpad",
|
||||
Object {
|
||||
"@created": "2019-02-12T21:01:22.479Z",
|
||||
"@timestamp": "2019-02-12T21:01:22.479Z",
|
||||
"assets": Object {
|
||||
"asset-123": Object {
|
||||
"@created": "2019-02-14T00:00:00.000Z",
|
||||
"id": "asset-123",
|
||||
"type": "dataurl",
|
||||
"value": "mockbase64data",
|
||||
},
|
||||
},
|
||||
"css": ".canvasPage { color: LavenderBlush; }",
|
||||
"name": "renamed workpad",
|
||||
},
|
||||
Object {
|
||||
"id": "123",
|
||||
"overwrite": true,
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue