@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.
@@ -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
- name = Cypress.env('dockerName'),
114
- source,
115
- destination
116
- }: CopyFromContainerProps,
117
- options?: Partial<Cypress.ExecOptions>
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
- return cy
213
- .exec(`docker exec -i ${name} ${command}`, { failOnNonZeroExit: false })
214
- .then((result) => {
215
- if (result.code) {
216
- // output will not be truncated
217
- throw new Error(`
218
- Execution of "${command}" failed
219
- Exit code: ${result.code}
220
- Stdout:\n${result.stdout}
221
- Stderr:\n${result.stderr}`);
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 cy.wrap(result);
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
- ({ name, image, portBindings }: StartContainerProps): Cypress.Chainable => {
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
- Cypress.Commands.add(
254
- 'createDirectory',
255
- (directoryPath: string): Cypress.Chainable => {
256
- return cy.task('createDirectory', directoryPath);
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
- version?: string;
312
+ webOs?: string;
313
+ webVersion?: string;
265
314
  }
266
315
 
267
316
  Cypress.Commands.add(
268
- 'startWebContainer',
317
+ 'startContainers',
269
318
  ({
270
- name = Cypress.env('dockerName'),
271
- os = Cypress.env('WEB_IMAGE_OS'),
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
- version = Cypress.env('WEB_IMAGE_VERSION')
274
- }: StartWebContainerProps = {}): Cypress.Chainable => {
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 image = `docker.centreon.com/centreon/centreon-web${slimSuffix}-${os}:${version}`;
335
+ const webImage = `docker.centreon.com/centreon/centreon-web${slimSuffix}-${webOs}:${webVersion}`;
278
336
 
279
337
  return cy
280
- .startContainer({
281
- image,
282
- name,
283
- portBindings: [{ destination: 4000, source: 80 }]
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.task(
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.exec(`docker logs ${name}`).then(({ stdout }) => {
391
- cy.writeFile(
392
- `results/logs/${Cypress.spec.name.replace(
393
- artifactIllegalCharactersMatcher,
394
- '_'
395
- )}/${Cypress.currentTest.title.replace(
396
- artifactIllegalCharactersMatcher,
397
- '_'
398
- )}/container-${name}.log`,
399
- stdout
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
- return cy.task('stopContainer', { name });
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
- startWebContainer: ({
610
- name,
611
- os,
680
+ startContainers: ({
681
+ databaseImage,
682
+ openidImage,
683
+ profiles,
612
684
  useSlim,
613
- version
614
- }?: StartWebContainerProps) => Cypress.Chainable;
685
+ webOs,
686
+ webVersion
687
+ }?: StartContainersProps) => Cypress.Chainable;
615
688
  stopContainer: ({ name }: StopContainerProps) => Cypress.Chainable;
616
- stopWebContainer: ({ name }?: StopWebContainerProps) => Cypress.Chainable;
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: true,
72
+ video: isDevelopment,
73
73
  videoCompression: 0,
74
74
  videosFolder: `${resultsFolder}/videos`
75
75
  });
@@ -11,7 +11,7 @@ export default (
11
11
  const width = 1920;
12
12
  const height = 1080;
13
13
 
14
- if (browser.family === 'chromium') {
14
+ if (browser.family === 'chromium' && browser.name !== 'electron') {
15
15
  if (browser.isHeadless) {
16
16
  launchOptions.args.push('--headless=new');
17
17
  }
@@ -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 Docker from 'dockerode';
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
- const docker = new Docker();
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
- const imageList = execSync(
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
- const webContainers = await docker.listContainers({
53
- all: true,
54
- filters: { name: [name] }
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
- const container = await docker.createContainer({
61
- AttachStderr: true,
62
- AttachStdin: false,
63
- AttachStdout: true,
64
- ExposedPorts: portBindings.reduce((accumulator, currentValue) => {
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
- const container = await docker.getContainer(name);
94
- await container.kill();
95
- await container.remove();
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-move-code-coverage-archive.3",
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
- "prettier": "^3.0.0",
28
- "eslint": "^8.53.0"
27
+ "eslint": "^8.53.0",
28
+ "prettier": "^3.0.0"
29
29
  },
30
30
  "dependencies": {
31
- "@badeball/cypress-cucumber-preprocessor": "^19.1.0",
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.9",
41
- "dockerode": "^4.0.0",
40
+ "cypress-terminal-report": "^5.3.10",
41
+ "dockerode": "^4.0.2",
42
42
  "dotenv": "^16.3.1",
43
- "esbuild": "^0.19.5",
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
- }