From 0b35f72a789104e597673a19f54d61284540a662 Mon Sep 17 00:00:00 2001 From: Derek Roberts Date: Thu, 8 Oct 2026 19:16:23 -0700 Subject: [PATCH] fix(api): answer 500 when soft delete fails The catch block only logged the error and never sent a response, so a database failure left the DELETE request hanging until the client timed out. It now logs through the logger and returns 500 like the other handlers. --- api/src/services/pub-code-service.js | 6 ++--- api/test/soft-delete-repo.test.js | 38 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 api/test/soft-delete-repo.test.js diff --git a/api/src/services/pub-code-service.js b/api/src/services/pub-code-service.js index d2f51a57..a7301bea 100644 --- a/api/src/services/pub-code-service.js +++ b/api/src/services/pub-code-service.js @@ -126,10 +126,10 @@ const softDeleteRepo = async (req, res) => { console.info(pubcodeEntityFromDB); res.status(200).json({ message: "Repo Marked as soft deleted." }); } - } catch (e) { - console.error(e); + } catch (error) { + logger.error("softDeleteRepo: ", error); + res.status(500).json({ message: "Internal server error" }); } - }; module.exports = { bulkLoad, diff --git a/api/test/soft-delete-repo.test.js b/api/test/soft-delete-repo.test.js new file mode 100644 index 00000000..3c381d62 --- /dev/null +++ b/api/test/soft-delete-repo.test.js @@ -0,0 +1,38 @@ +"use strict"; +const { test } = require("node:test"); +const assert = require("node:assert/strict"); + +process.env.LOG_LEVEL = "error"; +// The email service refuses to load without configuration; nothing is sent here. +process.env.CHES_TOKEN_URL = "http://localhost/token"; +process.env.CHES_CLIENT_ID = "test"; +process.env.CHES_CLIENT_SECRET = "test"; +process.env.CHES_API_URL = "http://localhost/ches"; + +const pubcodeEntity = require("../src/entities/pub-code-entity"); +const { softDeleteRepo } = require("../src/services/pub-code-service"); + +function fakeResponse() { + const res = { statusCode: undefined, body: undefined }; + res.status = (code) => { + res.statusCode = code; + return res; + }; + res.json = (body) => { + res.body = body; + return res; + }; + return res; +} + +test("soft delete answers 500 when the database fails", async (t) => { + t.mock.method(pubcodeEntity, "findOne", () => ({ + exec: () => Promise.reject(new Error("database unavailable")), + })); + const res = fakeResponse(); + + await softDeleteRepo({ params: { repo_name: "some-repo" } }, res); + + assert.equal(res.statusCode, 500); + assert.deepEqual(res.body, { message: "Internal server error" }); +});