Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/domain/dtos/filters/RunFilterDto.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ exports.RunFilterDto = Joi.object({
'Beam modes "{{#value}}" must contain only uppercase letters and single spaces between words.',
})),
beamTypes: BeamTypesDto,
pdpBeamTypes: CustomJoi.stringArray().items(Joi.string().trim().min(2).max(20)),
runNumbers: Joi.string().trim().custom(validateRange).messages({
[RANGE_INVALID]: '{{#message}}',
'string.base': 'Run numbers must be comma-separated numbers or ranges (e.g. 12,15-18)',
Expand Down
26 changes: 26 additions & 0 deletions lib/server/controllers/runs.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const { ApiConfig } = require('../../config/index.js');
const { DtoFactory } = require('../../domain/dtos/DtoFactory.js');
const { runService } = require('../services/run/RunService.js');
const { getAllBeamModes } = require('../services/beam/getAllBeamModes.js');
const { getAllPdpBeamTypes } = require('../services/beam/getAllPdpBeamTypes.js');
const { updateExpressResponseFromNativeError } = require('../express/updateExpressResponseFromNativeError.js');
const { runToHttpView } = require('./runsToHttpView.js');

Expand Down Expand Up @@ -321,6 +322,30 @@ const listBeamModes = async (_request, response, _next) => {
}
};

/**
* Retrieve a list of unique PDP beam types
*
* @param {Object} _request The *request* object represents the HTTP request and has properties for the request query
* string, parameters, body, HTTP headers, and so on.
* @param {Object} response The *response* object represents the HTTP response that an Express app sends when it gets
* an HTTP request.
* @param {NextFunction} _next The *next* object represents the next middleware function which is used to pass control to
* the next middleware function.
* @returns {undefined}
*/
const listPdpBeamTypes = async (_request, response, _next) => {
try {
const pdpBeamTypes = await getAllPdpBeamTypes();
if (pdpBeamTypes?.length > 0) {
response.status(200).json({ data: pdpBeamTypes });
} else {
response.status(204).json({ data: [] });
}
} catch {
response.status(502).json({ errors: ['Unable to retrieve list of PDP beam types'] });
}
};

// eslint-disable-next-line jsdoc/require-param
/**
* Retrieve distinct combination of levels of alice L3 and dipole current rounded to kilo amperes
Expand Down Expand Up @@ -348,6 +373,7 @@ module.exports = {
getFlpsByRunNumberHandler,
listReasonTypes,
listBeamModes,
listPdpBeamTypes,
listRuns,
startRun,
updateRunByRunNumber,
Expand Down
5 changes: 5 additions & 0 deletions lib/server/routers/runs.router.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ module.exports = {
path: 'beamModes',
controller: RunsController.listBeamModes,
},
{
method: 'get',
path: 'pdpBeamTypes',
controller: RunsController.listPdpBeamTypes,
},
{
method: 'get',
controller: [infoLoggerListenerMiddleware(FilterLogger), RunsController.listRuns],
Expand Down
32 changes: 32 additions & 0 deletions lib/server/services/beam/getAllPdpBeamTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* 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 { repositories: { RunRepository }, sequelize } = require('../../../database');
const { Op } = require('sequelize');

/**
* Return the a list of unique PDP beam types which is built from the runs data
*
* @returns {Promise<SequelizePdpBeamType[]>} Promise resolving with the list of unique PDP beam types
*/
exports.getAllPdpBeamTypes = async () => {
const pdpBeamTypes = await RunRepository.findAll({
where: {
pdp_beam_type: {
[Op.ne]: null,
},
},
attributes: [[sequelize.fn('DISTINCT', sequelize.col('pdp_beam_type')), 'name']],
});
return pdpBeamTypes;
};
5 changes: 5 additions & 0 deletions lib/usecases/run/GetAllRunsUseCase.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class GetAllRunsUseCase {
detectorsQcNotBadFraction,
beamModes,
beamTypes,
pdpBeamTypes,
} = filter;

if (runNumbers) {
Expand Down Expand Up @@ -120,6 +121,10 @@ class GetAllRunsUseCase {
filteringQueryBuilder.where('lhcBeamMode').oneOf(...beamModes);
}

if (pdpBeamTypes) {
filteringQueryBuilder.where('pdpBeamType').oneOf(...pdpBeamTypes);
}

if (beamTypes) {
filteringQueryBuilder.include({
association: 'lhcFill',
Expand Down
66 changes: 65 additions & 1 deletion test/api/runs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,52 @@ module.exports = () => {
expect(error.detail).to.equal(`"query.filter.beamTypes[0]" with value "${beamTypes}" fails to match the required pattern: /^[A-Za-z0-9]+ ?- ?[A-Za-z0-9]+$/`);
});

it('should successfully filter runs with pdpBeamType', async () => {
const pdpBeamType = 'pp';
const response = await request(server).get(`/api/runs?filter[pdpBeamTypes]=${pdpBeamType}`);

expect(response.status).to.equal(200);
const { data: runs } = response.body;

expect(runs).to.be.an('array');
expect(runs).to.have.lengthOf(6);
expect(runs.every(({ pdpBeamType: type }) => type === pdpBeamType)).to.be.true;
});

it('should successfully filter runs with multiple pdpBeamTypes', async () => {
const pdpBeamTypes = 'pp,PbPb';
const response = await request(server).get(`/api/runs?filter[pdpBeamTypes]=${pdpBeamTypes}`);

expect(response.status).to.equal(200);
const { data: runs } = response.body;

expect(runs).to.be.an('array');
expect(runs).to.have.lengthOf(10);
expect(runs.every(({ pdpBeamType: type }) => pdpBeamTypes.includes(type))).to.be.true;
});

it('should return 400 if pdpBeamTypes filter has the incorrect format', async () => {
const pdpBeamTypes = 'S'; // Too short
const response = await request(server).get(`/api/runs?filter[pdpBeamTypes]=${pdpBeamTypes}`);

expect(response.status).to.equal(400);

let { errors: [error] } = response.body;

expect(error.title).to.equal('Invalid Attribute');
expect(error.detail).to.equal(`"query.filter.pdpBeamTypes[0]" length must be at least 2 characters long`);

const pdpBeamTypesLong = 'This is definitely not a pdp beam type'; // Too short
const responseLong = await request(server).get(`/api/runs?filter[pdpBeamTypes]=${pdpBeamTypesLong}`);

expect(responseLong.status).to.equal(400);

({ errors: [error] } = responseLong.body);

expect(error.title).to.equal('Invalid Attribute');
expect(error.detail).to.equal(`"query.filter.pdpBeamTypes[0]" length must be less than or equal to 20 characters long`);
});

it('should return 400 if beamModes filter has the incorrect format', async () => {
const beamModeString = '*THERE\'S NON LETTERS IN HERE';
const response = await request(server).get(`/api/runs?filter[beamModes]=${beamModeString}`);
Expand Down Expand Up @@ -727,7 +773,6 @@ module.exports = () => {
});
});


describe('GET /api/runs/beamModes', () => {
it('should successfully return status 200 and list of beam modes', async () => {
const { body } = await request(server)
Expand All @@ -740,6 +785,25 @@ module.exports = () => {
expect(body.data[0].name).to.equal('STABLE BEAMS');
});
});

describe('GET /api/runs/pdpBeamTypes', () => {
it('should successfully return status 200 and list of pdp beam types', async () => {
const { body } = await request(server)
.get('/api/runs/pdpBeamTypes')
.expect(200);

expect(body.data).to.be.an('array');
expect(body.data).to.have.lengthOf(5);
expect(body.data).to.deep.equal([
{ name: 'pp' },
{ name: 'PbPb' },
{ name: 'technical' },
{ name: 'cosmic' },
{ name: 'OO' },
]);
});
});

describe('GET /api/runs/reasonTypes', () => {
it('should successfully return status 200 and list of reason types', async () => {
const { body } = await request(server)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* 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 { expect } = require('chai');
const { getAllPdpBeamTypes } = require('../../../../../lib/server/services/beam/getAllPdpBeamTypes.js');

module.exports = () => {
it('should successfully return the full list of not null PDP beam types from runs table', async () => {
const pdpBeamTypes = await getAllPdpBeamTypes();
expect(pdpBeamTypes.map(({ dataValues: { name } }) => ({ name }))).to.deep.eq([
{ name: 'cosmic' },
{ name: 'technical' },
{ name: 'pp' },
{ name: 'PbPb' },
{ name: 'pO' },
{ name: 'OO' },
{ name: 'NeNe' },
]);
});
};
18 changes: 18 additions & 0 deletions test/lib/server/services/pdpBeamTypes/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* 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 getAllPdpBeamTypes = require('./getAllPdpBeamTypes.test.js');

module.exports = () => {
describe('getAllPdpBeamTypes', getAllPdpBeamTypes);
};