test-utils.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import { IJobRepository, JobItem, JobItemHandler, QueueName } from '@app/domain';
  2. import { AppModule } from '@app/immich';
  3. import { dataSource } from '@app/infra';
  4. import { INestApplication } from '@nestjs/common';
  5. import { Test } from '@nestjs/testing';
  6. import * as fs from 'fs';
  7. import path from 'path';
  8. import { EntityTarget, ObjectLiteral } from 'typeorm';
  9. import { AppService } from '../src/microservices/app.service';
  10. export const IMMICH_TEST_ASSET_PATH = process.env.IMMICH_TEST_ASSET_PATH;
  11. export const IMMICH_TEST_ASSET_TEMP_PATH = path.normalize(`${IMMICH_TEST_ASSET_PATH}/temp/`);
  12. export interface ResetOptions {
  13. entities?: EntityTarget<ObjectLiteral>[];
  14. }
  15. export const db = {
  16. reset: async (options?: ResetOptions) => {
  17. if (!dataSource.isInitialized) {
  18. await dataSource.initialize();
  19. }
  20. await dataSource.transaction(async (em) => {
  21. const entities = options?.entities || [];
  22. const tableNames =
  23. entities.length > 0
  24. ? entities.map((entity) => em.getRepository(entity).metadata.tableName)
  25. : dataSource.entityMetadatas.map((entity) => entity.tableName);
  26. let deleteUsers = false;
  27. for (const tableName of tableNames) {
  28. if (tableName === 'users') {
  29. deleteUsers = true;
  30. continue;
  31. }
  32. await em.query(`DELETE FROM ${tableName} CASCADE;`);
  33. }
  34. if (deleteUsers) {
  35. await em.query(`DELETE FROM "users" CASCADE;`);
  36. }
  37. });
  38. },
  39. disconnect: async () => {
  40. if (dataSource.isInitialized) {
  41. await dataSource.destroy();
  42. }
  43. },
  44. };
  45. let _handler: JobItemHandler = () => Promise.resolve();
  46. interface TestAppOptions {
  47. jobs: boolean;
  48. }
  49. let app: INestApplication;
  50. export const testApp = {
  51. create: async (options?: TestAppOptions): Promise<[any, INestApplication]> => {
  52. const { jobs } = options || { jobs: false };
  53. const moduleFixture = await Test.createTestingModule({ imports: [AppModule], providers: [AppService] })
  54. .overrideProvider(IJobRepository)
  55. .useValue({
  56. addHandler: (_queueName: QueueName, _concurrency: number, handler: JobItemHandler) => (_handler = handler),
  57. addCronJob: jest.fn(),
  58. updateCronJob: jest.fn(),
  59. deleteCronJob: jest.fn(),
  60. validateCronExpression: jest.fn(),
  61. queue: (item: JobItem) => jobs && _handler(item),
  62. resume: jest.fn(),
  63. empty: jest.fn(),
  64. setConcurrency: jest.fn(),
  65. getQueueStatus: jest.fn(),
  66. getJobCounts: jest.fn(),
  67. pause: jest.fn(),
  68. } as IJobRepository)
  69. .compile();
  70. app = await moduleFixture.createNestApplication().init();
  71. if (jobs) {
  72. await app.get(AppService).init();
  73. }
  74. return [app.getHttpServer(), app];
  75. },
  76. reset: async () => {
  77. await db.reset();
  78. },
  79. teardown: async () => {
  80. await app.get(AppService).teardown();
  81. await db.disconnect();
  82. await app.close();
  83. },
  84. };
  85. export const runAllTests: boolean = process.env.IMMICH_RUN_ALL_TESTS === 'true';
  86. const directoryExists = async (dirPath: string) =>
  87. await fs.promises
  88. .access(dirPath)
  89. .then(() => true)
  90. .catch(() => false);
  91. export async function restoreTempFolder(): Promise<void> {
  92. if (await directoryExists(`${IMMICH_TEST_ASSET_TEMP_PATH}`)) {
  93. // Temp directory exists, delete all files inside it
  94. await fs.promises.rm(IMMICH_TEST_ASSET_TEMP_PATH, { recursive: true });
  95. }
  96. // Create temp folder
  97. await fs.promises.mkdir(IMMICH_TEST_ASSET_TEMP_PATH);
  98. }