diff --git a/tests/e2e/configs/inversify.config.ts b/tests/e2e/configs/inversify.config.ts index 0847de699ba..16b063be137 100644 --- a/tests/e2e/configs/inversify.config.ts +++ b/tests/e2e/configs/inversify.config.ts @@ -47,7 +47,7 @@ import { BASE_TEST_CONSTANTS, Platform } from '../constants/BASE_TEST_CONSTANTS' import { CheCodeLocatorLoader } from '../pageobjects/ide/CheCodeLocatorLoader'; import { LocatorLoader } from 'monaco-page-objects/out/locators/loader'; import { OauthPage } from '../pageobjects/git-providers/OauthPage'; -import { DevfilesRegistryHelper } from '../utils/DevfilesRegistryHelper'; +import { DevfilesHelper } from '../utils/DevfilesHelper'; import { Main as Generator } from '@eclipse-che/che-devworkspace-generator/lib/main'; import { ContainerTerminal, KubernetesCommandLineToolsExecutor } from '../utils/KubernetesCommandLineToolsExecutor'; import { ShellExecutor } from '../utils/ShellExecutor'; @@ -84,7 +84,7 @@ e2eContainer.bind(CLASSES.StringUtil).to(StringUtil); e2eContainer.bind(CLASSES.ApiUrlResolver).to(ApiUrlResolver); e2eContainer.bind(CLASSES.WorkspaceHandlingTests).to(WorkspaceHandlingTests); e2eContainer.bind(CLASSES.RedHatLoginPage).to(RedHatLoginPage); -e2eContainer.bind(CLASSES.DevfilesRegistryHelper).to(DevfilesRegistryHelper); +e2eContainer.bind(CLASSES.DevfilesRegistryHelper).to(DevfilesHelper); e2eContainer.bind(CLASSES.KubernetesCommandLineToolsExecutor).to(KubernetesCommandLineToolsExecutor); e2eContainer.bind(CLASSES.ShellExecutor).to(ShellExecutor); e2eContainer.bind(CLASSES.ContainerTerminal).to(ContainerTerminal); diff --git a/tests/e2e/index.ts b/tests/e2e/index.ts index 44027982124..d0cb8483b56 100644 --- a/tests/e2e/index.ts +++ b/tests/e2e/index.ts @@ -5,7 +5,7 @@ export * from './configs/mocharc'; export * from './driver/ChromeDriver'; export * from './driver/IDriver'; export * from './utils/BrowserTabsUtil'; -export * from './utils/DevfilesRegistryHelper'; +export * from './utils/DevfilesHelper'; export * from './utils/DevWorkspaceConfigurationHelper'; export * from './utils/DriverHelper'; export * from './utils/IContextParams'; diff --git a/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts b/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts index 996d8950757..b1bd1bffcd0 100644 --- a/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts +++ b/tests/e2e/specs/api/DevfileAcceptanceTestAPI.spec.ts @@ -16,7 +16,7 @@ import { StringUtil } from '../../utils/StringUtil'; import { Logger } from '../../utils/Logger'; import { e2eContainer } from '../../configs/inversify.config'; import { CLASSES } from '../../configs/inversify.types'; -import { DevfilesRegistryHelper } from '../../utils/DevfilesRegistryHelper'; +import { DevfilesHelper } from '../../utils/DevfilesHelper'; import { MOCHA_CONSTANTS } from '../../constants/MOCHA_CONSTANTS'; import { API_TEST_CONSTANTS } from '../../constants/API_TEST_CONSTANTS'; import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; @@ -26,7 +26,7 @@ import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; * info: https://mochajs.org/#delayed-root-suite */ void (async function (): Promise { - const devfilesRegistryHelper: DevfilesRegistryHelper = e2eContainer.get(CLASSES.DevfilesRegistryHelper); + const devfilesRegistryHelper: DevfilesHelper = e2eContainer.get(CLASSES.DevfilesRegistryHelper); let devfileSamples: any = []; if ( diff --git a/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts b/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts index 7a508ec91e9..cca2122e3a7 100644 --- a/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts +++ b/tests/e2e/specs/api/EmptyWorkspaceAPI.spec.ts @@ -34,9 +34,10 @@ suite('Empty workspace API test', function (): void { suiteSetup(`Create empty workspace with OC client ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, async function (): Promise { const workspaceName: string = 'empty-' + Math.floor(Math.random() * 1000); const devfileContent: string = 'schemaVersion: 2.2.0\n' + 'metadata:\n' + ` name: ${workspaceName}\n`; + const editorContent:string=''; devWorkspaceConfigurationHelper = new DevWorkspaceConfigurationHelper({ - devfileContent + devfileContent, editorContent }); devfileContext = await devWorkspaceConfigurationHelper.generateDevfileContext(); devWorkspaceName = devfileContext?.devWorkspace?.metadata?.name; diff --git a/tests/e2e/specs/api/InbuiltApplicationDevWorkspacesAPI.spec.ts b/tests/e2e/specs/api/InbuiltApplicationDevWorkspacesAPI.spec.ts index abb8342971c..77906dc1799 100644 --- a/tests/e2e/specs/api/InbuiltApplicationDevWorkspacesAPI.spec.ts +++ b/tests/e2e/specs/api/InbuiltApplicationDevWorkspacesAPI.spec.ts @@ -12,7 +12,7 @@ import { DevWorkspaceConfigurationHelper } from '../../utils/DevWorkspaceConfigu import { ShellString } from 'shelljs'; import { expect } from 'chai'; import { StringUtil } from '../../utils/StringUtil'; -import { DevfilesRegistryHelper } from '../../utils/DevfilesRegistryHelper'; +import { DevfilesHelper } from '../../utils/DevfilesHelper'; import { Logger } from '../../utils/Logger'; import { e2eContainer } from '../../configs/inversify.config'; import { CLASSES } from '../../configs/inversify.types'; @@ -27,7 +27,7 @@ import { MOCHA_CONSTANTS } from '../../constants/MOCHA_CONSTANTS'; */ void (async function (): Promise { - const devfilesRegistryHelper: DevfilesRegistryHelper = e2eContainer.get(CLASSES.DevfilesRegistryHelper); + const devfilesRegistryHelper: DevfilesHelper = e2eContainer.get(CLASSES.DevfilesRegistryHelper); let devfileSamples: any; if (MOCHA_CONSTANTS.MOCHA_DELAYED_SUITE) { devfileSamples = await devfilesRegistryHelper.collectPathsToDevfilesFromRegistry( diff --git a/tests/e2e/specs/api/PhpDevFileAPI.spec.ts b/tests/e2e/specs/api/PhpDevFileAPI.spec.ts new file mode 100644 index 00000000000..ea398b7fb64 --- /dev/null +++ b/tests/e2e/specs/api/PhpDevFileAPI.spec.ts @@ -0,0 +1,76 @@ +/** ******************************************************************* + * copyright (c) 2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import { BASE_TEST_CONSTANTS } from '../../constants/BASE_TEST_CONSTANTS'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; +import { DevfilesHelper } from '../../utils/DevfilesHelper'; +import { ContainerTerminal, KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { DevWorkspaceConfigurationHelper } from '../../utils/DevWorkspaceConfigurationHelper'; +import { DevfileContext } from '@eclipse-che/che-devworkspace-generator/lib/api/devfile-context'; +import { ShellString } from 'shelljs'; +import { expect } from 'chai'; +import { API_TEST_CONSTANTS } from '../../constants/API_TEST_CONSTANTS'; +import YAML from 'yaml'; +import { Logger } from '../../utils/Logger'; +import crypto from 'crypto'; + +suite('PHP devfile API test', function (): void { + const devfilesRegistryHelper: DevfilesHelper = e2eContainer.get(CLASSES.DevfilesRegistryHelper); + const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = e2eContainer.get( + CLASSES.KubernetesCommandLineToolsExecutor + ); + const devfileID: string = 'php'; + const containerTerminal: ContainerTerminal = e2eContainer.get(CLASSES.ContainerTerminal); + let devWorkspaceConfigurationHelper: DevWorkspaceConfigurationHelper; + let devfileContext: DevfileContext; + let devfileContent: string = ''; + + suiteSetup(`Prepare login ${BASE_TEST_CONSTANTS.TEST_ENVIRONMENT}`, function (): void { + kubernetesCommandLineToolsExecutor.loginToOcp(); + }); + + test(`Create ${devfileID} workspace`, async function (): Promise { + const randomPref: string = crypto.randomBytes(4).toString('hex'); + kubernetesCommandLineToolsExecutor.namespace = API_TEST_CONSTANTS.TS_API_TEST_NAMESPACE || 'admin-devspaces'; + devfileContent = devfilesRegistryHelper.getDevfileContent(devfileID); + const editorDevfileContent: string = devfilesRegistryHelper.obtainCheDevFileEditorFromCheConfigMap('editors-definitions'); + const uniqName: string = YAML.parse(devfileContent).metadata.name + randomPref; + kubernetesCommandLineToolsExecutor.workspaceName = uniqName; + + devWorkspaceConfigurationHelper = new DevWorkspaceConfigurationHelper({ + editorContent: editorDevfileContent, + devfileContent: devfileContent + }); + devfileContext = await devWorkspaceConfigurationHelper.generateDevfileContext(); + if (devfileContext.devWorkspace.metadata) { + devfileContext.devWorkspace.metadata.name = uniqName; + } + const devWorkspaceConfigurationYamlString: string = + devWorkspaceConfigurationHelper.getDevWorkspaceConfigurationYamlAsString(devfileContext); + const output: ShellString = kubernetesCommandLineToolsExecutor.applyAndWaitDevWorkspace(devWorkspaceConfigurationYamlString); + expect(output.stdout).contains('condition met'); + }); + + test('Check running application', function (): void { + const workdir: string = YAML.parse(devfileContent).commands[0].exec.workingDir; + const commandLine: string = YAML.parse(devfileContent).commands[0].exec.commandLine; + const containerName: string = YAML.parse(devfileContent).commands[0].exec.component; + Logger.info(`workdir from exec section of DevWorkspace file: ${workdir}`); + Logger.info(`commandLine from exec section of DevWorkspace file: ${commandLine}`); + const runCommandInBash: string = `cd ${workdir} && ${commandLine}`; + const output: ShellString = containerTerminal.execInContainerCommand(runCommandInBash, containerName); + expect(output.code).eqls(0); + expect(output.stdout.trim()).contains('Hello, world!'); + }); + + suiteTeardown('Delete workspace', function (): void { + kubernetesCommandLineToolsExecutor.deleteDevWorkspace(); + }); +}); diff --git a/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts b/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts index c2289ebd5ba..e75248bd784 100644 --- a/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts +++ b/tests/e2e/utils/DevWorkspaceConfigurationHelper.ts @@ -20,6 +20,7 @@ import { IContextParams } from './IContextParams'; import { e2eContainer } from '../configs/inversify.config'; import { CLASSES, EXTERNAL_CLASSES } from '../configs/inversify.types'; import getDecorators from 'inversify-inject-decorators'; +import {DevfilesHelper} from "./DevfilesHelper"; const { lazyInject } = getDecorators(e2eContainer); @@ -98,6 +99,7 @@ export class DevWorkspaceConfigurationHelper { return content; } + patchDevWorkspaceConfigWithBuildContainerAttribute(devfileContextDevWorkspace: any): void { Logger.debug(); devfileContextDevWorkspace.spec.template.attributes = YAML.parse(` diff --git a/tests/e2e/utils/DevfilesRegistryHelper.ts b/tests/e2e/utils/DevfilesHelper.ts similarity index 55% rename from tests/e2e/utils/DevfilesRegistryHelper.ts rename to tests/e2e/utils/DevfilesHelper.ts index 74834be0c1d..0edccaf2251 100644 --- a/tests/e2e/utils/DevfilesRegistryHelper.ts +++ b/tests/e2e/utils/DevfilesHelper.ts @@ -13,9 +13,76 @@ import YAML from 'yaml'; import { API_TEST_CONSTANTS, SUPPORTED_DEVFILE_REGISTRIES } from '../constants/API_TEST_CONSTANTS'; import { injectable } from 'inversify'; import { BASE_TEST_CONSTANTS, Platform } from '../constants/BASE_TEST_CONSTANTS'; +import { ShellExecutor } from './ShellExecutor'; +import { e2eContainer } from '../configs/inversify.config'; +import { CLASSES } from '../configs/inversify.types'; @injectable() -export class DevfilesRegistryHelper { +export class DevfilesHelper { + public getInternalClusterURLToDevFile(devFileName: string): string { + const devfileSampleURIPrefix: string = `/dashboard/api/airgap-sample/devfile/download?id=${devFileName}`; + let serviceClusterIp: string = ''; + let servicePort: string = ''; + serviceClusterIp = this.getShellExecutor().executeArbitraryShellScript( + `oc get svc devspaces-dashboard -n ${BASE_TEST_CONSTANTS.TS_PLATFORM}-${BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME()} -o=jsonpath='{.spec.clusterIP}'` + ); + servicePort = this.getShellExecutor().executeArbitraryShellScript( + `oc get svc devspaces-dashboard -n ${BASE_TEST_CONSTANTS.TS_PLATFORM}-${BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME()} -o=jsonpath='{.spec.ports[*].port}'` + ); + return `http://${serviceClusterIp}:${servicePort}${devfileSampleURIPrefix}`; + } + + /** + * grab devfile content from the Dashboard pod (currently, in the image of dashboard builds with devfile content and we use it for getting devfile description) + * @param podName + * @param containerName + * @param devFileName + */ + public obtainDevFileContentUsingPod(podName: string, containerName: string, devFileName: string): string { + const clusterURL: string = this.getInternalClusterURLToDevFile(devFileName); + this.getShellExecutor().executeCommand( + `oc exec -i ${podName} -n ${BASE_TEST_CONSTANTS.TS_PLATFORM}-${BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME()} -c ${containerName} -- sh -c 'curl -o /tmp/${devFileName}-devfile.yaml ${clusterURL}'` + ); + return this.getShellExecutor() + .executeArbitraryShellScript( + `oc exec -i ${podName} -n ${BASE_TEST_CONSTANTS.TS_PLATFORM}-${BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME()} -c ${containerName} -- cat /tmp/${devFileName}-devfile.yaml` + ) + .toString(); + } + + /** + * grab devfile content from the Che config map + * @param configMapName + */ + public obtainCheDevFileEditorFromCheConfigMap(configMapName: string): string { + return this.getShellExecutor().executeCommand( + `oc get configmap ${configMapName} -o jsonpath="{.data.che-code\\.yaml}" -n ${BASE_TEST_CONSTANTS.TS_PLATFORM}-${BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME()}` + ); + } + + /** + * find the Dashboard pod and container name and grab devfile content from it + * @param devSample + */ + public getDevfileContent(devSample: string): string { + const command: string = `oc get pods -n ${BASE_TEST_CONSTANTS.TS_PLATFORM}-${BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME()}`; + console.log(`command: ${command}`); + const podName: string = this.getShellExecutor() + .executeArbitraryShellScript( + `oc get pods -n ${BASE_TEST_CONSTANTS.TS_PLATFORM}-${BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME()} | grep dashboard | awk \'{print $1}\'` + ) + .trim(); + const containerName: string = this.getShellExecutor().executeArbitraryShellScript( + `oc get pod -n ${BASE_TEST_CONSTANTS.TS_PLATFORM}-${BASE_TEST_CONSTANTS.TESTING_APPLICATION_NAME()} ${podName} -o jsonpath=\'{.spec.containers[*].name}\'` + ); + const devfileContent: string = this.obtainDevFileContentUsingPod(podName, containerName, devSample); + return devfileContent; + } + + /** + * @deprecated applicable only for inbuilt devfiles + * @param sampleNamePatterns + */ async getInbuiltDevfilesRegistryContent(sampleNamePatterns?: string[]): Promise { Logger.trace(); @@ -35,6 +102,12 @@ export class DevfilesRegistryHelper { return await this.getContent(url); } + /** + * + * @deprecated applicable only for inbuilt devfiles + * @param isInbuilt + * @param sampleNamePatterns + */ async collectPathsToDevfilesFromRegistry(isInbuilt: boolean, sampleNamePatterns?: string[]): Promise { Logger.debug(); @@ -86,10 +159,6 @@ export class DevfilesRegistryHelper { return devfileSamples; } - async getEditorContent(entry: string): Promise { - return await this.getContent(`${BASE_TEST_CONSTANTS.TS_SELENIUM_BASE_URL}/${entry}`); - } - private filterSamples(sampleNamePatterns: string[] | undefined, content: any): Promise { if (sampleNamePatterns) { const commonSampleNamePattern: RegExp = new RegExp(sampleNamePatterns.join('|'), 'i'); @@ -97,7 +166,9 @@ export class DevfilesRegistryHelper { } return content; } - + private getShellExecutor(): ShellExecutor { + return e2eContainer.get(CLASSES.ShellExecutor); + } // eslint-disable-next-line @typescript-eslint/no-unused-vars private async getContent(url: string, headers?: object): Promise { Logger.trace(`${url}`);