mirror of
https://github.com/sasjs/server.git
synced 2026-01-11 16:20:06 +00:00
chore(specs): specs added for deploy upload file and zipped file
This commit is contained in:
35
api/package-lock.json
generated
35
api/package-lock.json
generated
@@ -32,6 +32,7 @@
|
|||||||
"api": "build/src/server.js"
|
"api": "build/src/server.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/adm-zip": "^0.5.0",
|
||||||
"@types/bcryptjs": "^2.4.2",
|
"@types/bcryptjs": "^2.4.2",
|
||||||
"@types/cookie-parser": "^1.4.2",
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.12",
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
"@types/supertest": "^2.0.11",
|
"@types/supertest": "^2.0.11",
|
||||||
"@types/swagger-ui-express": "^4.1.3",
|
"@types/swagger-ui-express": "^4.1.3",
|
||||||
"@types/unzipper": "^0.10.5",
|
"@types/unzipper": "^0.10.5",
|
||||||
|
"adm-zip": "^0.5.9",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"http-headers-validation": "^0.0.1",
|
"http-headers-validation": "^0.0.1",
|
||||||
"jest": "^27.0.6",
|
"jest": "^27.0.6",
|
||||||
@@ -1755,6 +1757,15 @@
|
|||||||
"yarn": ">=1.9.4"
|
"yarn": ">=1.9.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/adm-zip": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-FCJBJq9ODsQZUNURo5ILAQueuA8WJhRvuihS3ke2iI25mJlfV2LK8jG2Qj2z2AWg8U0FtWWqBHVRetceLskSaw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.1.15",
|
"version": "7.1.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz",
|
||||||
@@ -2283,6 +2294,15 @@
|
|||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/adm-zip": {
|
||||||
|
"version": "0.5.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz",
|
||||||
|
"integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/agent-base": {
|
"node_modules/agent-base": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
@@ -11886,6 +11906,15 @@
|
|||||||
"validator": "^13.6.0"
|
"validator": "^13.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/adm-zip": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-FCJBJq9ODsQZUNURo5ILAQueuA8WJhRvuihS3ke2iI25mJlfV2LK8jG2Qj2z2AWg8U0FtWWqBHVRetceLskSaw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/babel__core": {
|
"@types/babel__core": {
|
||||||
"version": "7.1.15",
|
"version": "7.1.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz",
|
||||||
@@ -12372,6 +12401,12 @@
|
|||||||
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
|
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"adm-zip": {
|
||||||
|
"version": "0.5.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz",
|
||||||
|
"integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"agent-base": {
|
"agent-base": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
"url": "^0.10.3"
|
"url": "^0.10.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/adm-zip": "^0.5.0",
|
||||||
"@types/bcryptjs": "^2.4.2",
|
"@types/bcryptjs": "^2.4.2",
|
||||||
"@types/cookie-parser": "^1.4.2",
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.12",
|
||||||
@@ -83,6 +84,7 @@
|
|||||||
"@types/supertest": "^2.0.11",
|
"@types/supertest": "^2.0.11",
|
||||||
"@types/swagger-ui-express": "^4.1.3",
|
"@types/swagger-ui-express": "^4.1.3",
|
||||||
"@types/unzipper": "^0.10.5",
|
"@types/unzipper": "^0.10.5",
|
||||||
|
"adm-zip": "^0.5.9",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"http-headers-validation": "^0.0.1",
|
"http-headers-validation": "^0.0.1",
|
||||||
"jest": "^27.0.6",
|
"jest": "^27.0.6",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Express } from 'express'
|
|||||||
import mongoose, { Mongoose } from 'mongoose'
|
import mongoose, { Mongoose } from 'mongoose'
|
||||||
import { MongoMemoryServer } from 'mongodb-memory-server'
|
import { MongoMemoryServer } from 'mongodb-memory-server'
|
||||||
import request from 'supertest'
|
import request from 'supertest'
|
||||||
|
import AdmZip from 'adm-zip'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
folderExists,
|
folderExists,
|
||||||
@@ -72,11 +73,52 @@ describe('drive', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('deploy', () => {
|
describe('deploy', () => {
|
||||||
const shouldFailAssertion = async (payload: any) => {
|
const makeRequest = async (payload: any, type: string = 'payload') => {
|
||||||
const res = await request(app)
|
const requestUrl =
|
||||||
.post('/SASjsApi/drive/deploy')
|
type === 'payload'
|
||||||
.auth(accessToken, { type: 'bearer' })
|
? '/SASjsApi/drive/deploy'
|
||||||
.send({ appLoc: '/Public', fileTree: payload })
|
: '/SASjsApi/drive/deploy/upload'
|
||||||
|
|
||||||
|
if (type === 'payload') {
|
||||||
|
return await request(app)
|
||||||
|
.post(requestUrl)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send({ appLoc: '/Public', fileTree: payload })
|
||||||
|
}
|
||||||
|
if (type === 'file') {
|
||||||
|
const deployContents = JSON.stringify({
|
||||||
|
appLoc: '/Public',
|
||||||
|
fileTree: payload
|
||||||
|
})
|
||||||
|
return await request(app)
|
||||||
|
.post(requestUrl)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.attach('file', Buffer.from(deployContents), 'deploy.json')
|
||||||
|
} else {
|
||||||
|
const deployContents = JSON.stringify({
|
||||||
|
appLoc: '/Public',
|
||||||
|
fileTree: payload
|
||||||
|
})
|
||||||
|
const zip = new AdmZip()
|
||||||
|
// add file directly
|
||||||
|
zip.addFile(
|
||||||
|
'deploy.json',
|
||||||
|
Buffer.from(deployContents, 'utf8'),
|
||||||
|
'entry comment goes here'
|
||||||
|
)
|
||||||
|
|
||||||
|
return await request(app)
|
||||||
|
.post(requestUrl)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.attach('file', zip.toBuffer(), 'deploy.json.zip')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldFailAssertion = async (
|
||||||
|
payload: any,
|
||||||
|
type: string = 'payload'
|
||||||
|
) => {
|
||||||
|
const res = await makeRequest(payload, type)
|
||||||
|
|
||||||
expect(res.statusCode).toEqual(400)
|
expect(res.statusCode).toEqual(400)
|
||||||
|
|
||||||
@@ -176,6 +218,240 @@ describe('drive', () => {
|
|||||||
|
|
||||||
await deleteFolder(path.join(getFilesFolder(), 'public'))
|
await deleteFolder(path.join(getFilesFolder(), 'public'))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('upload', () => {
|
||||||
|
it('should respond with payload example if valid JSON file was not provided', async () => {
|
||||||
|
await shouldFailAssertion(null, 'file')
|
||||||
|
await shouldFailAssertion(undefined, 'file')
|
||||||
|
await shouldFailAssertion('data', 'file')
|
||||||
|
await shouldFailAssertion({}, 'file')
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
userId: 1,
|
||||||
|
title: 'test is cool'
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
membersWRONG: []
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: {}
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
nameWRONG: 'jobs',
|
||||||
|
type: 'folder',
|
||||||
|
members: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'jobs',
|
||||||
|
type: 'WRONG',
|
||||||
|
members: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'jobs',
|
||||||
|
type: 'folder',
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'extract',
|
||||||
|
type: 'folder',
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'makedata1',
|
||||||
|
type: 'service',
|
||||||
|
codeWRONG: '%put Hello World!;'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should successfully deploy if valid JSON file was provided', async () => {
|
||||||
|
const deployContents = JSON.stringify({
|
||||||
|
appLoc: '/public',
|
||||||
|
fileTree: getTreeExample()
|
||||||
|
})
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/SASjsApi/drive/deploy/upload')
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.attach('file', Buffer.from(deployContents), 'deploy.json')
|
||||||
|
|
||||||
|
expect(res.statusCode).toEqual(200)
|
||||||
|
expect(res.text).toEqual(
|
||||||
|
'{"status":"success","message":"Files deployed successfully to @sasjs/server."}'
|
||||||
|
)
|
||||||
|
await expect(folderExists(getFilesFolder())).resolves.toEqual(true)
|
||||||
|
|
||||||
|
const testJobFolder = path.join(
|
||||||
|
getFilesFolder(),
|
||||||
|
'public',
|
||||||
|
'jobs',
|
||||||
|
'extract'
|
||||||
|
)
|
||||||
|
await expect(folderExists(testJobFolder)).resolves.toEqual(true)
|
||||||
|
|
||||||
|
const exampleService = getExampleService()
|
||||||
|
const testJobFile =
|
||||||
|
path.join(testJobFolder, exampleService.name) + '.sas'
|
||||||
|
|
||||||
|
await expect(fileExists(testJobFile)).resolves.toEqual(true)
|
||||||
|
|
||||||
|
await expect(readFile(testJobFile)).resolves.toEqual(
|
||||||
|
exampleService.code
|
||||||
|
)
|
||||||
|
|
||||||
|
await deleteFolder(path.join(getFilesFolder(), 'public'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('upload - zipped', () => {
|
||||||
|
it('should respond with payload example if valid Zipped file was not provided', async () => {
|
||||||
|
await shouldFailAssertion(null, 'zip')
|
||||||
|
await shouldFailAssertion(undefined, 'zip')
|
||||||
|
await shouldFailAssertion('data', 'zip')
|
||||||
|
await shouldFailAssertion({}, 'zip')
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
userId: 1,
|
||||||
|
title: 'test is cool'
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
membersWRONG: []
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: {}
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
nameWRONG: 'jobs',
|
||||||
|
type: 'folder',
|
||||||
|
members: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'jobs',
|
||||||
|
type: 'WRONG',
|
||||||
|
members: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'jobs',
|
||||||
|
type: 'folder',
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'extract',
|
||||||
|
type: 'folder',
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'makedata1',
|
||||||
|
type: 'service',
|
||||||
|
codeWRONG: '%put Hello World!;'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should successfully deploy if valid Zipped file was provided', async () => {
|
||||||
|
const deployContents = JSON.stringify({
|
||||||
|
appLoc: '/public',
|
||||||
|
fileTree: getTreeExample()
|
||||||
|
})
|
||||||
|
|
||||||
|
const zip = new AdmZip()
|
||||||
|
// add file directly
|
||||||
|
zip.addFile(
|
||||||
|
'deploy.json',
|
||||||
|
Buffer.from(deployContents, 'utf8'),
|
||||||
|
'entry comment goes here'
|
||||||
|
)
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/SASjsApi/drive/deploy/upload')
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.attach('file', zip.toBuffer(), 'deploy.json.zip')
|
||||||
|
|
||||||
|
expect(res.statusCode).toEqual(200)
|
||||||
|
expect(res.text).toEqual(
|
||||||
|
'{"status":"success","message":"Files deployed successfully to @sasjs/server."}'
|
||||||
|
)
|
||||||
|
await expect(folderExists(getFilesFolder())).resolves.toEqual(true)
|
||||||
|
|
||||||
|
const testJobFolder = path.join(
|
||||||
|
getFilesFolder(),
|
||||||
|
'public',
|
||||||
|
'jobs',
|
||||||
|
'extract'
|
||||||
|
)
|
||||||
|
await expect(folderExists(testJobFolder)).resolves.toEqual(true)
|
||||||
|
|
||||||
|
const exampleService = getExampleService()
|
||||||
|
const testJobFile =
|
||||||
|
path.join(testJobFolder, exampleService.name) + '.sas'
|
||||||
|
|
||||||
|
await expect(fileExists(testJobFile)).resolves.toEqual(true)
|
||||||
|
|
||||||
|
await expect(readFile(testJobFile)).resolves.toEqual(
|
||||||
|
exampleService.code
|
||||||
|
)
|
||||||
|
|
||||||
|
await deleteFolder(path.join(getFilesFolder(), 'public'))
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('folder', () => {
|
describe('folder', () => {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export const extractJSONFromZip = async (zipFile: Express.Multer.File) => {
|
|||||||
const fileName = entry.path as string
|
const fileName = entry.path as string
|
||||||
if (fileName.toUpperCase().endsWith('.JSON') && fileName === fileInZip) {
|
if (fileName.toUpperCase().endsWith('.JSON') && fileName === fileInZip) {
|
||||||
fileContent = await entry.buffer()
|
fileContent = await entry.buffer()
|
||||||
|
break
|
||||||
} else {
|
} else {
|
||||||
entry.autodrain()
|
entry.autodrain()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user