Răsfoiți Sursa

add tests for page-bulk-export-job-cron

Futa Arai 1 an în urmă
părinte
comite
c7d1ebdaaf

+ 5 - 1
apps/app/src/features/page-bulk-export/interfaces/page-bulk-export.ts

@@ -10,10 +10,14 @@ export const PageBulkExportFormat = {
 
 export type PageBulkExportFormat = typeof PageBulkExportFormat[keyof typeof PageBulkExportFormat]
 
-export const PageBulkExportJobStatus = {
+export const PageBulkExportJobInProgressStatus = {
   initializing: 'initializing', // preparing for export
   exporting: 'exporting', // exporting to fs
   uploading: 'uploading', // uploading to cloud storage
+} as const;
+
+export const PageBulkExportJobStatus = {
+  ...PageBulkExportJobInProgressStatus,
   completed: 'completed',
   failed: 'failed',
 } as const;

+ 161 - 0
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron.integ.ts

@@ -0,0 +1,161 @@
+import mongoose from 'mongoose';
+
+import { configManager } from '~/server/service/config-manager';
+
+import { PageBulkExportFormat, PageBulkExportJobStatus } from '../../interfaces/page-bulk-export';
+import PageBulkExportJob from '../models/page-bulk-export-job';
+
+import instanciatePageBulkExportJobCronService, { pageBulkExportJobCronService } from './page-bulk-export-job-cron';
+
+// TODO: use actual user model after ~/server/models/user.js becomes importable in vitest
+// ref: https://github.com/vitest-dev/vitest/issues/846
+const userSchema = new mongoose.Schema({
+  name: { type: String },
+  username: { type: String, required: true, unique: true },
+  email: { type: String, unique: true, sparse: true },
+}, {
+  timestamps: true,
+});
+const User = mongoose.model('User', userSchema);
+
+describe('PageBulkExportJobCronService', () => {
+  const crowi = { event: () => {} };
+  let user;
+
+  beforeAll(async() => {
+    user = await User.create({
+      name: 'Example for PageBulkExportJobCronService Test',
+      username: 'page bulk export job cron test user',
+      email: 'bulkExportCronTestUser@example.com',
+    });
+    instanciatePageBulkExportJobCronService(crowi);
+  });
+
+  beforeEach(async() => {
+    await PageBulkExportJob.deleteMany();
+  });
+
+  describe('deleteExpiredExportJobs', () => {
+    const jobId1 = new mongoose.Types.ObjectId();
+    const jobId2 = new mongoose.Types.ObjectId();
+    const jobId3 = new mongoose.Types.ObjectId();
+    const jobId4 = new mongoose.Types.ObjectId();
+
+    beforeEach(async() => {
+      await configManager.updateConfigsInTheSameNamespace('crowi', { 'app:bulkExportJobExpirationSeconds': 86400 }); // 1 day
+
+      await PageBulkExportJob.insertMany([
+        {
+          _id: jobId1,
+          user,
+          page: new mongoose.Types.ObjectId(),
+          format: PageBulkExportFormat.md,
+          status: PageBulkExportJobStatus.initializing,
+          createdAt: new Date(Date.now()),
+        },
+        {
+          _id: jobId2,
+          user,
+          page: new mongoose.Types.ObjectId(),
+          format: PageBulkExportFormat.md,
+          status: PageBulkExportJobStatus.exporting,
+          createdAt: new Date(Date.now() - 86400 * 1000 - 1),
+        },
+        {
+          _id: jobId3,
+          user,
+          page: new mongoose.Types.ObjectId(),
+          format: PageBulkExportFormat.md,
+          status: PageBulkExportJobStatus.uploading,
+          createdAt: new Date(Date.now() - 86400 * 1000 - 2),
+        },
+        {
+          _id: jobId4, user, page: new mongoose.Types.ObjectId(), format: PageBulkExportFormat.md, status: PageBulkExportJobStatus.failed,
+        },
+      ]);
+    });
+
+    test('should delete expired jobs', async() => {
+      expect(await PageBulkExportJob.find()).toHaveLength(4);
+      await pageBulkExportJobCronService?.deleteExpiredExportJobs();
+
+      const jobs = await PageBulkExportJob.find();
+      expect(jobs).toHaveLength(2);
+      expect(jobs.map(job => job._id).sort()).toStrictEqual([jobId1, jobId4].sort());
+    });
+  });
+
+  describe('deleteDownloadExpiredExportJobs', () => {
+    const jobId1 = new mongoose.Types.ObjectId();
+    const jobId2 = new mongoose.Types.ObjectId();
+    const jobId3 = new mongoose.Types.ObjectId();
+    const jobId4 = new mongoose.Types.ObjectId();
+
+    beforeEach(async() => {
+      await configManager.updateConfigsInTheSameNamespace('crowi', { 'app:bulkExportDownloadExpirationSeconds': 86400 }); // 1 day
+
+      await PageBulkExportJob.insertMany([
+        {
+          _id: jobId1,
+          user,
+          page: new mongoose.Types.ObjectId(),
+          format: PageBulkExportFormat.md,
+          status: PageBulkExportJobStatus.completed,
+          completedAt: new Date(Date.now()),
+        },
+        {
+          _id: jobId2,
+          user,
+          page: new mongoose.Types.ObjectId(),
+          format: PageBulkExportFormat.md,
+          status: PageBulkExportJobStatus.completed,
+          completedAt: new Date(Date.now() - 86400 * 1000 - 1),
+        },
+        {
+          _id: jobId3, user, page: new mongoose.Types.ObjectId(), format: PageBulkExportFormat.md, status: PageBulkExportJobStatus.initializing,
+        },
+        {
+          _id: jobId4, user, page: new mongoose.Types.ObjectId(), format: PageBulkExportFormat.md, status: PageBulkExportJobStatus.failed,
+        },
+      ]);
+    });
+
+    test('should delete download expired jobs', async() => {
+      expect(await PageBulkExportJob.find()).toHaveLength(4);
+      await pageBulkExportJobCronService?.deleteDownloadExpiredExportJobs();
+
+      const jobs = await PageBulkExportJob.find();
+      expect(jobs).toHaveLength(3);
+      expect(jobs.map(job => job._id).sort()).toStrictEqual([jobId1, jobId3, jobId4].sort());
+    });
+  });
+
+  describe('deleteFailedExportJobs', () => {
+    const jobId1 = new mongoose.Types.ObjectId();
+    const jobId2 = new mongoose.Types.ObjectId();
+    const jobId3 = new mongoose.Types.ObjectId();
+
+    beforeEach(async() => {
+      await PageBulkExportJob.insertMany([
+        {
+          _id: jobId1, user, page: new mongoose.Types.ObjectId(), format: PageBulkExportFormat.md, status: PageBulkExportJobStatus.failed,
+        },
+        {
+          _id: jobId2, user, page: new mongoose.Types.ObjectId(), format: PageBulkExportFormat.md, status: PageBulkExportJobStatus.initializing,
+        },
+        {
+          _id: jobId3, user, page: new mongoose.Types.ObjectId(), format: PageBulkExportFormat.md, status: PageBulkExportJobStatus.failed,
+        },
+      ]);
+    });
+
+    test('should delete failed export jobs', async() => {
+      expect(await PageBulkExportJob.find()).toHaveLength(3);
+      await pageBulkExportJobCronService?.deleteFailedExportJobs();
+
+      const jobs = await PageBulkExportJob.find();
+      expect(jobs).toHaveLength(1);
+      expect(jobs.map(job => job._id)).toStrictEqual([jobId2]);
+    });
+  });
+});

+ 2 - 2
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron.ts

@@ -2,7 +2,7 @@ import { configManager } from '~/server/service/config-manager';
 import CronService from '~/server/service/cron';
 import loggerFactory from '~/utils/logger';
 
-import { PageBulkExportJobStatus } from '../../interfaces/page-bulk-export';
+import { PageBulkExportJobInProgressStatus, PageBulkExportJobStatus } from '../../interfaces/page-bulk-export';
 import type { PageBulkExportJobDocument } from '../models/page-bulk-export-job';
 import PageBulkExportJob from '../models/page-bulk-export-job';
 
@@ -34,7 +34,7 @@ class PageBulkExportJobCronService extends CronService {
   async deleteExpiredExportJobs() {
     const exportJobExpirationSeconds = configManager.getConfig('crowi', 'app:bulkExportJobExpirationSeconds');
     const expiredExportJobs = await PageBulkExportJob.find({
-      status: PageBulkExportJobStatus.initializing,
+      $or: Object.values(PageBulkExportJobInProgressStatus).map(status => ({ status })),
       createdAt: { $lt: new Date(Date.now() - exportJobExpirationSeconds * 1000) },
     });
     for (const expiredExportJob of expiredExportJobs) {

+ 3 - 3
apps/app/src/features/page-bulk-export/server/service/page-bulk-export.ts

@@ -18,9 +18,9 @@ import type { SupportedActionType } from '~/interfaces/activity';
 import { SupportedAction, SupportedTargetModel } from '~/interfaces/activity';
 import { AttachmentType, FilePathOnStoragePrefix } from '~/server/interfaces/attachment';
 import type { ObjectIdLike } from '~/server/interfaces/mongoose-utils';
-import type { IAttachmentDocument } from '~/server/models';
-import { Attachment } from '~/server/models';
 import type { ActivityDocument } from '~/server/models/activity';
+import { Attachment } from '~/server/models/attachment';
+import type { IAttachmentDocument } from '~/server/models/attachment';
 import type { PageModel, PageDocument } from '~/server/models/page';
 import Subscription from '~/server/models/subscription';
 import type { FileUploader } from '~/server/service/file-uploader';
@@ -147,7 +147,7 @@ class PageBulkExportService {
    */
   async executePageBulkExportJob(pageBulkExportJob: HydratedDocument<PageBulkExportJobDocument>, activityParameters?: ActivityParameters): Promise<void> {
     try {
-      const User = this.crowi.model('User');
+      const User = mongoose.model('User');
       const user = await User.findById(getIdForRef(pageBulkExportJob.user));
 
       if (pageBulkExportJob.status === PageBulkExportJobStatus.initializing) {

+ 0 - 73
apps/app/test/integration/service/page-bulk-export-job-cron.test.ts

@@ -1,73 +0,0 @@
-// eslint-disable-next-line no-restricted-imports
-import axios from 'axios';
-
-import { PageBulkExportFormat, PageBulkExportJobStatus } from '../../../src/features/page-bulk-export/interfaces/page-bulk-export';
-import PageBulkExportJob from '../../../src/features/page-bulk-export/server/models/page-bulk-export-job';
-import { configManager } from '../../../src/server/service/config-manager';
-import { getInstance } from '../setup-crowi';
-
-const spyAxiosGet = jest.spyOn<typeof axios, 'get'>(
-  axios,
-  'get',
-);
-
-const spyAxiosPost = jest.spyOn<typeof axios, 'post'>(
-  axios,
-  'post',
-);
-
-describe('PageBulkExportJobCronService', () => {
-  let crowi;
-  let user;
-
-  beforeAll(async() => {
-    await configManager.loadConfigs();
-    await configManager.updateConfigsInTheSameNamespace('crowi', { 'app:fileUploadType': 'aws' });
-
-    crowi = await getInstance();
-    const User = crowi.model('User');
-    user = await User.create({
-      name: 'Example for PageBulkExportJobCronService Test',
-      username: 'page bulk export job cron test user',
-      email: 'bulkExportCronTestUser@example.com',
-      password: 'usertestpass',
-      createdAt: '2020-01-01',
-    });
-  });
-
-  beforeEach(async() => {
-    await PageBulkExportJob.deleteMany();
-  });
-
-  // describe('deleteDownloadExpiredExportJobs', () => {
-  //   beforeAll(async() => {
-  //     await configManager.updateConfigsInTheSameNamespace('crowi', { 'app:bulkExportDownloadExpirationSeconds': 86400 }); // 1 day
-  //   });
-  // });
-
-  describe('deleteFailedExportJobs', () => {
-    beforeAll(async() => {
-      await configManager.updateConfigsInTheSameNamespace('crowi', { 'app:bulkExportDownloadExpirationSeconds': 86400 }); // 1 day
-
-      await PageBulkExportJob.insertMany([
-        {
-          user, page: '/test-path1', format: PageBulkExportFormat.md, status: PageBulkExportJobStatus.failed,
-        },
-        {
-          user, page: '/test-path2', format: PageBulkExportFormat.md, status: PageBulkExportJobStatus.initializing,
-        },
-        {
-          user, page: '/test-path3', format: PageBulkExportFormat.md, status: PageBulkExportJobStatus.failed,
-        },
-      ]);
-    });
-
-    test('should delete failed export jobs', async() => {
-      expect(await PageBulkExportJob.find()).toHaveLength(2);
-      const pageBulkExportJobCronService = crowi.pageBulkExportJobCronService;
-      await pageBulkExportJobCronService.deleteFailedExportJobs();
-
-      expect(await PageBulkExportJob.find()).toHaveLength(1);
-    });
-  });
-});