Skip to content

Commit 9114239

Browse files
authored
[O2B-1111] Implement data passes API (#1325)
* add migration * add references * add model associations * add jsonRequest method * add abstract synchronizer * cleanup * cleanup * cleanup * cleanup * cleanup * simplify * cleanup * cleanup * add monalisa service * docs annotation * refactor * change main method to return void instead of boolean * db action * handle field mappings * remove abstract class * single concrete class * add variables * use env vars * linter * refactor * docs refactor * typo * refactor * refactor * fixes * refactored * not then chain * refactor{ * types * rename * use seuqlize to fetch last runs * add type, use URL class * remove file read * docs * add synchronizer factory * add docs * cleanup * no await * refactor * typdef * refactor context * rename * docs * docs * rename * working * rename * rename * add test for getting data passes * add test for getting data passes * sync test * add test for data pass sync * amend data * add details fetching * add env * fetching data passes and details * rename * add tests * rename * reduce test data size * docs * refactor * typo * typo * docs * rename * docs * cleanup * remove dead code * add service * cleanup * add filtering by periods * add data passes seeders * rename * add data passes service tests * test * revoke unfound changes * add controllers * rename * refactor * refactor * refactor * no dependency * refactor * refactor * refactor: * reaname' * rename * cleanup * docs * reaname * refactor * add router * restore * amend test * expose api * add test * add tests * amend * docs * amend test * amend * rename
1 parent fa6ab63 commit 9114239

7 files changed

Lines changed: 368 additions & 1 deletion

File tree

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* @license
3+
* Copyright CERN and copyright holders of ALICE O2. This software is
4+
* distributed under the terms of the GNU General Public License v3 (GPL
5+
* Version 3), copied verbatim in the file "COPYING".
6+
*
7+
* See http://alice-o2.web.cern.ch/license for full licensing information.
8+
*
9+
* In applying this license CERN does not waive the privileges and immunities
10+
* granted to it by virtue of its status as an Intergovernmental Organization
11+
* or submit itself to any jurisdiction.
12+
*/
13+
14+
const Joi = require('joi');
15+
const { ApiConfig } = require('../../config/index.js');
16+
const { DtoFactory } = require('../../domain/dtos/DtoFactory');
17+
const { dataPassService } = require('../services/dataPasses/DataPassService.js');
18+
const { dtoValidator } = require('../utilities/dtoValidator.js');
19+
const { countedItemsToHttpView } = require('../utilities/countedItemsToHttpView.js');
20+
const { updateExpressResponseFromNativeError } = require('../express/updateExpressResponseFromNativeError');
21+
const PaginationDto = require('../../domain/dtos/PaginationDto.js');
22+
23+
// eslint-disable-next-line valid-jsdoc
24+
/**
25+
* List All DataPasss with statistics
26+
*/
27+
const listDataPassesHandler = async (req, res) => {
28+
const validatedDTO = await dtoValidator(
29+
DtoFactory.queryOnly({
30+
filter: {
31+
lhcPeriodIds: Joi.array().items(Joi.string()),
32+
ids: Joi.array().items(Joi.number()),
33+
names: Joi.array().items(Joi.string()),
34+
},
35+
page: PaginationDto,
36+
sort: DtoFactory.order(['id', 'name', 'reconstructedEventsCount', 'outputSize']),
37+
}),
38+
req,
39+
res,
40+
);
41+
if (validatedDTO) {
42+
try {
43+
const { filter, page: { limit = ApiConfig.pagination.limit, offset } = {}, sort = { name: 'DESC' } } = validatedDTO.query;
44+
const { count, rows: items } = await dataPassService.getAll({
45+
filter,
46+
limit,
47+
offset,
48+
sort,
49+
});
50+
res.json(countedItemsToHttpView({ count, items }, limit));
51+
} catch (error) {
52+
updateExpressResponseFromNativeError(res, error);
53+
}
54+
}
55+
};
56+
57+
exports.DataPassesController = {
58+
listDataPassesHandler,
59+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @license
3+
* Copyright CERN and copyright holders of ALICE O2. This software is
4+
* distributed under the terms of the GNU General Public License v3 (GPL
5+
* Version 3), copied verbatim in the file "COPYING".
6+
*
7+
* See http://alice-o2.web.cern.ch/license for full licensing information.
8+
*
9+
* In applying this license CERN does not waive the privileges and immunities
10+
* granted to it by virtue of its status as an Intergovernmental Organization
11+
* or submit itself to any jurisdiction.
12+
*/
13+
14+
const { DataPassesController } = require('../controllers/dataPasses.controller.js');
15+
16+
exports.dataPassesRouter = {
17+
path: '/dataPasses',
18+
args: { public: false },
19+
children: [
20+
{
21+
method: 'get',
22+
controller: DataPassesController.listDataPassesHandler,
23+
},
24+
],
25+
};

lib/server/routers/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const subsystemsRoute = require('./subsystems.router');
3131
const tagsRoute = require('./tags.router');
3232
const { lhcPeriodsRouter } = require('./lhcPeriodsStatistics.router.js');
3333
const { isInTestMode } = require('../../utilities/env-utils');
34+
const { dataPassesRouter } = require('./dataPasses.router');
3435

3536
const routes = [
3637
attachmentRoute,
@@ -51,6 +52,7 @@ const routes = [
5152
subsystemsRoute,
5253
tagsRoute,
5354
lhcPeriodsRouter,
55+
dataPassesRouter,
5456
];
5557

5658
/**
File renamed without changes.

test/api/dataPasses.test.js

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
/**
2+
* @license
3+
* Copyright CERN and copyright holders of ALICE O2. This software is
4+
* distributed under the terms of the GNU General Public License v3 (GPL
5+
* Version 3), copied verbatim in the file "COPYING".
6+
*
7+
* See http://alice-o2.web.cern.ch/license for full licensing information.
8+
*
9+
* In applying this license CERN does not waive the privileges and immunities
10+
* granted to it by virtue of its status as an Intergovernmental Organization
11+
* or submit itself to any jurisdiction.
12+
*/
13+
14+
const { expect } = require('chai');
15+
const request = require('supertest');
16+
const { server } = require('../../lib/application');
17+
const { resetDatabaseContent } = require('../utilities/resetDatabaseContent.js');
18+
19+
const LHC22b_apass1 = {
20+
id: 1,
21+
name: 'LHC22b_apass1',
22+
description: 'Some random desc',
23+
reconstructedEventsCount: 50948694,
24+
outputSize: 56875682112600,
25+
lastRunNumber: 108,
26+
};
27+
28+
const LHC22b_apass2 = {
29+
id: 2,
30+
name: 'LHC22b_apass2',
31+
description: 'Some random desc',
32+
reconstructedEventsCount: 50848604,
33+
outputSize: 55765671112610,
34+
lastRunNumber: 55,
35+
};
36+
37+
const LHC22a_apass1 = {
38+
id: 3,
39+
name: 'LHC22a_apass1',
40+
description: 'Some random desc for apass 1',
41+
reconstructedEventsCount: 50848111,
42+
outputSize: 55761110122610,
43+
lastRunNumber: 105,
44+
};
45+
46+
module.exports = () => {
47+
before(resetDatabaseContent);
48+
49+
describe('GET /api/dataPasses', () => {
50+
it('should successfuly fetch all data', (done) => {
51+
request(server)
52+
.get('/api/dataPasses')
53+
.expect(200)
54+
.end((err, res) => {
55+
if (err) {
56+
done(err);
57+
return;
58+
}
59+
60+
const { data, meta } = res.body;
61+
expect(meta).to.be.eql({ page: { totalCount: 3, pageCount: 1 } });
62+
expect(data).to.be.an('array');
63+
expect(data).to.be.lengthOf(3);
64+
65+
done();
66+
});
67+
});
68+
it('should successfuly filter on ids', (done) => {
69+
request(server)
70+
.get('/api/dataPasses?filter[ids][]=1')
71+
.expect(200)
72+
.end((err, res) => {
73+
if (err) {
74+
done(err);
75+
return;
76+
}
77+
78+
const { data, meta } = res.body;
79+
expect(meta).to.be.eql({ page: { totalCount: 1, pageCount: 1 } });
80+
expect(data).to.be.an('array');
81+
expect(data).to.be.lengthOf(1);
82+
expect(data[0]).to.be.eql(LHC22b_apass1);
83+
84+
done();
85+
});
86+
});
87+
it('should successfuly filter on names', (done) => {
88+
request(server)
89+
.get('/api/dataPasses?filter[names][]=LHC22b_apass2')
90+
.expect(200)
91+
.end((err, res) => {
92+
if (err) {
93+
done(err);
94+
return;
95+
}
96+
97+
const { data } = res.body;
98+
expect(data).to.be.an('array');
99+
expect(data).to.be.lengthOf(1);
100+
expect(data[0]).to.be.eql(LHC22b_apass2);
101+
102+
done();
103+
});
104+
});
105+
it('should retrive no records when filtering on ids', (done) => {
106+
request(server)
107+
.get('/api/dataPasses?filter[ids][]=9999')
108+
.expect(200)
109+
.end((err, res) => {
110+
if (err) {
111+
done(err);
112+
return;
113+
}
114+
115+
const { data } = res.body;
116+
expect(data).to.be.an('array');
117+
expect(data).to.be.lengthOf(0);
118+
119+
done();
120+
});
121+
});
122+
it('should retrive no records when filtering on names', (done) => {
123+
request(server)
124+
.get('/api/dataPasses?filter[names][]=LHC22b_aasdfpass2asdf')
125+
.expect(200)
126+
.end((err, res) => {
127+
if (err) {
128+
done(err);
129+
return;
130+
}
131+
132+
const { data } = res.body;
133+
expect(data).to.be.an('array');
134+
expect(data).to.be.lengthOf(0);
135+
done();
136+
});
137+
});
138+
it('should succefully filter on ids given as array', (done) => {
139+
request(server)
140+
.get('/api/dataPasses?filter[ids][]=1&filter[ids][]=2')
141+
.expect(200)
142+
.end((err, res) => {
143+
if (err) {
144+
done(err);
145+
return;
146+
}
147+
148+
const { data } = res.body;
149+
expect(data).to.be.an('array');
150+
expect(data).to.be.lengthOf(2);
151+
done();
152+
});
153+
});
154+
it('should succefully filter on lhcPeriodIds', (done) => {
155+
request(server)
156+
.get('/api/dataPasses?filter[lhcPeriodIds][]=2')
157+
.expect(200)
158+
.end((err, res) => {
159+
if (err) {
160+
done(err);
161+
return;
162+
}
163+
164+
const { data: dataPasses } = res.body;
165+
expect(dataPasses).to.be.an('array');
166+
expect(dataPasses).to.be.lengthOf(2);
167+
expect(dataPasses).to.have.deep.members([LHC22b_apass2, LHC22b_apass1]);
168+
done();
169+
});
170+
});
171+
it('should successfuly sort on id and name', (done) => {
172+
request(server)
173+
.get('/api/dataPasses?sort[id]=DESC&sort[name]=ASC')
174+
.expect(200)
175+
.end((err, res) => {
176+
if (err) {
177+
done(err);
178+
return;
179+
}
180+
181+
const { data: dataPasses } = res.body;
182+
expect(dataPasses).to.be.an('array');
183+
expect(dataPasses).to.be.lengthOf(3);
184+
expect(dataPasses).to.have.ordered.deep.members([
185+
LHC22a_apass1,
186+
LHC22b_apass2,
187+
LHC22b_apass1,
188+
]);
189+
190+
done();
191+
});
192+
});
193+
it('should successfuly sort on outputSize', (done) => {
194+
request(server)
195+
.get('/api/dataPasses?sort[outputSize]=DESC')
196+
.expect(200)
197+
.end((err, res) => {
198+
if (err) {
199+
done(err);
200+
return;
201+
}
202+
203+
const { data: dataPasses } = res.body;
204+
expect(dataPasses).to.be.an('array');
205+
expect(dataPasses).to.be.lengthOf(3);
206+
expect(dataPasses).to.have.deep.ordered.members([LHC22b_apass1, LHC22b_apass2, LHC22a_apass1]);
207+
done();
208+
});
209+
});
210+
it('should support pagination', (done) => {
211+
request(server)
212+
.get('/api/dataPasses?page[offset]=1&sort[id]=desc')
213+
.expect(200)
214+
.end((err, res) => {
215+
if (err) {
216+
done(err);
217+
return;
218+
}
219+
220+
const { data: dataPasses } = res.body;
221+
expect(dataPasses).to.be.an('array');
222+
expect(dataPasses).to.have.ordered.deep.members([
223+
LHC22b_apass2,
224+
LHC22b_apass1,
225+
]);
226+
227+
done();
228+
});
229+
});
230+
it('should return 400 when bad query paramter provided', (done) => {
231+
request(server)
232+
.get('/api/dataPasses?a=1')
233+
.expect(400)
234+
.end((err, res) => {
235+
if (err) {
236+
done(err);
237+
return;
238+
}
239+
240+
const { errors } = res.body;
241+
const titleError = errors.find((err) => err.source.pointer === '/data/attributes/query/a');
242+
expect(titleError.detail).to.equal('"query.a" is not allowed');
243+
done();
244+
});
245+
});
246+
it('should return 400 if the limit is below 1', (done) => {
247+
request(server)
248+
.get('/api/dataPasses?page[limit]=0')
249+
.expect(400)
250+
.end((err, res) => {
251+
if (err) {
252+
done(err);
253+
return;
254+
}
255+
256+
const { errors } = res.body;
257+
const titleError = errors.find((err) => err.source.pointer === '/data/attributes/query/page/limit');
258+
expect(titleError.detail).to.equal('"query.page.limit" must be greater than or equal to 1');
259+
done();
260+
});
261+
});
262+
it('should return 400 if the limit is below 1', (done) => {
263+
request(server)
264+
.get('/api/dataPasses?page[limit]=0')
265+
.expect(400)
266+
.end((err, res) => {
267+
if (err) {
268+
done(err);
269+
return;
270+
}
271+
272+
const { errors } = res.body;
273+
const titleError = errors.find((err) => err.source.pointer === '/data/attributes/query/page/limit');
274+
expect(titleError.detail).to.equal('"query.page.limit" must be greater than or equal to 1');
275+
done();
276+
});
277+
});
278+
});
279+
};

test/api/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const SubsystemsSuite = require('./subsystems.test.js');
2929
const TagsSuite = require('./tags.test.js');
3030
const LhcPeriodsStatisticsSuite = require('./lhcPeriodsStatistics.test.js');
3131
const RunsWithRunId = require('./runs-with-runId.test.js');
32+
const DataPassesSuite = require('./dataPasses.test.js');
3233

3334
module.exports = () => {
3435
describe('Attachments API', AttachmentsSuite);
@@ -50,4 +51,5 @@ module.exports = () => {
5051
describe('Subsystems API', SubsystemsSuite);
5152
describe('Tags API', TagsSuite);
5253
describe('LhcPeriodsStatistics API', LhcPeriodsStatisticsSuite);
54+
describe('DataPassesSuite API', DataPassesSuite);
5355
};

0 commit comments

Comments
 (0)