Skip to content

Commit 6fe22d3

Browse files
committed
add: a test case for replacing file & fix name convention
1 parent e74537b commit 6fe22d3

File tree

7 files changed

+99
-25
lines changed

7 files changed

+99
-25
lines changed

docs/useCases.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,20 +1578,20 @@ Check if the file has been deleted, return a boolean.
15781578
##### Example call:
15791579

15801580
```typescript
1581-
import { fileHasBeenDeleted } from '@iqss/dataverse-client-javascript'
1581+
import { getFileHasBeenDeleted } from '@iqss/dataverse-client-javascript'
15821582

15831583
/* ... */
15841584

15851585
const fileId = 12345
15861586

1587-
await fileHasBeenDeleted.execute(fileId).then((hasBeenDeleted: boolean) => {
1587+
await getFileHasBeenDeleted.execute(fileId).then((hasBeenDeleted: boolean) => {
15881588
/* ... */
15891589
})
15901590

15911591
/* ... */
15921592
```
15931593

1594-
_See [use case](../src/files/domain/useCases/FileHasBeenDeleted.ts) implementation_.
1594+
_See [use case](../src/files/domain/useCases/GetFileHasBeenDeleted.ts) implementation_.
15951595

15961596
The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers.
15971597

src/files/domain/repositories/IFilesRepository.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,5 @@ export interface IFilesRepository {
8585
replace?: boolean
8686
): Promise<void>
8787

88-
fileHasBeenDeleted(fileId: number | string): Promise<boolean>
88+
getFileHasBeenDeleted(fileId: number | string): Promise<boolean>
8989
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { IFilesRepository } from '../repositories/IFilesRepository'
22
import { UseCase } from '../../../core/domain/useCases/UseCase'
33

4-
export class FileHasBeenDeleted implements UseCase<boolean> {
4+
export class GetFileHasBeenDeleted implements UseCase<boolean> {
55
constructor(private readonly filesRepository: IFilesRepository) {}
66

77
/**
@@ -11,6 +11,6 @@ export class FileHasBeenDeleted implements UseCase<boolean> {
1111
* @returns {Promise<boolean>} - A boolean indicating whether the file has been deleted or not.
1212
*/
1313
async execute(fileId: number | string): Promise<boolean> {
14-
return await this.filesRepository.fileHasBeenDeleted(fileId)
14+
return await this.filesRepository.getFileHasBeenDeleted(fileId)
1515
}
1616
}

src/files/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { RestrictFile } from './domain/useCases/RestrictFile'
1717
import { UpdateFileMetadata } from './domain/useCases/UpdateFileMetadata'
1818
import { UpdateFileTabularTags } from './domain/useCases/UpdateFileTabularTags'
1919
import { UpdateFileCategories } from './domain/useCases/UpdateFileCategories'
20-
import { FileHasBeenDeleted } from './domain/useCases/FileHasBeenDeleted'
20+
import { GetFileHasBeenDeleted } from './domain/useCases/GetFileHasBeenDeleted'
2121

2222
const filesRepository = new FilesRepository()
2323
const directUploadClient = new DirectUploadClient(filesRepository)
@@ -39,7 +39,7 @@ const restrictFile = new RestrictFile(filesRepository)
3939
const updateFileMetadata = new UpdateFileMetadata(filesRepository)
4040
const updateFileTabularTags = new UpdateFileTabularTags(filesRepository)
4141
const updateFileCategories = new UpdateFileCategories(filesRepository)
42-
const fileHasBeenDeleted = new FileHasBeenDeleted(filesRepository)
42+
const getFileHasBeenDeleted = new GetFileHasBeenDeleted(filesRepository)
4343

4444
export {
4545
getDatasetFiles,
@@ -59,7 +59,7 @@ export {
5959
updateFileTabularTags,
6060
updateFileCategories,
6161
replaceFile,
62-
fileHasBeenDeleted
62+
getFileHasBeenDeleted
6363
}
6464

6565
export { FileModel as File, FileEmbargo, FileChecksum } from './domain/models/FileModel'

src/files/infra/repositories/FilesRepository.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ export class FilesRepository extends ApiRepository implements IFilesRepository {
416416
})
417417
}
418418

