Merge pull request #1001 from Nek/ndudnik/validate-locations

feature: implement location validation on addLocation
This commit is contained in:
Fredrik Adelöw
2020-05-26 11:50:49 +02:00
committed by GitHub
3 changed files with 97 additions and 2 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ export default async function ({ logger, database }: PluginEnvironment) {
);
const entitiesCatalog = new DatabaseEntitiesCatalog(db);
const locationsCatalog = new DatabaseLocationsCatalog(db);
const locationsCatalog = new DatabaseLocationsCatalog(db, reader);
return await createRouter({ entitiesCatalog, locationsCatalog, logger });
}
@@ -0,0 +1,82 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { DatabaseLocationsCatalog } from './DatabaseLocationsCatalog';
import knex from 'knex';
import path from 'path';
import { Database } from '../database';
import { ReaderOutput } from '../ingestion/types';
import { getVoidLogger } from '@backstage/backend-common';
describe('DatabaseLocationsCatalog', () => {
const database = knex({
client: 'sqlite3',
connection: ':memory:',
useNullAsDefault: true,
});
database.client.pool.on('createSuccess', (_eventId: any, resource: any) => {
resource.run('PRAGMA foreign_keys = ON', () => {});
});
let db: Database;
let catalog: DatabaseLocationsCatalog;
const mockLocationReader = {
read: async (type: string, target: string): Promise<ReaderOutput[]> => {
if (type !== 'valid_type') {
throw new Error(`Unknown location type ${type}`);
}
if (target === 'valid_target') {
return Promise.resolve([{ type: 'data', data: {} }]);
}
throw new Error(
`Can't read location at ${target} with error: Something is broken`,
);
},
};
beforeEach(async () => {
await database.migrate.latest({
directory: path.resolve(__dirname, '../database/migrations'),
loadExtensions: ['.ts'],
});
db = new Database(database, getVoidLogger());
catalog = new DatabaseLocationsCatalog(db, mockLocationReader);
});
it('resolves to location with id', async () => {
return expect(
catalog.addLocation({ type: 'valid_type', target: 'valid_target' }),
).resolves.toEqual({
id: expect.anything(),
type: 'valid_type',
target: 'valid_target',
});
});
it('rejects for invalid type', async () => {
const type = 'invalid_type';
return expect(
catalog.addLocation({ type, target: 'valid_target' }),
).rejects.toThrow(/Unknown location type/);
});
it('rejects for unreadable target ', async () => {
const target = 'invalid_target';
return expect(
catalog.addLocation({ type: 'valid_type', target }),
).rejects.toThrow(
`Can't read location at ${target} with error: Something is broken`,
);
});
});
@@ -16,11 +16,24 @@
import { Database } from '../database';
import { AddLocation, Location, LocationsCatalog } from './types';
import { LocationReader } from '../ingestion';
export class DatabaseLocationsCatalog implements LocationsCatalog {
constructor(private readonly database: Database) {}
constructor(
private readonly database: Database,
private readonly reader: LocationReader,
) {}
async addLocation(location: AddLocation): Promise<Location> {
const outputs = await this.reader.read(location.type, location.target);
outputs.forEach(output => {
if (output.type === 'error') {
throw new Error(
`Can't read location at ${location.target}, ${output.error}`,
);
}
});
const added = await this.database.addLocation(location);
return added;
}