-
Notifications
You must be signed in to change notification settings - Fork 115
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: ⚡ add test and configuration for existing file uploads
- Loading branch information
Ignazio Bovo
committed
Aug 28, 2024
1 parent
6e1f6e0
commit ebd0f03
Showing
5 changed files
with
173 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 35 additions & 17 deletions
52
storage-node/src/services/storageProviders/IConnectionHandler.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,53 @@ | ||
export type UploadFileOutput = { | ||
key: string | ||
filePath: string | ||
} | ||
|
||
export type UploadFileIfNotExistsOutput = { | ||
key: string | ||
filePath: string | ||
alreadyExists: boolean | ||
} | ||
/** | ||
* Represents an abstract connection handler for a storage provider. | ||
*/ | ||
/** | ||
* Represents a connection handler for interacting with a remote storage bucket. | ||
* Represents a connection handler for interacting with a remote storage unit. | ||
* The storage unit can be a bucket in S3, a container in Azure Blob Storage, or similar concepts in other cloud storage services. | ||
* Within this storage unit, objects are organized using keys. A key is a string that defines the location of an object | ||
* within the storage unit. Keys use the format "<directory>/<filename>" with "/" as a delimiter to separate directories. | ||
*/ | ||
export interface IConnectionHandler { | ||
/** | ||
* Asynchronously uploads a file to the remote bucket. | ||
* @param filename - The key of the file in the remote bucket. | ||
* @param filePath - The file path of the file to upload. | ||
* Asynchronously uploads an object to the storage unit. It doesn't check if the object already exists. | ||
* @param key - The key of the object in the storage unit. | ||
* @param filePath - The local file path of the object to upload. | ||
* @returns A promise that resolves when the upload is complete or rejects with an error. | ||
*/ | ||
uploadFileToRemoteBucket(key: string, filePath: string): Promise<UploadFileOutput> | ||
|
||
/** | ||
* Asynchronously uploads an object to the storage unit if it does not exist. | ||
* @param key - The key of the object in the storage unit. | ||
* @param filePath - The local file path of the object to upload. | ||
* @returns A promise that resolves when the upload is complete or rejects with an error. | ||
*/ | ||
uploadFileToRemoteBucket(filename: string, filePath: string): Promise<any> | ||
uploadFileToRemoteBucketIfNotExists(key: string, filePath: string): Promise<UploadFileIfNotExistsOutput> | ||
|
||
/** | ||
* Asynchronously retrieves a file from the remote bucket. | ||
* @param filename - The key of the file to retrieve from the remote bucket. | ||
* @returns A promise that resolves in the presigned URL of the file or rejects with an error, 1h expiry | ||
* Asynchronously retrieves a presigned URL for an object in the storage unit. | ||
* @param key - The key of the object in the storage unit. | ||
* @returns A promise that resolves with the presigned URL of the object (1h expiry) or rejects with an error. | ||
*/ | ||
getRedirectUrlForObject(filename: string): Promise<string> | ||
getRedirectUrlForObject(key: string): Promise<string> | ||
|
||
/** | ||
* Asynchronously lists ALL files in the remote bucket, to be used during cache initialization only as it can be very slow. | ||
* @returns A promise that resolves with an array of file keys or rejects with an error. | ||
* Asynchronously lists ALL objects in the storage unit. To be used during cache initialization only as it can be very slow. | ||
* @returns A promise that resolves with an array of object keys or rejects with an error. | ||
*/ | ||
listFilesOnRemoteBucket(): Promise<string[]> | ||
|
||
/** | ||
* Asynchronously removes a file from the remote bucket. | ||
* @param filename - The key of the file to remove from the remote bucket. | ||
* Asynchronously removes an object from the storage unit. | ||
* @param key - The key of the object to remove from the storage unit. | ||
* @returns A promise that resolves when the removal is complete or rejects with an error. | ||
*/ | ||
removeObject(filename: string): Promise<void> | ||
removeObject(key: string): Promise<void> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
storage-node/src/services/storageProviders/tests/integration/connectionHandler.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3' | ||
import { AwsConnectionHandler } from '../../awsConnectionHandler' | ||
import { readFileSync } from 'fs' | ||
import { expect } from '@jest/globals' | ||
/** | ||
* @group integration | ||
* Test 1 | ||
* Arrange : localstack running with S3 bucket 'test-bucket' | ||
* Act: Upload file using AwsConnectionHandler './testfile.txt' to the bucket in 'testDir/testfile.txt' | ||
* Assert: using aws api download the file and compare hash for equality | ||
* Test 2 | ||
* Arrange : localstack running with S3 bucket 'test-bucket' | ||
* Act: Upload file './testfile.txt' to the bucket in 'testDir/testfile.txt' | ||
* Assert: using aws api download the file and compare hash for equality | ||
*/ | ||
|
||
const awsOptions = { | ||
accessKeyId: 'test', | ||
secretAccessKey: 'test', | ||
region: 'us-east-1', | ||
bucketName: 'test-bucket', | ||
} | ||
describe('AwsConnectionHandler full test suite', () => { | ||
const s3Client = new S3Client({ | ||
region: awsOptions.region, | ||
credentials: { | ||
accessKeyId: awsOptions.accessKeyId, | ||
secretAccessKey: awsOptions.secretAccessKey, | ||
}, | ||
forcePathStyle: true, | ||
tls: false, | ||
endpoint: 'http://localhost:4566', | ||
}) | ||
const awsConnectionHandler = new AwsConnectionHandler(awsOptions) | ||
|
||
it('upload file content correctly', async () => { | ||
const filePath = './testfile.txt' | ||
const bucketPath = 'testDir/testfile.txt' | ||
|
||
await awsConnectionHandler.uploadFileToRemoteBucket(filePath, bucketPath) | ||
|
||
const { Body } = await s3Client.send( | ||
new GetObjectCommand({ | ||
Bucket: awsOptions.bucketName, | ||
Key: bucketPath, | ||
}) | ||
) | ||
const expectedFileContent = readFileSync(filePath) | ||
const fileContent = await Body?.transformToByteArray() | ||
expect(fileContent).toEqual(expectedFileContent) | ||
}) | ||
it('no op upload if file already exists', async () => { | ||
const filePath = './testfile.txt' | ||
const bucketPath = 'testDir/testfile.txt' | ||
|
||
await awsConnectionHandler.uploadFileToRemoteBucket(filePath, bucketPath) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters