Skip to content

Commit

Permalink
feat: PR check GitHub Action
Browse files Browse the repository at this point in the history
Signed-off-by: mdolhalo <[email protected]>
  • Loading branch information
mdolhalo committed Jul 21, 2023
1 parent 8b1c67c commit d5e4a86
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 86 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/contributing-repositories-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#

# Eclipse Che workflow for checking repository list in CONTRIBUTING.md file
name: CI
name: Check repository list in CONTRIBUTING.md file

# Trigger the workflow on push or pull request
on:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/next-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# SPDX-License-Identifier: EPL-2.0
#

name: build-next
name: Build and push Next Che E2E image to quai.io

on:
workflow_dispatch:
Expand Down
169 changes: 169 additions & 0 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#
# Copyright (c) 2021-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
#

name: Empty Workspace test suite on minikube

# Trigger the workflow on pull request
on:
workflow_dispatch:
pull_request:
branches:
- main
- 7.**.x
paths:
- 'tests/e2e/**'
- '.github/workflows/pr-check.yml'
env:
LOCAL_TEST_DIR: /tmp

jobs:
pr-check:
runs-on: ubuntu-22.04

steps:
- name: Git checkout
uses: actions/checkout@v2

- name: Branch name
run: |
echo running on PR ${GITHUB_REF}, branch - ${GITHUB_HEAD_REF}
echo "pr_number=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')" >> "$GITHUB_ENV"
- name: Configuring nodejs 16.x version
uses: actions/setup-node@v3
with:
node-version: '16'

- name: Pull Che-Code Docker image
run: |
#
# pull che-code:latest docker image
#
docker pull quay.io/che-incubator/che-code:latest
- name: Start minikube
id: run-minikube
uses: che-incubator/setup-minikube-action@next
with:
minikube-version: v1.23.2

