From 64d22ffe6d46a15f2c7eeed05383254ad5bde235 Mon Sep 17 00:00:00 2001 From: George Raduta Date: Fri, 15 Nov 2024 13:19:57 +0100 Subject: [PATCH 1/3] Add middleware check on lock action --- Control/lib/api.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Control/lib/api.js b/Control/lib/api.js index dc7616ad6..df72eca5f 100644 --- a/Control/lib/api.js +++ b/Control/lib/api.js @@ -184,7 +184,10 @@ module.exports.setup = (http, ws) => { // Lock Service http.get('/locks', lockController.getLocksStateHandler.bind(lockController)); - http.put('/locks/:action/:detectorId', lockController.actionLockHandler.bind(lockController)); + http.put('/locks/:action/:detectorId', + minimumRoleMiddleware(Role.DETECTOR), + lockController.actionLockHandler.bind(lockController) + ); http.put('/locks/force/:action/:detectorId', minimumRoleMiddleware(Role.GLOBAL), lockController.actionForceLockHandler.bind(lockController)); From 5c7640149308b016e66a5d42e62f42af485d31c2 Mon Sep 17 00:00:00 2001 From: George Raduta Date: Fri, 15 Nov 2024 13:20:07 +0100 Subject: [PATCH 2/3] Add API test suite for lock actions --- Control/package-lock.json | 163 ++++++++++++++++++- Control/package.json | 3 +- Control/test/api/generateToken.js | 43 +++++ Control/test/api/lock/api-get-locks.test.js | 53 +++++++ Control/test/api/lock/api-put-locks.test.js | 167 ++++++++++++++++++++ Control/test/mocha-index.js | 3 + Control/test/test-config.js | 5 + 7 files changed, 435 insertions(+), 2 deletions(-) create mode 100644 Control/test/api/generateToken.js create mode 100644 Control/test/api/lock/api-get-locks.test.js create mode 100644 Control/test/api/lock/api-put-locks.test.js diff --git a/Control/package-lock.json b/Control/package-lock.json index 30105aaca..710a54b60 100644 --- a/Control/package-lock.json +++ b/Control/package-lock.json @@ -26,7 +26,8 @@ "nock": "^13.5.0", "nyc": "^17.1.0", "puppeteer": "^23.7.0", - "sinon": "19.0.2" + "sinon": "19.0.2", + "supertest": "7.0.0" }, "engines": { "node": ">= 20.x" @@ -1261,6 +1262,13 @@ "inBundle": true, "license": "MIT" }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, "node_modules/ast-types": { "version": "0.13.4", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", @@ -1280,6 +1288,13 @@ "inBundle": true, "license": "MIT" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/b4a": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", @@ -1766,12 +1781,35 @@ "text-hex": "1.0.x" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1824,6 +1862,13 @@ "inBundle": true, "license": "MIT" }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -1958,6 +2003,16 @@ "node": ">= 14" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1985,6 +2040,17 @@ "integrity": "sha512-BlmkSqV0V84E2WnEnoPnwyix57rQxAM5SKJjf4TbYOCGLAWtz8CDH8RIaGOjPgPCXo2Mce3kxSY497OySidY3Q==", "dev": true }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -2445,6 +2511,13 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -2612,6 +2685,36 @@ "node": ">=8.0.0" } }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.2.tgz", + "integrity": "sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^2.0.0", + "once": "^1.4.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2975,6 +3078,16 @@ "node": ">=16.0.0" } }, + "node_modules/hexoid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-2.0.0.tgz", + "integrity": "sha512-qlspKUK7IlSQv2o+5I7yhUd7TxlOG2Vr5LTa3ve2XSNVKAL/n/u/7KLvKmFNimomDIKvZFXWHv0T12mv7rT8Aw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -5420,6 +5533,54 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/superagent": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-9.0.2.tgz", + "integrity": "sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^3.5.1", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.0.0.tgz", + "integrity": "sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^9.0.1" + }, + "engines": { + "node": ">=14.18.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/Control/package.json b/Control/package.json index 0418bfe76..e72d10104 100644 --- a/Control/package.json +++ b/Control/package.json @@ -50,6 +50,7 @@ "nock": "^13.5.0", "nyc": "^17.1.0", "puppeteer": "^23.7.0", - "sinon": "19.0.2" + "sinon": "19.0.2", + "supertest": "7.0.0" } } diff --git a/Control/test/api/generateToken.js b/Control/test/api/generateToken.js new file mode 100644 index 000000000..f8990d6a3 --- /dev/null +++ b/Control/test/api/generateToken.js @@ -0,0 +1,43 @@ + +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. +*/ + +const jwt = require('jsonwebtoken'); +const { http, jwt: jwtConfig } = require('./../test-config.js'); + + +/** + * Provides JSON Web Token functionality such as token generation and verification with `jsonwebtoken` library + */ +const generateToken = (personid, username, name, access = '', secret) => { + return jwt.sign({ id: personid, username, name, access }, secret, { + expiresIn: '1d', + issuer: 'test-gui', + }); +}; + +const TEST_URL = 'http://' + http.hostname + ':' + http.port; +const ADMIN_TEST_TOKEN = generateToken(0, 'admin', 'Admin User', 'admin', jwtConfig.secret); +const GLOBAL_TEST_TOKEN = generateToken(1, 'global', 'Global User', 'global', jwtConfig.secret); +const DET_MID_TEST_TOKEN = generateToken(2, 'det-mid', 'Detector User', 'det-mid', jwtConfig.secret); +const GUEST_TEST_TOKEN = generateToken(3, 'guest', 'Guest User', 'guest', jwtConfig.secret); + +module.exports = { + ADMIN_TEST_TOKEN, + GLOBAL_TEST_TOKEN, + DET_MID_TEST_TOKEN, + GUEST_TEST_TOKEN, + TEST_URL, +}; + diff --git a/Control/test/api/lock/api-get-locks.test.js b/Control/test/api/lock/api-get-locks.test.js new file mode 100644 index 000000000..6276ba311 --- /dev/null +++ b/Control/test/api/lock/api-get-locks.test.js @@ -0,0 +1,53 @@ + +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. +*/ + +const request = require('supertest'); +const { ADMIN_TEST_TOKEN, TEST_URL } = require('../generateToken.js'); + +describe(`'API - GET - /locks' test suite`, () => { + before(async () => { + // release ALL locks via API to prepare test-setup for API PUT tests + await request(`${TEST_URL}/api/locks`) + .put(`/force/release/ALL?token=${ADMIN_TEST_TOKEN}`); + }); + + it('should successfully get all locks state', async () => { + await request(`${TEST_URL}/api/locks`) + .get(`/?token=${ADMIN_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'FREE' }, + DCS: { name: 'DCS', state: 'FREE' }, + ODC: { name: 'ODC', state: 'FREE' } + }); + }); + + it('should return unauthorized error for missing token requests', async () => { + await request(`${TEST_URL}/api/locks`) + .get('/') + .expect(403, { + error: '403 - Json Web Token Error', + message: 'You must provide a JWT token' + }); + }); + + it('should return unauthorized error for invalid token requests', async () => { + await request(`${TEST_URL}/api/locks`) + .get('/?token=invalid-token') + .expect(403, { + error: '403 - Json Web Token Error', + message: 'Invalid JWT token provided' + }); + }); +}); diff --git a/Control/test/api/lock/api-put-locks.test.js b/Control/test/api/lock/api-put-locks.test.js new file mode 100644 index 000000000..75928354b --- /dev/null +++ b/Control/test/api/lock/api-put-locks.test.js @@ -0,0 +1,167 @@ + +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. +*/ + +const request = require('supertest'); +const { ADMIN_TEST_TOKEN, TEST_URL, DET_MID_TEST_TOKEN, GUEST_TEST_TOKEN, GLOBAL_TEST_TOKEN } = require('../generateToken.js'); +const { DetectorLockAction } = require('../../../lib/common/lock/detectorLockAction.enum.js'); + +describe(`'API - PUT - /locks/:action/:detectorId' test suite`, () => { + before(async () => { + // release ALL locks via API to prepare test-setup for API PUT tests + await request(`${TEST_URL}/api/locks`) + .put(`/force/release/ALL?token=${ADMIN_TEST_TOKEN}`); + }); + + it('should successfully take lock as detector user for their detector', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.TAKE}/MID?token=${DET_MID_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'TAKEN', owner: { username: 'det-mid', fullName: 'Detector User', personid: 2 } }, + DCS: { name: 'DCS', state: 'FREE' }, + ODC: { name: 'ODC', state: 'FREE' } + }); + }); + + it('should return unauthorized error for attempt to take already owned lock', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.TAKE}/MID?token=${ADMIN_TEST_TOKEN}`) + .expect(403, { + message: 'Unauthorized TAKE action for lock of detector MID by user Admin User' + }); + }); + + it('should return unauthorized error for attempt to take lock as Guest User', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.TAKE}/DCS?token=${GUEST_TEST_TOKEN}`) + .expect(403, { + message: 'Not enough permissions for this operation' + }); + }); + + it('should successfully FORCE take lock as ADMIN user', async () => { + await request(`${TEST_URL}/api/locks/force`) + .put(`/${DetectorLockAction.TAKE}/MID?token=${ADMIN_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, + DCS: { name: 'DCS', state: 'FREE' }, + ODC: { name: 'ODC', state: 'FREE' } + }); + }); + + it('should successfully FORCE take lock as GLOBAL user', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/force/${DetectorLockAction.TAKE}/MID?token=${GLOBAL_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + DCS: { name: 'DCS', state: 'FREE' }, + ODC: { name: 'ODC', state: 'FREE' } + }); + }); + + it('should successfully take lock as ADMIN user', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.TAKE}/DCS?token=${ADMIN_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + DCS: { name: 'DCS', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, + ODC: { name: 'ODC', state: 'FREE' } + }); + }); + + it('should successfully take ALL available lock as Global user', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.TAKE}/ALL?token=${GLOBAL_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + DCS: { name: 'DCS', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, + ODC: { name: 'ODC', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + }); + }); + + it('should successfully FORCE take ALL available lock as Global user', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/force/${DetectorLockAction.TAKE}/ALL?token=${GLOBAL_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + DCS: { name: 'DCS', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + ODC: { name: 'ODC', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + }); + }); + + it('should successfully FORCE take ALL available lock as Admin user', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/force/${DetectorLockAction.TAKE}/ALL?token=${ADMIN_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, + DCS: { name: 'DCS', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, + ODC: { name: 'ODC', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, + }); + }); + + it('should return error for attempt to release a lock as a guest user', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.RELEASE}/MID?token=${GUEST_TEST_TOKEN}`) + .expect(403, { + message: 'Not enough permissions for this operation' + }); + }); + + it('should return error for attempt to release a lock not owned by user', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.RELEASE}/MID?token=${DET_MID_TEST_TOKEN}`) + .expect(403, { + message: 'Unauthorized RELEASE action for lock of detector MID by user Detector User' + }); + }); + + it('should successfully release a lock', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.RELEASE}/MID?token=${ADMIN_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'FREE' }, + DCS: { name: 'DCS', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, + ODC: { name: 'ODC', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, + }); + }); + + it('should successfully force release a lock from another user as Global', async () => { + await request(`${TEST_URL}/api/locks`) + .put(`/force/${DetectorLockAction.RELEASE}/DCS?token=${GLOBAL_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'FREE' }, + DCS: { name: 'DCS', state: 'FREE' }, + ODC: { name: 'ODC', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, + }); + }); + + it('should successfully force release ALL locks from all users', async () => { + // first we retake a lock to ensure we have a lock to release from different types of users + await request(`${TEST_URL}/api/locks`) + .put(`/${DetectorLockAction.TAKE}/DCS?token=${GLOBAL_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'FREE' }, + DCS: { name: 'DCS', state: 'TAKEN', owner: { username: 'global', fullName: 'Global User', personid: 1 } }, + ODC: { name: 'ODC', state: 'TAKEN', owner: { username: 'admin', fullName: 'Admin User', personid: 0 } }, + }); + + await request(`${TEST_URL}/api/locks`) + .put(`/force/${DetectorLockAction.RELEASE}/ALL?token=${GLOBAL_TEST_TOKEN}`) + .expect(200, { + MID: { name: 'MID', state: 'FREE' }, + DCS: { name: 'DCS', state: 'FREE' }, + ODC: { name: 'ODC', state: 'FREE' }, + }); + }); +}); diff --git a/Control/test/mocha-index.js b/Control/test/mocha-index.js index c50463318..35d1b4167 100644 --- a/Control/test/mocha-index.js +++ b/Control/test/mocha-index.js @@ -170,6 +170,9 @@ describe('Control', function() { require('./public/page-hardware-mocha'); require('./public/page-lock-mocha'); + require('./api/lock/api-get-locks.test') + require('./api/lock/api-put-locks.test') + beforeEach(() => this.ok = true); afterEach(() => { diff --git a/Control/test/test-config.js b/Control/test/test-config.js index 88cb10f29..527bbeee3 100644 --- a/Control/test/test-config.js +++ b/Control/test/test-config.js @@ -21,6 +21,11 @@ module.exports = { // cert: './cert/cert.pem', tls: false, }, + jwt: { + secret: 'test-secret', + issuer: 'test-gui', + expiration: '1d', + }, grpc: { hostname: 'localhost', port: 9090, From e0298ce79c3ec31d481d294687344207558c58d5 Mon Sep 17 00:00:00 2001 From: George Raduta Date: Fri, 15 Nov 2024 13:26:52 +0100 Subject: [PATCH 3/3] Fix GH warnings --- Control/test/mocha-index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Control/test/mocha-index.js b/Control/test/mocha-index.js index 35d1b4167..239827c4f 100644 --- a/Control/test/mocha-index.js +++ b/Control/test/mocha-index.js @@ -170,8 +170,8 @@ describe('Control', function() { require('./public/page-hardware-mocha'); require('./public/page-lock-mocha'); - require('./api/lock/api-get-locks.test') - require('./api/lock/api-put-locks.test') + require('./api/lock/api-get-locks.test'); + require('./api/lock/api-put-locks.test'); beforeEach(() => this.ok = true);