-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: Add Che update e2e test #1117
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# | ||
# Copyright (c) 2021 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 | ||
# | ||
# Contributors: | ||
# Red Hat, Inc. - initial API and implementation | ||
name: Minikube E2E | ||
on: pull_request | ||
jobs: | ||
minikube-e2e-update: | ||
name: e2e update tests | ||
runs-on: ubuntu-20.04 | ||
steps: | ||
- uses: actions/checkout@v1 | ||
- name: Provision minikube cluster | ||
run: | | ||
minikube start --memory=6000 | ||
minikube addons enable ingress | ||
- name: Install chectl dependencies | ||
run: yarn | ||
- name: Run e2e update tests minikube | ||
run: | | ||
export PLATFORM=minikube | ||
export INSTALLER=operator | ||
yarn test --coverage=false --forceExit --testRegex=test/e2e/e2e-upgrade.test.ts |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/********************************************************************* | ||
* Copyright (c) 2021 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 | ||
**********************************************************************/ | ||
|
||
// tslint:disable: no-console | ||
|
||
import { expect } from '@oclif/test' | ||
|
||
import { CheGithubClient } from '../../src/api/github-client' | ||
import { isKubernetesPlatformFamily } from '../../src/util' | ||
|
||
import { DEVFILE_URL, E2eHelper, NAMESPACE, NIGHTLY } from './util' | ||
|
||
const helper = new E2eHelper() | ||
jest.setTimeout(1000000) | ||
|
||
const binChectl = `${process.cwd()}/bin/run` | ||
|
||
const PLATFORM = process.env.PLATFORM || 'minikube' | ||
|
||
const INSTALLER = 'operator' | ||
|
||
const UPDATE_CHE_TIMEOUT_MS = 5 * 60 * 1000 | ||
const WORKSPACE_START_TIMEOUT_MS = 5 * 60 * 1000 | ||
const CHE_VERSION_TIMEOUT_MS = 50 * 1000 | ||
|
||
describe('Test Che upgrade', () => { | ||
let cheVersion: string | ||
|
||
describe('Prepare latest stable Che', () => { | ||
it(`Deploy Che using ${INSTALLER} installer and self signed certificates`, async () => { | ||
// Retrieve latest stable Che version | ||
const githubClient = new CheGithubClient() | ||
const latestStableCheTag = (await githubClient.getTemplatesTagInfo(INSTALLER, 'latest'))! | ||
cheVersion = latestStableCheTag.name | ||
|
||
const deployCommand = `${binChectl} server:deploy --platform=${PLATFORM} --installer=${INSTALLER} --version=${cheVersion} --chenamespace=${NAMESPACE} --telemetry=off --che-operator-cr-patch-yaml=test/e2e/resources/cr-patch.yaml` | ||
await helper.runCliCommand(deployCommand) | ||
|
||
await helper.waitForVersionInCheCR(cheVersion, CHE_VERSION_TIMEOUT_MS) | ||
}) | ||
|
||
it('Prepare test workspace', async () => { | ||
await runLoginTest() | ||
|
||
// Create | ||
await helper.runCliCommand(binChectl, ['workspace:create', `--devfile=${DEVFILE_URL}`, '--telemetry=off', `-n ${NAMESPACE}`]) | ||
const workspaceId = await helper.getWorkspaceId() | ||
|
||
// Start | ||
await helper.runCliCommand(binChectl, ['workspace:start', workspaceId, `-n ${NAMESPACE}`, '--telemetry=off']) | ||
await helper.waitWorkspaceStatus('RUNNING', WORKSPACE_START_TIMEOUT_MS) | ||
|
||
// Stop | ||
await helper.runCliCommand(binChectl, ['workspace:stop', workspaceId, `-n ${NAMESPACE}`, '--telemetry=off']) | ||
const workspaceStatus = await helper.getWorkspaceStatus() | ||
// The status could be STOPPING or STOPPED | ||
expect(workspaceStatus).to.contain('STOP') | ||
}) | ||
}) | ||
|
||
describe('Test Che update', () => { | ||
it('Update Che to nightly version', async () => { | ||
await helper.runCliCommand(binChectl, ['server:update', '-y', `-n ${NAMESPACE}`, '--telemetry=off']) | ||
await helper.waitForCheServerImageTag(NIGHTLY, UPDATE_CHE_TIMEOUT_MS) | ||
}) | ||
|
||
it('Check updated Che version', async () => { | ||
await helper.waitForVersionInCheCR(NIGHTLY, CHE_VERSION_TIMEOUT_MS) | ||
}) | ||
}) | ||
|
||
describe('Test updated Che', () => { | ||
it('Start existing workspace after update', async () => { | ||
// Relogin | ||
await runLoginTest() | ||
|
||
const workspaceId = await helper.getWorkspaceId() | ||
await helper.runCliCommand(binChectl, ['workspace:start', workspaceId, `-n ${NAMESPACE}`, '--telemetry=off']) | ||
await helper.waitWorkspaceStatus('RUNNING', WORKSPACE_START_TIMEOUT_MS) | ||
}) | ||
}) | ||
|
||
describe('Test Che downgrade', () => { | ||
it('Downgrade Che', async () => { | ||
await helper.runCliCommand(binChectl, ['server:update', '-y', `--version=${cheVersion}`, `-n ${NAMESPACE}`, '--telemetry=off']) | ||
await helper.waitForCheServerImageTag(cheVersion, UPDATE_CHE_TIMEOUT_MS) | ||
}) | ||
|
||
it('Check downgraded Che version', async () => { | ||
await helper.waitForVersionInCheCR(cheVersion, CHE_VERSION_TIMEOUT_MS) | ||
}) | ||
}) | ||
|
||
}) | ||
|
||
async function runLoginTest() { | ||
let cheApiEndpoint: string | ||
if (isKubernetesPlatformFamily(PLATFORM)) { | ||
cheApiEndpoint = await helper.K8SHostname('che', NAMESPACE) + '/api' | ||
} else { | ||
cheApiEndpoint = await helper.OCHostname('che', NAMESPACE) + '/api' | ||
} | ||
|
||
const stdout = await helper.runCliCommand(binChectl, ['auth:login', cheApiEndpoint, '-u', 'admin', '-p', 'admin', '-n', `${NAMESPACE}`, '--telemetry=off']) | ||
expect(stdout).to.contain('Successfully logged into') | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,11 @@ interface WorkspaceInfo { | |
|
||
const binChectl = `${process.cwd()}/bin/run` | ||
|
||
export const DEVFILE_URL = 'https://raw.githubusercontent.com/eclipse/che-devfile-registry/master/devfiles/quarkus/devfile.yaml' | ||
|
||
export const NAMESPACE = 'eclipse-che' | ||
export const NIGHTLY = 'nightly' | ||
|
||
//Utilities to help e2e tests | ||
export class E2eHelper { | ||
protected kubeHelper: KubeHelper | ||
|
@@ -40,6 +45,28 @@ export class E2eHelper { | |
this.oc = new OpenShiftHelper() | ||
} | ||
|
||
async runCliCommand(command: string, args?: string[], printOutput = true): Promise<string> { | ||
if (printOutput) { | ||
// tslint:disable-next-line: no-console | ||
console.log(`Running command: ${command} ${args ? args.join(' ') : ''}`) | ||
} | ||
|
||
const { exitCode, stdout, stderr } = await execa(command, args, { shell: true }) | ||
|
||
if (printOutput) { | ||
// tslint:disable-next-line: no-console | ||
console.log(stdout) | ||
if (exitCode !== 0) { | ||
// tslint:disable-next-line: no-console | ||
console.log(stderr) | ||
} | ||
} | ||
|
||
expect(exitCode).toEqual(0) | ||
|
||
return stdout | ||
} | ||
|
||
// Return an array with all user workspaces | ||
// async getAllWorkspaces(isOpenshiftPlatformFamily: string): Promise<chetypes.workspace.Workspace[]> { | ||
private async getAllWorkspaces(): Promise<WorkspaceInfo[]> { | ||
|
@@ -85,6 +112,20 @@ export class E2eHelper { | |
return workspaceStatus | ||
} | ||
|
||
async waitWorkspaceStatus(status: string, timeoutMs: number): Promise<boolean> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Usually There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea is to wait for an event and then decide what to do: fail or continue. But maybe it is not needed for tests... |
||
const delayMs = 1000 * 5 | ||
|
||
let totalTimeMs = 0 | ||
while (totalTimeMs < timeoutMs) { | ||
if (await this.getWorkspaceStatus() === status) { | ||
return true | ||
} | ||
await this.sleep(delayMs) | ||
totalTimeMs += delayMs | ||
} | ||
return false | ||
} | ||
|
||
//Return a route from Openshift adding protocol | ||
async OCHostname(ingressName: string, namespace: string): Promise<string> { | ||
if (await this.oc.routeExist(ingressName, namespace)) { | ||
|
@@ -112,4 +153,40 @@ export class E2eHelper { | |
// tslint:disable-next-line no-string-based-set-timeout | ||
return new Promise(resolve => setTimeout(resolve, ms)) | ||
} | ||
|
||
async waitForVersionInCheCR(version: string, timeoutMs: number): Promise<void> { | ||
const delayMs = 5 * 1000 | ||
|
||
let totalTimeMs = 0 | ||
while (totalTimeMs < timeoutMs) { | ||
const cheCR = await this.kubeHelper.getCheCluster(NAMESPACE) | ||
if (cheCR && cheCR.status && cheCR.status.cheVersion === version) { | ||
return | ||
} | ||
await this.sleep(delayMs) | ||
totalTimeMs += delayMs | ||
} | ||
throw new Error(`Che CR version ${version} has not appeared in ${timeoutMs / 1000}s`) | ||
} | ||
|
||
async waitForCheServerImageTag(tag: string, timeoutMs: number): Promise<void> { | ||
const delayMs = 5 * 1000 | ||
const chePodNameRegExp = new RegExp('che-[0-9a-f]+-.*') | ||
|
||
let totalTimeMs = 0 | ||
while (totalTimeMs < timeoutMs) { | ||
const pods = (await this.kubeHelper.listNamespacedPod(NAMESPACE)).items | ||
const pod = pods.find((pod => pod.metadata && pod.metadata.name && pod.metadata.name.match(chePodNameRegExp))) | ||
if (pod && pod.status && pod.status.containerStatuses && pod.status.containerStatuses[0].image) { | ||
const imageTag = pod.status.containerStatuses[0].image.split(':')[1] | ||
if (imageTag === tag) { | ||
return | ||
} | ||
} | ||
await this.sleep(delayMs) | ||
totalTimeMs += delayMs | ||
} | ||
throw new Error(`Che server image tag ${tag} has not appeared in ${timeoutMs / 1000}s `) | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should check that workspace starts after downgrade.... But up to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use-case in the tests, at least my thoughts about it, is that downgrade is used if a user have completed upgrade, but something stopped to work due to a bug, but the user need the feature, so a step back is taken temporally and right after upgrade... So no need in such check.
If a used needs specific version of Che, it is possible to install it via
version
flag, no need to downgrade.