Merge 403 and unsupported type errors into single error

This commit is contained in:
Mike Cote 2019-04-25 23:01:51 -04:00
parent 38b402b623
commit 99aea10c0f
44 changed files with 564 additions and 619 deletions

View file

@ -269,37 +269,6 @@ exports[`Flyout conflicts should handle errors 1`] = `
</EuiCallOut>
`;
exports[`Flyout errors should display unsupported type errors properly 1`] = `
<EuiCallOut
color="warning"
iconType="help"
size="m"
title={
<FormattedMessage
defaultMessage="Import failed"
id="kbn.management.objects.objectsTable.flyout.importFailedTitle"
values={Object {}}
/>
}
>
<p>
<FormattedMessage
defaultMessage="Failed to import {failedImportCount} of {totalImportCount} objects. Import failed"
id="kbn.management.objects.objectsTable.flyout.importFailedDescription"
values={
Object {
"failedImportCount": 1,
"totalImportCount": 1,
}
}
/>
</p>
<p>
wigwags [id=1] unsupported type
</p>
</EuiCallOut>
`;
exports[`Flyout legacy conflicts should allow conflict resolution 1`] = `
<EuiFlyout
closeButtonAriaLabel="Closes this dialog"

View file

@ -313,75 +313,6 @@ describe('Flyout', () => {
});
});
describe('errors', () => {
const { importFile } = require('../../../../../lib/import_file');
const { resolveImportErrors } = require('../../../../../lib/resolve_import_errors');
it('should display unsupported type errors properly', async () => {
const component = shallowWithIntl(<Flyout.WrappedComponent {...defaultProps} />);
// Ensure all promises resolve
await Promise.resolve();
// Ensure the state changes are reflected
component.update();
importFile.mockImplementation(() => ({
success: false,
successCount: 0,
errors: [
{
id: '1',
type: 'wigwags',
title: 'My Title',
error: {
type: 'unsupported_type',
}
},
],
}));
resolveImportErrors.mockImplementation(() => ({
status: 'success',
importCount: 0,
failedImports: [
{
error: {
type: 'unsupported_type',
},
obj: {
id: '1',
type: 'wigwags',
title: 'My Title',
},
},
],
}));
component.setState({ file: mockFile, isLegacyFile: false });
// Go through the import flow
await component.instance().import();
component.update();
// Ensure all promises resolve
await Promise.resolve();
expect(component.state('status')).toBe('success');
expect(component.state('failedImports')).toEqual([
{
error: {
type: 'unsupported_type',
},
obj: {
id: '1',
type: 'wigwags',
title: 'My Title',
},
},
]);
expect(component.find('EuiFlyout EuiCallOut')).toMatchSnapshot();
});
});
describe('legacy conflicts', () => {
const { importLegacyFile } = require('../../../../../lib/import_legacy_file');
const {

View file

@ -602,17 +602,6 @@ class FlyoutUI extends Component {
}
);
});
} else if (error.type === 'unsupported_type') {
return intl.formatMessage(
{
id: 'kbn.management.objects.objectsTable.flyout.importFailedUnsupportedType',
defaultMessage: '{type} [id={id}] unsupported type',
},
{
id: obj.id,
type: obj.type,
},
);
}
return getField(error, 'body.message', error.message || '');
}).join(' ')}

View file

@ -23,22 +23,28 @@ describe('getSortedObjectsForExport()', () => {
const savedObjectsClient = {
errors: {} as any,
find: jest.fn(),
canFind: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
delete: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
afterEach(() => {
savedObjectsClient.find.mockReset();
savedObjectsClient.bulkGet.mockReset();
savedObjectsClient.create.mockReset();
savedObjectsClient.bulkCreate.mockReset();
savedObjectsClient.delete.mockReset();
savedObjectsClient.get.mockReset();
savedObjectsClient.update.mockReset();
beforeEach(() => {
jest.resetAllMocks();
savedObjectsClient.canBulkCreate.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
savedObjectsClient.canBulkGet.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
savedObjectsClient.canFind.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
});
test('exports selected types and sorts them', async () => {
@ -66,6 +72,7 @@ describe('getSortedObjectsForExport()', () => {
savedObjectsClient,
exportSizeLimit: 500,
types: ['index-pattern', 'search'],
supportedTypes: ['index-pattern', 'search'],
});
expect(response).toMatchInlineSnapshot(`
Array [
@ -137,6 +144,7 @@ Array [
savedObjectsClient,
exportSizeLimit: 1,
types: ['index-pattern', 'search'],
supportedTypes: ['index-pattern', 'search'],
})
).rejects.toThrowErrorMatchingInlineSnapshot(`"Can't export more than 1 objects"`);
});
@ -165,6 +173,7 @@ Array [
exportSizeLimit: 10000,
savedObjectsClient,
types: ['index-pattern', 'search'],
supportedTypes: ['index-pattern', 'search'],
objects: [
{
type: 'index-pattern',
@ -249,6 +258,7 @@ Array [
exportSizeLimit: 10000,
savedObjectsClient,
types: ['index-pattern', 'search'],
supportedTypes: ['index-pattern', 'search'],
objects: [
{
type: 'search',
@ -315,6 +325,7 @@ Array [
exportSizeLimit: 1,
savedObjectsClient,
types: ['index-pattern', 'search'],
supportedTypes: ['index-pattern', 'search'],
objects: [
{
type: 'index-pattern',

View file

@ -33,6 +33,26 @@ interface ExportObjectsOptions {
savedObjectsClient: SavedObjectsClient;
exportSizeLimit: number;
includeReferencesDeep?: boolean;
supportedTypes: string[];
}
function throwIfInvalidTypes(
action: string,
objectTypes: string[],
supportedTypes: string[],
authorizedTypes: Array<{ type: string; can: boolean }>
) {
const invalidTypes = new Set([
...objectTypes.filter(type => !supportedTypes.includes(type)),
...authorizedTypes.filter(resp => resp.can === false).map(resp => resp.type),
]);
if (invalidTypes.size) {
throw Boom.badRequest(
`Unable to ${action} ${Array.from(invalidTypes)
.sort()
.join(',')}`
);
}
}
async function fetchObjectsToExport({
@ -40,13 +60,22 @@ async function fetchObjectsToExport({
types,
exportSizeLimit,
savedObjectsClient,
supportedTypes,
}: {
objects?: ObjectToExport[];
types?: string[];
exportSizeLimit: number;
savedObjectsClient: SavedObjectsClient;
supportedTypes: string[];
}) {
if (objects) {
const objectTypes = [...new Set(objects.map(obj => obj.type))];
throwIfInvalidTypes(
'bulk_get',
objectTypes,
supportedTypes,
await savedObjectsClient.canBulkGet(objectTypes)
);
if (objects.length > exportSizeLimit) {
throw Boom.badRequest(`Can't export more than ${exportSizeLimit} objects`);
}
@ -61,6 +90,13 @@ async function fetchObjectsToExport({
}
return bulkGetResult.saved_objects;
}
throwIfInvalidTypes(
'find',
types || [],
supportedTypes,
await savedObjectsClient.canFind(types || [])
);
const findResponse = await savedObjectsClient.find({
type: types,
sortField: '_id',
@ -79,12 +115,14 @@ export async function getSortedObjectsForExport({
savedObjectsClient,
exportSizeLimit,
includeReferencesDeep = false,
supportedTypes,
}: ExportObjectsOptions) {
const objectsToExport = await fetchObjectsToExport({
types,
objects,
savedObjectsClient,
exportSizeLimit,
supportedTypes,
});
return sortObjects(
includeReferencesDeep

View file

@ -114,9 +114,12 @@ describe('injectNestedDependencies', () => {
const savedObjectsClient = {
errors: {} as any,
find: jest.fn(),
canFind: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
delete: jest.fn(),
get: jest.fn(),
update: jest.fn(),

View file

@ -27,13 +27,8 @@ describe('collectSavedObjects()', () => {
this.push(null);
},
});
const result = await collectSavedObjects({ readStream, objectLimit: 10, supportedTypes: [] });
expect(result).toMatchInlineSnapshot(`
Object {
"collectedObjects": Array [],
"errors": Array [],
}
`);
const result = await collectSavedObjects({ readStream, objectLimit: 10 });
expect(result).toMatchInlineSnapshot(`Array []`);
});
test('collects objects from stream', async () => {
@ -46,19 +41,15 @@ Object {
const result = await collectSavedObjects({
readStream,
objectLimit: 1,
supportedTypes: ['a'],
});
expect(result).toMatchInlineSnapshot(`
Object {
"collectedObjects": Array [
Object {
"foo": true,
"migrationVersion": Object {},
"type": "a",
},
],
"errors": Array [],
}
Array [
Object {
"foo": true,
"migrationVersion": Object {},
"type": "a",
},
]
`);
});
@ -72,19 +63,15 @@ Object {
const result = await collectSavedObjects({
readStream,
objectLimit: 1,
supportedTypes: ['a'],
});
expect(result).toMatchInlineSnapshot(`
Object {
"collectedObjects": Array [
Object {
"foo": true,
"migrationVersion": Object {},
"type": "a",
},
],
"errors": Array [],
}
Array [
Object {
"foo": true,
"migrationVersion": Object {},
"type": "a",
},
]
`);
});
@ -100,58 +87,6 @@ Object {
collectSavedObjects({
readStream,
objectLimit: 1,
supportedTypes: ['a'],
})
).rejects.toThrowErrorMatchingInlineSnapshot(`"Can't import more than 1 objects"`);
});
test('unsupported types return as import errors', async () => {
const readStream = new Readable({
read() {
this.push('{"id":"1","type":"a","attributes":{"title":"my title"}}\n');
this.push('{"id":"2","type":"b","attributes":{"title":"my title 2"}}\n');
this.push(null);
},
});
const result = await collectSavedObjects({ readStream, objectLimit: 2, supportedTypes: ['1'] });
expect(result).toMatchInlineSnapshot(`
Object {
"collectedObjects": Array [],
"errors": Array [
Object {
"error": Object {
"type": "unsupported_type",
},
"id": "1",
"title": "my title",
"type": "a",
},
Object {
"error": Object {
"type": "unsupported_type",
},
"id": "2",
"title": "my title 2",
"type": "b",
},
],
}
`);
});
test('unsupported types still count towards object limit', async () => {
const readStream = new Readable({
read() {
this.push('{"foo":true,"type":"a"}\n');
this.push('{"bar":true,"type":"b"}\n');
this.push(null);
},
});
await expect(
collectSavedObjects({
readStream,
objectLimit: 1,
supportedTypes: ['a'],
})
).rejects.toThrowErrorMatchingInlineSnapshot(`"Can't import more than 1 objects"`);
});

View file

@ -27,22 +27,18 @@ import {
} from '../../../utils/streams';
import { SavedObject } from '../service';
import { createLimitStream } from './create_limit_stream';
import { ImportError } from './types';
interface CollectSavedObjectsOptions {
readStream: Readable;
objectLimit: number;
filter?: (obj: SavedObject) => boolean;
supportedTypes: string[];
}
export async function collectSavedObjects({
readStream,
objectLimit,
filter,
supportedTypes,
}: CollectSavedObjectsOptions) {
const errors: ImportError[] = [];
const collectedObjects: SavedObject[] = await createPromiseFromStreams([
readStream,
createSplitStream('\n'),
@ -53,20 +49,6 @@ export async function collectSavedObjects({
}),
createFilterStream<SavedObject>(obj => !!obj),
createLimitStream(objectLimit),
createFilterStream<SavedObject>(obj => {
if (supportedTypes.includes(obj.type)) {
return true;
}
errors.push({
id: obj.id,
type: obj.type,
title: obj.attributes.title,
error: {
type: 'unsupported_type',
},
});
return false;
}),
createFilterStream<SavedObject>(obj => (filter ? filter(obj) : true)),
createMapStream((obj: SavedObject) => {
// Ensure migrations execute on every saved object
@ -74,8 +56,5 @@ export async function collectSavedObjects({
}),
createConcatStream([]),
]);
return {
errors,
collectedObjects,
};
return collectedObjects;
}

View file

@ -59,16 +59,28 @@ describe('importSavedObjects()', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
beforeEach(() => {
jest.resetAllMocks();
savedObjectsClient.canBulkCreate.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
savedObjectsClient.canBulkGet.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
savedObjectsClient.canFind.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
});
test('returns early when no objects exist', async () => {
@ -443,83 +455,14 @@ Object {
savedObjectsClient.bulkCreate.mockResolvedValue({
saved_objects: savedObjects,
});
const result = await importSavedObjects({
readStream,
objectLimit: 5,
overwrite: false,
savedObjectsClient,
supportedTypes: ['index-pattern', 'search', 'visualization', 'dashboard'],
});
expect(result).toMatchInlineSnapshot(`
Object {
"errors": Array [
Object {
"error": Object {
"type": "unsupported_type",
},
"id": "1",
"title": "my title",
"type": "wigwags",
},
],
"success": false,
"successCount": 4,
}
`);
expect(savedObjectsClient.bulkCreate).toMatchInlineSnapshot(`
[MockFunction] {
"calls": Array [
Array [
Array [
Object {
"attributes": Object {
"title": "My Index Pattern",
},
"id": "1",
"migrationVersion": Object {},
"references": Array [],
"type": "index-pattern",
},
Object {
"attributes": Object {
"title": "My Search",
},
"id": "2",
"migrationVersion": Object {},
"references": Array [],
"type": "search",
},
Object {
"attributes": Object {
"title": "My Visualization",
},
"id": "3",
"migrationVersion": Object {},
"references": Array [],
"type": "visualization",
},
Object {
"attributes": Object {
"title": "My Dashboard",
},
"id": "4",
"migrationVersion": Object {},
"references": Array [],
"type": "dashboard",
},
],
Object {
"overwrite": false,
},
],
],
"results": Array [
Object {
"type": "return",
"value": Promise {},
},
],
}
`);
await expect(
importSavedObjects({
readStream,
objectLimit: 5,
overwrite: false,
savedObjectsClient,
supportedTypes: ['index-pattern', 'search', 'visualization', 'dashboard'],
})
).rejects.toThrowErrorMatchingInlineSnapshot(`"Unable to bulk_create wigwags"`);
});
});

View file

@ -17,6 +17,7 @@
* under the License.
*/
import Boom from 'boom';
import { Readable } from 'stream';
import { SavedObjectsClient } from '../service';
import { collectSavedObjects } from './collect_saved_objects';
@ -48,11 +49,19 @@ export async function importSavedObjects({
let errorAccumulator: ImportError[] = [];
// Get the objects to import
const {
errors: collectorErrors,
collectedObjects: objectsFromStream,
} = await collectSavedObjects({ readStream, objectLimit, supportedTypes });
errorAccumulator = [...errorAccumulator, ...collectorErrors];
const objectsFromStream = await collectSavedObjects({ readStream, objectLimit });
const objectTypes = [...new Set(objectsFromStream.map(obj => obj.type))];
const authorizedTypes = await savedObjectsClient.canBulkCreate(objectTypes);
const invalidTypes = [
...new Set([
...objectTypes.filter(type => !supportedTypes.includes(type)),
...authorizedTypes.filter(resp => resp.can === false).map(resp => resp.type),
]),
];
if (invalidTypes.length) {
throw Boom.badRequest(`Unable to bulk_create ${invalidTypes.sort().join(',')}`);
}
// Validate references
const { filteredObjects, errors: validationErrors } = await validateReferences(

View file

@ -65,16 +65,28 @@ describe('resolveImportErrors()', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
beforeEach(() => {
jest.resetAllMocks();
savedObjectsClient.canBulkCreate.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
savedObjectsClient.canBulkGet.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
savedObjectsClient.canFind.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
});
test('works with empty parameters', async () => {
@ -494,36 +506,21 @@ Object {
savedObjectsClient.bulkCreate.mockResolvedValue({
saved_objects: [],
});
const result = await resolveImportErrors({
readStream,
objectLimit: 5,
retries: [
{
id: 'i',
type: 'wigwags',
overwrite: false,
replaceReferences: [],
},
],
savedObjectsClient,
supportedTypes: ['index-pattern', 'search', 'visualization', 'dashboard'],
});
expect(result).toMatchInlineSnapshot(`
Object {
"errors": Array [
Object {
"error": Object {
"type": "unsupported_type",
},
"id": "1",
"title": "my title",
"type": "wigwags",
},
],
"success": false,
"successCount": 0,
}
`);
expect(savedObjectsClient.bulkCreate).toMatchInlineSnapshot(`[MockFunction]`);
await expect(
resolveImportErrors({
readStream,
objectLimit: 5,
retries: [
{
id: '1',
type: 'wigwags',
overwrite: false,
replaceReferences: [],
},
],
savedObjectsClient,
supportedTypes: ['index-pattern', 'search', 'visualization', 'dashboard'],
})
).rejects.toThrowErrorMatchingInlineSnapshot(`"Unable to bulk_create wigwags"`);
});
});

View file

@ -17,6 +17,7 @@
* under the License.
*/
import Boom from 'boom';
import { Readable } from 'stream';
import { SavedObjectsClient } from '../service';
import { collectSavedObjects } from './collect_saved_objects';
@ -52,15 +53,23 @@ export async function resolveImportErrors({
const filter = createObjectsFilter(retries);
// Get the objects to resolve errors
const { errors: collectorErrors, collectedObjects: objectsToResolve } = await collectSavedObjects(
{
readStream,
objectLimit,
filter,
supportedTypes,
}
);
errorAccumulator = [...errorAccumulator, ...collectorErrors];
const objectsToResolve = await collectSavedObjects({
readStream,
objectLimit,
filter,
});
const objectTypes = [...new Set(objectsToResolve.map(obj => obj.type))];
const authorizedTypes = await savedObjectsClient.canBulkCreate(objectTypes);
const invalidTypes = [
...new Set([
...objectTypes.filter(type => !supportedTypes.includes(type)),
...authorizedTypes.filter(resp => resp.can === false).map(resp => resp.type),
]),
];
if (invalidTypes.length) {
throw Boom.badRequest(`Unable to bulk_create ${invalidTypes.sort().join(',')}`);
}
// Create a map of references to replace for each object to avoid iterating through
// retries for every object to resolve

View file

@ -32,10 +32,6 @@ export interface ConflictError {
type: 'conflict';
}
export interface UnsupportedTypeError {
type: 'unsupported_type';
}
export interface UnknownError {
type: 'unknown';
message: string;
@ -58,5 +54,5 @@ export interface ImportError {
id: string;
type: string;
title?: string;
error: ConflictError | UnsupportedTypeError | MissingReferencesError | UnknownError;
error: ConflictError | MissingReferencesError | UnknownError;
}

View file

@ -23,10 +23,13 @@ describe('getNonExistingReferenceAsKeys()', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
@ -223,10 +226,13 @@ describe('validateReferences()', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};

View file

@ -26,10 +26,13 @@ describe('POST /api/saved_objects/_bulk_create', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};

View file

@ -26,10 +26,13 @@ describe('POST /api/saved_objects/_bulk_get', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};

View file

@ -26,10 +26,13 @@ describe('POST /api/saved_objects/{type}', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};

View file

@ -26,10 +26,13 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};

View file

@ -33,10 +33,13 @@ describe('POST /api/saved_objects/_export', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
@ -128,6 +131,9 @@ Array [
"savedObjectsClient": Object {
"bulkCreate": [MockFunction],
"bulkGet": [MockFunction],
"canBulkCreate": [MockFunction],
"canBulkGet": [MockFunction],
"canFind": [MockFunction],
"create": [MockFunction],
"delete": [MockFunction],
"errors": Object {},
@ -135,6 +141,10 @@ Array [
"get": [MockFunction],
"update": [MockFunction],
},
"supportedTypes": Array [
"index-pattern",
"search",
],
"types": Array [
"search",
],

View file

@ -51,14 +51,12 @@ export const createExportRoute = (
payload: Joi.object()
.keys({
type: Joi.array()
.items(Joi.string().valid(supportedTypes))
.items(Joi.string())
.single()
.optional(),
objects: Joi.array()
.items({
type: Joi.string()
.valid(supportedTypes)
.required(),
type: Joi.string().required(),
id: Joi.string().required(),
})
.max(server.config().get('savedObjects.maxImportExportSize'))
@ -71,6 +69,7 @@ export const createExportRoute = (
async handler(request: ExportRequest, h: Hapi.ResponseToolkit) {
const { savedObjectsClient } = request.pre;
const docsToExport = await getSortedObjectsForExport({
supportedTypes,
savedObjectsClient,
types: request.payload.type,
objects: request.payload.objects,

View file

@ -26,10 +26,13 @@ describe('GET /api/saved_objects/_find', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};

View file

@ -26,10 +26,13 @@ describe('GET /api/saved_objects/{type}/{id}', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};

View file

@ -26,10 +26,13 @@ describe('POST /api/saved_objects/_import', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
@ -37,6 +40,15 @@ describe('POST /api/saved_objects/_import', () => {
beforeEach(() => {
server = createMockServer();
jest.resetAllMocks();
savedObjectsClient.canBulkCreate.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
savedObjectsClient.canBulkGet.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
savedObjectsClient.canFind.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
const prereqs = {
getSavedObjectsClient: {

View file

@ -26,10 +26,13 @@ describe('POST /api/saved_objects/_resolve_import_errors', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};
@ -37,6 +40,15 @@ describe('POST /api/saved_objects/_resolve_import_errors', () => {
beforeEach(() => {
server = createMockServer();
jest.resetAllMocks();
savedObjectsClient.canBulkCreate.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
savedObjectsClient.canBulkGet.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
savedObjectsClient.canFind.mockImplementation((types: string[]) =>
types.map(type => ({ type, can: true }))
);
const prereqs = {
getSavedObjectsClient: {

View file

@ -26,10 +26,13 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => {
const savedObjectsClient = {
errors: {} as any,
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
get: jest.fn(),
update: jest.fn(),
};

View file

@ -127,14 +127,24 @@ export declare class SavedObjectsClient {
objects: Array<BulkCreateObject<T>>,
options?: CreateOptions
): Promise<BulkCreateResponse<T>>;
public canBulkCreate(
types: string[]
): Promise<
Array<{
type: string;
can: boolean;
}>
>;
public delete(type: string, id: string, options?: BaseOptions): Promise<{}>;
public find<T extends SavedObjectAttributes = any>(
options: FindOptions
): Promise<FindResponse<T>>;
public canFind(types: string[]): Promise<Array<{ type: string; can: boolean }>>;
public bulkGet<T extends SavedObjectAttributes = any>(
objects: BulkGetObjects,
options?: BaseOptions
): Promise<BulkGetResponse<T>>;
public canBulkGet(types: string[]): Promise<Array<{ type: string; can: boolean }>>;
public get<T extends SavedObjectAttributes = any>(
type: string,
id: string,

View file

@ -122,6 +122,19 @@ export class SavedObjectsClient {
return this._repository.bulkCreate(objects, options);
}
/**
* Function is used to validate if each type of saved object can be created in bulk.
*
* This is and should only be used by import / export / resolve import errors to merge
* invalid types and unauthorized types in a single error response.
*
* @param {Array<string>} types Types of saved objects
* @return [{ type, can }]
*/
async canBulkCreate(types) {
return types.map(type => ({ type, can: true }));
}
/**
* Deletes an object
*
@ -155,6 +168,19 @@ export class SavedObjectsClient {
return this._repository.find(options);
}
/**
* Function is used to validate if each type of saved object can be created used with find.
*
* This is and should only be used by import / export / resolve import errors to merge
* invalid types and unauthorized types in a single error response.
*
* @param {Array<string>} types Types of saved objects
* @return [{ type, can }]
*/
async canFind(types) {
return types.map(type => ({ type, can: true }));
}
/**
* Returns an array of objects by id
*
@ -173,6 +199,19 @@ export class SavedObjectsClient {
return this._repository.bulkGet(objects, options);
}
/**
* Function is used to validate if each type of saved object can be created used in bulk get.
*
* This is and should only be used by import / export / resolve import errors to merge
* invalid types and unauthorized types in a single error response.
*
* @param {Array<string>} types Types of saved objects
* @return [{ type, can }]
*/
async canBulkGet(types) {
return types.map(type => ({ type, can: true }));
}
/**
* Gets a single object
*

View file

@ -138,12 +138,7 @@ export default function ({ getService }) {
expect(resp.body).to.eql({
statusCode: 400,
error: 'Bad Request',
message: 'child "type" fails because ["type" at position 0 fails because ' +
'["0" must be one of [config, index-pattern, visualization, search, dashboard, url]]]',
validation: {
source: 'payload',
keys: ['type.0'],
}
message: 'Unable to find wigwags',
});
});
});

View file

@ -112,26 +112,17 @@ export default function ({ getService }) {
});
});
it('should return 200 when trying to import unsupported types', async () => {
it('should return 400 when trying to import unsupported types', async () => {
const fileBuffer = Buffer.from('{"id":"1","type":"wigwags","attributes":{"title":"my title"},"references":[]}', 'utf8');
await supertest
.post('/api/saved_objects/_import')
.attach('file', fileBuffer, 'export.ndjson')
.expect(200)
.expect(400)
.then(resp => {
expect(resp.body).to.eql({
success: false,
successCount: 0,
errors: [
{
id: '1',
type: 'wigwags',
title: 'my title',
error: {
type: 'unsupported_type',
},
},
],
statusCode: 400,
error: 'Bad Request',
message: 'Unable to bulk_create wigwags',
});
});
});

View file

@ -88,27 +88,18 @@ export default function ({ getService }) {
});
});
it('should return 200 when retrying unsupported types', async () => {
it('should return 400 when retrying unsupported types', async () => {
const fileBuffer = Buffer.from('{"id":"1","type":"wigwags","attributes":{"title":"my title"},"references":[]}', 'utf8');
await supertest
.post('/api/saved_objects/_resolve_import_errors')
.field('retries', JSON.stringify([{ type: 'wigwags', id: '1' }]))
.attach('file', fileBuffer, 'export.ndjson')
.expect(200)
.expect(400)
.then(resp => {
expect(resp.body).to.eql({
success: false,
successCount: 0,
errors: [
{
id: '1',
type: 'wigwags',
title: 'my title',
error: {
type: 'unsupported_type',
},
},
],
statusCode: 400,
error: 'Bad Request',
message: 'Unable to bulk_create wigwags',
});
});
});

View file

@ -48,6 +48,10 @@ export class SecureSavedObjectsClientWrapper {
return await this._baseClient.bulkCreate(objects, options);
}
async canBulkCreate(types) {
return await this._checkAuthorizedTypes(types, 'bulk_create');
}
async delete(type, id, options) {
await this._ensureAuthorized(
type,
@ -68,6 +72,10 @@ export class SecureSavedObjectsClientWrapper {
return this._baseClient.find(options);
}
async canFind(types) {
return await this._checkAuthorizedTypes(types, 'find');
}
async bulkGet(objects = [], options = {}) {
const types = uniq(objects.map(o => o.type));
await this._ensureAuthorized(
@ -79,6 +87,10 @@ export class SecureSavedObjectsClientWrapper {
return await this._baseClient.bulkGet(objects, options);
}
async canBulkGet(types) {
return await this._checkAuthorizedTypes(types, 'bulk_get');
}
async get(type, id, options = {}) {
await this._ensureAuthorized(
type,
@ -108,6 +120,19 @@ export class SecureSavedObjectsClientWrapper {
}
}
async _checkAuthorizedTypes(typeOrTypes, action) {
const types = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes];
const actionsToTypesMap = new Map(types.map(type => [this._actions.savedObject.get(type, action), type]));
const actions = Array.from(actionsToTypesMap.keys());
const { privileges } = await this._checkSavedObjectPrivileges(actions);
const missingPrivileges = this._getMissingPrivileges(privileges);
const invalidTypes = missingPrivileges.map(privilege => actionsToTypesMap.get(privilege));
return types.map(type => ({
type,
can: !invalidTypes.includes(type),
}));
}
async _ensureAuthorized(typeOrTypes, action, args) {
const types = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes];
const actionsToTypesMap = new Map(types.map(type => [this._actions.savedObject.get(type, action), type]));

View file

@ -33,9 +33,12 @@ const createMockClient = () => {
return {
get: jest.fn(),
bulkGet: jest.fn(),
canBulkGet: jest.fn(),
find: jest.fn(),
canFind: jest.fn(),
create: jest.fn(),
bulkCreate: jest.fn(),
canBulkCreate: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
errors,

View file

@ -117,6 +117,12 @@ export class SpacesSavedObjectsClient implements SavedObjectsClient {
});
}
public async canBulkCreate(types: string[]) {
throwErrorIfTypesContainsSpace(types);
return await this.client.canBulkCreate(types);
}
/**
* Deletes an object
*
@ -168,6 +174,12 @@ export class SpacesSavedObjectsClient implements SavedObjectsClient {
});
}
public async canFind(types: string[]) {
throwErrorIfTypesContainsSpace(types);
return await this.client.canFind(types);
}
/**
* Returns an array of objects by id
*
@ -192,6 +204,12 @@ export class SpacesSavedObjectsClient implements SavedObjectsClient {
});
}
public async canBulkGet(types: string[]) {
throwErrorIfTypesContainsSpace(types);
return await this.client.canBulkGet(types);
}
/**
* Gets a single object
*

View file

@ -27,21 +27,21 @@ interface ExportTestDefinition {
}
export function exportTestSuiteFactory(esArchiver: any, supertest: SuperTest<any>) {
const createExpectRbacForbidden = (type: string) => (resp: { [key: string]: any }) => {
const createExpectBadRequest = (type: string) => (resp: { [key: string]: any }) => {
// In export only, the API uses "bulk_get" or "find" depending on the parameters it receives.
// The best that could be done here is to have an if statement to ensure at least one of the
// two errors has been thrown.
if (resp.body.message.indexOf(`bulk_get`) !== -1) {
expect(resp.body).to.eql({
statusCode: 403,
error: 'Forbidden',
statusCode: 400,
error: 'Bad Request',
message: `Unable to bulk_get ${type}`,
});
return;
}
expect(resp.body).to.eql({
statusCode: 403,
error: 'Forbidden',
statusCode: 400,
error: 'Bad Request',
message: `Unable to find ${type}`,
});
};
@ -136,7 +136,7 @@ export function exportTestSuiteFactory(esArchiver: any, supertest: SuperTest<any
exportTest.only = makeExportTest(describe.only);
return {
createExpectRbacForbidden,
createExpectBadRequest,
expectTypeOrObjectsRequired,
createExpectVisualizationResults,
exportTest,

View file

@ -53,28 +53,27 @@ export function importTestSuiteFactory(es: any, esArchiver: any, supertest: Supe
});
};
const expectUnknownType = (resp: { [key: string]: any }) => {
const expectBadRequest = (resp: { [key: string]: any }) => {
expect(resp.body).to.eql({
success: false,
successCount: 2,
errors: [
{
id: '1',
type: 'wigwags',
title: 'Wigwags title',
error: {
type: 'unsupported_type',
},
},
],
statusCode: 400,
error: 'Bad Request',
message: `Unable to bulk_create dashboard,globaltype`,
});
};
const expectRbacForbidden = (resp: { [key: string]: any }) => {
const expectBadRequestWithUnknownType = (resp: { [key: string]: any }) => {
expect(resp.body).to.eql({
statusCode: 403,
error: 'Forbidden',
message: `Unable to bulk_create dashboard,globaltype`,
statusCode: 400,
error: 'Bad Request',
message: `Unable to bulk_create dashboard,globaltype,wigwags`,
});
};
const expectBadRequestForUnknownType = (resp: { [key: string]: any }) => {
expect(resp.body).to.eql({
statusCode: 400,
error: 'Bad Request',
message: `Unable to bulk_create wigwags`,
});
};
@ -135,7 +134,8 @@ export function importTestSuiteFactory(es: any, esArchiver: any, supertest: Supe
return {
importTest,
createExpectResults,
expectRbacForbidden,
expectUnknownType,
expectBadRequest,
expectBadRequestWithUnknownType,
expectBadRequestForUnknownType,
};
}

View file

@ -57,28 +57,27 @@ export function resolveImportErrorsTestSuiteFactory(
});
};
const expectUnknownType = (resp: { [key: string]: any }) => {
const expectBadRequest = (resp: { [key: string]: any }) => {
expect(resp.body).to.eql({
success: false,
successCount: 1,
errors: [
{
id: '1',
type: 'wigwags',
title: 'Wigwags title',
error: {
type: 'unsupported_type',
},
},
],
statusCode: 400,
error: 'Bad Request',
message: `Unable to bulk_create dashboard`,
});
};
const expectRbacForbidden = (resp: { [key: string]: any }) => {
const expectBadRequestWithUnknownType = (resp: { [key: string]: any }) => {
expect(resp.body).to.eql({
statusCode: 403,
error: 'Forbidden',
message: `Unable to bulk_create dashboard`,
statusCode: 400,
error: 'Bad Request',
message: `Unable to bulk_create dashboard,wigwags`,
});
};
const expectBadRequestForUnknownType = (resp: { [key: string]: any }) => {
expect(resp.body).to.eql({
statusCode: 400,
error: 'Bad Request',
message: `Unable to bulk_create wigwags`,
});
};
@ -163,7 +162,8 @@ export function resolveImportErrorsTestSuiteFactory(
return {
resolveImportErrorsTest,
createExpectResults,
expectRbacForbidden,
expectUnknownType,
expectBadRequest,
expectBadRequestWithUnknownType,
expectBadRequestForUnknownType,
};
}

View file

@ -16,7 +16,7 @@ export default function({ getService }: TestInvoker) {
describe('export', () => {
const {
createExpectRbacForbidden,
createExpectBadRequest,
expectTypeOrObjectsRequired,
createExpectVisualizationResults,
exportTest,
@ -59,9 +59,9 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
spaceAwareType: {
description: 'forbidden login and find visualization message',
statusCode: 403,
response: createExpectRbacForbidden('visualization'),
description: 'bad request login and find visualization message',
statusCode: 400,
response: createExpectBadRequest('visualization'),
},
noTypeOrObjects: {
description: 'bad request, type or object is required',
@ -93,9 +93,9 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
spaceAwareType: {
description: 'forbidden login and find visualization message',
statusCode: 403,
response: createExpectRbacForbidden('visualization'),
description: 'bad request login and find visualization message',
statusCode: 400,
response: createExpectBadRequest('visualization'),
},
noTypeOrObjects: {
description: 'bad request, type or object is required',
@ -212,9 +212,9 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
spaceAwareType: {
description: 'forbidden login and find visualization message',
statusCode: 403,
response: createExpectRbacForbidden('visualization'),
description: 'bad request login and find visualization message',
statusCode: 400,
response: createExpectBadRequest('visualization'),
},
noTypeOrObjects: {
description: 'bad request, type or object is required',

View file

@ -18,8 +18,9 @@ export default function({ getService }: TestInvoker) {
const {
importTest,
createExpectResults,
expectRbacForbidden,
expectUnknownType,
expectBadRequest,
expectBadRequestWithUnknownType,
expectBadRequestForUnknownType,
} = importTestSuiteFactory(es, esArchiver, supertest);
describe('_import', () => {
@ -60,12 +61,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -79,8 +80,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(scenario.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -90,12 +91,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -109,8 +110,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(scenario.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -120,12 +121,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -139,8 +140,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(scenario.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -150,12 +151,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -169,8 +170,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(scenario.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -180,12 +181,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -195,12 +196,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});

View file

@ -18,8 +18,9 @@ export default function({ getService }: TestInvoker) {
const {
resolveImportErrorsTest,
createExpectResults,
expectRbacForbidden,
expectUnknownType,
expectBadRequest,
expectBadRequestWithUnknownType,
expectBadRequestForUnknownType,
} = resolveImportErrorsTestSuiteFactory(es, esArchiver, supertest);
describe('_resolve_import_errors', () => {
@ -60,12 +61,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -79,8 +80,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(scenario.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -90,12 +91,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -109,8 +110,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(scenario.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -122,12 +123,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
}
@ -142,8 +143,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(scenario.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -153,12 +154,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -174,8 +175,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(scenario.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
}
@ -188,12 +189,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
}
@ -206,12 +207,12 @@ export default function({ getService }: TestInvoker) {
spaceId: scenario.spaceId,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
}

View file

@ -15,7 +15,7 @@ export default function({ getService }: TestInvoker) {
describe('export', () => {
const {
createExpectRbacForbidden,
createExpectBadRequest,
expectTypeOrObjectsRequired,
createExpectVisualizationResults,
exportTest,
@ -25,9 +25,9 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.NOT_A_KIBANA_USER,
tests: {
spaceAwareType: {
description: 'forbidden login and find visualization message',
statusCode: 403,
response: createExpectRbacForbidden('visualization'),
description: 'bad request login and find visualization message',
statusCode: 400,
response: createExpectBadRequest('visualization'),
},
noTypeOrObjects: {
description: 'bad request, type or object is required',
@ -57,9 +57,9 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_LEGACY_USER,
tests: {
spaceAwareType: {
description: 'forbidden login and find visualization message',
statusCode: 403,
response: createExpectRbacForbidden('visualization'),
description: 'bad request login and find visualization message',
statusCode: 400,
response: createExpectBadRequest('visualization'),
},
noTypeOrObjects: {
description: 'bad request, type or object is required',
@ -138,8 +138,8 @@ export default function({ getService }: TestInvoker) {
tests: {
spaceAwareType: {
description: 'only the visualization',
statusCode: 403,
response: createExpectRbacForbidden('visualization'),
statusCode: 400,
response: createExpectBadRequest('visualization'),
},
noTypeOrObjects: {
description: 'bad request, type or object is required',
@ -154,8 +154,8 @@ export default function({ getService }: TestInvoker) {
tests: {
spaceAwareType: {
description: 'only the visualization',
statusCode: 403,
response: createExpectRbacForbidden('visualization'),
statusCode: 400,
response: createExpectBadRequest('visualization'),
},
noTypeOrObjects: {
description: 'bad request, type or object is required',
@ -170,8 +170,8 @@ export default function({ getService }: TestInvoker) {
tests: {
spaceAwareType: {
description: 'only the visualization',
statusCode: 403,
response: createExpectRbacForbidden('visualization'),
statusCode: 400,
response: createExpectBadRequest('visualization'),
},
noTypeOrObjects: {
description: 'bad request, type or object is required',
@ -186,8 +186,8 @@ export default function({ getService }: TestInvoker) {
tests: {
spaceAwareType: {
description: 'only the visualization',
statusCode: 403,
response: createExpectRbacForbidden('visualization'),
statusCode: 400,
response: createExpectBadRequest('visualization'),
},
noTypeOrObjects: {
description: 'bad request, type or object is required',

View file

@ -17,8 +17,9 @@ export default function({ getService }: TestInvoker) {
const {
importTest,
createExpectResults,
expectRbacForbidden,
expectUnknownType,
expectBadRequest,
expectBadRequestWithUnknownType,
expectBadRequestForUnknownType,
} = importTestSuiteFactory(es, esArchiver, supertest);
describe('_import', () => {
@ -26,12 +27,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.NOT_A_KIBANA_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -44,8 +45,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -54,12 +55,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_LEGACY_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -72,8 +73,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -82,12 +83,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -100,8 +101,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -110,12 +111,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -124,12 +125,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -138,12 +139,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -152,12 +153,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -166,12 +167,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});

View file

@ -17,8 +17,9 @@ export default function({ getService }: TestInvoker) {
const {
resolveImportErrorsTest,
createExpectResults,
expectRbacForbidden,
expectUnknownType,
expectBadRequest,
expectBadRequestWithUnknownType,
expectBadRequestForUnknownType,
} = resolveImportErrorsTestSuiteFactory(es, esArchiver, supertest);
describe('_resolve_import_errors', () => {
@ -26,12 +27,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.NOT_A_KIBANA_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -44,8 +45,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -54,12 +55,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_LEGACY_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -72,8 +73,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -82,12 +83,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_DUAL_PRIVILEGES_DASHBOARD_ONLY_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -100,8 +101,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -110,12 +111,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_RBAC_DASHBOARD_ONLY_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -124,12 +125,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_ALL_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -138,12 +139,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_RBAC_DEFAULT_SPACE_READ_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -152,12 +153,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_ALL_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});
@ -166,12 +167,12 @@ export default function({ getService }: TestInvoker) {
user: AUTHENTICATION.KIBANA_RBAC_SPACE_1_READ_USER,
tests: {
default: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequest,
},
unknownType: {
statusCode: 403,
response: expectRbacForbidden,
statusCode: 400,
response: expectBadRequestWithUnknownType,
},
},
});

View file

@ -14,11 +14,11 @@ export default function({ getService }: TestInvoker) {
const esArchiver = getService('esArchiver');
const es = getService('es');
const { importTest, createExpectResults, expectUnknownType } = importTestSuiteFactory(
es,
esArchiver,
supertest
);
const {
importTest,
createExpectResults,
expectBadRequestForUnknownType,
} = importTestSuiteFactory(es, esArchiver, supertest);
describe('_import', () => {
importTest('in the current space (space_1)', {
@ -29,8 +29,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(SPACES.SPACE_1.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -43,8 +43,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(SPACES.DEFAULT.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});

View file

@ -17,7 +17,7 @@ export default function({ getService }: TestInvoker) {
const {
resolveImportErrorsTest,
createExpectResults,
expectUnknownType,
expectBadRequestForUnknownType,
} = resolveImportErrorsTestSuiteFactory(es, esArchiver, supertest);
describe('_resolve_import_errors', () => {
@ -29,8 +29,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(SPACES.SPACE_1.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});
@ -43,8 +43,8 @@ export default function({ getService }: TestInvoker) {
response: createExpectResults(SPACES.DEFAULT.spaceId),
},
unknownType: {
statusCode: 200,
response: expectUnknownType,
statusCode: 400,
response: expectBadRequestForUnknownType,
},
},
});