Added concurrency test, and added CORS and CORS test
Unit Tests with docker compose / unit-test (push) Successful in 24s Details
Build image / build (push) Successful in 42s Details

This commit is contained in:
Sugui 2024-04-21 12:26:59 +02:00
parent fac0a38858
commit 2f140996d5
8 changed files with 53 additions and 8 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -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"

View File

@ -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);

View File

@ -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<GelbooruServiceResponse> {
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(

10
test/app.test.ts Normal file
View File

@ -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('*');
})
})

View File

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

View File

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

View File

@ -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==