mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 05:26:47 +00:00
8e4261ed81
Both were left open by the audit and are closed here. days, packing, photos and reservations each built a service outside the container at module load for nobody: only their own delegation tests imported them, and three domain docblocks were still telling readers to go through them. photos.bridge's own comment pointed at src/services/, a directory deleted two PRs ago. The cases that exercised them kept their assertions and call the service the bridge delegated to, so nothing that was proved stopped being proved. Twelve bridges remain, each with a live out-of-container caller. Coverage measured src/** but gated only src/nest/**, so the boot path, the scheduler, the MCP handler and the migrations sat under no floor at all. That is the same 9,602 lines where this audit found its worst defect, and a swallowed EADDRINUSE is exactly the kind of thing an untested boot path hides. Seven globs now pin what is measured today. They are floors to raise, not targets that have been met: src/*.ts is at 39% statements and src/db at 38% branches, and writing those numbers down is the point. src/demo/** is deliberately left out. It measures 0%, and a floor of zero asserts nothing; it needs tests before it needs a threshold.
76 lines
3.1 KiB
TypeScript
76 lines
3.1 KiB
TypeScript
/**
|
|
* trek_photos media_type persistence (#823): a local or provider photo row can
|
|
* be registered as a video and the discriminator round-trips.
|
|
*/
|
|
import { describe, it, expect, vi, beforeAll, beforeEach, afterAll } from 'vitest';
|
|
|
|
const { testDb, dbMock } = vi.hoisted(() => {
|
|
const Database = require('better-sqlite3');
|
|
const db = new Database(':memory:');
|
|
// FKs off: this suite only checks media_type persistence, not owner/user integrity.
|
|
db.exec('PRAGMA foreign_keys = OFF');
|
|
const mock = { db, closeDb: () => {}, reinitialize: () => {}, getPlaceWithTags: () => null, canAccessTrip: () => null, isOwner: () => false };
|
|
return { testDb: db, dbMock: mock };
|
|
});
|
|
|
|
vi.mock('../../../src/db/database', () => dbMock);
|
|
vi.mock('../../../src/config', () => ({
|
|
JWT_SECRET: 'test-secret',
|
|
ENCRYPTION_KEY: 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2',
|
|
updateJwtSecret: () => {},
|
|
}));
|
|
|
|
import { createTables } from '../../../src/db/schema';
|
|
import { runMigrations } from '../../../src/db/migrations';
|
|
import { createUser } from '../../helpers/factories';
|
|
import { TrekPhotosRepository } from '../../../src/nest/photos/trek-photos.repository';
|
|
import { DatabaseService } from '../../../src/nest/database/database.service';
|
|
import { db as trekDb } from '../../../src/db/database';
|
|
|
|
// Was photos.bridge, deleted with the other three that had no consumer outside
|
|
// the container. These call the repository directly now.
|
|
const trekPhotos = new TrekPhotosRepository(new DatabaseService(trekDb));
|
|
const getOrCreateTrekPhoto = (...a: Parameters<TrekPhotosRepository['getOrCreate']>) => trekPhotos.getOrCreate(...a);
|
|
const getOrCreateLocalTrekPhoto = (...a: Parameters<TrekPhotosRepository['getOrCreateLocal']>) => trekPhotos.getOrCreateLocal(...a);
|
|
const resolveTrekPhoto = (id: number) => trekPhotos.resolve(id);
|
|
|
|
beforeAll(() => {
|
|
createTables(testDb);
|
|
runMigrations(testDb);
|
|
});
|
|
|
|
beforeEach(() => {
|
|
testDb.prepare('DELETE FROM trek_photos').run();
|
|
});
|
|
|
|
afterAll(() => {
|
|
testDb.close();
|
|
});
|
|
|
|
describe('trek_photos media_type', () => {
|
|
it('migration added media_type (default image) and duration_ms', () => {
|
|
const cols = (testDb.prepare("PRAGMA table_info('trek_photos')").all() as { name: string }[]).map(c => c.name);
|
|
expect(cols).toContain('media_type');
|
|
expect(cols).toContain('duration_ms');
|
|
});
|
|
|
|
it('a local photo defaults to image', () => {
|
|
const id = getOrCreateLocalTrekPhoto('journey/a.jpg');
|
|
expect(resolveTrekPhoto(id)!.media_type).toBe('image');
|
|
});
|
|
|
|
it('a local video stores media_type=video + duration', () => {
|
|
const id = getOrCreateLocalTrekPhoto('journey/clip.mp4', 'journey/poster.jpg', null, null, 'video', 4200);
|
|
const row = resolveTrekPhoto(id)!;
|
|
expect(row.media_type).toBe('video');
|
|
expect(row.duration_ms).toBe(4200);
|
|
expect(row.thumbnail_path).toBe('journey/poster.jpg');
|
|
});
|
|
|
|
it('a provider photo can be registered as video', () => {
|
|
const { user } = createUser(testDb);
|
|
const id = getOrCreateTrekPhoto('immich', 'asset-1', user.id, undefined, 'video');
|
|
expect(resolveTrekPhoto(id)!.media_type).toBe('video');
|
|
});
|
|
});
|