diff --git a/src/core_plugins/kibana/server/lib/__tests__/relationships.js b/src/core_plugins/kibana/server/lib/__tests__/relationships.js index 371f18462ed91..1c5473fe5e311 100644 --- a/src/core_plugins/kibana/server/lib/__tests__/relationships.js +++ b/src/core_plugins/kibana/server/lib/__tests__/relationships.js @@ -77,6 +77,7 @@ describe('findRelationships', () => { const size = 10; const savedObjectsClient = { + get: () => {}, find: () => ({ saved_objects: [ { @@ -202,6 +203,7 @@ describe('findRelationships', () => { const size = 10; const savedObjectsClient = { + get: () => {}, find: options => { if (options.type === 'visualization') { return { diff --git a/src/core_plugins/kibana/server/lib/management/saved_objects/relationships.js b/src/core_plugins/kibana/server/lib/management/saved_objects/relationships.js index 55e28db2203fd..e98bebe4c4066 100644 --- a/src/core_plugins/kibana/server/lib/management/saved_objects/relationships.js +++ b/src/core_plugins/kibana/server/lib/management/saved_objects/relationships.js @@ -25,29 +25,34 @@ async function findDashboardRelationships(id, size, savedObjectsClient) { const panelsJSON = JSON.parse(dashboard.attributes.panelsJSON); if (panelsJSON) { const visualizationIds = panelsJSON.map(panel => panel.id); - const visualizationResponse = await savedObjectsClient.bulkGet(visualizationIds.slice(0, size).map(id => ({ - id, - type: 'visualization', - }))); - - visualizations.push(...visualizationResponse.saved_objects.reduce((accum, object) => { - if (!object.error) { - accum.push({ - id: object.id, - title: object.attributes.title, - }); - } - return accum; - }, [])); + const visualizationResponse = await savedObjectsClient.bulkGet( + visualizationIds.slice(0, size).map(id => ({ + id, + type: 'visualization', + })) + ); + + visualizations.push( + ...visualizationResponse.saved_objects.reduce((accum, object) => { + if (!object.error) { + accum.push({ + id: object.id, + title: object.attributes.title, + }); + } + return accum; + }, []) + ); } return { visualizations }; } async function findVisualizationRelationships(id, size, savedObjectsClient) { + await savedObjectsClient.get('visualization', id); const allDashboardsResponse = await savedObjectsClient.find({ type: 'dashboard', - fields: ['title', 'panelsJSON'] + fields: ['title', 'panelsJSON'], }); const dashboards = []; @@ -71,7 +76,6 @@ async function findVisualizationRelationships(id, size, savedObjectsClient) { break; } } - return { dashboards }; } @@ -92,7 +96,7 @@ async function findSavedSearchRelationships(id, size, savedObjectsClient) { type: 'visualization', searchFields: ['savedSearchId'], search: id, - fields: ['title'] + fields: ['title'], }); const visualizations = allVisualizationsResponse.saved_objects.reduce((accum, object) => { @@ -109,6 +113,7 @@ async function findSavedSearchRelationships(id, size, savedObjectsClient) { } async function findIndexPatternRelationships(id, size, savedObjectsClient) { + await savedObjectsClient.get('index-pattern', id); const [allVisualizationsResponse, savedSearchResponse] = await Promise.all([ savedObjectsClient.find({ type: 'visualization', @@ -159,7 +164,6 @@ async function findIndexPatternRelationships(id, size, savedObjectsClient) { break; } } - return { visualizations, searches }; } diff --git a/src/core_plugins/kibana/server/routes/api/management/saved_objects/relationships.js b/src/core_plugins/kibana/server/routes/api/management/saved_objects/relationships.js index 6cead2f57f936..34eca71cc2610 100644 --- a/src/core_plugins/kibana/server/routes/api/management/saved_objects/relationships.js +++ b/src/core_plugins/kibana/server/routes/api/management/saved_objects/relationships.js @@ -20,6 +20,7 @@ import Boom from 'boom'; import Joi from 'joi'; import { findRelationships } from '../../../../lib/management/saved_objects/relationships'; +import { isNotFoundError } from '../../../../../../../server/saved_objects/service/lib/errors'; export function registerRelationships(server) { server.route({ @@ -33,7 +34,7 @@ export function registerRelationships(server) { }), query: Joi.object().keys({ size: Joi.number(), - }) + }), }, }, @@ -43,18 +44,15 @@ export function registerRelationships(server) { const size = req.query.size || 10; try { - const response = await findRelationships( - type, - id, - size, - req.getSavedObjectsClient(), - ); - + const response = await findRelationships(type, id, size, req.getSavedObjectsClient()); reply(response); - } - catch (err) { + } catch (err) { + if (isNotFoundError(err)) { + reply(Boom.boomify(new Error('Resource not found'), { statusCode: 404 })); + return; + } reply(Boom.boomify(err, { statusCode: 500 })); } - } + }, }); } diff --git a/test/api_integration/apis/management/saved_objects/relationships.js b/test/api_integration/apis/management/saved_objects/relationships.js index 9f11dbb8f132e..45b0a8b82e4a2 100644 --- a/test/api_integration/apis/management/saved_objects/relationships.js +++ b/test/api_integration/apis/management/saved_objects/relationships.js @@ -18,101 +18,195 @@ */ import expect from 'expect.js'; +const Joi = require('joi'); export default function ({ getService }) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); + const GENERIC_RESPONSE_SCHEMA = Joi.array().items( + Joi.object().keys({ + id: Joi.string() + .uuid() + .required(), + title: Joi.string() + .required() + .min(1), + }) + ); + describe('relationships', () => { before(() => esArchiver.load('management/saved_objects')); after(() => esArchiver.unload('management/saved_objects')); - it('should work for searches', async () => { - await supertest - .get( - `/api/kibana/management/saved_objects/relationships/search/960372e0-3224-11e8-a572-ffca06da1357` - ) - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - visualizations: [ - { - id: 'a42c0580-3224-11e8-a572-ffca06da1357', - title: 'VisualizationFromSavedSearch', - }, - ], - indexPatterns: [ - { - id: '8963ca30-3224-11e8-a572-ffca06da1357', - title: 'saved_objects*', - }, - ], + const SEARCH_RESPONSE_SCHEMA = Joi.object().keys({ + visualizations: GENERIC_RESPONSE_SCHEMA, + indexPatterns: GENERIC_RESPONSE_SCHEMA, + }); + + describe('searches', async () => { + it('should validate search response schema', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/search/960372e0-3224-11e8-a572-ffca06da1357`) + .expect(200) + .then(resp => { + const validationResult = Joi.validate(resp.body, SEARCH_RESPONSE_SCHEMA); + expect(validationResult.error).to.be(null); + }); + }); + + it('should work for searches', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/search/960372e0-3224-11e8-a572-ffca06da1357`) + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + visualizations: [ + { + id: 'a42c0580-3224-11e8-a572-ffca06da1357', + title: 'VisualizationFromSavedSearch', + }, + ], + indexPatterns: [ + { + id: '8963ca30-3224-11e8-a572-ffca06da1357', + title: 'saved_objects*', + }, + ], + }); }); - }); + }); + + //TODO: https://github.com/elastic/kibana/issues/19713 causes this test to fail. + it.skip('should return 404 if search finds no results', async () => { + await supertest.get(`/api/kibana/management/saved_objects/relationships/search/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`).expect(404); + }); }); - it('should work for dashboards', async () => { - await supertest - .get( - `/api/kibana/management/saved_objects/relationships/dashboard/b70c7ae0-3224-11e8-a572-ffca06da1357` - ) - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - visualizations: [ - { - id: 'add810b0-3224-11e8-a572-ffca06da1357', - title: 'Visualization', - }, - { - id: 'a42c0580-3224-11e8-a572-ffca06da1357', - title: 'VisualizationFromSavedSearch', - }, - ], + describe('dashboards', async () => { + const DASHBOARD_RESPONSE_SCHEMA = Joi.object().keys({ + visualizations: GENERIC_RESPONSE_SCHEMA, + }); + + it('should validate dashboard response schema', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/dashboard/b70c7ae0-3224-11e8-a572-ffca06da1357`) + .expect(200) + .then(resp => { + const validationResult = Joi.validate(resp.body, DASHBOARD_RESPONSE_SCHEMA); + expect(validationResult.error).to.be(null); + }); + }); + + it('should work for dashboards', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/dashboard/b70c7ae0-3224-11e8-a572-ffca06da1357`) + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + visualizations: [ + { + id: 'add810b0-3224-11e8-a572-ffca06da1357', + title: 'Visualization', + }, + { + id: 'a42c0580-3224-11e8-a572-ffca06da1357', + title: 'VisualizationFromSavedSearch', + }, + ], + }); }); - }); + }); + + //TODO: https://github.com/elastic/kibana/issues/19713 causes this test to fail. + it.skip('should return 404 if dashboard finds no results', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/dashboard/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`) + .expect(404); + }); }); - it('should work for visualizations', async () => { - await supertest - .get( - `/api/kibana/management/saved_objects/relationships/visualization/a42c0580-3224-11e8-a572-ffca06da1357` - ) - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - dashboards: [ - { - id: 'b70c7ae0-3224-11e8-a572-ffca06da1357', - title: 'Dashboard', - }, - ], + describe('visualizations', async () => { + const VISUALIZATIONS_RESPONSE_SCHEMA = Joi.object().keys({ + dashboards: GENERIC_RESPONSE_SCHEMA, + }); + + it('should validate visualization response schema', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/visualization/a42c0580-3224-11e8-a572-ffca06da1357`) + .expect(200) + .then(resp => { + const validationResult = Joi.validate(resp.body, VISUALIZATIONS_RESPONSE_SCHEMA); + expect(validationResult.error).to.be(null); }); - }); + }); + + it('should work for visualizations', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/visualization/a42c0580-3224-11e8-a572-ffca06da1357`) + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + dashboards: [ + { + id: 'b70c7ae0-3224-11e8-a572-ffca06da1357', + title: 'Dashboard', + }, + ], + }); + }); + }); + + it('should return 404 if visualizations finds no results', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/visualization/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`) + .expect(404); + }); }); - it('should work for index patterns', async () => { - await supertest - .get( - `/api/kibana/management/saved_objects/relationships/index-pattern/8963ca30-3224-11e8-a572-ffca06da1357` - ) - .expect(200) - .then(resp => { - expect(resp.body).to.eql({ - searches: [ - { - id: '960372e0-3224-11e8-a572-ffca06da1357', - title: 'OneRecord', - }, - ], - visualizations: [ - { - id: 'add810b0-3224-11e8-a572-ffca06da1357', - title: 'Visualization', - }, - ], + describe('index patterns', async () => { + const INDEX_PATTERN_RESPONSE_SCHEMA = Joi.object().keys({ + searches: GENERIC_RESPONSE_SCHEMA, + visualizations: GENERIC_RESPONSE_SCHEMA, + }); + + it('should validate visualization response schema', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/index-pattern/8963ca30-3224-11e8-a572-ffca06da1357`) + .expect(200) + .then(resp => { + const validationResult = Joi.validate(resp.body, INDEX_PATTERN_RESPONSE_SCHEMA); + expect(validationResult.error).to.be(null); + }); + }); + + it('should work for index patterns', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/index-pattern/8963ca30-3224-11e8-a572-ffca06da1357`) + .expect(200) + .then(resp => { + expect(resp.body).to.eql({ + searches: [ + { + id: '960372e0-3224-11e8-a572-ffca06da1357', + title: 'OneRecord', + }, + ], + visualizations: [ + { + id: 'add810b0-3224-11e8-a572-ffca06da1357', + title: 'Visualization', + }, + ], + }); }); - }); + }); + + it('should return 404 if index pattern finds no results', async () => { + await supertest + .get(`/api/kibana/management/saved_objects/relationships/index-pattern/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`) + .expect(404); + }); }); }); }