460 lines
12 KiB
TypeScript
460 lines
12 KiB
TypeScript
'use strict'
|
|
import dotenv from 'dotenv'
|
|
import app from '../app'
|
|
import { S3Backend } from '../storage/backend'
|
|
|
|
dotenv.config({ path: '.env.test' })
|
|
const anonKey = process.env.ANON_KEY || ''
|
|
|
|
beforeAll(() => {
|
|
jest.spyOn(S3Backend.prototype, 'deleteObjects').mockImplementation(() => {
|
|
return Promise.resolve()
|
|
})
|
|
|
|
jest.spyOn(S3Backend.prototype, 'getObject').mockImplementation(() => {
|
|
return Promise.resolve({
|
|
metadata: {
|
|
httpStatusCode: 200,
|
|
size: 3746,
|
|
mimetype: 'image/png',
|
|
lastModified: new Date('Thu, 12 Aug 2021 16:00:00 GMT'),
|
|
eTag: 'abc',
|
|
cacheControl: 'no-cache',
|
|
contentLength: 3746,
|
|
},
|
|
httpStatusCode: 200,
|
|
body: Buffer.from(''),
|
|
})
|
|
})
|
|
})
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
})
|
|
|
|
/*
|
|
* GET /bucket/:id
|
|
*/
|
|
// @todo add RLS tests for buckets
|
|
describe('testing GET bucket', () => {
|
|
test('user is able to get bucket details', async () => {
|
|
const bucketId = 'bucket2'
|
|
const response = await app().inject({
|
|
method: 'GET',
|
|
url: `/bucket/${bucketId}`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(200)
|
|
const responseJSON = JSON.parse(response.body)
|
|
expect(responseJSON).toMatchObject({
|
|
id: bucketId,
|
|
name: bucketId,
|
|
public: false,
|
|
file_size_limit: null,
|
|
allowed_mime_types: null,
|
|
})
|
|
})
|
|
|
|
test('checking RLS: anon user is not able to get bucket details', async () => {
|
|
const bucketId = 'bucket2'
|
|
const response = await app().inject({
|
|
method: 'GET',
|
|
url: `/bucket/${bucketId}`,
|
|
headers: {
|
|
authorization: `Bearer ${anonKey}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is not able to get bucket details without Auth header', async () => {
|
|
const response = await app().inject({
|
|
method: 'GET',
|
|
url: '/bucket/bucket2',
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('return 404 when reading a non existent bucket', async () => {
|
|
const response = await app().inject({
|
|
method: 'GET',
|
|
url: '/object/notfound',
|
|
headers: {
|
|
authorization: `Bearer ${anonKey}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(404)
|
|
})
|
|
})
|
|
|
|
/*
|
|
* GET /bucket
|
|
*/
|
|
describe('testing GET all buckets', () => {
|
|
test('user is able to get all buckets', async () => {
|
|
const response = await app().inject({
|
|
method: 'GET',
|
|
url: `/bucket`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(200)
|
|
const responseJSON = JSON.parse(response.body)
|
|
expect(responseJSON.length).toBeGreaterThanOrEqual(10)
|
|
expect(responseJSON[0]).toMatchObject({
|
|
id: expect.any(String),
|
|
name: expect.any(String),
|
|
public: expect.any(Boolean),
|
|
file_size_limit: null,
|
|
allowed_mime_types: null,
|
|
})
|
|
})
|
|
|
|
test('checking RLS: anon user is not able to get all buckets', async () => {
|
|
const response = await app().inject({
|
|
method: 'GET',
|
|
url: `/bucket`,
|
|
headers: {
|
|
authorization: `Bearer ${anonKey}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(200)
|
|
const responseJSON = JSON.parse(response.body)
|
|
expect(responseJSON.length).toBe(0)
|
|
})
|
|
|
|
test('user is not able to all buckets details without Auth header', async () => {
|
|
const response = await app().inject({
|
|
method: 'GET',
|
|
url: `/bucket`,
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
})
|
|
/*
|
|
* POST /bucket
|
|
*/
|
|
describe('testing POST bucket', () => {
|
|
test('user is able to create a bucket', async () => {
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
payload: {
|
|
name: 'newbucket',
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(200)
|
|
const responseJSON = JSON.parse(response.body)
|
|
expect(responseJSON.name).toBe('newbucket')
|
|
})
|
|
|
|
test('user is not able to create a bucket with a /', async () => {
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
payload: {
|
|
name: 'newbucket/test',
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
expect(response.json()).toEqual({
|
|
error: 'Invalid Input',
|
|
message: 'Bucket name invalid',
|
|
statusCode: '400',
|
|
})
|
|
})
|
|
|
|
test('checking RLS: anon user is not able to create a bucket', async () => {
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket`,
|
|
headers: {
|
|
authorization: `Bearer ${anonKey}`,
|
|
},
|
|
payload: {
|
|
name: 'newbucket1',
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is not able to create a bucket without Auth header', async () => {
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket`,
|
|
payload: {
|
|
name: 'newbucket1',
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is not able to create a bucket with the same name', async () => {
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
payload: {
|
|
name: 'bucket2',
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
})
|
|
|
|
/*
|
|
* PUT /bucket
|
|
*/
|
|
describe('testing public bucket functionality', () => {
|
|
test('user is able to make a bucket public and private', async () => {
|
|
const bucketId = 'public-bucket'
|
|
const makePublicResponse = await app().inject({
|
|
method: 'PUT',
|
|
url: `/bucket/${bucketId}`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
payload: {
|
|
public: true,
|
|
},
|
|
})
|
|
expect(makePublicResponse.statusCode).toBe(200)
|
|
const makePublicJSON = JSON.parse(makePublicResponse.body)
|
|
expect(makePublicJSON.message).toBe('Successfully updated')
|
|
|
|
const publicResponse = await app().inject({
|
|
method: 'GET',
|
|
url: `/object/public/public-bucket/favicon.ico`,
|
|
})
|
|
expect(publicResponse.statusCode).toBe(200)
|
|
expect(publicResponse.headers['etag']).toBe('abc')
|
|
expect(publicResponse.headers['last-modified']).toBe('Thu, 12 Aug 2021 16:00:00 GMT')
|
|
|
|
const mockGetObject = jest.spyOn(S3Backend.prototype, 'getObject')
|
|
mockGetObject.mockRejectedValue({
|
|
$metadata: {
|
|
httpStatusCode: 304,
|
|
},
|
|
})
|
|
const notModifiedResponse = await app().inject({
|
|
method: 'GET',
|
|
url: `/object/public/public-bucket/favicon.ico`,
|
|
headers: {
|
|
'if-modified-since': 'Thu, 12 Aug 2021 16:00:00 GMT',
|
|
'if-none-match': 'abc',
|
|
},
|
|
})
|
|
expect(notModifiedResponse.statusCode).toBe(304)
|
|
expect(mockGetObject.mock.calls[1][3]).toMatchObject({
|
|
ifModifiedSince: 'Thu, 12 Aug 2021 16:00:00 GMT',
|
|
ifNoneMatch: 'abc',
|
|
})
|
|
|
|
const makePrivateResponse = await app().inject({
|
|
method: 'PUT',
|
|
url: `/bucket/${bucketId}`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
payload: {
|
|
public: false,
|
|
},
|
|
})
|
|
expect(makePrivateResponse.statusCode).toBe(200)
|
|
const makePrivateJSON = JSON.parse(makePrivateResponse.body)
|
|
expect(makePrivateJSON.message).toBe('Successfully updated')
|
|
|
|
const privateResponse = await app().inject({
|
|
method: 'GET',
|
|
url: `/object/public/public-bucket/favicon.ico`,
|
|
})
|
|
expect(privateResponse.statusCode).toBe(400)
|
|
})
|
|
|
|
test('checking RLS: anon user is not able to update a bucket', async () => {
|
|
const bucketId = 'public-bucket'
|
|
const response = await app().inject({
|
|
method: 'PUT',
|
|
url: `/bucket/${bucketId}`,
|
|
headers: {
|
|
authorization: `Bearer ${anonKey}`,
|
|
},
|
|
payload: {
|
|
public: true,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is not able to update a bucket without a auth header', async () => {
|
|
const bucketId = 'public-bucket'
|
|
const response = await app().inject({
|
|
method: 'PUT',
|
|
url: `/bucket/${bucketId}`,
|
|
payload: {
|
|
public: true,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is not able to update a non-existent bucket', async () => {
|
|
const bucketId = 'notfound'
|
|
const response = await app().inject({
|
|
method: 'PUT',
|
|
url: `/bucket/${bucketId}`,
|
|
payload: {
|
|
public: true,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
})
|
|
|
|
describe('testing DELETE bucket', () => {
|
|
test('user is able to delete a bucket', async () => {
|
|
const bucketId = 'bucket4'
|
|
const response = await app().inject({
|
|
method: 'DELETE',
|
|
url: `/bucket/${bucketId}`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(200)
|
|
const responseJSON = JSON.parse(response.body)
|
|
expect(responseJSON.message).toBe('Successfully deleted')
|
|
})
|
|
|
|
test('checking RLS: anon user is not able to delete a bucket', async () => {
|
|
const bucketId = 'bucket5'
|
|
const response = await app().inject({
|
|
method: 'DELETE',
|
|
url: `/bucket/${bucketId}`,
|
|
headers: {
|
|
authorization: `Bearer ${anonKey}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is not able to delete bucket without Auth header', async () => {
|
|
const bucketId = 'bucket5'
|
|
const response = await app().inject({
|
|
method: 'DELETE',
|
|
url: `/bucket/${bucketId}`,
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is not able to delete bucket a non empty bucket', async () => {
|
|
const bucketId = 'bucket2'
|
|
const response = await app().inject({
|
|
method: 'DELETE',
|
|
url: `/bucket/${bucketId}`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is not able to delete a non-existent bucket', async () => {
|
|
const bucketId = 'notfound'
|
|
const response = await app().inject({
|
|
method: 'DELETE',
|
|
url: `/bucket/${bucketId}`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
})
|
|
|
|
describe('testing EMPTY bucket', () => {
|
|
test('user is able to empty a bucket', async () => {
|
|
const bucketId = 'bucket3'
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket/${bucketId}/empty`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(200)
|
|
const responseJSON = JSON.parse(response.body)
|
|
expect(responseJSON.message).toBe('Successfully emptied')
|
|
})
|
|
|
|
test('user is able to empty a bucket with a service key', async () => {
|
|
const bucketId = 'bucket3'
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket/${bucketId}/empty`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.SERVICE_KEY}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(200)
|
|
const responseJSON = JSON.parse(response.body)
|
|
expect(responseJSON.message).toBe('Successfully emptied')
|
|
})
|
|
|
|
test('user is able to delete a bucket', async () => {
|
|
const bucketId = 'bucket3'
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket/${bucketId}/empty`,
|
|
headers: {
|
|
authorization: `Bearer ${anonKey}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is not able to empty a bucket without Auth Header', async () => {
|
|
const bucketId = 'bucket3'
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket/${bucketId}/empty`,
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is not able to empty a non existent bucket', async () => {
|
|
const bucketId = 'notfound'
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket/${bucketId}/empty`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(400)
|
|
})
|
|
|
|
test('user is able to empty an already empty bucket', async () => {
|
|
const bucketId = 'bucket5'
|
|
const response = await app().inject({
|
|
method: 'POST',
|
|
url: `/bucket/${bucketId}/empty`,
|
|
headers: {
|
|
authorization: `Bearer ${process.env.AUTHENTICATED_KEY}`,
|
|
},
|
|
})
|
|
expect(response.statusCode).toBe(200)
|
|
})
|
|
})
|