diff --git a/bun.lockb b/bun.lockb index 347f41e..fe1d977 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index ef606ba..28ba82e 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,10 @@ "typescript": "^5.0.0" }, "dependencies": { + "@types/cors": "^2.8.17", "async-mutex": "^0.5.0", "compression": "^1.7.4", + "cors": "^2.8.5", "express": "^4.19.2", "express-list-endpoints": "^6.0.0", "winston": "^3.13.0" diff --git a/src/app.ts b/src/app.ts index e34f131..8dda20e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,4 +1,5 @@ import compression from "compression"; +import cors from "cors"; import express from "express"; import listEndpoints from "express-list-endpoints"; import * as imageController from "src/controllers/imageController"; @@ -7,6 +8,7 @@ const app = express(); app.use(express.json()); app.use(compression()); +app.use(cors()); app.get("/", (_, res) => { const endpoints = listEndpoints(app); diff --git a/src/services/gelbooruApiService.ts b/src/services/gelbooruApiService.ts index f584892..9e5b151 100644 --- a/src/services/gelbooruApiService.ts +++ b/src/services/gelbooruApiService.ts @@ -3,9 +3,10 @@ import logger from "src/logger"; import GelbooruApiResponse from "src/types/GelbooruApiResponse"; import GelbooruServiceResponse from "src/types/GelbooruServiceResponse"; +export const LIMIT = env.GELBOORU_IMAGES_PER_REQUEST || 100; +export const TAGS = encodeURIComponent(env.GELBOORU_TAGS || ""); + export async function get(): Promise { - const LIMIT = env.GELBOORU_IMAGES_PER_REQUEST || 100; - const TAGS = encodeURIComponent(env.GELBOORU_TAGS || ""); const url: string = `https://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=${LIMIT}&json=1&tags=${TAGS}`; const response: GelbooruApiResponse = (await fetch(url).then( diff --git a/test/app.test.ts b/test/app.test.ts new file mode 100644 index 0000000..efa5e79 --- /dev/null +++ b/test/app.test.ts @@ -0,0 +1,10 @@ +import { describe, expect, it } from "bun:test"; +import app from "src/app"; +import request from "supertest"; + +describe("CORS implementation", () => { + it("should implement CORS", async () => { + const { headers } = await request(app).get('/'); + expect(headers['access-control-allow-origin']).toEqual('*'); + }) +}) \ No newline at end of file diff --git a/test/ImageController/ImageController.test.ts b/test/imageController.test.ts similarity index 83% rename from test/ImageController/ImageController.test.ts rename to test/imageController.test.ts index 4c8746b..ea35df1 100644 --- a/test/ImageController/ImageController.test.ts +++ b/test/imageController.test.ts @@ -9,8 +9,6 @@ afterAll(() => { describe("endpoint returns the correct status codes", () => { it("should return 200 if successful", async () => { - // Can't mock ImageService partially because of bun incomplete implementation of testing :( - // It goes to the network directly to test const res = await request(app).get("/image"); expect(res.status).toBe(200); }); diff --git a/test/ImageService/ImageService.test.ts b/test/imageService.test.ts similarity index 72% rename from test/ImageService/ImageService.test.ts rename to test/imageService.test.ts index 67e36c0..5f909c0 100644 --- a/test/ImageService/ImageService.test.ts +++ b/test/imageService.test.ts @@ -1,16 +1,28 @@ import { afterAll, describe, expect, it, jest, mock, spyOn } from "bun:test"; import Image from "src/types/Image"; +import request from "supertest"; import * as gelbooruApiService from "src/services/gelbooruApiService"; import * as botApiService from "src/services/botApiService"; import * as imageService from "src/services/imageService"; +import app from "src/app"; +import { response } from "express"; afterAll(() => { jest.restoreAllMocks(); }) describe("the service is thread-safe", () => { - it("should run normally when 2 processes call the get() method with 1 remaining image in the queue", async () => { - // TODO + it("should not crash when multiple processes call the get() method with 1 remaining image in the queue", async () => { + const NUM_OF_REQUESTS = 110; + + const getFn = spyOn(imageService, "get"); + + const promises = Array(NUM_OF_REQUESTS).fill(null) + .map(_ => request(app).get("/image")); + const responses = await Promise.all(promises); + + expect(getFn).toHaveBeenCalledTimes(NUM_OF_REQUESTS); + responses.forEach(res => expect(res.status).toBe(200)); }) }) diff --git a/yarn.lock b/yarn.lock index ff9aa21..288f4bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,6 +1,6 @@ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 -# bun ./bun.lockb --hash: 9A5A612BBFD3E7ED-76a31de2b7c4bbe8-8DB93E498B9CBB30-9cf1116024820c4f +# bun ./bun.lockb --hash: 4B368415A9637562-70781726b75e86ab-6261B8AB82430501-a22712f647bcbfe3 "@colors/colors@1.6.0", "@colors/colors@^1.6.0": @@ -44,6 +44,13 @@ resolved "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz" integrity sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q== +"@types/cors@^2.8.17": + version "2.8.17" + resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz" + integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA== + dependencies: + "@types/node" "*" + "@types/express@*", "@types/express@^4.17.21": version "4.17.21" resolved "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz" @@ -336,6 +343,14 @@ cookiejar@^2.1.4: resolved "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz" integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -689,6 +704,11 @@ negotiator@0.6.3: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +object-assign@^4: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + object-inspect@^1.13.1: version "1.13.1" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz" @@ -953,7 +973,7 @@ utils-merge@1.0.1: resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -vary@~1.1.2: +vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==