- name: Install chectl
run: bash <(curl -sL https://www.eclipse.org/che/chectl/) --channel=next

- name: Deploy Che
run: |
#
# load Che-Code image into minikube
#
minikube image load quay.io/che-incubator/che-code:latest
minikube image list
# get patch file to set up resources
wget https://raw.githubusercontent.com/che-incubator/che-code/main/build/test/github-minikube-checluster-patch.yaml -P /tmp
#
# deploy Che
#
chectl server:deploy \
--batch \
--platform minikube \
--k8spodwaittimeout=120000 \
--k8spodreadytimeout=120000 \
--che-operator-cr-patch-yaml "/tmp/github-minikube-checluster-patch.yaml"
#
# apply patch
#
kubectl patch devworkspaceoperatorconfigs \
-n eclipse-che devworkspace-config \
--patch '{"config": {"workspace": {"imagePullPolicy": "IfNotPresent"}}}' \
--type merge
- name: Pull Universal Base Image
run: |
minikube image pull quay.io/devfile/universal-developer-image:ubi8-latest
- name: Run Empty Workspace API test
run: |
cd tests/e2e
npm ci
export TS_PLATFORM=kubernetes &&
export TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL=kubectl &&
export TS_SELENIUM_VALUE_OPENSHIFT_OAUTH=false &&
export TS_SELENIUM_BASE_URL=https://$(kubectl get ingress che -n eclipse-che -o jsonpath='{.spec.rules[0].host}') &&
export NODE_TLS_REJECT_UNAUTHORIZED=0 &&
export TS_SELENIUM_LOG_LEVEL=TRACE &&
export TS_SELENIUM_DEFAULT_ATTEMPTS=2 &&
export USERSTORY=EmptyWorkspaceAPI &&
export TS_API_TEST_UDI_IMAGE=quay.io/devfile/universal-developer-image:ubi8-latest &&
npm run driver-less-test
- name: Build E2E test docker image
run: |
set -xe
cd tests/e2e
docker build -t quay.io/eclipse/che-e2e:"${{ env.pr_number }}" -f build/dockerfiles/Dockerfile .
- name: Run Empty Workspace UI test from che-e2e container
run: |
docker run \
--shm-size=2048m \
-p 5920:5920 \
--network="host" \
-e TS_PLATFORM=kubernetes \
-e TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL=kubectl \
-e [email protected] \
-e TS_SELENIUM_K8S_PASSWORD=admin \
-e TS_SELENIUM_VALUE_OPENSHIFT_OAUTH=false \
-e TS_SELENIUM_BASE_URL=https://$(kubectl get ingress che -n eclipse-che -o jsonpath='{.spec.rules[0].host}') \
-e TS_SELENIUM_LOAD_PAGE_TIMEOUT=60000 \
-e TS_SELENIUM_START_WORKSPACE_TIMEOUT=120000 \
-e TS_COMMON_DASHBOARD_WAIT_TIMEOUT=30000 \
-e NODE_TLS_REJECT_UNAUTHORIZED=0 \
-e DELETE_WORKSPACE_ON_FAILED_TEST=true \
-e VIDEO_RECORDING=true \
-e TS_SELENIUM_LOG_LEVEL=TRACE \
-e TS_SELENIUM_DEFAULT_ATTEMPTS=2 \
-v ${LOCAL_TEST_DIR}/tests/e2e/report:/tmp/e2e/report:Z \
-v ${LOCAL_TEST_DIR}/tests/e2e/video:/tmp/ffmpeg_report:Z \
-e TEST_SUITE=test \
-e USERSTORY=EmptyWorkspace \
quay.io/eclipse/che-e2e:"${{ env.pr_number }}"
- name: Bump logs
if: always()
run: |
NS=admin-che
TARGET_DIR="/tmp/pr-check-artifacts/${NS}-info"
mkdir -p "$TARGET_DIR"
for POD in $(kubectl get pods -o name -n ${NS}); do
for CONTAINER in $(kubectl get -n ${NS} ${POD} -o jsonpath="{.spec.containers[*].name}"); do
echo "[INFO] Downloading logs $POD/$CONTAINER in $NS"
# container name includes `pod/` prefix. remove it
LOGS_FILE=$TARGET_DIR/$(echo ${POD}-${CONTAINER}.log | sed 's|pod/||g')
kubectl logs ${POD} -c ${CONTAINER} -n ${NS} > $LOGS_FILE || true
done
done
echo "[INFO] Bumping events in namespace ${NS}"
kubectl get events -n $NS > $TARGET_DIR/events.log || true
- name: Store e2e artifacts
if: always()
uses: actions/upload-artifact@v3
with:
name: e2e-artifacts
path: /tmp/tests

- name: Store k8s logs
if: always()
uses: actions/upload-artifact@v3
with:
name: k8s-logs
path: /tmp/pr-check-artifacts/admin-che-info
2 changes: 1 addition & 1 deletion .github/workflows/typescript-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# SPDX-License-Identifier: EPL-2.0
#

name: typescript-publish-next
name: Publish Next Che E2E Tests to npmjs

on:
workflow_dispatch:
Expand Down
62 changes: 17 additions & 45 deletions tests/e2e/pageobjects/dashboard/Dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,17 @@ import { DriverHelper } from '../../utils/DriverHelper';
import { TimeoutConstants } from '../../constants/TimeoutConstants';
import { Workspaces } from './Workspaces';
import { Logger } from '../../utils/Logger';
import { OAuthConstants } from '../../constants/OAuthConstants';
import { BaseTestConstants } from '../../constants/BaseTestConstants';

@injectable()
export class Dashboard {
private static readonly WORKSPACES_BUTTON_XPATH: string = `//div[@id='page-sidebar']//a[contains(text(), 'Workspaces (')]`;
private static readonly CREATE_WORKSPACE_BUTTON_XPATH: string = `//div[@id='page-sidebar']//a[text()='Create Workspace']`;
private static readonly LOADER_PAGE_STEP_TITLES_XPATH: string = '//*[@data-testid="step-title"]';
private static readonly STARTING_PAGE_LOADER_CSS: string = '.main-page-loader';
private static readonly LOADER_ALERT_XPATH: string = '//*[@data-testid="loader-alert"]';
private static readonly LOGOUT_BUTTON_XPATH: string = '//button[text()="Logout"]';

private static getUserDropdownMenuButtonLocator(): By {
Logger.debug(`Dashboard.getUserDropdownMenuButtonLocator: get current user.`);

const currentUser: string = OAuthConstants.TS_SELENIUM_OCP_USERNAME;
Logger.debug(`Dashboard.getUserDropdownMenuButtonLocator: ${currentUser}.`);

return By.xpath(`//*[text()="${currentUser}"]//parent::button`);

}
private static readonly WORKSPACES_BUTTON: By = By.xpath(`//div[@id='page-sidebar']//a[contains(text(), 'Workspaces (')]`);
private static readonly CREATE_WORKSPACE_BUTTON: By = By.xpath(`//div[@id='page-sidebar']//a[text()='Create Workspace']`);
private static readonly LOADER_PAGE_STEP_TITLES: By = By.xpath('//*[@data-testid="step-title"]');
private static readonly STARTING_PAGE_LOADER: By = By.css('.main-page-loader');
private static readonly LOADER_ALERT: By = By.xpath('//*[@data-testid="loader-alert"]');
private static readonly LOGOUT_BUTTON: By = By.xpath('//button[text()="Logout"]');
private static readonly USER_SETTINGS_DROPDOWN: By = By.xpath('//header//button/span[text()!=\'\']//parent::button');

constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper,
@inject(CLASSES.Workspaces) private readonly workspaces: Workspaces) {
Expand Down Expand Up @@ -82,65 +72,47 @@ export class Dashboard {
async waitPage(timeout: number = TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT): Promise<void> {
Logger.debug('Dashboard.waitPage');

await this.driverHelper.waitVisibility(By.xpath(Dashboard.WORKSPACES_BUTTON_XPATH), timeout);
await this.driverHelper.waitVisibility(By.xpath(Dashboard.CREATE_WORKSPACE_BUTTON_XPATH), timeout);
await this.driverHelper.waitVisibility(Dashboard.WORKSPACES_BUTTON, timeout);
await this.driverHelper.waitVisibility(Dashboard.CREATE_WORKSPACE_BUTTON, timeout);
}

async clickWorkspacesButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise<void> {
Logger.debug('Dashboard.clickWorkspacesButton');

await this.driverHelper.waitAndClick(By.xpath(Dashboard.WORKSPACES_BUTTON_XPATH), timeout);
await this.driverHelper.waitAndClick(Dashboard.WORKSPACES_BUTTON, timeout);
}

async clickCreateWorkspaceButton(timeout: number = TimeoutConstants.TS_CLICK_DASHBOARD_ITEM_TIMEOUT): Promise<void> {
Logger.debug('Dashboard.clickCreateWorkspaceButton');

await this.driverHelper.waitAndClick(By.xpath(Dashboard.CREATE_WORKSPACE_BUTTON_XPATH), timeout);
await this.driverHelper.waitAndClick(Dashboard.CREATE_WORKSPACE_BUTTON, timeout);
}

async getLoaderAlert(timeout: number = TimeoutConstants.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise<string> {
Logger.debug('Dashboard.getLoaderAlert');

return await this.driverHelper.waitAndGetText(By.xpath(Dashboard.LOADER_ALERT_XPATH), timeout);
return await this.driverHelper.waitAndGetText(Dashboard.LOADER_ALERT, timeout);
}

async waitLoader(timeout: number = TimeoutConstants.TS_WAIT_LOADER_PRESENCE_TIMEOUT): Promise<void> {
Logger.debug('Dashboard.waitLoader');

await this.driverHelper.waitAllPresence(By.xpath(Dashboard.LOADER_PAGE_STEP_TITLES_XPATH), timeout);
}

async waitLoaderDisappearance(timeout: number = TimeoutConstants.TS_WAIT_LOADER_ABSENCE_TIMEOUT): Promise<void> {
Logger.debug('Dashboard.waitLoaderDisappearance');

await this.driverHelper.waitDisappearance(By.xpath(Dashboard.LOADER_PAGE_STEP_TITLES_XPATH), timeout);
}

async waitDisappearanceNavigationMenu(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise<void> {
Logger.debug('Dashboard.waitDisappearanceNavigationMenu');

await this.driverHelper.waitDisappearance(By.id('chenavmenu'), timeout);
await this.driverHelper.waitAllPresence(Dashboard.LOADER_PAGE_STEP_TITLES, timeout);
}

async waitStartingPageLoaderDisappearance(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise<void> {
Logger.debug(`Dashboard.waitStartingPageLoaderDisappearance`);

await this.driverHelper.waitDisappearance(By.css(Dashboard.STARTING_PAGE_LOADER_CSS), timeout);
await this.driverHelper.waitDisappearance(Dashboard.STARTING_PAGE_LOADER, timeout);
await this.driverHelper.wait(TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING);
}

async getRecentWorkspaceName(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise<string> {
Logger.debug(`Dashboard.getRecentWorkspaceName`);

return await this.driverHelper.waitAndGetText(By.css('[data-testid="recent-workspace-item"]'), timeout);
}

async logout(timeout: number = TimeoutConstants.TS_COMMON_DASHBOARD_WAIT_TIMEOUT): Promise<void> {
Logger.debug(`Dashboard.logout`);

await this.openDashboard();
await this.driverHelper.waitAndClick(Dashboard.getUserDropdownMenuButtonLocator(), timeout);
await this.driverHelper.waitAndClick(By.xpath(Dashboard.LOGOUT_BUTTON_XPATH), timeout);
await this.driverHelper.waitDisappearance(Dashboard.getUserDropdownMenuButtonLocator(), timeout);
await this.driverHelper.waitAndClick(Dashboard.USER_SETTINGS_DROPDOWN, timeout);
await this.driverHelper.waitAndClick(Dashboard.LOGOUT_BUTTON, timeout);
await this.driverHelper.waitDisappearance(Dashboard.USER_SETTINGS_DROPDOWN, timeout);
}
}
26 changes: 17 additions & 9 deletions tests/e2e/specs/SmokeTest.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
import { SideBarView, ViewSection } from 'monaco-page-objects';
import { SideBarView, ViewItem, ViewSection } from 'monaco-page-objects';
import { ProjectAndFileTests } from '../tests-library/ProjectAndFileTests';
import { CLASSES } from '../configs/inversify.types';
import { e2eContainer } from '../configs/inversify.config';
Expand All @@ -17,14 +17,17 @@ import { Logger } from '../utils/Logger';
import { LoginTests } from '../tests-library/LoginTests';
import { StringUtil } from '../utils/StringUtil';
import { FactoryTestConstants } from '../constants/FactoryTestConstants';
import { BrowserTabsUtil } from '../utils/BrowserTabsUtil';
import { expect } from 'chai';
import { BaseTestConstants } from '../constants/BaseTestConstants';

const factoryUrl: string = FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL || 'https://github.com/che-incubator/quarkus-api-example.git';
const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests);
const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests);
const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests);
let projectName: string;
const browserTabsUtil: BrowserTabsUtil = e2eContainer.get(CLASSES.BrowserTabsUtil);

suite(`The SmokeTest userstory`, async function (): Promise<void> {
const factoryUrl: string = FactoryTestConstants.TS_SELENIUM_FACTORY_GIT_REPO_URL || 'https://github.com/che-incubator/quarkus-api-example.git';
let projectSection: ViewSection;
suite(`Create workspace from factory:${factoryUrl}`, async function (): Promise<void> {
loginTests.loginIntoChe();
Expand All @@ -37,17 +40,22 @@ suite(`The SmokeTest userstory`, async function (): Promise<void> {
await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor();
});
test('Check a project folder has been created', async function (): Promise<void> {
projectName = StringUtil.getProjectNameFromGitUrl(factoryUrl);
const projectName: string = StringUtil.getProjectNameFromGitUrl(factoryUrl);
projectSection = await new SideBarView().getContent().getSection(projectName);
Logger.debug(`new SideBarView().getContent().getSection: get ${projectName}`);
});
test('Check the project files was imported', async function (): Promise<void> {
const label: string = 'devfile.yaml';
await projectSection.findItem(label);
Logger.debug(`projectSection.findItem: find ${label}`);
Logger.debug(`projectSection.findItem: find ${BaseTestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME}`);
const isFileImported: ViewItem | undefined = await projectSection.findItem(BaseTestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME);
expect(isFileImported).not.eqls(undefined);
});
test('Stopping and deleting the workspace', async function (): Promise<void> {
await workspaceHandlingTests.stopAndRemoveWorkspace(WorkspaceHandlingTests.getWorkspaceName());
test('Stop the workspace', async function (): Promise<void> {
await workspaceHandlingTests.stopWorkspace(WorkspaceHandlingTests.getWorkspaceName());
await browserTabsUtil.closeAllTabsExceptCurrent();
});
test('Delete the workspace', async function (): Promise<void> {
await workspaceHandlingTests.removeWorkspace(WorkspaceHandlingTests.getWorkspaceName());
});
loginTests.logoutFromChe();
});
});
Loading

0 comments on commit d5e4a86

Please sign in to comment.