Skip to content

Commit

Permalink
More config in helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
flurdy committed May 14, 2024
1 parent 07e2000 commit 5cc0f03
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 65 deletions.
32 changes: 31 additions & 1 deletion src/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,16 @@ const config = convict({
default: 'cdp-uploader-smoke-test-bucket',
env: 'UPLOADER_SMOKE_TEST_BUCKET'
},
smokeTestPath: {
doc: 'S3 prefix path for test uploads',
format: String,
default: 'smoke-test',
env: 'UPLOADER_SMOKE_TEST_PATH'
},
uploadScanInterval: {
doc: 'How long to delay each poll for scan completion',
format: Number,
default: 2000,
default: 3000,
env: 'UPLOAD_SCAN_INTERVAL'
},
uploadMaxAttempts: {
Expand All @@ -45,11 +51,35 @@ const config = convict({
default: 30,
env: 'UPLOAD_MAX_ATTEMPTS'
},
uploadOnlyTimeout: {
doc: 'How long to poll for upload initial completion',
format: Number,
default: 1000 * 20,
env: 'UPLOAD_ONLY_TIMEOUT'
},
uploadScanTimeout: {
doc: 'How long to poll for scan completion',
format: Number,
default: 1000 * 60,
env: 'UPLOAD_SCAN_TIMEOUT'
},
cleanFileName: {
doc: 'A file to upload that is clean',
format: String,
default: 'clean-file.txt',
env: 'CLEAN_FILE_NAME'
},
virusFileName: {
doc: 'A file to upload that is a virus',
format: String,
default: 'eicar-virus.txt',
env: 'VIRUS_FILE_NAME'
},
redirectUrl: {
doc: 'A URL to redirect to after upload',
format: String,
default: 'http://httpstat.us/200',
env: 'UPLOAD_REDIRECT_URL'
}
})

Expand Down
87 changes: 81 additions & 6 deletions src/helpers/upload-helpers.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
import FormData from 'form-data'
import { readFile } from 'node:fs/promises'
import { setTimeout } from 'node:timers/promises'

import { config } from '~/src/config'
import {
initiateUpload,
uploadFile,
uploadStatus
} from '~/src/helpers/uploader-fetch'

async function createPayload(filename) {
const file = await readFile(`./${filename}`)
const pollInterval = config.get('uploadScanInterval')
const maxAttempts = config.get('uploadMaxAttempts')
const cleanFilename = config.get('cleanFileName')
const virusFilename = config.get('virusFileName')
const destinationBucket = config.get('smokeTestBucket')
const destinationPath = config.get('smokeTestPath')
const redirectUrl = config.get('redirectUrl')
const initiatePayload = {
redirect: redirectUrl,
destinationBucket,
destinationPath
}

async function readCleanFile() {
return await readFileToUpload(cleanFilename)
}

async function readVirusFile() {
return await readFileToUpload(virusFilename)
}

async function readFileToUpload(filename) {
return await readFile(`./testdata/${filename}`)
}

async function createFormPayloadWithFile(file, filename) {
const payload = new FormData()
payload.append('field1', 'val1')
payload.append('field2', 'val2')
Expand All @@ -27,12 +53,61 @@ async function findFileDetails(statusUrl) {
}
}

async function initiateAndUpload(filename, initiatePayload) {
async function findFileDetailsWhenReady(statusUrl) {
let isUploadReady = false
let attempts = 0
do {
const { uploadStatus, fileDetails } = await findFileDetails(statusUrl)
if (uploadStatus === 'ready' && fileDetails.fileStatus !== 'pending') {
isUploadReady = true
}
attempts++
await setTimeout(pollInterval)
} while (!isUploadReady && attempts < maxAttempts)
return { isUploadReady, attempts }
}

async function cleanFileUpload() {
const cleanFile = await readCleanFile()
return await initiateBufferAndUpload(
cleanFile,
cleanFilename,
initiatePayload
)
}

async function virusFileUpload() {
const virusFile = await readVirusFile()
return await initiateBufferAndUpload(
virusFile,
virusFilename,
initiatePayload
)
}

async function initiateWithPayload() {
return await initiateUpload(initiatePayload)
}

async function initiateBufferAndUpload(file, filename, initiatePayload) {
const formPayload = await createFormPayloadWithFile(file, filename)
return await initiateAndUpload(formPayload, initiatePayload)
}

async function initiateAndUpload(formPayload, initiatePayload) {
const { uploadId, uploadUrl, statusUrl } =
await initiateUpload(initiatePayload)
const payload = await createPayload(filename)
const { uploadStatusCode, location } = await uploadFile(uploadUrl, payload)
const { uploadStatusCode, location } = await uploadFile(
uploadUrl,
formPayload
)
return { uploadId, uploadStatusCode, statusUrl, location }
}

export { createPayload, findFileDetails, initiateAndUpload }
export {
cleanFileUpload,
findFileDetails,
findFileDetailsWhenReady,
initiateWithPayload,
virusFileUpload
}
85 changes: 27 additions & 58 deletions src/test/specs/upload-file/upload-journey.test.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
import { validate } from 'uuid'
import { setTimeout } from 'node:timers/promises'

import { config } from '~/src/config'
import { initiateUpload, uploadStatus } from '~/src/helpers/uploader-fetch'
import { uploadStatus } from '~/src/helpers/uploader-fetch'
import {
findFileDetails,
initiateAndUpload
findFileDetailsWhenReady,
cleanFileUpload,
initiateWithPayload,
virusFileUpload
} from '~/src/helpers/upload-helpers'

const uploaderBaseUrl = config.get('uploaderBaseUrl')
const destinationBucket = config.get('smokeTestBucket')
const destinationPath = 'smoke-test'
const cleanFilename = config.get('cleanFileName')
const uploadTimeout = config.get('uploadOnlyTimeout')
const scanTimeout = config.get('uploadScanTimeout')
const pollInterval = config.get('uploadScanInterval')
const maxAttempts = config.get('uploadMaxAttempts')
const cleanFilename = 'unicorn-small.jpg'
const virusFilename = 'unicorn-virus.jpg'
const redirectUrl = 'http://httpstat.us/200'

const initiatePayload = {
redirect: redirectUrl,
destinationBucket,
destinationPath
}
const redirectUrl = config.get('redirectUrl')

describe('CDP File uploader Smoke Test', () => {
it('should initiate a file upload', async () => {
const { uploadId, uploadUrl, statusUrl } =
await initiateUpload(initiatePayload)
const { uploadId, uploadUrl, statusUrl } = await initiateWithPayload()
expect(validate(uploadId)).toBeTruthy()
expect(uploadUrl).toMatch(`${uploaderBaseUrl}/upload-and-scan/${uploadId}`)
expect(statusUrl).toMatch(`${uploaderBaseUrl}/status/${uploadId}`)
Expand All @@ -36,9 +27,11 @@ describe('CDP File uploader Smoke Test', () => {
})

describe('Start file upload journey', () => {
jest.setTimeout(uploadTimeout)

it('should upload a file', async () => {
const { uploadId, uploadStatusCode, statusUrl, location } =
await initiateAndUpload(cleanFilename, initiatePayload)
await cleanFileUpload()
expect(uploadStatusCode).toEqual(302)
expect(location).toEqual(`${redirectUrl}?uploadId=${uploadId}`)
const { uploadStatus, fileDetails } = await findFileDetails(statusUrl)
Expand All @@ -55,49 +48,25 @@ describe('CDP File uploader Smoke Test', () => {
jest.setTimeout(scanTimeout)

it('should get scanned as clean', async () => {
const { statusUrl } = await initiateAndUpload(
cleanFilename,
initiatePayload
)
let isUploadReady = false
let attempts = 0
do {
const { uploadStatus, fileDetails } = await findFileDetails(statusUrl)
if (
uploadStatus === 'ready' &&
fileDetails.fileStatus !== 'pending'
) {
isUploadReady = true
}
attempts++
await setTimeout(pollInterval)
} while (!isUploadReady && attempts < maxAttempts)
const { statusUrl } = await cleanFileUpload()
const { isUploadReady } = await findFileDetailsWhenReady(statusUrl)
expect(isUploadReady).toBeTruthy()
const { fileDetails } = await findFileDetails(statusUrl)
const { uploadStatus, fileDetails } = await findFileDetails(statusUrl)
expect(uploadStatus).toEqual('ready')
expect(fileDetails.fileStatus).toEqual('complete')
})
})
// })

// This depends on the test harness being able to serve the virus file
it('should get rejected as infected', async () => {
const { statusUrl } = await initiateAndUpload(
virusFilename,
initiatePayload
)
let isUploadReady = false
let attempts = 0
do {
const { uploadStatus, fileDetails } = await findFileDetails(statusUrl)
if (uploadStatus === 'ready' && fileDetails.fileStatus !== 'pending') {
isUploadReady = true
}
attempts++
await setTimeout(pollInterval)
} while (!isUploadReady && attempts < maxAttempts)
expect(isUploadReady).toBeTruthy()
const { rejectedFiles, fileDetails } = await findFileDetails(statusUrl)
expect(fileDetails.fileStatus).toEqual('rejected')
expect(rejectedFiles).toBe(1)
it('should get rejected as infected', async () => {
const { statusUrl } = await virusFileUpload()
const { isUploadReady } = await findFileDetailsWhenReady(statusUrl)
expect(isUploadReady).toBeTruthy()
const { uploadStatus, rejectedFiles, fileDetails } =
await findFileDetails(statusUrl)
expect(uploadStatus).toEqual('ready')
expect(fileDetails.fileStatus).toEqual('rejected')
expect(rejectedFiles).toBe(1)
})
})
})
})
1 change: 1 addition & 0 deletions testdata/clean-file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello World! This is a clean file for testing purposes.
1 change: 1 addition & 0 deletions testdata/eicar-virus.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
Binary file removed unicorn-small.jpg
Binary file not shown.
Binary file removed unicorn-virus.jpg
Binary file not shown.

0 comments on commit 5cc0f03

Please sign in to comment.