Files
speckle-server/packages/server/modules/fileuploads/tests/unit/fileuploads.spec.ts
T
Gergő Jedlicska 2e86a723c6 feat(fileimport-service): add next gen file importer (#4697)
* feat(fileimport-service): add next gen file importer

* feat(fileimports): integrate server and fileimporter

* chore(dui3): remove leftover artifacts

* fix(server): test typing fixes

* fix(fileimports): test and pr comment fixes

* feat(fileimports: moare test fixes

* fix(fileimports): tests and yarn dedupe
2025-05-23 10:27:00 +02:00

140 lines
5.0 KiB
TypeScript

import cryptoRandomString from 'crypto-random-string'
import { db } from '@/db/knex'
import { getStreamBranchByNameFactory } from '@/modules/core/repositories/branches'
import {
getFileInfoFactory,
saveUploadFileFactory
} from '@/modules/fileuploads/repositories/fileUploads'
import { insertNewUploadAndNotifyFactory } from '@/modules/fileuploads/services/management'
import { publish } from '@/modules/shared/utils/subscriptions'
import { testLogger as logger } from '@/observability/logging'
import { sleep } from '@/test/helpers'
import { expect } from 'chai'
import { FileUploadConvertedStatus } from '@/modules/fileuploads/helpers/types'
import { TIME } from '@speckle/shared'
import { initUploadTestEnvironment } from '@/modules/fileuploads/tests/helpers/init'
import { pushJobToFileImporterFactory } from '@/modules/fileuploads/services/createFileImport'
import { assign } from 'lodash'
import { buildFileUploadMessage } from '@/modules/fileuploads/tests/helpers/creation'
import { getFeatureFlags } from '@speckle/shared/environment'
import { JobPayload } from '@speckle/shared/workers/fileimport'
const { createStream, createUser, garbageCollector } = initUploadTestEnvironment()
const { FF_NEXT_GEN_FILE_IMPORTER_ENABLED } = getFeatureFlags()
describe('FileUploads @fileuploads', () => {
const userOne = {
name: cryptoRandomString({ length: 10 }),
email: `${cryptoRandomString({ length: 10 })}@example.org`,
password: cryptoRandomString({ length: 10 })
}
let userOneId: string
let createdStreamId: string
before(async () => {
userOneId = await createUser(userOne)
})
beforeEach(async () => {
createdStreamId = await createStream({ ownerId: userOneId })
})
afterEach(async () => {
createdStreamId = ''
})
describe('Convert files', () => {
it('Should garbage collect expired files', async () => {
const insertNewUploadAndNotify = insertNewUploadAndNotifyFactory({
getStreamBranchByName: getStreamBranchByNameFactory({ db }),
saveUploadFile: saveUploadFileFactory({ db }),
publish
})
const fileId = cryptoRandomString({ length: 10 })
await insertNewUploadAndNotify({
streamId: createdStreamId,
branchName: 'main',
userId: userOneId,
fileId,
fileName: 'testfile.txt',
fileSize: 100,
fileType: 'text/plain'
})
await sleep(2000)
await garbageCollector({ logger, timeoutThresholdSeconds: 1 })
const results = await getFileInfoFactory({ db })({ fileId })
if (!results) {
expect(results).to.not.be.undefined
return //HACK to appease typescript
}
expect(results.convertedStatus).to.be.equal(FileUploadConvertedStatus.Error)
})
it('Should not garbage collect files that are not expired', async () => {
const insertNewUploadAndNotify = insertNewUploadAndNotifyFactory({
getStreamBranchByName: getStreamBranchByNameFactory({ db }),
saveUploadFile: saveUploadFileFactory({ db }),
publish
})
const fileId = cryptoRandomString({ length: 10 })
await insertNewUploadAndNotify({
streamId: createdStreamId,
branchName: 'main',
userId: userOneId,
fileId,
fileName: 'testfile.txt',
fileSize: 100,
fileType: 'text/plain'
})
// timeout far in the future, so it won't be garbage collected
await garbageCollector({ logger, timeoutThresholdSeconds: 1 * TIME.hour })
const results = await getFileInfoFactory({ db })({ fileId })
if (!results) {
expect(results).to.not.be.undefined
return //HACK to appease typescript
}
expect(results.convertedStatus).to.be.equal(FileUploadConvertedStatus.Queued)
})
})
;(FF_NEXT_GEN_FILE_IMPORTER_ENABLED ? describe : describe.skip)(
'how file upload pushes a message to file-import service',
() => {
it('uses a fn that given the necessary ids, tokens and url pushes a message to the queue', async () => {
let usedUserId = undefined
const result = {}
const token = cryptoRandomString({ length: 40 })
const serverOrigin = `https://${cryptoRandomString({ length: 10 })}`
const upload = buildFileUploadMessage()
const pushJobToFileImporter = pushJobToFileImporterFactory({
getServerOrigin: () => serverOrigin,
scheduleJob: async (jobData) => {
assign(result, jobData)
},
createAppToken: (args) => {
usedUserId = args.userId
return Promise.resolve(token)
}
})
await pushJobToFileImporter(upload)
expect(usedUserId).to.equal(upload.userId)
const expected: JobPayload = {
jobId: upload.jobId,
fileName: upload.fileName,
token,
serverUrl: serverOrigin,
modelId: upload.modelId,
fileType: upload.fileType,
projectId: upload.projectId,
timeOutSeconds: 1200,
blobId: upload.blobId
}
expect(result).to.deep.equal(expected)
})
}
)
})