419-
public async fileHasBeenDeleted(fileId: number | string): Promise<boolean> {
419+
public async getFileHasBeenDeleted(fileId: number | string): Promise<boolean> {
420420
return this.doGet(this.buildApiEndpoint(this.filesResourceName, 'hasBeenDeleted', fileId), true)
421421
.then((response) => response.data.data)
422422
.catch((error) => {

test/integration/files/FilesRepository.test.ts

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as crypto from 'crypto'
12
import { FilesRepository } from '../../../src/files/infra/repositories/FilesRepository'
23
import {
34
ApiConfig,
@@ -43,6 +44,7 @@ import {
4344
} from '../../testHelpers/collections/collectionHelper'
4445
import { RestrictFileDTO } from '../../../src/files/domain/dtos/RestrictFileDTO'
4546
import { DatasetsRepository } from '../../../src/datasets/infra/repositories/DatasetsRepository'
47+
import { DirectUploadClient } from '../../../src/files/infra/clients/DirectUploadClient'
4648

4749
describe('FilesRepository', () => {
4850
const sut: FilesRepository = new FilesRepository()
@@ -840,9 +842,10 @@ describe('FilesRepository', () => {
840842
})
841843
})
842844

843-
describe('fileHasBeenDeleted', () => {
845+
describe('getFileHasBeenDeleted', () => {
844846
let deleFileTestDatasetIds: CreatedDatasetIdentifiers
845847
const testTextFile1Name = 'test-file-1.txt'
848+
const testTextFile2Name = 'test-file-2.txt'
846849
let fileId: number
847850

848851
beforeAll(async () => {
@@ -870,15 +873,15 @@ describe('FilesRepository', () => {
870873
})
871874

872875
test('should return False if a file has not been deleted', async () => {
873-
const hasBeenDeleted = await sut.fileHasBeenDeleted(fileId)
876+
const hasBeenDeleted = await sut.getFileHasBeenDeleted(fileId)
874877
expect(hasBeenDeleted).toBe(false)
875878
})
876879

877880
test('should return error if the dataset is unpublished and the file has been deleted', async () => {
878881
await sut.deleteFile(fileId)
879882

880883
const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`)
881-
await expect(sut.fileHasBeenDeleted(nonExistentFiledId)).rejects.toThrow(expectedError)
884+
await expect(sut.getFileHasBeenDeleted(nonExistentFiledId)).rejects.toThrow(expectedError)
882885
})
883886

884887
test('should return True when the dataset is published and the file has not been deleted', async () => {
@@ -899,22 +902,93 @@ describe('FilesRepository', () => {
899902
)
900903
fileId = datasetFiles.files[0].id
901904

902-
const notDeleted = await sut.fileHasBeenDeleted(fileId)
905+
const notDeleted = await sut.getFileHasBeenDeleted(fileId)
903906
expect(notDeleted).toBe(false)
904907

905908
await sut.deleteFile(fileId)
906909

907-
const hasBeenDeleted = await sut.fileHasBeenDeleted(fileId)
910+
const hasBeenDeleted = await sut.getFileHasBeenDeleted(fileId)
908911
expect(hasBeenDeleted).toBe(true)
909912
})
910913

911-
test('should return error when file does not exist', async () => {
912-
const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`)
914+
test('should return True when file has been replaced', async () => {
915+
const directUploadSut: DirectUploadClient = new DirectUploadClient(sut)
916+
917+
// Upload original file
918+
await uploadFileViaApi(deleFileTestDatasetIds.numericId, testTextFile1Name).catch(() => {
919+
throw new Error(`Error while uploading file ${testTextFile1Name}`)
920+
})
921+
922+
const datasetFiles = await sut.getDatasetFiles(
923+
deleFileTestDatasetIds.numericId,
924+
latestDatasetVersionId,
925+
false,
926+
FileOrderCriteria.NAME_AZ
927+
)
928+
const originalFileId = datasetFiles.files[0].id
929+
930+
const createTestFileUploadDestination = async (file: File, testDatasetId: number) => {
931+
const filesRepository = new FilesRepository()
932+
const destination = await filesRepository.getFileUploadDestination(testDatasetId, file)
933+
destination.urls.forEach((destinationUrl, index) => {
934+
destination.urls[index] = destinationUrl.replace('localstack', 'localhost')
935+
})
936+
return destination
937+
}
938+
939+
// Create a new file and replace the original file
940+
const newFileBlob = await createSinglepartFileBlob(testTextFile2Name, 2000)
941+
const newDestination = await createTestFileUploadDestination(
942+
newFileBlob,
943+
deleFileTestDatasetIds.numericId
944+
)
945+
946+
const progressMock = jest.fn()
947+
const abortController = new AbortController()
948+
949+
const newStorageId = await directUploadSut.uploadFile(
950+
deleFileTestDatasetIds.numericId,
951+
newFileBlob,
952+
progressMock,
953+
abortController,
954+
newDestination
955+
)
913956

914-
await expect(sut.fileHasBeenDeleted(nonExistentFiledId)).rejects.toThrow(expectedError)
957+
const fileArrayBuffer = await newFileBlob.arrayBuffer()
958+
const fileBuffer = Buffer.from(fileArrayBuffer)
959+
960+
const calculateBlobChecksum = (blob: Buffer): string => {
961+
const hash = crypto.createHash('md5')
962+
hash.update(blob)
963+
return hash.digest('hex')
964+
}
965+
966+
const newUploadedFileDTO = {
967+
fileName: newFileBlob.name,
968+
storageId: newStorageId,
969+
checksumType: 'md5',
970+
checksumValue: calculateBlobChecksum(fileBuffer),
971+
mimeType: newFileBlob.type
972+
}
973+
974+
//Publish the dataset and check if the original file has been deleted
975+
await publishDatasetViaApi(deleFileTestDatasetIds.numericId)
976+
977+
await waitForNoLocks(deleFileTestDatasetIds.numericId, 10)
978+
979+
await sut.replaceFile(originalFileId, newUploadedFileDTO)
980+
981+
const isDeleted = await sut.getFileHasBeenDeleted(originalFileId)
982+
expect(isDeleted).toBe(true)
915983
})
916984
})
917985

986+
test('should return error when file does not exist', async () => {
987+
const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`)
988+
989+
await expect(sut.getFileHasBeenDeleted(nonExistentFiledId)).rejects.toThrow(expectedError)
990+
})
991+
918992
describe('restrictFile', () => {
919993
let restrictFileDatasetIds: CreatedDatasetIdentifiers
920994
const testTextFile1Name = 'test-file-1.txt'

test/unit/files/FileHasBeenDeleted.test.ts renamed to test/unit/files/GetFileHasBeenDeleted.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { IFilesRepository } from '../../../src/files/domain/repositories/IFilesRepository'
2-
import { FileHasBeenDeleted } from '../../../src/files/domain/useCases/FileHasBeenDeleted'
2+
import { GetFileHasBeenDeleted } from '../../../src/files/domain/useCases/GetFileHasBeenDeleted'
33
import { ReadError } from '../../../src'
44

55
describe('execute', () => {
66
test('should return true when file has been deleted', async () => {
77
const filesRepositoryStub: IFilesRepository = {} as IFilesRepository
8-
filesRepositoryStub.fileHasBeenDeleted = jest.fn().mockResolvedValue(true)
9-
const sut = new FileHasBeenDeleted(filesRepositoryStub)
8+
filesRepositoryStub.getFileHasBeenDeleted = jest.fn().mockResolvedValue(true)
9+
const sut = new GetFileHasBeenDeleted(filesRepositoryStub)
1010

1111
const result = await sut.execute(1)
1212

@@ -15,8 +15,8 @@ describe('execute', () => {
1515

1616
test('should return false when file has not been deleted', async () => {
1717
const filesRepositoryStub: IFilesRepository = {} as IFilesRepository
18-
filesRepositoryStub.fileHasBeenDeleted = jest.fn().mockResolvedValue(false)
19-
const sut = new FileHasBeenDeleted(filesRepositoryStub)
18+
filesRepositoryStub.getFileHasBeenDeleted = jest.fn().mockResolvedValue(false)
19+
const sut = new GetFileHasBeenDeleted(filesRepositoryStub)
2020

2121
const result = await sut.execute(1)
2222

@@ -25,8 +25,8 @@ describe('execute', () => {
2525

2626
test('should return error result on repository error', async () => {
2727
const filesRepositoryStub: IFilesRepository = {} as IFilesRepository
28-
filesRepositoryStub.fileHasBeenDeleted = jest.fn().mockRejectedValue(new ReadError())
29-
const sut = new FileHasBeenDeleted(filesRepositoryStub)
28+
filesRepositoryStub.getFileHasBeenDeleted = jest.fn().mockRejectedValue(new ReadError())
29+
const sut = new GetFileHasBeenDeleted(filesRepositoryStub)
3030

3131
await expect(sut.execute(1)).rejects.toThrow(ReadError)
3232
})

0 commit comments

Comments
 (0)