diff --git a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts new file mode 100644 index 0000000000..9692d55150 --- /dev/null +++ b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.test.ts @@ -0,0 +1,69 @@ +/* + * 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'; +jest.mock('../ingestion/LocationReaders'); + +import knex from 'knex'; +import path from 'path'; + +import { Database } from '../database'; + +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; + + beforeEach(async () => { + await database.migrate.latest({ + directory: path.resolve(__dirname, '../database/migrations'), + loadExtensions: ['.ts'], + }); + db = new Database(database); + catalog = new DatabaseLocationsCatalog(db); + }); + 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.toEqual(new Error(`Unknown location type ${type}`)); + }); + it('rejects for unreadable target ', async () => { + const target = 'invalid_target'; + return expect( + catalog.addLocation({ type: 'valid_type', target }), + ).rejects.toEqual( + new Error( + `Can't read location at ${target} with error: Something is broken`, + ), + ); + }); +}); diff --git a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts index e9f1512074..4b2a3a8006 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseLocationsCatalog.ts @@ -16,11 +16,24 @@ import { Database } from '../database'; import { AddLocation, Location, LocationsCatalog } from './types'; +import { LocationReaders } from '../ingestion'; export class DatabaseLocationsCatalog implements LocationsCatalog { constructor(private readonly database: Database) {} async addLocation(location: AddLocation): Promise { + const outputs = await LocationReaders.create().read( + location.type, + location.target, + ); + outputs.forEach(output => { + if (output.type === 'error') { + throw new Error( + `Can't read location at ${location.target} with error: ${output.error.message}`, + ); + } + }); + const added = await this.database.addLocation(location); return added; } diff --git a/plugins/catalog-backend/src/ingestion/__mocks__/LocationReaders.ts b/plugins/catalog-backend/src/ingestion/__mocks__/LocationReaders.ts new file mode 100644 index 0000000000..1bfa815280 --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/__mocks__/LocationReaders.ts @@ -0,0 +1,43 @@ +/* + * 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 { LocationSource } from '../sources/types'; +import { LocationReader, ReaderOutput } from '../types'; + +export class LocationReaders implements LocationReader { + static create(): LocationReader { + return { + read: (type, target) => { + 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`, + ); + }, + }; + } + + constructor(private readonly sources: Record) {} + + // eslint-disable-next-line + async read(type: string, target: string): Promise { + return []; + } +}