1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2024-12-25 02:04:15 +02:00

improving db scheme. Adding Mysql tests

This commit is contained in:
Patrik J. Braun 2019-01-27 14:36:42 -05:00
parent 8ed202b53d
commit d92003eeee
22 changed files with 342 additions and 150 deletions

View File

@ -1,9 +1,15 @@
dist: trusty
language: node_js
node_js:
- '10'
- '11'
- '10'
- '11'
env:
- Server-database-mysql-host='localhost'
- Server-database-mysql-username='root'
- Server-database-mysql-password=''
- Server-database-mysql-database='pigallery2_travis'
services:
- mysql
addons:
chrome: stable
before_install:

View File

@ -222,7 +222,7 @@ export class GalleryMWs {
}
public static async autocomplete(req: Request, res: Response, next: NextFunction) {
if (Config.Client.Search.autocompleteEnabled === false) {
if (Config.Client.Search.AutoComplete.enabled === false) {
return next();
}
if (!(req.params.text)) {

View File

@ -17,16 +17,17 @@ import {DataStructureVersion} from '../../../common/DataStructureVersion';
import {FileEntity} from './enitites/FileEntity';
import {FaceRegionEntry} from './enitites/FaceRegionEntry';
import {PersonEntry} from './enitites/PersonEntry';
import {Utils} from '../../../common/Utils';
export class SQLConnection {
private static connection: Connection = null;
constructor() {
}
private static connection: Connection = null;
public static async getConnection(): Promise<Connection> {
if (this.connection == null) {
const options: any = this.getDriver(Config.Server.database);
@ -44,8 +45,10 @@ export class SQLConnection {
VersionEntity
];
options.synchronize = false;
//options.logging = 'all';
this.connection = await createConnection(options);
// options.logging = 'all';
this.connection = await this.createConnection(options);
await SQLConnection.schemeSync(this.connection);
}
return this.connection;
@ -72,7 +75,7 @@ export class SQLConnection {
];
options.synchronize = false;
// options.logging = "all";
const conn = await createConnection(options);
const conn = await this.createConnection(options);
await SQLConnection.schemeSync(conn);
await conn.close();
return true;
@ -92,6 +95,38 @@ export class SQLConnection {
}
public static async close() {
try {
if (this.connection != null) {
await this.connection.close();
this.connection = null;
}
} catch (err) {
console.error(err);
}
}
private static async createConnection(options: ConnectionOptions) {
if (options.type === 'sqlite') {
return await createConnection(options);
}
try {
return await createConnection(options);
} catch (e) {
if (e.sqlMessage === 'Unknown database \'' + options.database + '\'') {
Logger.debug('creating database: ' + options.database);
const tmpOption = Utils.clone(options);
// @ts-ignore
delete tmpOption.database;
const tmpConn = await createConnection(tmpOption);
await tmpConn.query('CREATE DATABASE IF NOT EXISTS ' + options.database);
await tmpConn.close();
return await createConnection(options);
}
throw e;
}
}
private static async schemeSync(connection: Connection) {
let version = null;
try {
@ -145,16 +180,5 @@ export class SQLConnection {
return driver;
}
public static async close() {
try {
if (this.connection != null) {
await this.connection.close();
this.connection = null;
}
} catch (err) {
console.error(err);
}
}
}

View File

@ -9,6 +9,7 @@ import {VideoEntity} from './enitites/VideoEntity';
import {PersonEntry} from './enitites/PersonEntry';
import {FaceRegionEntry} from './enitites/FaceRegionEntry';
import {SelectQueryBuilder} from 'typeorm';
import {Config} from '../../../common/config/private/Config';
export class SearchManager implements ISearchManager {
@ -40,7 +41,7 @@ export class SearchManager implements ISearchManager {
.createQueryBuilder('photo')
.select('DISTINCT(photo.metadata.keywords)')
.where('photo.metadata.keywords LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
.limit(5)
.limit(Config.Client.Search.AutoComplete.maxItemsPerCategory)
.getRawMany())
.map(r => <Array<string>>(<string>r.metadataKeywords).split(','))
.forEach(keywords => {
@ -52,7 +53,8 @@ export class SearchManager implements ISearchManager {
.createQueryBuilder('person')
.select('DISTINCT(person.name)')
.where('person.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
.limit(5)
.limit(Config.Client.Search.AutoComplete.maxItemsPerCategory)
.orderBy('person.name')
.getRawMany())
.map(r => r.name), SearchTypes.person));
@ -64,7 +66,7 @@ export class SearchManager implements ISearchManager {
.orWhere('photo.metadata.positionData.state LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
.orWhere('photo.metadata.positionData.city LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
.groupBy('photo.metadata.positionData.country, photo.metadata.positionData.state, photo.metadata.positionData.city')
.limit(5)
.limit(Config.Client.Search.AutoComplete.maxItemsPerCategory)
.getRawMany())
.filter(pm => !!pm)
.map(pm => <Array<string>>[pm.city || '', pm.country || '', pm.state || ''])
@ -77,7 +79,7 @@ export class SearchManager implements ISearchManager {
.createQueryBuilder('media')
.select('DISTINCT(media.name)')
.where('media.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
.limit(5)
.limit(Config.Client.Search.AutoComplete.maxItemsPerCategory)
.getRawMany())
.map(r => r.name), SearchTypes.photo));
@ -86,7 +88,7 @@ export class SearchManager implements ISearchManager {
.createQueryBuilder('media')
.select('DISTINCT(media.metadata.caption) as caption')
.where('media.metadata.caption LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
.limit(5)
.limit(Config.Client.Search.AutoComplete.maxItemsPerCategory)
.getRawMany())
.map(r => r.caption), SearchTypes.photo));
@ -95,7 +97,7 @@ export class SearchManager implements ISearchManager {
.createQueryBuilder('media')
.select('DISTINCT(media.name)')
.where('media.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
.limit(5)
.limit(Config.Client.Search.AutoComplete.maxItemsPerCategory)
.getRawMany())
.map(r => r.name), SearchTypes.video));
@ -103,7 +105,7 @@ export class SearchManager implements ISearchManager {
.createQueryBuilder('dir')
.select('DISTINCT(dir.name)')
.where('dir.name LIKE :text COLLATE utf8_general_ci', {text: '%' + text + '%'})
.limit(5)
.limit(Config.Client.Search.AutoComplete.maxItemsPerCategory)
.getRawMany())
.map(r => r.name), SearchTypes.directory));

View File

@ -1,4 +1,4 @@
import {Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn, Unique, Index} from 'typeorm';
import {Column, Entity, Index, ManyToOne, OneToMany, PrimaryGeneratedColumn, Unique} from 'typeorm';
import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO';
import {MediaEntity} from './MediaEntity';
import {FileEntity} from './FileEntity';
@ -8,7 +8,7 @@ import {FileEntity} from './FileEntity';
export class DirectoryEntity implements DirectoryDTO {
@Index()
@PrimaryGeneratedColumn()
@PrimaryGeneratedColumn({unsigned: true})
id: number;
@Index()
@ -22,18 +22,28 @@ export class DirectoryEntity implements DirectoryDTO {
/**
* last time the directory was modified (from outside, eg.: a new media was added)
*/
@Column('bigint')
@Column('bigint', {
unsigned: true, transformer: {
from: v => parseInt(v, 10),
to: v => v
}
})
public lastModified: number;
/**
* Last time the directory was fully scanned, not only for a few media to create a preview
*/
@Column({type: 'bigint', nullable: true})
@Column({
type: 'bigint', nullable: true, unsigned: true, transformer: {
from: v => parseInt(v, 10),
to: v => v
}
})
public lastScanned: number;
isPartial?: boolean;
@Column('smallint')
@Column('smallint', {unsigned: true})
mediaCount: number;
@Index()

View File

@ -20,7 +20,7 @@ export class FaceRegionBoxEntry implements FaceRegionBox {
@Entity()
export class FaceRegionEntry {
@PrimaryGeneratedColumn()
@PrimaryGeneratedColumn({unsigned: true})
id: number;
@Column(type => FaceRegionBoxEntry)

View File

@ -7,7 +7,7 @@ import {FileDTO} from '../../../../common/entities/FileDTO';
export class FileEntity implements FileDTO {
@Index()
@PrimaryGeneratedColumn()
@PrimaryGeneratedColumn({unsigned: true})
id: number;
@Column('text')

View File

@ -1,4 +1,4 @@
import {Column, Entity, OneToMany, ManyToOne, PrimaryGeneratedColumn, TableInheritance, Unique, Index} from 'typeorm';
import {Column, Entity, Index, ManyToOne, OneToMany, PrimaryGeneratedColumn, TableInheritance, Unique} from 'typeorm';
import {DirectoryEntity} from './DirectoryEntity';
import {MediaDimension, MediaDTO, MediaMetadata} from '../../../../common/entities/MediaDTO';
import {OrientationTypes} from 'ts-exif-parser';
@ -22,10 +22,15 @@ export class MediaMetadataEntity implements MediaMetadata {
@Column(type => MediaDimensionEntity)
size: MediaDimensionEntity;
@Column('bigint')
@Column('bigint', {
unsigned: true, transformer: {
from: v => parseInt(v, 10),
to: v => v
}
})
creationDate: number;
@Column('int')
@Column('int', {unsigned: true})
fileSize: number;
@Column('simple-array')
@ -37,30 +42,30 @@ export class MediaMetadataEntity implements MediaMetadata {
@Column(type => PositionMetaDataEntity)
positionData: PositionMetaDataEntity;
@Column('tinyint', {default: OrientationTypes.TOP_LEFT})
@Column('tinyint', {unsigned: true, default: OrientationTypes.TOP_LEFT})
orientation: OrientationTypes;
@OneToMany(type => FaceRegionEntry, faceRegion => faceRegion.media)
faces: FaceRegionEntry[];
@Column('int')
@Column('int', {unsigned: true})
bitRate: number;
@Column('bigint')
@Column('int', {unsigned: true})
duration: number;
}
// TODO: fix inheritance once its working in typeorm
@Entity()
@Unique(['name', 'directory'])
@TableInheritance({column: {type: 'varchar', name: 'type'}})
@TableInheritance({column: {type: 'varchar', name: 'type', length: 32}})
export abstract class MediaEntity implements MediaDTO {
@Index()
@PrimaryGeneratedColumn()
@PrimaryGeneratedColumn({unsigned: true})
id: number;
@Column('text')
@Column()
name: string;
@Index()

View File

@ -6,7 +6,7 @@ import {FaceRegionEntry} from './FaceRegionEntry';
@Unique(['name'])
export class PersonEntry {
@Index()
@PrimaryGeneratedColumn()
@PrimaryGeneratedColumn({unsigned: true})
id: number;
@Column()

View File

@ -5,7 +5,7 @@ import {UserDTO} from '../../../../common/entities/UserDTO';
@Entity()
export class SharingEntity implements SharingDTO {
@PrimaryGeneratedColumn()
@PrimaryGeneratedColumn({unsigned: true})
id: number;
@Column()
@ -17,10 +17,20 @@ export class SharingEntity implements SharingDTO {
@Column({type: 'text', nullable: true})
password: string;
@Column()
@Column('bigint', {
unsigned: true, transformer: {
from: v => parseInt(v, 10),
to: v => v
}
})
expires: number;
@Column()
@Column('bigint', {
unsigned: true, transformer: {
from: v => parseInt(v, 10),
to: v => v
}
})
timeStamp: number;
@Column()

View File

@ -1 +1 @@
export const DataStructureVersion = 8;
export const DataStructureVersion = 9;

View File

@ -7,14 +7,19 @@ export module ClientConfig {
OpenStreetMap, Mapbox, Custom
}
export interface AutoCompleteConfig {
enabled: boolean;
maxItemsPerCategory: number;
cacheTimeout: number;
}
export interface SearchConfig {
enabled: boolean;
instantSearchEnabled: boolean;
autocompleteEnabled: boolean;
InstantSearchTimeout: number;
autocompleteCacheTimeout: number;
instantSearchCacheTimeout: number;
searchCacheTimeout: number;
AutoComplete: AutoCompleteConfig;
}
export interface SharingConfig {
@ -95,11 +100,14 @@ export class PublicConfigClass {
Search: {
enabled: true,
instantSearchEnabled: true,
autocompleteEnabled: true,
InstantSearchTimeout: 3000,
autocompleteCacheTimeout: 1000 * 60 * 60,
searchCacheTimeout: 1000 * 60 * 60,
instantSearchCacheTimeout: 1000 * 60 * 60
instantSearchCacheTimeout: 1000 * 60 * 60,
AutoComplete: {
enabled: true,
cacheTimeout: 1000 * 60 * 60,
maxItemsPerCategory: 5
}
},
Sharing: {
enabled: true,

View File

@ -77,7 +77,7 @@ export class GalleryCacheService {
const tmp = localStorage.getItem(key);
if (tmp != null) {
const value: CacheItem<AutoCompleteItem[]> = JSON.parse(tmp);
if (value.timestamp < Date.now() - Config.Client.Search.autocompleteCacheTimeout) {
if (value.timestamp < Date.now() - Config.Client.Search.AutoComplete.cacheTimeout) {
localStorage.removeItem(key);
return null;
}

View File

@ -54,7 +54,7 @@ export class GallerySearchComponent implements OnDestroy {
const searchText = (<HTMLInputElement>event.target).value.trim();
if (Config.Client.Search.autocompleteEnabled &&
if (Config.Client.Search.AutoComplete.enabled &&
this.cache.lastAutocomplete !== searchText) {
this.cache.lastAutocomplete = searchText;
this.autocomplete(searchText).catch(console.error);
@ -92,7 +92,7 @@ export class GallerySearchComponent implements OnDestroy {
}
private async autocomplete(searchText: string) {
if (!Config.Client.Search.autocompleteEnabled) {
if (!Config.Client.Search.AutoComplete.enabled) {
return;
}
if (searchText.trim() === '.') {

View File

@ -15,12 +15,15 @@ export class SettingsService {
Client: {
Search: {
enabled: true,
autocompleteEnabled: true,
AutoComplete: {
enabled: true,
cacheTimeout: 1000 * 60 * 60,
maxItemsPerCategory: 5
},
instantSearchEnabled: true,
InstantSearchTimeout: 0,
searchCacheTimeout: 1000 * 60 * 60,
instantSearchCacheTimeout: 1000 * 60 * 60,
autocompleteCacheTimeout: 1000 * 60 * 60
},
Thumbnail: {
concurrentThumbnailGenerations: null,

View File

@ -0,0 +1,107 @@
import {Config} from '../../common/config/private/Config';
import {DatabaseType} from '../../common/config/private/IPrivateConfig';
import * as fs from 'fs';
import * as path from 'path';
import {SQLConnection} from '../../backend/model/sql/SQLConnection';
declare let describe: any;
const savedDescribe = describe;
export class SQLTestHelper {
static enable = {
sqlite: true,
mysql: true
};
public static readonly savedDescribe = savedDescribe;
tempDir: string;
dbPath: string;
constructor(public dbType: DatabaseType) {
this.tempDir = path.resolve(__dirname, './tmp');
this.dbPath = path.resolve(__dirname, './tmp', 'test.db');
}
static describe(name: string, tests: (helper?: SQLTestHelper) => void) {
savedDescribe(name, async () => {
if (SQLTestHelper.enable.sqlite) {
const helper = new SQLTestHelper(DatabaseType.sqlite);
savedDescribe('sqlite', () => {
return tests(helper);
});
}
if (SQLTestHelper.enable.mysql) {
const helper = new SQLTestHelper(DatabaseType.mysql);
savedDescribe('mysql', function () {
this.timeout(99999999);
// @ts-ignore
return tests(helper);
});
}
});
}
public async initDB() {
if (this.dbType === DatabaseType.sqlite) {
await this.initSQLite();
} else {
await this.initMySQL();
}
}
public async clearDB() {
if (this.dbType === DatabaseType.sqlite) {
await this.clearUpSQLite();
} else {
await this.clearUpMysql();
}
}
private async initSQLite() {
await this.resetSQLite();
Config.Server.database.type = DatabaseType.sqlite;
Config.Server.database.sqlite.storage = this.dbPath;
}
private async initMySQL() {
Config.Server.database.type = DatabaseType.mysql;
Config.Server.database.mysql.database = 'pigallery2_test';
await this.resetMySQL();
}
private async resetSQLite() {
await SQLConnection.close();
if (fs.existsSync(this.dbPath)) {
fs.unlinkSync(this.dbPath);
}
if (fs.existsSync(this.tempDir)) {
fs.rmdirSync(this.tempDir);
}
}
private async resetMySQL() {
Config.Server.database.type = DatabaseType.mysql;
Config.Server.database.mysql.database = 'pigallery2_test';
const conn = await SQLConnection.getConnection();
await conn.query('DROP DATABASE IF EXISTS ' + conn.options.database);
await conn.query('CREATE DATABASE IF NOT EXISTS ' + conn.options.database);
await SQLConnection.close();
}
private async clearUpMysql() {
Config.Server.database.type = DatabaseType.mysql;
Config.Server.database.mysql.database = 'pigallery2_test';
const conn = await SQLConnection.getConnection();
await conn.query('DROP DATABASE IF EXISTS ' + conn.options.database);
await SQLConnection.close();
}
private async clearUpSQLite() {
return this.resetSQLite();
}
}

View File

@ -16,7 +16,6 @@ import {
PositionMetaDataEntity
} from '../../../../../backend/model/sql/enitites/PhotoEntity';
import {MediaDimensionEntity} from '../../../../../backend/model/sql/enitites/MediaEntity';
import {DataStructureVersion} from '../../../../../common/DataStructureVersion';
import {VersionEntity} from '../../../../../backend/model/sql/enitites/VersionEntity';
describe('Typeorm integration', () => {

View File

@ -0,0 +1,58 @@
import {expect} from 'chai';
import {TestHelper} from './TestHelper';
import {SQLTestHelper} from '../../../SQLTestHelper';
import {GalleryManager} from '../../../../../backend/model/sql/GalleryManager';
import {IndexingManager} from '../../../../../backend/model/sql/IndexingManager';
import {DirectoryDTO} from '../../../../../common/entities/DirectoryDTO';
import {Utils} from '../../../../../common/Utils';
import {ObjectManagerRepository} from '../../../../../backend/model/ObjectManagerRepository';
import {PersonManager} from '../../../../../backend/model/sql/PersonManager';
import {MediaEntity} from '../../../../../backend/model/sql/enitites/MediaEntity';
class IndexingManagerTest extends IndexingManager {
public async saveToDB(scannedDirectory: DirectoryDTO): Promise<void> {
return super.saveToDB(scannedDirectory);
}
}
// to help WebStorm to handle the test cases
declare let describe: any;
declare const after: any;
describe = SQLTestHelper.describe;
describe('GalleryManager', (sqlHelper: SQLTestHelper) => {
beforeEach(async () => {
await sqlHelper.initDB();
ObjectManagerRepository.getInstance().PersonManager = new PersonManager();
});
after(async () => {
await sqlHelper.clearDB();
});
it('should get random photo', async () => {
const gm = new GalleryManager();
const im = new IndexingManagerTest();
const parent = TestHelper.getRandomizedDirectoryEntry();
const p1 = TestHelper.getRandomizedPhotoEntry(parent, 'Photo1');
expect(await gm.getRandomPhoto({})).to.not.exist;
DirectoryDTO.removeReferences(parent);
await im.saveToDB(Utils.clone(parent));
delete p1.metadata.faces;
delete p1.directory;
delete p1.id;
const found: MediaEntity = <any>await gm.getRandomPhoto({});
delete found.metadata.bitRate;
delete found.metadata.duration;
delete found.directory;
delete found.id;
expect(Utils.clone(found)).to.be.deep.equal(Utils.clone(p1));
});
});

View File

@ -1,8 +1,7 @@
import {expect} from 'chai';
import * as fs from 'fs';
import * as path from 'path';
import {Config} from '../../../../../common/config/private/Config';
import {DatabaseType, ReIndexingSensitivity} from '../../../../../common/config/private/IPrivateConfig';
import {ReIndexingSensitivity} from '../../../../../common/config/private/IPrivateConfig';
import {SQLConnection} from '../../../../../backend/model/sql/SQLConnection';
import {GalleryManager} from '../../../../../backend/model/sql/GalleryManager';
import {DirectoryDTO} from '../../../../../common/entities/DirectoryDTO';
@ -15,6 +14,7 @@ import {FileDTO} from '../../../../../common/entities/FileDTO';
import {IndexingManager} from '../../../../../backend/model/sql/IndexingManager';
import {ObjectManagerRepository} from '../../../../../backend/model/ObjectManagerRepository';
import {PersonManager} from '../../../../../backend/model/sql/PersonManager';
import {SQLTestHelper} from '../../../SQLTestHelper';
class GalleryManagerTest extends GalleryManager {
@ -41,43 +41,22 @@ class IndexingManagerTest extends IndexingManager {
}
}
describe('IndexingManager', () => {
// to help WebStorm to handle the test cases
declare let describe: any;
declare const after: any;
describe = SQLTestHelper.describe;
describe('IndexingManager', (sqlHelper: SQLTestHelper) => {
const tempDir = path.join(__dirname, '../../tmp');
const dbPath = path.join(tempDir, 'test.db');
const setUpSqlDB = async () => {
if (fs.existsSync(dbPath)) {
fs.unlinkSync(dbPath);
}
if (!fs.existsSync(tempDir)) {
fs.mkdirSync(tempDir);
}
Config.Server.database.type = DatabaseType.sqlite;
Config.Server.database.sqlite.storage = dbPath;
ObjectManagerRepository.getInstance().PersonManager = new PersonManager();
};
const tearDownSqlDB = async () => {
await SQLConnection.close();
if (fs.existsSync(dbPath)) {
fs.unlinkSync(dbPath);
}
if (fs.existsSync(tempDir)) {
fs.rmdirSync(tempDir);
}
};
beforeEach(async () => {
await setUpSqlDB();
await sqlHelper.initDB();
ObjectManagerRepository.getInstance().PersonManager = new PersonManager();
});
afterEach(async () => {
await tearDownSqlDB();
after(async () => {
await sqlHelper.clearDB();
});
const removeIds = (dir: DirectoryDTO) => {
@ -245,7 +224,7 @@ describe('IndexingManager', () => {
expect(selected.media.length).to.deep.equal(subDir.media.length);
}) as any).timeout(40000);
describe('Test listDirectory', () => {
SQLTestHelper.savedDescribe('Test listDirectory', () => {
const statSync = fs.statSync;
let dirTime = 0;
const indexedTime = {

View File

@ -1,8 +1,4 @@
import {expect} from 'chai';
import * as fs from 'fs';
import * as path from 'path';
import {Config} from '../../../../../common/config/private/Config';
import {DatabaseType} from '../../../../../common/config/private/IPrivateConfig';
import {SQLConnection} from '../../../../../backend/model/sql/SQLConnection';
import {PhotoEntity} from '../../../../../backend/model/sql/enitites/PhotoEntity';
import {SearchManager} from '../../../../../backend/model/sql/SearchManager';
@ -15,12 +11,15 @@ import {VideoEntity} from '../../../../../backend/model/sql/enitites/VideoEntity
import {PersonEntry} from '../../../../../backend/model/sql/enitites/PersonEntry';
import {FaceRegionEntry} from '../../../../../backend/model/sql/enitites/FaceRegionEntry';
import {PhotoDTO} from '../../../../../common/entities/PhotoDTO';
import {SQLTestHelper} from '../../../SQLTestHelper';
import {Config} from '../../../../../common/config/private/Config';
describe('SearchManager', () => {
// to help WebStorm to handle the test cases
declare let describe: any;
declare const after: any;
describe = SQLTestHelper.describe;
const tempDir = path.join(__dirname, '../../tmp');
const dbPath = path.join(tempDir, 'test.db');
describe('SearchManager', (sqlHelper: SQLTestHelper) => {
const dir = TestHelper.getDirectoryEntry();
const p = TestHelper.getPhotoEntry1(dir);
@ -31,15 +30,7 @@ describe('SearchManager', () => {
const v = TestHelper.getVideoEntry1(dir);
const setUpSqlDB = async () => {
if (fs.existsSync(dbPath)) {
fs.unlinkSync(dbPath);
}
if (!fs.existsSync(tempDir)) {
fs.mkdirSync(tempDir);
}
Config.Server.database.type = DatabaseType.sqlite;
Config.Server.database.sqlite.storage = dbPath;
await sqlHelper.initDB();
const savePhoto = async (photo: PhotoDTO) => {
const savedPhoto = await pr.save(photo);
@ -66,24 +57,15 @@ describe('SearchManager', () => {
await SQLConnection.close();
};
const tearDownSqlDB = async () => {
await SQLConnection.close();
if (fs.existsSync(dbPath)) {
fs.unlinkSync(dbPath);
}
if (fs.existsSync(tempDir)) {
fs.rmdirSync(tempDir);
}
};
beforeEach(async () => {
await setUpSqlDB();
});
afterEach(async () => {
await tearDownSqlDB();
});
after(async () => {
await sqlHelper.clearDB();
});
it('should get autocomplete', async () => {
const sm = new SearchManager();
@ -103,6 +85,8 @@ describe('SearchManager', () => {
new AutoCompleteItem('wars dir', SearchTypes.directory)]);
expect((await sm.autocomplete('arch'))).eql([new AutoCompleteItem('Research City', SearchTypes.position)]);
Config.Client.Search.AutoComplete.maxItemsPerCategory = 99999;
expect((await sm.autocomplete('a')).sort(cmp)).eql([
new AutoCompleteItem('Boba Fett', SearchTypes.keyword),
new AutoCompleteItem('Boba Fett', SearchTypes.person),
@ -113,6 +97,7 @@ describe('SearchManager', () => {
new AutoCompleteItem('Han Solo', SearchTypes.person),
new AutoCompleteItem('death star', SearchTypes.keyword),
new AutoCompleteItem('Padmé Amidala', SearchTypes.person),
new AutoCompleteItem('Obivan Kenobi', SearchTypes.person),
new AutoCompleteItem('Padmé Amidala', SearchTypes.keyword),
new AutoCompleteItem('Natalie Portman', SearchTypes.keyword),
new AutoCompleteItem('Han Solo\'s dice', SearchTypes.photo),
@ -121,10 +106,24 @@ describe('SearchManager', () => {
new AutoCompleteItem('wars dir', SearchTypes.directory),
new AutoCompleteItem('Research City', SearchTypes.position)].sort(cmp));
Config.Client.Search.AutoComplete.maxItemsPerCategory = 1;
expect((await sm.autocomplete('a')).sort(cmp)).eql([
new AutoCompleteItem('Anakin', SearchTypes.keyword),
new AutoCompleteItem('star wars', SearchTypes.keyword),
new AutoCompleteItem('death star', SearchTypes.keyword),
new AutoCompleteItem('Anakin Skywalker', SearchTypes.person),
new AutoCompleteItem('Han Solo\'s dice', SearchTypes.photo),
new AutoCompleteItem('Kamino', SearchTypes.position),
new AutoCompleteItem('Research City', SearchTypes.position),
new AutoCompleteItem('wars dir', SearchTypes.directory),
new AutoCompleteItem('Boba Fett', SearchTypes.keyword)].sort(cmp));
Config.Client.Search.AutoComplete.maxItemsPerCategory = 5;
expect((await sm.autocomplete('sw')).sort(cmp)).to.deep.equal([new AutoCompleteItem('sw1', SearchTypes.photo),
new AutoCompleteItem('sw2', SearchTypes.photo), new AutoCompleteItem(v.name, SearchTypes.video)].sort(cmp));
expect((await sm.autocomplete(v.name)).sort(cmp)).to.deep.equal([new AutoCompleteItem(v.name, SearchTypes.video)]);
});

View File

@ -1,32 +1,23 @@
import {expect} from 'chai';
import * as fs from 'fs';
import * as path from 'path';
import {Config} from '../../../../../common/config/private/Config';
import {DatabaseType} from '../../../../../common/config/private/IPrivateConfig';
import {SQLConnection} from '../../../../../backend/model/sql/SQLConnection';
import {SharingManager} from '../../../../../backend/model/sql/SharingManager';
import {SharingDTO} from '../../../../../common/entities/SharingDTO';
import {UserEntity} from '../../../../../backend/model/sql/enitites/UserEntity';
import {UserDTO, UserRoles} from '../../../../../common/entities/UserDTO';
import {SQLTestHelper} from '../../../SQLTestHelper';
describe('SharingManager', () => {
// to help WebStorm to handle the test cases
declare let describe: any;
declare const after: any;
describe = SQLTestHelper.describe;
describe('SharingManager', (sqlHelper: SQLTestHelper) => {
const tempDir = path.join(__dirname, '../../tmp');
const dbPath = path.join(tempDir, 'test.db');
let creator: UserDTO = null;
const setUpSqlDB = async () => {
if (fs.existsSync(dbPath)) {
fs.unlinkSync(dbPath);
}
if (!fs.existsSync(tempDir)) {
fs.mkdirSync(tempDir);
}
Config.Server.database.type = DatabaseType.sqlite;
Config.Server.database.sqlite.storage = dbPath;
await sqlHelper.initDB();
const conn = await SQLConnection.getConnection();
@ -41,22 +32,13 @@ describe('SharingManager', () => {
await SQLConnection.close();
};
const teardownUpSqlDB = async () => {
await SQLConnection.close();
if (fs.existsSync(dbPath)) {
fs.unlinkSync(dbPath);
}
if (fs.existsSync(tempDir)) {
fs.rmdirSync(tempDir);
}
};
beforeEach(async () => {
await setUpSqlDB();
});
afterEach(async () => {
await teardownUpSqlDB();
after(async () => {
await sqlHelper.clearDB();
});

View File

@ -258,7 +258,7 @@ export class TestHelper {
name: rndStr() + '.jpg',
directory: dir,
metadata: m,
readyThumbnails: null,
readyThumbnails: [],
readyIcon: false
};