@centreon/js-config 24.4.1-MON-move-code-coverage-archive.3 → 24.4.1-MON-23368-containers.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cypress/e2e/commands.ts
CHANGED
|
@@ -100,6 +100,24 @@ Cypress.Commands.add(
|
|
|
100
100
|
}
|
|
101
101
|
);
|
|
102
102
|
|
|
103
|
+
Cypress.Commands.add('getContainerId', (containerName: string) => {
|
|
104
|
+
cy.log(`Getting container id of ${containerName}`);
|
|
105
|
+
|
|
106
|
+
return cy.task('getContainerId', containerName);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
Cypress.Commands.add('getContainerIpAddress', (containerName: string) => {
|
|
110
|
+
cy.log(`Getting container ip address of ${containerName}`);
|
|
111
|
+
|
|
112
|
+
return cy.task('getContainerIpAddress', containerName);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
Cypress.Commands.add('getContainersLogs', () => {
|
|
116
|
+
cy.log('Getting containers logs');
|
|
117
|
+
|
|
118
|
+
return cy.task('getContainersLogs');
|
|
119
|
+
});
|
|
120
|
+
|
|
103
121
|
interface CopyFromContainerProps {
|
|
104
122
|
destination: string;
|
|
105
123
|
name?: string;
|
|
@@ -108,15 +126,14 @@ interface CopyFromContainerProps {
|
|
|
108
126
|
|
|
109
127
|
Cypress.Commands.add(
|
|
110
128
|
'copyFromContainer',
|
|
111
|
-
(
|
|
112
|
-
{
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
destination
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return cy.exec(`docker cp ${name}:${source} "${destination}"`, options);
|
|
129
|
+
({ name = 'web', source, destination }: CopyFromContainerProps) => {
|
|
130
|
+
cy.log(`Copy content from ${name}:${source} to ${destination}`);
|
|
131
|
+
|
|
132
|
+
return cy.task('copyFromContainer', {
|
|
133
|
+
destination,
|
|
134
|
+
serviceName: name,
|
|
135
|
+
source
|
|
136
|
+
});
|
|
120
137
|
}
|
|
121
138
|
);
|
|
122
139
|
|
|
@@ -129,13 +146,11 @@ interface CopyToContainerProps {
|
|
|
129
146
|
Cypress.Commands.add(
|
|
130
147
|
'copyToContainer',
|
|
131
148
|
(
|
|
132
|
-
{
|
|
133
|
-
name = Cypress.env('dockerName'),
|
|
134
|
-
source,
|
|
135
|
-
destination
|
|
136
|
-
}: CopyToContainerProps,
|
|
149
|
+
{ name = 'web', source, destination }: CopyToContainerProps,
|
|
137
150
|
options?: Partial<Cypress.ExecOptions>
|
|
138
151
|
) => {
|
|
152
|
+
cy.log(`Copy content from ${source} to ${name}:${destination}`);
|
|
153
|
+
|
|
139
154
|
return cy.exec(`docker cp ${source} ${name}:${destination}`, options);
|
|
140
155
|
}
|
|
141
156
|
);
|
|
@@ -202,27 +217,59 @@ Cypress.Commands.add('waitForContainerAndSetToken', (): Cypress.Chainable => {
|
|
|
202
217
|
});
|
|
203
218
|
|
|
204
219
|
interface ExecInContainerProps {
|
|
205
|
-
command: string
|
|
220
|
+
command: string | Array<string>;
|
|
206
221
|
name: string;
|
|
207
222
|
}
|
|
208
223
|
|
|
224
|
+
interface ExecInContainerResult {
|
|
225
|
+
exitCode: number;
|
|
226
|
+
output: string;
|
|
227
|
+
}
|
|
228
|
+
|
|
209
229
|
Cypress.Commands.add(
|
|
210
230
|
'execInContainer',
|
|
211
231
|
({ command, name }: ExecInContainerProps): Cypress.Chainable => {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
232
|
+
const commands =
|
|
233
|
+
typeof command === 'string' || command instanceof String
|
|
234
|
+
? [command]
|
|
235
|
+
: command;
|
|
236
|
+
|
|
237
|
+
const results = commands.reduce(
|
|
238
|
+
(acc, runCommand) => {
|
|
239
|
+
cy.task<ExecInContainerResult>(
|
|
240
|
+
'execInContainer',
|
|
241
|
+
{ command: runCommand, name },
|
|
242
|
+
{ timeout: 600000 }
|
|
243
|
+
).then((result) => {
|
|
244
|
+
if (result.exitCode) {
|
|
245
|
+
// output will not be truncated
|
|
246
|
+
throw new Error(`
|
|
247
|
+
Execution of "${runCommand}" failed
|
|
248
|
+
Exit code: ${result.exitCode}
|
|
249
|
+
Output:\n${result.output}`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
acc.output = `${acc.output}${result.output}`;
|
|
253
|
+
});
|
|
223
254
|
|
|
224
|
-
return
|
|
225
|
-
}
|
|
255
|
+
return acc;
|
|
256
|
+
},
|
|
257
|
+
{ exitCode: 0, output: '' }
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
return cy.wrap(results);
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
interface RequestOnDatabaseProps {
|
|
265
|
+
database: string;
|
|
266
|
+
query: string;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
Cypress.Commands.add(
|
|
270
|
+
'requestOnDatabase',
|
|
271
|
+
({ database, query }: RequestOnDatabaseProps): Cypress.Chainable => {
|
|
272
|
+
return cy.task('requestOnDatabase', { database, query });
|
|
226
273
|
}
|
|
227
274
|
);
|
|
228
275
|
|
|
@@ -232,6 +279,7 @@ interface PortBinding {
|
|
|
232
279
|
}
|
|
233
280
|
|
|
234
281
|
interface StartContainerProps {
|
|
282
|
+
command?: string;
|
|
235
283
|
image: string;
|
|
236
284
|
name: string;
|
|
237
285
|
portBindings: Array<PortBinding>;
|
|
@@ -239,145 +287,71 @@ interface StartContainerProps {
|
|
|
239
287
|
|
|
240
288
|
Cypress.Commands.add(
|
|
241
289
|
'startContainer',
|
|
242
|
-
({
|
|
290
|
+
({
|
|
291
|
+
command,
|
|
292
|
+
name,
|
|
293
|
+
image,
|
|
294
|
+
portBindings
|
|
295
|
+
}: StartContainerProps): Cypress.Chainable => {
|
|
243
296
|
cy.log(`Starting container ${name} from image ${image}`);
|
|
244
297
|
|
|
245
298
|
return cy.task(
|
|
246
299
|
'startContainer',
|
|
247
|
-
{ image, name, portBindings },
|
|
300
|
+
{ command, image, name, portBindings },
|
|
248
301
|
{ timeout: 600000 } // 10 minutes because docker pull can be very slow
|
|
249
302
|
);
|
|
250
303
|
}
|
|
251
304
|
);
|
|
252
305
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
interface StartWebContainerProps {
|
|
261
|
-
name?: string;
|
|
262
|
-
os?: string;
|
|
306
|
+
interface StartContainersProps {
|
|
307
|
+
databaseImage?: string;
|
|
308
|
+
openidImage?: string;
|
|
309
|
+
profiles?: Array<string>;
|
|
310
|
+
samlImage?: string;
|
|
263
311
|
useSlim?: boolean;
|
|
264
|
-
|
|
312
|
+
webOs?: string;
|
|
313
|
+
webVersion?: string;
|
|
265
314
|
}
|
|
266
315
|
|
|
267
316
|
Cypress.Commands.add(
|
|
268
|
-
'
|
|
317
|
+
'startContainers',
|
|
269
318
|
({
|
|
270
|
-
|
|
271
|
-
|
|
319
|
+
databaseImage = Cypress.env('DATABASE_IMAGE'),
|
|
320
|
+
openidImage = `docker.centreon.com/centreon/keycloak:${Cypress.env(
|
|
321
|
+
'OPENID_IMAGE_VERSION'
|
|
322
|
+
)}`,
|
|
323
|
+
profiles = [],
|
|
324
|
+
samlImage = `docker.centreon.com/centreon/keycloak:${Cypress.env(
|
|
325
|
+
'SAML_IMAGE_VERSION'
|
|
326
|
+
)}`,
|
|
272
327
|
useSlim = true,
|
|
273
|
-
|
|
274
|
-
|
|
328
|
+
webOs = Cypress.env('WEB_IMAGE_OS'),
|
|
329
|
+
webVersion = Cypress.env('WEB_IMAGE_VERSION')
|
|
330
|
+
}: StartContainersProps = {}): Cypress.Chainable => {
|
|
331
|
+
cy.log('Starting containers ...');
|
|
332
|
+
|
|
275
333
|
const slimSuffix = useSlim ? '-slim' : '';
|
|
276
334
|
|
|
277
|
-
const
|
|
335
|
+
const webImage = `docker.centreon.com/centreon/centreon-web${slimSuffix}-${webOs}:${webVersion}`;
|
|
278
336
|
|
|
279
337
|
return cy
|
|
280
|
-
.
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
338
|
+
.task(
|
|
339
|
+
'startContainers',
|
|
340
|
+
{ databaseImage, openidImage, profiles, samlImage, webImage },
|
|
341
|
+
{ timeout: 600000 } // 10 minutes because docker pull can be very slow
|
|
342
|
+
)
|
|
285
343
|
.then(() => {
|
|
286
344
|
const baseUrl = 'http://127.0.0.1:4000';
|
|
287
345
|
|
|
288
346
|
Cypress.config('baseUrl', baseUrl);
|
|
289
347
|
|
|
290
|
-
return cy.
|
|
291
|
-
'waitOn',
|
|
292
|
-
`${baseUrl}/centreon/api/latest/platform/installation/status`
|
|
293
|
-
);
|
|
348
|
+
return cy.wrap(null);
|
|
294
349
|
})
|
|
295
350
|
.visit('/') // this is necessary to refresh browser cause baseUrl has changed (flash appears in video)
|
|
296
351
|
.setUserTokenApiV1();
|
|
297
352
|
}
|
|
298
353
|
);
|
|
299
354
|
|
|
300
|
-
interface StopWebContainerProps {
|
|
301
|
-
name?: string;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
Cypress.Commands.add(
|
|
305
|
-
'stopWebContainer',
|
|
306
|
-
({
|
|
307
|
-
name = Cypress.env('dockerName')
|
|
308
|
-
}: StopWebContainerProps = {}): Cypress.Chainable => {
|
|
309
|
-
const logDirectory = `results/logs/${Cypress.spec.name.replace(
|
|
310
|
-
artifactIllegalCharactersMatcher,
|
|
311
|
-
'_'
|
|
312
|
-
)}/${Cypress.currentTest.title.replace(
|
|
313
|
-
artifactIllegalCharactersMatcher,
|
|
314
|
-
'_'
|
|
315
|
-
)}`;
|
|
316
|
-
|
|
317
|
-
return cy
|
|
318
|
-
.visitEmptyPage()
|
|
319
|
-
.createDirectory(logDirectory)
|
|
320
|
-
.copyFromContainer({
|
|
321
|
-
destination: `${logDirectory}/broker`,
|
|
322
|
-
name,
|
|
323
|
-
source: '/var/log/centreon-broker'
|
|
324
|
-
})
|
|
325
|
-
.copyFromContainer({
|
|
326
|
-
destination: `${logDirectory}/engine`,
|
|
327
|
-
name,
|
|
328
|
-
source: '/var/log/centreon-engine'
|
|
329
|
-
})
|
|
330
|
-
.copyFromContainer({
|
|
331
|
-
destination: `${logDirectory}/centreon`,
|
|
332
|
-
name,
|
|
333
|
-
source: '/var/log/centreon'
|
|
334
|
-
})
|
|
335
|
-
.copyFromContainer({
|
|
336
|
-
destination: `${logDirectory}/centreon-gorgone`,
|
|
337
|
-
name,
|
|
338
|
-
source: '/var/log/centreon-gorgone'
|
|
339
|
-
})
|
|
340
|
-
.then(() => {
|
|
341
|
-
if (Cypress.env('WEB_IMAGE_OS').includes('alma')) {
|
|
342
|
-
return cy.copyFromContainer({
|
|
343
|
-
destination: `${logDirectory}/php`,
|
|
344
|
-
name,
|
|
345
|
-
source: '/var/log/php-fpm'
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return cy.copyFromContainer(
|
|
350
|
-
{
|
|
351
|
-
destination: `${logDirectory}/php8.1-fpm-centreon-error.log`,
|
|
352
|
-
name,
|
|
353
|
-
source: '/var/log/php8.1-fpm-centreon-error.log'
|
|
354
|
-
},
|
|
355
|
-
{ failOnNonZeroExit: false }
|
|
356
|
-
);
|
|
357
|
-
})
|
|
358
|
-
.then(() => {
|
|
359
|
-
if (Cypress.env('WEB_IMAGE_OS').includes('alma')) {
|
|
360
|
-
return cy.copyFromContainer({
|
|
361
|
-
destination: `${logDirectory}/httpd`,
|
|
362
|
-
name,
|
|
363
|
-
source: '/var/log/httpd'
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return cy.copyFromContainer(
|
|
368
|
-
{
|
|
369
|
-
destination: `${logDirectory}/apache2`,
|
|
370
|
-
name,
|
|
371
|
-
source: '/var/log/apache2'
|
|
372
|
-
},
|
|
373
|
-
{ failOnNonZeroExit: false }
|
|
374
|
-
);
|
|
375
|
-
})
|
|
376
|
-
.exec(`chmod -R 755 "${logDirectory}"`)
|
|
377
|
-
.stopContainer({ name });
|
|
378
|
-
}
|
|
379
|
-
);
|
|
380
|
-
|
|
381
355
|
interface StopContainerProps {
|
|
382
356
|
name: string;
|
|
383
357
|
}
|
|
@@ -387,20 +361,109 @@ Cypress.Commands.add(
|
|
|
387
361
|
({ name }: StopContainerProps): Cypress.Chainable => {
|
|
388
362
|
cy.log(`Stopping container ${name}`);
|
|
389
363
|
|
|
390
|
-
cy.
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
364
|
+
return cy.task('stopContainer', { name });
|
|
365
|
+
}
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
Cypress.Commands.add('stopContainers', (): Cypress.Chainable => {
|
|
369
|
+
cy.log('Stopping containers ...');
|
|
370
|
+
|
|
371
|
+
const logDirectory = `results/logs/${Cypress.spec.name.replace(
|
|
372
|
+
artifactIllegalCharactersMatcher,
|
|
373
|
+
'_'
|
|
374
|
+
)}/${Cypress.currentTest.title.replace(
|
|
375
|
+
artifactIllegalCharactersMatcher,
|
|
376
|
+
'_'
|
|
377
|
+
)}`;
|
|
378
|
+
|
|
379
|
+
const name = 'web';
|
|
380
|
+
|
|
381
|
+
return cy
|
|
382
|
+
.visitEmptyPage()
|
|
383
|
+
.createDirectory(logDirectory)
|
|
384
|
+
.getContainersLogs()
|
|
385
|
+
.then((containersLogs: Array<Array<string>>) => {
|
|
386
|
+
Object.entries(containersLogs).forEach(([containerName, logs]) => {
|
|
387
|
+
cy.writeFile(
|
|
388
|
+
`results/logs/${Cypress.spec.name.replace(
|
|
389
|
+
artifactIllegalCharactersMatcher,
|
|
390
|
+
'_'
|
|
391
|
+
)}/${Cypress.currentTest.title.replace(
|
|
392
|
+
artifactIllegalCharactersMatcher,
|
|
393
|
+
'_'
|
|
394
|
+
)}/container-${containerName}.log`,
|
|
395
|
+
logs
|
|
396
|
+
);
|
|
397
|
+
});
|
|
398
|
+
})
|
|
399
|
+
.copyFromContainer({
|
|
400
|
+
destination: `${logDirectory}/broker`,
|
|
401
|
+
name,
|
|
402
|
+
source: '/var/log/centreon-broker'
|
|
403
|
+
})
|
|
404
|
+
.copyFromContainer({
|
|
405
|
+
destination: `${logDirectory}/engine`,
|
|
406
|
+
name,
|
|
407
|
+
source: '/var/log/centreon-engine'
|
|
408
|
+
})
|
|
409
|
+
.copyFromContainer({
|
|
410
|
+
destination: `${logDirectory}/centreon`,
|
|
411
|
+
name,
|
|
412
|
+
source: '/var/log/centreon'
|
|
413
|
+
})
|
|
414
|
+
.copyFromContainer({
|
|
415
|
+
destination: `${logDirectory}/centreon-gorgone`,
|
|
416
|
+
name,
|
|
417
|
+
source: '/var/log/centreon-gorgone'
|
|
418
|
+
})
|
|
419
|
+
.then(() => {
|
|
420
|
+
if (Cypress.env('WEB_IMAGE_OS').includes('alma')) {
|
|
421
|
+
return cy.copyFromContainer({
|
|
422
|
+
destination: `${logDirectory}/php`,
|
|
423
|
+
name,
|
|
424
|
+
source: '/var/log/php-fpm'
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return cy.copyFromContainer(
|
|
429
|
+
{
|
|
430
|
+
destination: `${logDirectory}/php8.1-fpm-centreon-error.log`,
|
|
431
|
+
name,
|
|
432
|
+
source: '/var/log/php8.1-fpm-centreon-error.log'
|
|
433
|
+
},
|
|
434
|
+
{ failOnNonZeroExit: false }
|
|
400
435
|
);
|
|
401
|
-
})
|
|
436
|
+
})
|
|
437
|
+
.then(() => {
|
|
438
|
+
if (Cypress.env('WEB_IMAGE_OS').includes('alma')) {
|
|
439
|
+
return cy.copyFromContainer({
|
|
440
|
+
destination: `${logDirectory}/httpd`,
|
|
441
|
+
name,
|
|
442
|
+
source: '/var/log/httpd'
|
|
443
|
+
});
|
|
444
|
+
}
|
|
402
445
|
|
|
403
|
-
|
|
446
|
+
return cy.copyFromContainer(
|
|
447
|
+
{
|
|
448
|
+
destination: `${logDirectory}/apache2`,
|
|
449
|
+
name,
|
|
450
|
+
source: '/var/log/apache2'
|
|
451
|
+
},
|
|
452
|
+
{ failOnNonZeroExit: false }
|
|
453
|
+
);
|
|
454
|
+
})
|
|
455
|
+
.exec(`chmod -R 755 "${logDirectory}"`)
|
|
456
|
+
.task(
|
|
457
|
+
'stopContainers',
|
|
458
|
+
{},
|
|
459
|
+
{ timeout: 600000 } // 10 minutes because docker pull can be very slow
|
|
460
|
+
);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
Cypress.Commands.add(
|
|
464
|
+
'createDirectory',
|
|
465
|
+
(directoryPath: string): Cypress.Chainable => {
|
|
466
|
+
return cy.task('createDirectory', directoryPath);
|
|
404
467
|
}
|
|
405
468
|
);
|
|
406
469
|
|
|
@@ -576,6 +639,9 @@ declare global {
|
|
|
576
639
|
command,
|
|
577
640
|
name
|
|
578
641
|
}: ExecInContainerProps) => Cypress.Chainable;
|
|
642
|
+
getContainerId: (containerName: string) => Cypress.Chainable;
|
|
643
|
+
getContainerIpAddress: (containerName: string) => Cypress.Chainable;
|
|
644
|
+
getContainersLogs: () => Cypress.Chainable;
|
|
579
645
|
getIframeBody: () => Cypress.Chainable;
|
|
580
646
|
getTimeFromHeader: () => Cypress.Chainable;
|
|
581
647
|
getWebVersion: () => Cypress.Chainable;
|
|
@@ -586,7 +652,6 @@ declare global {
|
|
|
586
652
|
dashboard: Dashboard,
|
|
587
653
|
patch: PatchDashboardBody
|
|
588
654
|
) => Cypress.Chainable;
|
|
589
|
-
|
|
590
655
|
loginByTypeOfUser: ({
|
|
591
656
|
jsonName,
|
|
592
657
|
loginViaApi
|
|
@@ -597,23 +662,31 @@ declare global {
|
|
|
597
662
|
rootItemNumber,
|
|
598
663
|
subMenu
|
|
599
664
|
}: NavigateToProps) => Cypress.Chainable;
|
|
665
|
+
requestOnDatabase: ({
|
|
666
|
+
database,
|
|
667
|
+
query
|
|
668
|
+
}: RequestOnDatabaseProps) => Cypress.Chainable;
|
|
600
669
|
shareDashboardToUser: ({
|
|
601
670
|
dashboardName,
|
|
602
671
|
userName,
|
|
603
672
|
role
|
|
604
673
|
}: ShareDashboardToUserProps) => Cypress.Chainable;
|
|
605
674
|
startContainer: ({
|
|
675
|
+
command,
|
|
606
676
|
name,
|
|
607
|
-
image
|
|
677
|
+
image,
|
|
678
|
+
portBindings
|
|
608
679
|
}: StartContainerProps) => Cypress.Chainable;
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
680
|
+
startContainers: ({
|
|
681
|
+
databaseImage,
|
|
682
|
+
openidImage,
|
|
683
|
+
profiles,
|
|
612
684
|
useSlim,
|
|
613
|
-
|
|
614
|
-
|
|
685
|
+
webOs,
|
|
686
|
+
webVersion
|
|
687
|
+
}?: StartContainersProps) => Cypress.Chainable;
|
|
615
688
|
stopContainer: ({ name }: StopContainerProps) => Cypress.Chainable;
|
|
616
|
-
|
|
689
|
+
stopContainers: () => Cypress.Chainable;
|
|
617
690
|
visitEmptyPage: () => Cypress.Chainable;
|
|
618
691
|
waitForContainerAndSetToken: () => Cypress.Chainable;
|
|
619
692
|
}
|
|
@@ -13,7 +13,6 @@ import tasks from './tasks';
|
|
|
13
13
|
|
|
14
14
|
interface ConfigurationOptions {
|
|
15
15
|
cypressFolder?: string;
|
|
16
|
-
dockerName?: string;
|
|
17
16
|
env?: Record<string, unknown>;
|
|
18
17
|
envFile?: string;
|
|
19
18
|
isDevelopment?: boolean;
|
|
@@ -24,7 +23,6 @@ export default ({
|
|
|
24
23
|
specPattern,
|
|
25
24
|
cypressFolder,
|
|
26
25
|
isDevelopment,
|
|
27
|
-
dockerName,
|
|
28
26
|
env,
|
|
29
27
|
envFile
|
|
30
28
|
}: ConfigurationOptions): Cypress.ConfigOptions => {
|
|
@@ -41,6 +39,7 @@ export default ({
|
|
|
41
39
|
return defineConfig({
|
|
42
40
|
chromeWebSecurity: false,
|
|
43
41
|
defaultCommandTimeout: 6000,
|
|
42
|
+
downloadsFolder: `${resultsFolder}/downloads`,
|
|
44
43
|
e2e: {
|
|
45
44
|
excludeSpecPattern: ['*.js', '*.ts', '*.md'],
|
|
46
45
|
fixturesFolder: 'fixtures',
|
|
@@ -60,16 +59,17 @@ export default ({
|
|
|
60
59
|
},
|
|
61
60
|
env: {
|
|
62
61
|
...env,
|
|
62
|
+
DATABASE_IMAGE: 'bitnami/mariadb:10.5',
|
|
63
63
|
OPENID_IMAGE_VERSION: process.env.MAJOR || '24.04',
|
|
64
|
+
SAML_IMAGE_VERSION: process.env.MAJOR || '24.04',
|
|
64
65
|
WEB_IMAGE_OS: 'alma9',
|
|
65
|
-
WEB_IMAGE_VERSION: webImageVersion
|
|
66
|
-
dockerName: dockerName || 'centreon-dev'
|
|
66
|
+
WEB_IMAGE_VERSION: webImageVersion
|
|
67
67
|
},
|
|
68
68
|
execTimeout: 60000,
|
|
69
69
|
requestTimeout: 10000,
|
|
70
70
|
retries: 0,
|
|
71
71
|
screenshotsFolder: `${resultsFolder}/screenshots`,
|
|
72
|
-
video:
|
|
72
|
+
video: isDevelopment,
|
|
73
73
|
videoCompression: 0,
|
|
74
74
|
videosFolder: `${resultsFolder}/videos`
|
|
75
75
|
});
|
package/cypress/e2e/plugins.ts
CHANGED
package/cypress/e2e/tasks.ts
CHANGED
|
@@ -1,10 +1,39 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
1
2
|
import { execSync } from 'child_process';
|
|
2
3
|
import { existsSync, mkdirSync } from 'fs';
|
|
3
4
|
|
|
4
|
-
import
|
|
5
|
+
import tar from 'tar-fs';
|
|
6
|
+
import {
|
|
7
|
+
DockerComposeEnvironment,
|
|
8
|
+
GenericContainer,
|
|
9
|
+
StartedDockerComposeEnvironment,
|
|
10
|
+
StartedTestContainer,
|
|
11
|
+
Wait,
|
|
12
|
+
getContainerRuntimeClient
|
|
13
|
+
} from 'testcontainers';
|
|
14
|
+
import { createConnection } from 'mysql2/promise';
|
|
15
|
+
|
|
16
|
+
interface Containers {
|
|
17
|
+
[key: string]: StartedTestContainer;
|
|
18
|
+
}
|
|
5
19
|
|
|
6
20
|
export default (on: Cypress.PluginEvents): void => {
|
|
7
|
-
|
|
21
|
+
let dockerEnvironment: StartedDockerComposeEnvironment | null = null;
|
|
22
|
+
const containers: Containers = {};
|
|
23
|
+
|
|
24
|
+
const getContainer = (containerName): StartedTestContainer => {
|
|
25
|
+
let container;
|
|
26
|
+
|
|
27
|
+
if (dockerEnvironment !== null) {
|
|
28
|
+
container = dockerEnvironment.getContainer(`${containerName}-1`);
|
|
29
|
+
} else if (containers[containerName]) {
|
|
30
|
+
container = containers[containerName];
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error(`Cannot get container ${containerName}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return container;
|
|
36
|
+
};
|
|
8
37
|
|
|
9
38
|
interface PortBinding {
|
|
10
39
|
destination: number;
|
|
@@ -12,6 +41,7 @@ export default (on: Cypress.PluginEvents): void => {
|
|
|
12
41
|
}
|
|
13
42
|
|
|
14
43
|
interface StartContainerProps {
|
|
44
|
+
command?: string;
|
|
15
45
|
image: string;
|
|
16
46
|
name: string;
|
|
17
47
|
portBindings: Array<PortBinding>;
|
|
@@ -22,6 +52,27 @@ export default (on: Cypress.PluginEvents): void => {
|
|
|
22
52
|
}
|
|
23
53
|
|
|
24
54
|
on('task', {
|
|
55
|
+
copyFromContainer: async ({ destination, serviceName, source }) => {
|
|
56
|
+
try {
|
|
57
|
+
if (dockerEnvironment !== null) {
|
|
58
|
+
const container = dockerEnvironment.getContainer(`${serviceName}-1`);
|
|
59
|
+
|
|
60
|
+
await container
|
|
61
|
+
.copyArchiveFromContainer(source)
|
|
62
|
+
.then((archiveStream) => {
|
|
63
|
+
return new Promise<void>((resolve) => {
|
|
64
|
+
const dest = tar.extract(destination);
|
|
65
|
+
archiveStream.pipe(dest);
|
|
66
|
+
dest.on('finish', resolve);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error(error);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return null;
|
|
75
|
+
},
|
|
25
76
|
createDirectory: async (directoryPath: string) => {
|
|
26
77
|
if (!existsSync(directoryPath)) {
|
|
27
78
|
mkdirSync(directoryPath, { recursive: true });
|
|
@@ -29,70 +80,143 @@ export default (on: Cypress.PluginEvents): void => {
|
|
|
29
80
|
|
|
30
81
|
return null;
|
|
31
82
|
},
|
|
83
|
+
execInContainer: async ({ command, name }) => {
|
|
84
|
+
const { exitCode, output } = await getContainer(name).exec([
|
|
85
|
+
'bash',
|
|
86
|
+
'-c',
|
|
87
|
+
command
|
|
88
|
+
]);
|
|
89
|
+
|
|
90
|
+
return { exitCode, output };
|
|
91
|
+
},
|
|
92
|
+
getContainerId: (containerName: string) =>
|
|
93
|
+
getContainer(containerName).getId(),
|
|
94
|
+
getContainerIpAddress: (containerName: string) => {
|
|
95
|
+
const container = getContainer(containerName);
|
|
96
|
+
|
|
97
|
+
const networkNames = container.getNetworkNames();
|
|
98
|
+
|
|
99
|
+
return container.getIpAddress(networkNames[0]);
|
|
100
|
+
},
|
|
101
|
+
getContainersLogs: async () => {
|
|
102
|
+
try {
|
|
103
|
+
const { dockerode } = (await getContainerRuntimeClient()).container;
|
|
104
|
+
const loggedContainers = await dockerode.listContainers();
|
|
105
|
+
|
|
106
|
+
return loggedContainers.reduce((acc, container) => {
|
|
107
|
+
const containerName = container.Names[0].replace('/', '');
|
|
108
|
+
acc[containerName] = execSync(`docker logs -t ${container.Id}`, {
|
|
109
|
+
stdio: 'pipe'
|
|
110
|
+
}).toString('utf8');
|
|
111
|
+
|
|
112
|
+
return acc;
|
|
113
|
+
}, {});
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.warn('Cannot get containers logs');
|
|
116
|
+
console.warn(error);
|
|
117
|
+
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
requestOnDatabase: async ({ database, query }) => {
|
|
122
|
+
let container: StartedTestContainer | null = null;
|
|
123
|
+
|
|
124
|
+
if (dockerEnvironment !== null) {
|
|
125
|
+
container = dockerEnvironment.getContainer('db-1');
|
|
126
|
+
} else {
|
|
127
|
+
container = getContainer('web');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const client = await createConnection({
|
|
131
|
+
database,
|
|
132
|
+
host: container.getHost(),
|
|
133
|
+
password: 'centreon',
|
|
134
|
+
port: container.getMappedPort(3306),
|
|
135
|
+
user: 'centreon'
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const [rows, fields] = await client.execute(query);
|
|
139
|
+
|
|
140
|
+
await client.end();
|
|
141
|
+
|
|
142
|
+
return [rows, fields];
|
|
143
|
+
},
|
|
32
144
|
startContainer: async ({
|
|
145
|
+
command,
|
|
33
146
|
image,
|
|
34
147
|
name,
|
|
35
148
|
portBindings = []
|
|
36
149
|
}: StartContainerProps) => {
|
|
37
|
-
|
|
38
|
-
'docker image list --format "{{.Repository}}:{{.Tag}}"'
|
|
39
|
-
).toString('utf8');
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
!imageList.match(
|
|
43
|
-
new RegExp(
|
|
44
|
-
`^${image.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}`,
|
|
45
|
-
'm'
|
|
46
|
-
)
|
|
47
|
-
)
|
|
48
|
-
) {
|
|
49
|
-
execSync(`docker pull ${image}`);
|
|
50
|
-
}
|
|
150
|
+
let container = await new GenericContainer(image).withName(name);
|
|
51
151
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
152
|
+
portBindings.forEach(({ source, destination }) => {
|
|
153
|
+
container = container.withExposedPorts({
|
|
154
|
+
container: source,
|
|
155
|
+
host: destination
|
|
156
|
+
});
|
|
55
157
|
});
|
|
56
|
-
if (webContainers.length) {
|
|
57
|
-
return webContainers[0];
|
|
58
|
-
}
|
|
59
158
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
accumulator[`${currentValue.source}/tcp`] = {};
|
|
66
|
-
|
|
67
|
-
return accumulator;
|
|
68
|
-
}, {}),
|
|
69
|
-
HostConfig: {
|
|
70
|
-
PortBindings: portBindings.reduce((accumulator, currentValue) => {
|
|
71
|
-
accumulator[`${currentValue.source}/tcp`] = [
|
|
72
|
-
{
|
|
73
|
-
HostIP: '127.0.0.1',
|
|
74
|
-
HostPort: `${currentValue.destination}`
|
|
75
|
-
}
|
|
76
|
-
];
|
|
77
|
-
|
|
78
|
-
return accumulator;
|
|
79
|
-
}, {})
|
|
80
|
-
},
|
|
81
|
-
Image: image,
|
|
82
|
-
OpenStdin: false,
|
|
83
|
-
StdinOnce: false,
|
|
84
|
-
Tty: true,
|
|
85
|
-
name
|
|
86
|
-
});
|
|
159
|
+
if (command) {
|
|
160
|
+
container
|
|
161
|
+
.withCommand(['bash', '-c', command])
|
|
162
|
+
.withWaitStrategy(Wait.forSuccessfulCommand('ls'));
|
|
163
|
+
}
|
|
87
164
|
|
|
88
|
-
await container.start();
|
|
165
|
+
containers[name] = await container.start();
|
|
89
166
|
|
|
90
167
|
return container;
|
|
91
168
|
},
|
|
169
|
+
startContainers: async ({
|
|
170
|
+
composeFilePath = `${__dirname}/../../../../../.github/docker/`,
|
|
171
|
+
databaseImage,
|
|
172
|
+
openidImage,
|
|
173
|
+
profiles,
|
|
174
|
+
samlImage,
|
|
175
|
+
webImage
|
|
176
|
+
}) => {
|
|
177
|
+
try {
|
|
178
|
+
const composeFile = 'docker-compose.yml';
|
|
179
|
+
|
|
180
|
+
dockerEnvironment = await new DockerComposeEnvironment(
|
|
181
|
+
composeFilePath,
|
|
182
|
+
composeFile
|
|
183
|
+
)
|
|
184
|
+
.withEnvironment({
|
|
185
|
+
MYSQL_IMAGE: databaseImage,
|
|
186
|
+
OPENID_IMAGE: openidImage,
|
|
187
|
+
SAML_IMAGE: samlImage,
|
|
188
|
+
WEB_IMAGE: webImage
|
|
189
|
+
})
|
|
190
|
+
.withProfiles(...profiles)
|
|
191
|
+
.withWaitStrategy('web', Wait.forHealthCheck())
|
|
192
|
+
.up();
|
|
193
|
+
|
|
194
|
+
return null;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (error instanceof Error) {
|
|
197
|
+
console.error(error.message);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
},
|
|
92
203
|
stopContainer: async ({ name }: StopContainerProps) => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
204
|
+
if (containers[name]) {
|
|
205
|
+
const container = containers[name];
|
|
206
|
+
|
|
207
|
+
await container.stop();
|
|
208
|
+
|
|
209
|
+
delete containers[name];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return null;
|
|
213
|
+
},
|
|
214
|
+
stopContainers: async () => {
|
|
215
|
+
if (dockerEnvironment !== null) {
|
|
216
|
+
await dockerEnvironment.down();
|
|
217
|
+
|
|
218
|
+
dockerEnvironment = null;
|
|
219
|
+
}
|
|
96
220
|
|
|
97
221
|
return null;
|
|
98
222
|
},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@centreon/js-config",
|
|
3
3
|
"description": "Centreon Frontend shared build configuration",
|
|
4
|
-
"version": "24.4.1-MON-
|
|
4
|
+
"version": "24.4.1-MON-23368-containers.81",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/centreon/centreon-frontend.git"
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"cypress"
|
|
25
25
|
],
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"
|
|
28
|
-
"
|
|
27
|
+
"eslint": "^8.53.0",
|
|
28
|
+
"prettier": "^3.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@badeball/cypress-cucumber-preprocessor": "^
|
|
31
|
+
"@badeball/cypress-cucumber-preprocessor": "^20.0.1",
|
|
32
32
|
"@bahmutov/cypress-esbuild-preprocessor": "^2.2.0",
|
|
33
33
|
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
|
34
34
|
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"@types/cypress-cucumber-preprocessor": "^4.0.5",
|
|
38
38
|
"@types/dockerode": "^3.3.23",
|
|
39
39
|
"cypress-multi-reporters": "^1.6.4",
|
|
40
|
-
"cypress-terminal-report": "^5.3.
|
|
41
|
-
"dockerode": "^4.0.
|
|
40
|
+
"cypress-terminal-report": "^5.3.10",
|
|
41
|
+
"dockerode": "^4.0.2",
|
|
42
42
|
"dotenv": "^16.3.1",
|
|
43
|
-
"esbuild": "^0.19.
|
|
43
|
+
"esbuild": "^0.19.11",
|
|
44
44
|
"eslint": "^8.53.0",
|
|
45
45
|
"eslint-config-airbnb": "19.0.4",
|
|
46
46
|
"eslint-config-prettier": "^8.5.0",
|
|
@@ -58,6 +58,9 @@
|
|
|
58
58
|
"eslint-plugin-react-hooks": "^4.5.0",
|
|
59
59
|
"eslint-plugin-sort-keys-fix": "^1.1.2",
|
|
60
60
|
"eslint-plugin-typescript-sort-keys": "^2.1.0",
|
|
61
|
-
"mochawesome": "^7.1.3"
|
|
61
|
+
"mochawesome": "^7.1.3",
|
|
62
|
+
"mysql2": "^3.7.0",
|
|
63
|
+
"tar-fs": "^3.0.4",
|
|
64
|
+
"testcontainers": "^10.5.0"
|
|
62
65
|
}
|
|
63
66
|
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
const filePath = process.argv[2];
|
|
5
|
-
|
|
6
|
-
const { error: logError } = console;
|
|
7
|
-
|
|
8
|
-
try {
|
|
9
|
-
const outFile = fs.readFileSync(path.resolve(filePath)).toString();
|
|
10
|
-
const outFileJson = JSON.parse(outFile);
|
|
11
|
-
|
|
12
|
-
const finalOutJson = Object.entries(outFileJson)
|
|
13
|
-
.map(([key, value]) => {
|
|
14
|
-
if (key.includes('node_modules')) {
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return [key, value];
|
|
19
|
-
})
|
|
20
|
-
.filter((v) => v)
|
|
21
|
-
.reduce(
|
|
22
|
-
(acc, [key, value]) => ({
|
|
23
|
-
...acc,
|
|
24
|
-
[key]: value
|
|
25
|
-
}),
|
|
26
|
-
{}
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
fs.writeFileSync(
|
|
30
|
-
path.resolve(filePath),
|
|
31
|
-
JSON.stringify(finalOutJson, null, 2)
|
|
32
|
-
);
|
|
33
|
-
} catch (error) {
|
|
34
|
-
logError(error.message);
|
|
35
|
-
}
|