Skip to content

Commit 2f9d491

Browse files
authored
[Test] Rework NodeJS Express devfile API test (#23287)
* add API e2e test for NodeJS Express
1 parent 04d0b55 commit 2f9d491

File tree

3 files changed

+196
-39
lines changed

3 files changed

+196
-39
lines changed

tests/e2e/CODE_STYLE.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ Automated lint checking and code format performs with ESLint and Prettier tools
3333
pre-commit hook.
3434
Full set of rules can be found:
3535

36-
- [.eslintrc](.eslintrc.js)
37-
- [.prettierrc](.prettierrc.json)
36+
- [.eslintrc](.eslintrc.js)
37+
- [.prettierrc](.prettierrc.json)
3838

3939
### Preferable code style
4040

tests/e2e/README.md

+37-37
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,33 @@
22

33
## Requirements
44

5-
- node 16.x
6-
- "Chrome" browser 114.x or later
7-
- deployed Che 7 with accessible URL
5+
- node 16.x
6+
- "Chrome" browser 114.x or later
7+
- deployed Che 7 with accessible URL
88

99
## Before launch
1010

1111
**Perform commands:**
1212

13-
- `export TS_SELENIUM_BASE_URL=<Che7 URL>`
14-
- `npm ci`
13+
- `export TS_SELENIUM_BASE_URL=<Che7 URL>`
14+
- `npm ci`
1515

1616
Note: If there is any modifications in package.json, manually execute the `npm install` to update the package-lock.json. So that errors can be avoided while executing npm ci
1717

1818
## Default launch
1919

20-
- Provide connection credentials:
21-
- `export TS_SELENIUM_OCP_USERNAME=<username>`
22-
- `export TS_SELENIUM_OCP_PASSWORD=<password>`
23-
- `npm run test`
20+
- Provide connection credentials:
21+
- `export TS_SELENIUM_OCP_USERNAME=<username>`
22+
- `export TS_SELENIUM_OCP_PASSWORD=<password>`
23+
- `npm run test`
2424

2525
## Custom launch
2626

27-
- Use environment variables which described in the "constants" folder
28-
- Use environment variables for setting timeouts if needed. You can see the list in **`'TimeoutConstants.ts'`**. You can see the list of those variables and their value if you set the `'TS_SELENIUM_PRINT_TIMEOUT_VARIABLES = true'`
29-
- To test one specification export file name as `export USERSTORY=<spec-file-name-without-extension> && npm run test` (example: `-e USERSTORY=Quarkus`)
30-
- To run test without Selenium WebDriver (API tests etc.) use `export USERSTORY=<spec-file-name-without-extension> && npm run driver-less-test` (example: `-e USERSTORY=CloneGitRepoAPI`)
31-
- This project support application testing deployed on Kubernetes or Openshift platform. Openshift is default value. To switch into Kubernetes, please, use `TS_PLATFORM=kubernetes` environmental variable and `TS_SELENIUM_K8S_PASSWORD`, `TS_SELENIUM_K8S_USERNAME` to provide credentials. The sample of test command in this case:
27+
- Use environment variables which described in the "constants" folder
28+
- Use environment variables for setting timeouts if needed. You can see the list in **`'TimeoutConstants.ts'`**. You can see the list of those variables and their value if you set the `'TS_SELENIUM_PRINT_TIMEOUT_VARIABLES = true'`
29+
- To test one specification export file name as `export USERSTORY=<spec-file-name-without-extension> && npm run test` (example: `-e USERSTORY=Quarkus`)
30+
- To run test without Selenium WebDriver (API tests etc.) use `export USERSTORY=<spec-file-name-without-extension> && npm run driver-less-test` (example: `-e USERSTORY=CloneGitRepoAPI`)
31+
- This project support application testing deployed on Kubernetes or Openshift platform. Openshift is default value. To switch into Kubernetes, please, use `TS_PLATFORM=kubernetes` environmental variable and `TS_SELENIUM_K8S_PASSWORD`, `TS_SELENIUM_K8S_USERNAME` to provide credentials. The sample of test command in this case:
3232
```
3333
export TS_PLATFORM=kubernetes && \
3434
export TS_SELENIUM_K8S_USERNAME=<username> && \
@@ -37,21 +37,21 @@ Note: If there is any modifications in package.json, manually execute the `npm i
3737
npm run test
3838
```
3939
Also, environmental variables can be set in files in "constants" folder.
40-
- Local test results can be represented with Allure reporter `npm run open-allure-dasboard`
40+
- Local test results can be represented with Allure reporter `npm run open-allure-dasboard`
4141
4242
## Docker launch
4343
44-
- open terminal and go to the "e2e" directory
45-
- export the `"TS_SELENIUM_BASE_URL"` variable with "Che" url
46-
- run command `"npm run test-docker"`
44+
- open terminal and go to the "e2e" directory
45+
- export the `"TS_SELENIUM_BASE_URL"` variable with "Che" url
46+
- run command `"npm run test-docker"`
4747
4848
## Docker launch with changed tests
4949
5050
**For launching tests with local changes perform next steps:**
5151
52-
- open terminal and go to the "e2e" directory
53-
- export the `"TS_SELENIUM_BASE_URL"` variable with "Che" url
54-
- run command `"npm run test-docker-mount-e2e"`
52+
- open terminal and go to the "e2e" directory
53+
- export the `"TS_SELENIUM_BASE_URL"` variable with "Che" url
54+
- run command `"npm run test-docker-mount-e2e"`
5555
5656
## Debug docker launch
5757
@@ -62,27 +62,27 @@ The `'eclipse/che-e2e'` docker image has VNC server installed inside. For connec
6262
**The easiest way to do that is to perform steps which are described in the "Docker launch" paragraph.
6363
For running tests without docker, please perform next steps:**
6464
65-
- Deploy Che on Kubernetes infrastructure by using 'Minikube' and 'Chectl' <https://github.com/eclipse-che/che-server/blob/HEAD/deploy/kubernetes/README.md>
66-
- Create workspace by using 'Chectl' and devfile
67-
- link to 'Chectl' manual <https://github.com/che-incubator/chectl#chectl-workspacestart>
68-
- link to devfile ( **`For successfull test passing, exactly provided devfile should be used`** )
69-
<https://gist.githubusercontent.com/Ohrimenko1988/93f5426f4ebc1705c55feb8ff0396a49/raw/cbea89ad145ba33ed34a151a12c50f045f9f3b78/yaml-ls-bug.yaml>
70-
- Provide the **`'TS_SELENIUM_BASE_URL'`** environment variable as described above
71-
- export TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME=EmptyWorkspace (default value, see BASE_TEST_CONSTANTS.ts)
72-
- perform command **`export USERSTORY=$TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME && npm run test-all-devfiles`**
65+
- Deploy Che on Kubernetes infrastructure by using 'Minikube' and 'Chectl' <https://github.com/eclipse-che/che-server/blob/HEAD/deploy/kubernetes/README.md>
66+
- Create workspace by using 'Chectl' and devfile
67+
- link to 'Chectl' manual <https://github.com/che-incubator/chectl#chectl-workspacestart>
68+
- link to devfile ( **`For successfull test passing, exactly provided devfile should be used`** )
69+
<https://gist.githubusercontent.com/Ohrimenko1988/93f5426f4ebc1705c55feb8ff0396a49/raw/cbea89ad145ba33ed34a151a12c50f045f9f3b78/yaml-ls-bug.yaml>
70+
- Provide the **`'TS_SELENIUM_BASE_URL'`** environment variable as described above
71+
- export TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME=EmptyWorkspace (default value, see BASE_TEST_CONSTANTS.ts)
72+
- perform command **`export USERSTORY=$TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME && npm run test-all-devfiles`**
7373
7474
## Launching the DevWorkspaceHappyPath spec file using Che with oauth authentication
7575
7676
**Setup next environment variables:**
7777
78-
- export TS_SELENIUM_BASE_URL=\<Che-URL\>
79-
- export TS_SELENIUM_OCP_USERNAME=\<cluster-username\>
80-
- export TS_SELENIUM_OCP_PASSWORD=\<cluster-password\>
81-
- export TS_SELENIUM_VALUE_OPENSHIFT_OAUTH="true"
82-
- export TS_OCP_LOGIN_PAGE_PROVIDER_TITLE=\<login-provide-title\>
83-
- export TS_SELENIUM_DEVWORKSPACE_URL=\<devworkspace-url\>
84-
- export TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME=EmptyWorkspace (default value, see BASE_TEST_CONSTANTS.ts)
78+
- export TS_SELENIUM_BASE_URL=\<Che-URL\>
79+
- export TS_SELENIUM_OCP_USERNAME=\<cluster-username\>
80+
- export TS_SELENIUM_OCP_PASSWORD=\<cluster-password\>
81+
- export TS_SELENIUM_VALUE_OPENSHIFT_OAUTH="true"
82+
- export TS_OCP_LOGIN_PAGE_PROVIDER_TITLE=\<login-provide-title\>
83+
- export TS_SELENIUM_DEVWORKSPACE_URL=\<devworkspace-url\>
84+
- export TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME=EmptyWorkspace (default value, see BASE_TEST_CONSTANTS.ts)
8585
8686
**Execute the npm command:**
8787
88-
- perform command `export USERSTORY=$TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME && npm run test-all-devfiles`
88+
- perform command `export USERSTORY=$TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME && npm run test-all-devfiles`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/** *******************************************************************
2+
* copyright (c) 2024 Red Hat, Inc.
3+
*
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
**********************************************************************/
10+
import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS';
11+
import { e2eContainer } from '../../configs/inversify.config';
12+
import { CLASSES } from '../../configs/inversify.types';
13+
import { DevfilesHelper } from '../../utils/DevfilesHelper';
14+
import { ContainerTerminal, KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor';
15+
import { DevWorkspaceConfigurationHelper } from '../../utils/DevWorkspaceConfigurationHelper';
16+
import { DevfileContext } from '@eclipse-che/che-devworkspace-generator/lib/api/devfile-context';
17+
import { ShellString } from 'shelljs';
18+
import { expect } from 'chai';
19+
import { API_TEST_CONSTANTS } from '../../constants/API_TEST_CONSTANTS';
20+
import YAML from 'yaml';
21+
import { Logger } from '../../utils/Logger';
22+
import crypto from 'crypto';
23+
24+
suite('NodeJS Express devfile API test', function (): void {
25+
const devfilesRegistryHelper: DevfilesHelper = e2eContainer.get(CLASSES.DevfilesRegistryHelper);
26+
const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get(
27+
CLASSES.KubernetesCommandLineToolsExecutor
28+
);
29+
const devfileID: string = 'nodejs-express';
30+
const containerTerminal: ContainerTerminal = e2eContainer.get(CLASSES.ContainerTerminal);
31+
let devWorkspaceConfigurationHelper: DevWorkspaceConfigurationHelper;
32+
let devfileContext: DevfileContext;
33+
let devfileContent: string = '';
34+
let devfileName: string = '';
35+
36+
suiteSetup(`Prepare login ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void {
37+
kubernetesCommandLineToolsExecutor.loginToOcp();
38+
});
39+
40+
test(`Create ${devfileID} workspace`, async function (): Promise<void> {
41+
const randomPref: string = crypto.randomBytes(4).toString('hex');
42+
kubernetesCommandLineToolsExecutor.namespace = API_TEST_CONSTANTS.TS_API_TEST_NAMESPACE || 'admin-devspaces';
43+
devfileContent = devfilesRegistryHelper.getDevfileContent(devfileID);
44+
const editorDevfileContent: string = devfilesRegistryHelper.obtainCheDevFileEditorFromCheConfigMap('editors-definitions');
45+
devfileName = YAML.parse(devfileContent).metadata.name;
46+
const uniqueName: string = YAML.parse(devfileContent).metadata.name + randomPref;
47+
kubernetesCommandLineToolsExecutor.workspaceName = uniqueName;
48+
49+
devWorkspaceConfigurationHelper = new DevWorkspaceConfigurationHelper({
50+
editorContent: editorDevfileContent,
51+
devfileContent: devfileContent
52+
});
53+
devfileContext = await devWorkspaceConfigurationHelper.generateDevfileContext();
54+
if (devfileContext.devWorkspace.metadata) {
55+
devfileContext.devWorkspace.metadata.name = uniqueName;
56+
}
57+
const devWorkspaceConfigurationYamlString: string =
58+
devWorkspaceConfigurationHelper.getDevWorkspaceConfigurationYamlAsString(devfileContext);
59+
const output: ShellString = kubernetesCommandLineToolsExecutor.applyAndWaitDevWorkspace(devWorkspaceConfigurationYamlString);
60+
expect(output.stdout).contains('condition met');
61+
});
62+
63+
test('Check packaging application', function (): void {
64+
const containerName: string = YAML.parse(devfileContent).commands[0].exec.component;
65+
66+
if (BASE_TEST_CONSTANTS.IS_CLUSTER_DISCONNECTED()) {
67+
Logger.info('Test cluster is disconnected. Ignore Self-Signed Certificate error.');
68+
const ignoreSelfSignedCertificateErrorCommand: string = 'npm config set strict-ssl false';
69+
const output: ShellString = containerTerminal.execInContainerCommand(ignoreSelfSignedCertificateErrorCommand, containerName);
70+
expect(output.code).eqls(0);
71+
}
72+
73+
const workdir: string = YAML.parse(devfileContent).commands[0].exec.workingDir;
74+
const commandLine: string = YAML.parse(devfileContent).commands[0].exec.commandLine;
75+
Logger.info(`workdir from exec section of DevWorkspace file: ${workdir}`);
76+
Logger.info(`commandLine from exec section of DevWorkspace file: ${commandLine}`);
77+
78+
let runCommandInBash: string = commandLine.replaceAll('$', '\\$'); // don't wipe out env. vars like "${PROJECTS_ROOT}"
79+
if (workdir !== undefined && workdir !== '') {
80+
runCommandInBash = `cd ${workdir} && ` + runCommandInBash;
81+
}
82+
83+
const output: ShellString = containerTerminal.execInContainerCommand(runCommandInBash, containerName);
84+
expect(output.code).eqls(0);
85+
86+
const outputText: string = output.stdout.trim();
87+
expect(outputText).contains('packages in');
88+
});
89+
90+
test('Check "run the web app" command', function (): void {
91+
const containerName: string = YAML.parse(devfileContent).commands[0].exec.component;
92+
const workdir: string = YAML.parse(devfileContent).commands[1].exec.workingDir;
93+
const commandLine: string = YAML.parse(devfileContent).commands[1].exec.commandLine;
94+
Logger.info(`workdir from exec section of DevWorkspace file: ${workdir}`);
95+
Logger.info(`commandLine from exec section of DevWorkspace file: ${commandLine}`);
96+
97+
let runCommandInBash: string = commandLine.replaceAll('$', '\\$'); // don't wipe out env. vars like "${PROJECTS_ROOT}"
98+
if (workdir !== undefined && workdir !== '') {
99+
runCommandInBash = `cd ${workdir} && ` + runCommandInBash;
100+
}
101+
102+
const output: ShellString = containerTerminal.execInContainerCommandWithTimeout(runCommandInBash, containerName);
103+
expect(output.code).eqls(124);
104+
105+
const outputText: string = output.stdout.trim();
106+
expect(outputText).contains('Example app listening on port 3000!');
107+
});
108+
109+
test('Check "stop the web app" command', function (): void {
110+
const containerName: string = YAML.parse(devfileContent).commands[0].exec.component;
111+
const workdir: string = YAML.parse(devfileContent).commands[4].exec.workingDir;
112+
const commandLine: string = YAML.parse(devfileContent).commands[4].exec.commandLine;
113+
Logger.info(`workdir from exec section of DevWorkspace file: ${workdir}`);
114+
Logger.info(`commandLine from exec section of DevWorkspace file: ${commandLine}`);
115+
116+
// stop app command has single and double quotes in the command line, so it should be escaped properly to run by oc exec command in bash
117+
// stop command -> `node_server_pids=$(pgrep -fx '.*nodemon (--inspect )?app.js' | tr "\\n" " ") && echo "Stopping node server with PIDs: ${node_server_pids}" && kill -15 ${node_server_pids} &>/dev/null && echo 'Done.''`
118+
119+
// prettier changes next line to `replaceAll("'", "'\"'\"'")` that throws an error from eslint.
120+
// prettier-ignore
121+
let runCommandInBash: string = commandLine.replaceAll('\'', '\'\"\'\"\'');
122+
123+
if (workdir !== undefined && workdir !== '') {
124+
runCommandInBash = `cd ${workdir} && ` + runCommandInBash;
125+
}
126+
127+
const output: ShellString = containerTerminal.execInContainerCommand(runCommandInBash, containerName);
128+
expect(output.code).eqls(0);
129+
130+
const outputText: string = output.stdout.trim();
131+
expect(outputText).contains('Done.');
132+
});
133+
134+
test('Check "Run the web app (debugging enabled)" command', function (): void {
135+
const containerName: string = YAML.parse(devfileContent).commands[0].exec.component;
136+
137+
const workdir: string = YAML.parse(devfileContent).commands[3].exec.workingDir;
138+
const commandLine: string = YAML.parse(devfileContent).commands[3].exec.commandLine;
139+
Logger.info(`workdir from exec section of DevWorkspace file: ${workdir}`);
140+
Logger.info(`commandLine from exec section of DevWorkspace file: ${commandLine}`);
141+
142+
let runCommandInBash: string = commandLine.replaceAll('$', '\\$'); // don't wipe out env. vars like "${PROJECTS_ROOT}"
143+
if (workdir !== undefined && workdir !== '') {
144+
runCommandInBash = `cd ${workdir} && ` + runCommandInBash;
145+
}
146+
147+
const output: ShellString = containerTerminal.execInContainerCommandWithTimeout(runCommandInBash, containerName);
148+
expect(output.code).eqls(124);
149+
150+
const outputText: string = output.stdout.trim();
151+
expect(outputText).contains('Example app listening on port 3000!');
152+
});
153+
154+
suiteTeardown('Delete workspace', function (): void {
155+
kubernetesCommandLineToolsExecutor.deleteDevWorkspace(devfileName);
156+
});
157+
});

0 commit comments

Comments
 (0)