refactor: config init event for first config load (#13930)

This commit is contained in:
Zack Pollard 2024-11-05 16:30:56 +00:00 committed by GitHub
parent c383e115af
commit d456d35510
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 160 additions and 146 deletions

View file

@ -5,6 +5,7 @@ import { mapLibrary } from 'src/dtos/library.dto';
import { UserEntity } from 'src/entities/user.entity';
import { AssetType, ImmichWorker } from 'src/enum';
import { IAssetRepository } from 'src/interfaces/asset.interface';
import { IConfigRepository } from 'src/interfaces/config.interface';
import { IDatabaseRepository } from 'src/interfaces/database.interface';
import {
IJobRepository,
@ -16,7 +17,6 @@ import {
} from 'src/interfaces/job.interface';
import { ILibraryRepository } from 'src/interfaces/library.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { LibraryService } from 'src/services/library.service';
import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub';
@ -35,30 +35,28 @@ describe(LibraryService.name, () => {
let sut: LibraryService;
let assetMock: Mocked<IAssetRepository>;
let configMock: Mocked<IConfigRepository>;
let databaseMock: Mocked<IDatabaseRepository>;
let jobMock: Mocked<IJobRepository>;
let libraryMock: Mocked<ILibraryRepository>;
let storageMock: Mocked<IStorageRepository>;
let systemMock: Mocked<ISystemMetadataRepository>;
beforeEach(() => {
({ sut, assetMock, databaseMock, jobMock, libraryMock, storageMock, systemMock } = newTestService(LibraryService));
({ sut, assetMock, configMock, databaseMock, jobMock, libraryMock, storageMock } = newTestService(LibraryService));
databaseMock.tryLock.mockResolvedValue(true);
configMock.getWorker.mockReturnValue(ImmichWorker.MICROSERVICES);
});
it('should work', () => {
expect(sut).toBeDefined();
});
describe('onBootstrapEvent', () => {
describe('onConfigInit', () => {
it('should init cron job and handle config changes', async () => {
systemMock.get.mockResolvedValue(systemConfigStub.libraryScan);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: defaults });
expect(jobMock.addCronJob).toHaveBeenCalled();
expect(systemMock.get).toHaveBeenCalled();
await sut.onConfigUpdate({
oldConfig: defaults,
@ -82,7 +80,6 @@ describe(LibraryService.name, () => {
libraryStub.externalLibraryWithImportPaths2,
]);
systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
libraryMock.get.mockImplementation((id) =>
Promise.resolve(
[libraryStub.externalLibraryWithImportPaths1, libraryStub.externalLibraryWithImportPaths2].find(
@ -91,7 +88,7 @@ describe(LibraryService.name, () => {
),
);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
expect(storageMock.watch.mock.calls).toEqual(
expect.arrayContaining([
@ -102,33 +99,30 @@ describe(LibraryService.name, () => {
});
it('should not initialize watcher when watching is disabled', async () => {
systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchDisabled);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchDisabled as SystemConfig });
expect(storageMock.watch).not.toHaveBeenCalled();
});
it('should not initialize watcher when lock is taken', async () => {
systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
databaseMock.tryLock.mockResolvedValue(false);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
expect(storageMock.watch).not.toHaveBeenCalled();
});
it('should not initialize library scan cron job when lock is taken', async () => {
systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
databaseMock.tryLock.mockResolvedValue(false);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
expect(jobMock.addCronJob).not.toHaveBeenCalled();
});
it('should not initialize watcher or library scan job when running on api', async () => {
await sut.onBootstrap(ImmichWorker.API);
configMock.getWorker.mockReturnValue(ImmichWorker.API);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryScan as SystemConfig });
expect(jobMock.addCronJob).not.toHaveBeenCalled();
});
@ -136,19 +130,13 @@ describe(LibraryService.name, () => {
describe('onConfigUpdateEvent', () => {
beforeEach(async () => {
systemMock.get.mockResolvedValue(defaults);
databaseMock.tryLock.mockResolvedValue(true);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
});
it('should do nothing if oldConfig is not provided', async () => {
await sut.onConfigUpdate({ newConfig: systemConfigStub.libraryScan as SystemConfig });
expect(jobMock.updateCronJob).not.toHaveBeenCalled();
await sut.onConfigInit({ newConfig: defaults });
});
it('should do nothing if instance does not have the watch lock', async () => {
databaseMock.tryLock.mockResolvedValue(false);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: defaults });
await sut.onConfigUpdate({ newConfig: systemConfigStub.libraryScan as SystemConfig, oldConfig: defaults });
expect(jobMock.updateCronJob).not.toHaveBeenCalled();
});
@ -156,9 +144,7 @@ describe(LibraryService.name, () => {
it('should update cron job and enable watching', async () => {
libraryMock.getAll.mockResolvedValue([]);
await sut.onConfigUpdate({
newConfig: {
library: { ...systemConfigStub.libraryScan.library, ...systemConfigStub.libraryWatchEnabled.library },
} as SystemConfig,
newConfig: systemConfigStub.libraryScanAndWatch as SystemConfig,
oldConfig: defaults,
});
@ -172,15 +158,11 @@ describe(LibraryService.name, () => {
it('should update cron job and disable watching', async () => {
libraryMock.getAll.mockResolvedValue([]);
await sut.onConfigUpdate({
newConfig: {
library: { ...systemConfigStub.libraryScan.library, ...systemConfigStub.libraryWatchEnabled.library },
} as SystemConfig,
newConfig: systemConfigStub.libraryScanAndWatch as SystemConfig,
oldConfig: defaults,
});
await sut.onConfigUpdate({
newConfig: {
library: { ...systemConfigStub.libraryScan.library, ...systemConfigStub.libraryWatchDisabled.library },
} as SystemConfig,
newConfig: systemConfigStub.libraryScan as SystemConfig,
oldConfig: defaults,
});
@ -703,12 +685,10 @@ describe(LibraryService.name, () => {
libraryMock.get.mockResolvedValue(libraryStub.externalLibraryWithImportPaths1);
libraryMock.getAll.mockResolvedValue([libraryStub.externalLibraryWithImportPaths1]);
systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
const mockClose = vitest.fn();
storageMock.watch.mockImplementation(makeMockWatcher({ close: mockClose }));
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
await sut.delete(libraryStub.externalLibraryWithImportPaths1.id);
expect(mockClose).toHaveBeenCalled();
@ -837,12 +817,11 @@ describe(LibraryService.name, () => {
});
it('should create watched with import paths', async () => {
systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
libraryMock.create.mockResolvedValue(libraryStub.externalLibraryWithImportPaths1);
libraryMock.get.mockResolvedValue(libraryStub.externalLibraryWithImportPaths1);
libraryMock.getAll.mockResolvedValue([]);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
await sut.create({
ownerId: authStub.admin.user.id,
importPaths: libraryStub.externalLibraryWithImportPaths1.importPaths,
@ -902,10 +881,9 @@ describe(LibraryService.name, () => {
describe('update', () => {
beforeEach(async () => {
systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
libraryMock.getAll.mockResolvedValue([]);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
});
it('should throw an error if an import path is invalid', async () => {
@ -944,9 +922,7 @@ describe(LibraryService.name, () => {
describe('watching disabled', () => {
beforeEach(async () => {
systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchDisabled);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchDisabled as SystemConfig });
});
it('should not watch library', async () => {
@ -960,9 +936,8 @@ describe(LibraryService.name, () => {
describe('watching enabled', () => {
beforeEach(async () => {
systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
libraryMock.getAll.mockResolvedValue([]);
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
});
it('should watch library', async () => {
@ -1114,7 +1089,6 @@ describe(LibraryService.name, () => {
libraryStub.externalLibraryWithImportPaths2,
]);
systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1);
libraryMock.get.mockImplementation((id) =>
@ -1128,7 +1102,7 @@ describe(LibraryService.name, () => {
const mockClose = vitest.fn();
storageMock.watch.mockImplementation(makeMockWatcher({ close: mockClose }));
await sut.onBootstrap(ImmichWorker.MICROSERVICES);
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
await sut.onShutdown();
expect(mockClose).toHaveBeenCalledTimes(2);