feature: implement location validation on addLocation
This commit is contained in:
@@ -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`,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -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<Location> {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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<string, LocationSource>) {}
|
||||
|
||||
// eslint-disable-next-line
|
||||
async read(type: string, target: string): Promise<ReaderOutput[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user