chatdesk-ui/storage_v1.19.1/src/test/bucket.test.ts

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)
})
})