From 4c110827961174377b16e28f7c2552bc3a284ba9 Mon Sep 17 00:00:00 2001 From: Sabir Hassan Date: Wed, 17 Aug 2022 21:24:30 +0500 Subject: [PATCH] chore: addressed comments --- README.md | 7 +- api/.env.example | 2 +- api/src/routes/api/spec/stp.spec.ts | 271 ++++++++++------------------ 3 files changed, 106 insertions(+), 174 deletions(-) diff --git a/README.md b/README.md index 233f7b3..f3555d2 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,12 @@ MODE= # Priority is given to the runtime that comes first in the string. # Possible options at the moment are sas and js -# options: [sas|js|py|sas,js|js,sas|py,sas|sas,py|py,js|js,py|sas,js,py|sas,py,js|js,sas,py|js,py,sas|py,sas,js|py,js,sas] default:sas +# This string sets the priority of the available analytic runtimes +# Valid runtimes are SAS (sas), JavaScript (js) and Python (py) +# For each option provided, there should be a corresponding path, +# eg SAS_PATH, NODE_PATH or PYTHON_PATH +# Priority is given to runtimes earlier in the string +# Example options: [sas,js,py | js,py | sas | sas,js] RUN_TIMES= # Path to SAS executable (sas.exe / sas.sh) diff --git a/api/.env.example b/api/.env.example index 705e0d2..a8d7980 100644 --- a/api/.env.example +++ b/api/.env.example @@ -14,7 +14,7 @@ HELMET_COEP=[true|false] if omitted HELMET default will be used DB_CONNECT=mongodb+srv://:@/?retryWrites=true&w=majority -RUN_TIMES=[sas|js|py|sas,js|js,sas|py,sas|sas,py|py,js|js,py|sas,js,py|sas,py,js|js,sas,py|js,py,sas|py,sas,js|py,js,sas] default considered as sas +RUN_TIMES=[sas,js,py | js,py | sas | sas,js] default considered as sas SAS_PATH=/opt/sas/sas9/SASHome/SASFoundation/9.4/sas NODE_PATH=~/.nvm/versions/node/v16.14.0/bin/node PYTHON_PATH=/usr/bin/python diff --git a/api/src/routes/api/spec/stp.spec.ts b/api/src/routes/api/spec/stp.spec.ts index 5c1e0be..9b05b98 100644 --- a/api/src/routes/api/spec/stp.spec.ts +++ b/api/src/routes/api/spec/stp.spec.ts @@ -43,6 +43,7 @@ const sampleJsProgram = `console.log('hello world!/')` const samplePyProgram = `print('hello world!/')` const filesFolder = getFilesFolder() +const testFilesFolder = `test-stp-${generateTimestamp()}` let app: Express let accessToken: string @@ -75,8 +76,6 @@ describe('stp', () => { }) describe('execute', () => { - const testFilesFolder = `test-stp-${generateTimestamp()}` - describe('get', () => { describe('with runtime js', () => { const testFilesFolder = `test-stp-${generateTimestamp()}` @@ -96,21 +95,15 @@ describe('stp', () => { }) it('should execute js program when both js and sas program are present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(jsProgramPath, sampleJsProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.JS) + await makeRequestAndAssert( + [RunTimeType.JS, RunTimeType.SAS], + 200, + RunTimeType.JS + ) }) it('should throw error when js program is not present but sas program exists', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - await createFile(sasProgramPath, sampleSasProgram) - - await makeRequestAndAssert(programPath, 400) + await makeRequestAndAssert([], 400) }) }) @@ -132,23 +125,15 @@ describe('stp', () => { }) it('should execute python program when python, js and sas programs are present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(jsProgramPath, sampleJsProgram) - await createFile(pyProgramPath, samplePyProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.PY) + await makeRequestAndAssert( + [RunTimeType.PY, RunTimeType.SAS, RunTimeType.JS], + 200, + RunTimeType.PY + ) }) it('should throw error when py program is not present but js or sas program exists', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - await createFile(sasProgramPath, sampleSasProgram) - - await makeRequestAndAssert(programPath, 400) + await makeRequestAndAssert([], 400) }) }) @@ -168,21 +153,11 @@ describe('stp', () => { }) it('should execute sas program when both sas and js programs are present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(jsProgramPath, sampleJsProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.SAS) + await makeRequestAndAssert([RunTimeType.SAS], 200, RunTimeType.SAS) }) it('should throw error when sas program do not exit but js exists', async () => { - const programPath = path.join(testFilesFolder, 'program') - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - await createFile(jsProgramPath, sampleJsProgram) - - await makeRequestAndAssert(programPath, 400) + await makeRequestAndAssert([], 400) }) }) @@ -202,27 +177,19 @@ describe('stp', () => { }) it('should execute js program when both js and sas program are present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(jsProgramPath, sampleJsProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.JS) + await makeRequestAndAssert( + [RunTimeType.SAS, RunTimeType.JS], + 200, + RunTimeType.JS + ) }) it('should execute sas program when js program is not present but sas program exists', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - await createFile(sasProgramPath, sampleSasProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.SAS) + await makeRequestAndAssert([RunTimeType.SAS], 200, RunTimeType.SAS) }) it('should throw error when both sas and js programs do not exist', async () => { - const programPath = path.join(testFilesFolder, 'program') - - await makeRequestAndAssert(programPath, 400) + await makeRequestAndAssert([], 400) }) }) @@ -242,27 +209,19 @@ describe('stp', () => { }) it('should execute python program when both python and sas program are present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(pyProgramPath, samplePyProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.PY) + await makeRequestAndAssert( + [RunTimeType.PY, RunTimeType.SAS], + 200, + RunTimeType.PY + ) }) it('should execute sas program when python program is not present but sas program exists', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - await createFile(sasProgramPath, sampleSasProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.SAS) + await makeRequestAndAssert([RunTimeType.SAS], 200, RunTimeType.SAS) }) it('should throw error when both sas and js programs do not exist', async () => { - const programPath = path.join(testFilesFolder, 'program') - - await makeRequestAndAssert(programPath, 400) + await makeRequestAndAssert([], 400) }) }) @@ -282,27 +241,19 @@ describe('stp', () => { }) it('should execute sas program when both sas and js programs exist', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(jsProgramPath, sampleJsProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.SAS) + await makeRequestAndAssert( + [RunTimeType.SAS, RunTimeType.JS], + 200, + RunTimeType.SAS + ) }) it('should execute js program when sas program is not present but js program exists', async () => { - const programPath = path.join(testFilesFolder, 'program') - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - await createFile(jsProgramPath, sampleJsProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.JS) + await makeRequestAndAssert([RunTimeType.JS], 200, RunTimeType.JS) }) it('should throw error when both sas and js programs do not exist', async () => { - const programPath = path.join(testFilesFolder, 'program') - - await makeRequestAndAssert(programPath, 400) + await makeRequestAndAssert([], 400) }) }) @@ -322,27 +273,19 @@ describe('stp', () => { }) it('should execute sas program when both sas and python programs exist', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(pyProgramPath, samplePyProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.SAS) + await makeRequestAndAssert( + [RunTimeType.SAS, RunTimeType.PY], + 200, + RunTimeType.SAS + ) }) it('should execute python program when sas program is not present but python program exists', async () => { - const programPath = path.join(testFilesFolder, 'program') - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - await createFile(pyProgramPath, samplePyProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.PY) + await makeRequestAndAssert([RunTimeType.PY], 200, RunTimeType.PY) }) it('should throw error when both sas and python programs do not exist', async () => { - const programPath = path.join(testFilesFolder, 'program') - - await makeRequestAndAssert(programPath, 400) + await makeRequestAndAssert([], 400) }) }) @@ -362,39 +305,27 @@ describe('stp', () => { }) it('should execute sas program when it exists, no matter js and python programs exist or not', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(jsProgramPath, sampleJsProgram) - await createFile(pyProgramPath, samplePyProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.SAS) + await makeRequestAndAssert( + [RunTimeType.SAS, RunTimeType.PY, RunTimeType.JS], + 200, + RunTimeType.SAS + ) }) it('should execute js program when sas program is absent but js and python programs are present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - await createFile(jsProgramPath, sampleJsProgram) - await createFile(pyProgramPath, samplePyProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.JS) + await makeRequestAndAssert( + [RunTimeType.JS, RunTimeType.PY], + 200, + RunTimeType.JS + ) }) it('should execute python program when both sas and js programs are not present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - await createFile(pyProgramPath, samplePyProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.PY) + await makeRequestAndAssert([RunTimeType.PY], 200, RunTimeType.PY) }) it('should throw error when no program exists', async () => { - const programPath = path.join(testFilesFolder, 'program') - - await makeRequestAndAssert(programPath, 400) + await makeRequestAndAssert([], 400) }) }) @@ -414,39 +345,27 @@ describe('stp', () => { }) it('should execute js program when it exists, no matter sas and python programs exist or not', async () => { - const programPath = path.join(testFilesFolder, 'program') - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - await createFile(jsProgramPath, sampleJsProgram) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(pyProgramPath, samplePyProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.JS) + await makeRequestAndAssert( + [RunTimeType.JS, RunTimeType.SAS, RunTimeType.PY], + 200, + RunTimeType.JS + ) }) it('should execute sas program when js program is absent but sas and python programs are present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(pyProgramPath, samplePyProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.SAS) + await makeRequestAndAssert( + [RunTimeType.SAS, RunTimeType.PY], + 200, + RunTimeType.SAS + ) }) it('should execute python program when both sas and js programs are not present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - await createFile(pyProgramPath, samplePyProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.PY) + await makeRequestAndAssert([RunTimeType.PY], 200, RunTimeType.PY) }) it('should throw error when no program exists', async () => { - const programPath = path.join(testFilesFolder, 'program') - - await makeRequestAndAssert(programPath, 400) + await makeRequestAndAssert([], 400) }) }) @@ -466,38 +385,27 @@ describe('stp', () => { }) it('should execute python program when it exists, no matter sas and js programs exist or not', async () => { - const programPath = path.join(testFilesFolder, 'program') - const pyProgramPath = path.join(filesFolder, `${programPath}.py`) - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - await createFile(pyProgramPath, samplePyProgram) - await createFile(jsProgramPath, sampleJsProgram) - await createFile(sasProgramPath, sampleSasProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.PY) + await makeRequestAndAssert( + [RunTimeType.PY, RunTimeType.SAS, RunTimeType.JS], + 200, + RunTimeType.PY + ) }) it('should execute sas program when python program is absent but sas and js programs are present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const sasProgramPath = path.join(filesFolder, `${programPath}.sas`) - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - await createFile(sasProgramPath, sampleSasProgram) - await createFile(jsProgramPath, sampleJsProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.SAS) + await makeRequestAndAssert( + [RunTimeType.SAS, RunTimeType.JS], + 200, + RunTimeType.SAS + ) }) it('should execute js program when both sas and python programs are not present', async () => { - const programPath = path.join(testFilesFolder, 'program') - const jsProgramPath = path.join(filesFolder, `${programPath}.js`) - await createFile(jsProgramPath, sampleJsProgram) - - await makeRequestAndAssert(programPath, 200, RunTimeType.JS) + await makeRequestAndAssert([RunTimeType.JS], 200, RunTimeType.JS) }) it('should throw error when no program exists', async () => { - const programPath = path.join(testFilesFolder, 'program') - await makeRequestAndAssert(programPath, 400) + await makeRequestAndAssert([], 400) }) }) }) @@ -505,10 +413,29 @@ describe('stp', () => { }) const makeRequestAndAssert = async ( - programPath: string, + programTypes: RunTimeType[], expectedStatusCode: number, expectedRuntime?: RunTimeType ) => { + const programPath = path.join(testFilesFolder, 'program') + for (const programType of programTypes) { + if (programType === RunTimeType.JS) + await createFile( + path.join(filesFolder, `${programPath}.js`), + sampleJsProgram + ) + else if (programType === RunTimeType.PY) + await createFile( + path.join(filesFolder, `${programPath}.py`), + samplePyProgram + ) + else if (programType === RunTimeType.SAS) + await createFile( + path.join(filesFolder, `${programPath}.sas`), + sampleSasProgram + ) + } + await request(app) .get(`/SASjsApi/stp/execute?_program=${programPath}`) .auth(accessToken, { type: 'bearer' })