@defra-fish/fulfilment-job
Version:
Rod Licensing Sales Fulfilment Job
110 lines (98 loc) • 4.52 kB
JavaScript
import { writeS3PartFile, readS3PartFiles, createS3WriteStream } from '../s3.js'
import stream from 'stream'
import AwsMock from 'aws-sdk'
import { FulfilmentRequestFile } from '@defra-fish/dynamics-lib'
import { fulfilmentDataTransformer } from '../../transform/fulfilment-transform.js'
jest.mock('fs')
jest.mock('stream')
jest.mock('../../config.js', () => ({
s3: {
bucket: 'testbucket'
}
}))
describe('s3', () => {
beforeEach(() => {
jest.clearAllMocks()
AwsMock.__resetAll()
})
describe('writeS3PartFile', () => {
it('writes a part file to S3', async () => {
const testFile = Object.assign(new FulfilmentRequestFile(), { fileName: 'example.json' })
const mockDataArray = []
AwsMock.S3.mockedMethods.upload.mockImplementationOnce(() => ({ promise: jest.fn(async () => ({ Location: 'example.json/part0' })) }))
stream.pipeline.mockImplementation(
jest.fn((streams, callback) => {
expect(streams[0]).toStrictEqual(mockDataArray)
expect(streams[1]).toStrictEqual(fulfilmentDataTransformer)
expect(streams[2]).toStrictEqual(expect.any(stream.PassThrough))
callback()
})
)
await writeS3PartFile(testFile, 0, [])
expect(stream.pipeline).toHaveBeenCalled()
expect(AwsMock.S3.mockedMethods.upload).toHaveBeenCalledWith({
Bucket: 'testbucket',
Key: 'example.json/part0',
Body: expect.any(stream.PassThrough)
})
})
})
describe('readS3PartFiles', () => {
it('reads all part files for a given file and returns a stream for each', async () => {
const mockCreateReadStream = createMockReadStream()
AwsMock.S3.__setResponse('listObjectsV2', {
Contents: [{ Key: '/example.json/part0' }, { Key: '/example.json/part1' }]
})
AwsMock.S3.mockedMethods.getObject.mockImplementation(() => ({ createReadStream: mockCreateReadStream }))
const testFile = Object.assign(new FulfilmentRequestFile(), { fileName: 'example.json' })
const [stream1, stream2] = await readS3PartFiles(testFile)
expect(mockCreateReadStream.mock.results[0].value).toBe(stream1)
expect(mockCreateReadStream.mock.results[1].value).toBe(stream2)
expect(AwsMock.S3.mockedMethods.getObject).toHaveBeenNthCalledWith(1, { Bucket: 'testbucket', Key: '/example.json/part0' })
expect(AwsMock.S3.mockedMethods.getObject).toHaveBeenNthCalledWith(2, { Bucket: 'testbucket', Key: '/example.json/part1' })
})
it('sets encoding on readable stream', async () => {
const mockCreateReadStream = createMockReadStream()
AwsMock.S3.__setResponse('listObjectsV2', {
Contents: [{ Key: '/example.json/part0' }]
})
AwsMock.S3.mockedMethods.getObject.mockImplementation(() => ({ createReadStream: mockCreateReadStream }))
const testFile = Object.assign(new FulfilmentRequestFile(), { fileName: 'example.json' })
const [readStream] = await readS3PartFiles(testFile)
expect(readStream.setEncoding).toHaveBeenCalledWith('utf8')
})
const createMockReadStream = () =>
jest.fn(() => ({
setEncoding: jest.fn()
}))
})
describe('createS3WriteStream', () => {
it('creates a writable stream to an object in S3', async () => {
AwsMock.S3.mockedMethods.upload.mockImplementationOnce(() => ({ promise: jest.fn(async () => ({ Location: 'example/key' })) }))
const passThroughEmitSpy = jest.spyOn(stream.PassThrough.prototype, 'emit')
const { s3WriteStream, managedUpload } = createS3WriteStream('example/key')
await expect(managedUpload).resolves.toBeUndefined()
expect(AwsMock.S3.mockedMethods.upload).toHaveBeenCalledWith({
Bucket: 'testbucket',
Key: 'example/key',
Body: expect.any(stream.PassThrough)
})
expect(s3WriteStream.write).toBeDefined()
expect(passThroughEmitSpy).not.toHaveBeenCalled()
})
it('rejects the managed upload promise if an error occurs uploading', async () => {
AwsMock.S3.mockedMethods.upload.mockImplementationOnce(() => ({
promise: jest.fn(async () => {
throw new Error('Test error')
})
}))
const { s3WriteStream, managedUpload } = createS3WriteStream('example/key')
await expect(managedUpload).rejects.toThrow('Test error')
expect(AwsMock.S3.mockedMethods.upload).toHaveBeenCalledWith({
Bucket: 'testbucket',
Key: 'example/key',
Body: s3WriteStream
})
})
})
})