fileStore.test.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. import request from 'supertest';
  2. import express from 'express';
  3. import { jest } from '@jest/globals';
  4. import path from 'path';
  5. import fs from 'fs';
  6. import tempy from 'tempy';
  7. import aws from '@aws-sdk/client-s3';
  8. import { getDirname } from '../utils.js';
  9. import fileStore from '../fileStore';
  10. import {
  11. MemoryFileBackend,
  12. DiskFileBackend,
  13. S3FileBackend,
  14. } from '../fileStore/backends';
  15. import { S3_ACCESS_KEY, S3_SECRET_KEY, S3_ENDPOINT } from '../settings';
  16. const { S3, DeleteObjectsCommand, ListObjectsCommand } = aws;
  17. const __dirname = getDirname(import.meta.url);
  18. jest.mock('nanoid', () => {
  19. let count = 0;
  20. return {
  21. customAlphabet: () =>
  22. jest.fn(() => {
  23. return 'nanoid_' + count++;
  24. }),
  25. };
  26. });
  27. const tempDestination = tempy.directory({ prefix: 'test__' });
  28. const fileStores = [
  29. ['memory', MemoryFileBackend(), { prefix: 'pref' }],
  30. [
  31. 'disk',
  32. DiskFileBackend({
  33. destination: tempDestination,
  34. prefix: 'pref',
  35. }),
  36. { prefix: 'pref' },
  37. ],
  38. ];
  39. const S3_BUCKET_TEST = process.env.S3_BUCKET_TEST;
  40. if (S3_BUCKET_TEST) {
  41. fileStores.push([
  42. 's3',
  43. S3FileBackend({
  44. bucket: process.env.S3_BUCKET_TEST,
  45. secretKey: S3_SECRET_KEY,
  46. accessKey: S3_ACCESS_KEY,
  47. endpoint: S3_ENDPOINT,
  48. }),
  49. {
  50. prefix: 'pref',
  51. },
  52. ]);
  53. }
  54. describe.each(fileStores)(
  55. 'Backend <%s> file store',
  56. (backendType, backend, options) => {
  57. let app;
  58. let query;
  59. beforeAll(() => {
  60. app = express();
  61. app.use(express.json());
  62. app.use(
  63. '/:siteId/pref/:boxId/:id/file',
  64. (req, _, next) => {
  65. req.siteId = req.params.siteId;
  66. req.boxId = req.params.boxId;
  67. req.resourceId = req.params.id;
  68. next();
  69. },
  70. fileStore(backend, options)
  71. );
  72. query = request(app);
  73. });
  74. afterAll(async () => {
  75. // Clean files
  76. if (backendType === 'disk') {
  77. try {
  78. fs.rmdirSync(tempDestination, { recursive: true });
  79. } catch (e) {
  80. console.log(e);
  81. }
  82. return;
  83. }
  84. // Clean bucket
  85. if (backendType === 's3') {
  86. const { bucket, secretKey, accessKey, endpoint } = {
  87. bucket: process.env.S3_BUCKET_TEST,
  88. secretKey: S3_SECRET_KEY,
  89. accessKey: S3_ACCESS_KEY,
  90. endpoint: S3_ENDPOINT,
  91. };
  92. const s3 = new S3({
  93. secretAccessKey: secretKey,
  94. accessKeyId: accessKey,
  95. endpoint: endpoint,
  96. });
  97. const params = {
  98. Bucket: bucket,
  99. };
  100. const data = await s3.send(new ListObjectsCommand(params));
  101. if (data.Contents) {
  102. const deleteParams = {
  103. Bucket: bucket,
  104. Delete: { Objects: data.Contents.map(({ Key }) => ({ Key })) },
  105. };
  106. await s3.send(new DeleteObjectsCommand(deleteParams));
  107. return;
  108. }
  109. }
  110. if (backendType === 'memory') {
  111. return;
  112. }
  113. });
  114. it('should store file', async () => {
  115. const boxId = 'box010';
  116. const res = await query
  117. .post(`/mysiteid/pref/${boxId}/1234/file/`)
  118. .attach('file', path.resolve(__dirname, 'testFile.txt'))
  119. .expect(200);
  120. expect(res.text).toEqual(
  121. expect.stringContaining(`mysiteid/pref/${boxId}/1234/file/`)
  122. );
  123. });
  124. it('should retreive image file', async () => {
  125. const boxId = 'box020';
  126. const res = await query
  127. .post(`/mysiteid/pref/${boxId}/1234/file/`)
  128. .attach('file', path.resolve(__dirname, 'test.png'))
  129. .expect(200);
  130. const fileUrl = res.text;
  131. const fileRes = await query
  132. .get(`/${fileUrl}`)
  133. .buffer(false)
  134. .redirects(1)
  135. .expect(200);
  136. expect(fileRes.type).toBe('image/png');
  137. expect(fileRes.body.length).toBe(6174);
  138. });
  139. it('should retreive text file', async () => {
  140. const boxId = 'box025';
  141. const res = await query
  142. .post(`/mysiteid/pref/${boxId}/1234/file/`)
  143. .set('Content-Type', 'text/plain')
  144. .attach('file', path.resolve(__dirname, 'testFile.txt'))
  145. .expect(200);
  146. const fileUrl = res.text;
  147. const fileRes = await query
  148. .get(`/${fileUrl}`)
  149. .buffer(false)
  150. .redirects(1)
  151. .expect(200);
  152. expect(fileRes.type).toBe('text/plain');
  153. });
  154. it('should list files', async () => {
  155. const boxId = 'box030';
  156. const fileListEmpty = await query
  157. .get(`/mysiteid/pref/${boxId}/1235/file/`)
  158. .expect(200);
  159. expect(Array.isArray(fileListEmpty.body)).toBe(true);
  160. expect(fileListEmpty.body.length).toBe(0);
  161. const res = await query
  162. .post(`/mysiteid/pref/${boxId}/1235/file/`)
  163. .attach('file', path.resolve(__dirname, 'testFile.txt'))
  164. .expect(200);
  165. const res2 = await query
  166. .post(`/mysiteid/pref/${boxId}/1235/file/`)
  167. .attach('file', path.resolve(__dirname, 'test.png'))
  168. .expect(200);
  169. const fileList = await query
  170. .get(`/mysiteid/pref/${boxId}/1235/file/`)
  171. .expect(200);
  172. expect(Array.isArray(fileList.body)).toBe(true);
  173. expect(fileList.body.length).toBe(2);
  174. expect(fileList.body[0]).toEqual(
  175. expect.stringContaining(`mysiteid/pref/${boxId}/1235/file/`)
  176. );
  177. });
  178. it('should delete file', async () => {
  179. const boxId = 'box040';
  180. const res = await query
  181. .post(`/mysiteid/pref/${boxId}/1234/file/`)
  182. .attach('file', path.resolve(__dirname, 'test.png'))
  183. .expect(200);
  184. const fileUrl = res.text;
  185. await query.delete(`/${fileUrl}`).buffer(false).expect(200);
  186. const fileList = await query
  187. .get(`/mysiteid/pref/${boxId}/1234/file/`)
  188. .expect(200);
  189. expect(fileList.body.length).toBe(0);
  190. });
  191. it('should return 404', async () => {
  192. const boxId = 'box050';
  193. await query.get(`/mysiteid/pref/${boxId}/1234/file/nofile`).expect(404);
  194. await query
  195. .delete(`/mysiteid/pref/${boxId}/1234/file/nofile`)
  196. .expect(404);
  197. // To create box
  198. await query
  199. .post(`/mysiteid/pref/${boxId}/1234/file/`)
  200. .attach('file', path.resolve(__dirname, 'test.png'))
  201. .expect(200);
  202. await query.get(`/mysiteid/pref/${boxId}/1234/file/nofile2`).expect(404);
  203. await query
  204. .delete(`/mysiteid/pref/${boxId}/1234/file/nofile2`)
  205. .expect(404);
  206. });
  207. }
  208. );