mirror of
https://github.com/bitnami/charts.git
synced 2026-03-03 06:58:45 +08:00
[bitnami/jupyterhub] Add tests and publishing using VIB (#13432)
* [bitnami/jupyterhub] Add tests and publishing using VIB Signed-off-by: FraPazGal <fdepaz@vmware.com> * Remove unused params Signed-off-by: FraPazGal <fdepaz@vmware.com> * Update runtime_params Signed-off-by: FraPazGal <fdepaz@vmware.com> * Update runtime_params and add missing goss tests Signed-off-by: FraPazGal <fdepaz@vmware.com> * Remove unused runtime_param Signed-off-by: FraPazGal <fdepaz@vmware.com> * Update runtime_params per suggestion Signed-off-by: FraPazGal <fdepaz@vmware.com> Signed-off-by: FraPazGal <fdepaz@vmware.com>
This commit is contained in:
committed by
GitHub
parent
1bf577d013
commit
0b9b51a5ef
1
.github/workflows/cd-pipeline.yml
vendored
1
.github/workflows/cd-pipeline.yml
vendored
@@ -35,6 +35,7 @@ on: # rebuild any PRs and main branch changes
|
||||
- 'bitnami/jasperreports/**'
|
||||
- 'bitnami/jenkins/**'
|
||||
- 'bitnami/joomla/**'
|
||||
- 'bitnami/jupyterhub/**'
|
||||
- 'bitnami/kafka/**'
|
||||
- 'bitnami/keycloak/**'
|
||||
- 'bitnami/kibana/**'
|
||||
|
||||
8
.vib/jupyterhub/cypress/cypress.json
Normal file
8
.vib/jupyterhub/cypress/cypress.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"baseUrl": "http://localhost/",
|
||||
"defaultCommandTimeout": 30000,
|
||||
"env": {
|
||||
"username": "test_user",
|
||||
"password": "ComplicatedPassword123!4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "908534a5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Hello World!"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(\"Hello\" + \" World!\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "215c7ef4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/// <reference types="cypress" />
|
||||
import { random } from '../support/utils';
|
||||
|
||||
it('allows to upload and execute a python notebook', () => {
|
||||
const notebookName = `notebook_template_${random}.ipynb`;
|
||||
const userName = Cypress.env('username');
|
||||
|
||||
cy.login();
|
||||
cy.visit(`/user/${userName}/tree/tmp`);
|
||||
cy.contains('Upload').should('be.visible');
|
||||
cy.get('[type=file]').selectFile('cypress/fixtures/notebook_template.ipynb', {
|
||||
force: true,
|
||||
});
|
||||
cy.get('.filename_input').clear().type(notebookName);
|
||||
cy.contains('button', 'Upload').click();
|
||||
cy.contains('a', notebookName);
|
||||
|
||||
cy.visit(`/user/${userName}/notebooks/tmp/${notebookName}`);
|
||||
cy.contains('button', 'Run').click();
|
||||
cy.contains('Hello World!');
|
||||
});
|
||||
|
||||
it('allows generating an API token', () => {
|
||||
cy.login();
|
||||
cy.visit('/hub/token');
|
||||
// We need to wait until the background API request is finished
|
||||
cy.contains(/\d+Z/).should('not.exist');
|
||||
cy.contains('button', 'API token').click();
|
||||
cy.get('#token-result')
|
||||
.should('be.visible')
|
||||
.invoke('text')
|
||||
.then((apiToken) => {
|
||||
cy.request({
|
||||
url: '/hub/api/users',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `token ${apiToken}`,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.eq(200);
|
||||
expect(response.body[0].name).to.eq(Cypress.env('username'));
|
||||
});
|
||||
});
|
||||
});
|
||||
35
.vib/jupyterhub/cypress/cypress/support/commands.js
Normal file
35
.vib/jupyterhub/cypress/cypress/support/commands.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const COMMAND_DELAY = 2000;
|
||||
|
||||
for (const command of ['click']) {
|
||||
Cypress.Commands.overwrite(command, (originalFn, ...args) => {
|
||||
const origVal = originalFn(...args);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(origVal);
|
||||
}, COMMAND_DELAY);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add(
|
||||
'login',
|
||||
(username = Cypress.env('username'), password = Cypress.env('password')) => {
|
||||
cy.visit('/hub/login');
|
||||
cy.get('#username_input').type(username);
|
||||
cy.get('#password_input').type(password);
|
||||
cy.get('#login_submit').click();
|
||||
// The authentication is not completed until the page is rendered
|
||||
cy.contains('Launcher');
|
||||
}
|
||||
);
|
||||
|
||||
Cypress.on('uncaught:exception', (err, runnable) => {
|
||||
// we expect a 3rd party library error with message 'list not defined'
|
||||
// and don't want to fail the test so we return false
|
||||
if (err.message.includes('Cannot read properties of null')) {
|
||||
return false;
|
||||
}
|
||||
// we still want to ensure there are no other unexpected
|
||||
// errors, so we let them fail the test
|
||||
});
|
||||
20
.vib/jupyterhub/cypress/cypress/support/index.js
Normal file
20
.vib/jupyterhub/cypress/cypress/support/index.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
3
.vib/jupyterhub/cypress/cypress/support/utils.js
Normal file
3
.vib/jupyterhub/cypress/cypress/support/utils.js
Normal file
@@ -0,0 +1,3 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
export let random = (Math.random() + 1).toString(36).substring(7);
|
||||
39
.vib/jupyterhub/goss/goss.yaml
Normal file
39
.vib/jupyterhub/goss/goss.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
http:
|
||||
http://jupyterhub-hub:{{ .Vars.hub.service.ports.http }}/hub/health:
|
||||
status: 200
|
||||
http://jupyterhub-proxy-api:{{ .Vars.proxy.service.api.ports.http }}:
|
||||
status: 404
|
||||
file:
|
||||
/etc/jupyterhub:
|
||||
exists: true
|
||||
filetype: directory
|
||||
mode: "0755"
|
||||
owner: root
|
||||
/etc/jupyterhub/jupyterhub_config.py:
|
||||
exists: true
|
||||
filetype: file
|
||||
mode: "0644"
|
||||
owner: root
|
||||
contains:
|
||||
- /hub_container_port.*{{ .Vars.hub.containerPorts.http }}/
|
||||
/usr/local/etc/jupyterhub/secret/values.yaml:
|
||||
exists: true
|
||||
filetype: symlink
|
||||
mode: "0777"
|
||||
owner: root
|
||||
contains:
|
||||
- postgresql://{{ .Vars.postgresql.auth.username }}@jupyterhub-postgresql:{{ .Vars.postgresql.service.ports.postgresql }}/{{ .Vars.postgresql.auth.database }}
|
||||
- /uid.*{{ .Vars.singleuser.containerSecurityContext.runAsUser }}/
|
||||
- /fsGid.*{{ .Vars.singleuser.podSecurityContext.fsGroup }}/
|
||||
- /type.*dynamic/
|
||||
/var/run/secrets/kubernetes.io/serviceaccount:
|
||||
exists: {{ .Vars.hub.serviceAccount.automountServiceAccountToken }}
|
||||
filetype: directory
|
||||
mode: "3777"
|
||||
command:
|
||||
check-user-info:
|
||||
exec: id
|
||||
exit-status: 0
|
||||
stdout:
|
||||
- uid={{ .Vars.hub.containerSecurityContext.runAsUser }}
|
||||
- /groups=.*{{ .Vars.hub.podSecurityContext.fsGroup }}/
|
||||
29
.vib/jupyterhub/goss/vars.yaml
Normal file
29
.vib/jupyterhub/goss/vars.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
hub:
|
||||
containerPorts:
|
||||
http: 8082
|
||||
containerSecurityContext:
|
||||
runAsUser: 1002
|
||||
podSecurityContext:
|
||||
fsGroup: 1002
|
||||
serviceAccount:
|
||||
automountServiceAccountToken: true
|
||||
service:
|
||||
ports:
|
||||
http: 8082
|
||||
proxy:
|
||||
service:
|
||||
api:
|
||||
ports:
|
||||
http: 8000
|
||||
singleuser:
|
||||
containerSecurityContext:
|
||||
runAsUser: 1002
|
||||
podSecurityContext:
|
||||
fsGroup: 1002
|
||||
postgresql:
|
||||
auth:
|
||||
username: bn_vib_jupyterhub
|
||||
database: bitnami_vib_jupyterhub
|
||||
service:
|
||||
ports:
|
||||
postgresql: 5432
|
||||
@@ -16,6 +16,56 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"verify": {
|
||||
"context": {
|
||||
"resources": {
|
||||
"url": "{SHA_ARCHIVE}",
|
||||
"path": "/bitnami/jupyterhub"
|
||||
},
|
||||
"runtime_parameters": "aHViOgogIGJhc2VVcmw6IC8KICBhZG1pblVzZXI6IHRlc3RfdXNlcgogIHBhc3N3b3JkOiBDb21wbGljYXRlZFBhc3N3b3JkMTIzITQKICBjb250YWluZXJQb3J0czoKICAgIGh0dHA6IDgwODIKICBjb250YWluZXJTZWN1cml0eUNvbnRleHQ6CiAgICBlbmFibGVkOiB0cnVlCiAgICBydW5Bc1VzZXI6IDEwMDIKICBwb2RTZWN1cml0eUNvbnRleHQ6CiAgICBlbmFibGVkOiB0cnVlCiAgICBmc0dyb3VwOiAxMDAyCiAgc2VydmljZUFjY291bnQ6CiAgICBjcmVhdGU6IHRydWUKICAgIGF1dG9tb3VudFNlcnZpY2VBY2NvdW50VG9rZW46IHRydWUKICByYmFjOgogICAgY3JlYXRlOiB0cnVlCiAgc2VydmljZToKICAgIHBvcnRzOgogICAgICBodHRwOiA4MDgyCnByb3h5OgogIHNlcnZpY2U6CiAgICBhcGk6CiAgICAgIHBvcnRzOgogICAgICAgIGh0dHA6IDgwMDAKICAgIHB1YmxpYzoKICAgICAgdHlwZTogTG9hZEJhbGFuY2VyCiAgICAgIHBvcnRzOgogICAgICAgIGh0dHA6IDgwCmltYWdlUHVsbGVyOgogIGVuYWJsZWQ6IHRydWUKc2luZ2xldXNlcjoKICBjb250YWluZXJTZWN1cml0eUNvbnRleHQ6CiAgICBlbmFibGVkOiB0cnVlCiAgICBydW5Bc1VzZXI6IDEwMDIKICBwb2RTZWN1cml0eUNvbnRleHQ6CiAgICBlbmFibGVkOiB0cnVlCiAgICBmc0dyb3VwOiAxMDAyCiAgcGVyc2lzdGVuY2U6CiAgICBlbmFibGVkOiB0cnVlCnBvc3RncmVzcWw6CiAgZW5hYmxlZDogdHJ1ZQogIGF1dGg6CiAgICB1c2VybmFtZTogYm5fdmliX2p1cHl0ZXJodWIKICAgIGRhdGFiYXNlOiBiaXRuYW1pX3ZpYl9qdXB5dGVyaHViCiAgc2VydmljZToKICAgIHBvcnRzOgogICAgICBwb3N0Z3Jlc3FsOiA1NDMy",
|
||||
"target_platform": {
|
||||
"target_platform_id": "{VIB_ENV_TARGET_PLATFORM}",
|
||||
"size": {
|
||||
"name": "S4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"action_id": "health-check",
|
||||
"params": {
|
||||
"endpoint": "lb-jupyterhub-proxy-public-http",
|
||||
"app_protocol": "HTTP"
|
||||
}
|
||||
},
|
||||
{
|
||||
"action_id": "goss",
|
||||
"params": {
|
||||
"resources": {
|
||||
"path": "/.vib/jupyterhub/goss"
|
||||
},
|
||||
"remote": {
|
||||
"workload": "deploy-jupyterhub-hub"
|
||||
},
|
||||
"vars_file": "vars.yaml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"action_id": "cypress",
|
||||
"params": {
|
||||
"resources": {
|
||||
"path": "/.vib/jupyterhub/cypress"
|
||||
},
|
||||
"endpoint": "lb-jupyterhub-proxy-public-http",
|
||||
"app_protocol": "HTTP",
|
||||
"env": {
|
||||
"username": "test_user",
|
||||
"password": "ComplicatedPassword123!4"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"publish": {
|
||||
"actions": [
|
||||
{
|
||||
|
||||
@@ -15,6 +15,56 @@
|
||||
"action_id": "helm-lint"
|
||||
}
|
||||
]
|
||||
},
|
||||
"verify": {
|
||||
"context": {
|
||||
"resources": {
|
||||
"url": "{SHA_ARCHIVE}",
|
||||
"path": "/bitnami/jupyterhub"
|
||||
},
|
||||
"runtime_parameters": "aHViOgogIGJhc2VVcmw6IC8KICBhZG1pblVzZXI6IHRlc3RfdXNlcgogIHBhc3N3b3JkOiBDb21wbGljYXRlZFBhc3N3b3JkMTIzITQKICBjb250YWluZXJQb3J0czoKICAgIGh0dHA6IDgwODIKICBjb250YWluZXJTZWN1cml0eUNvbnRleHQ6CiAgICBlbmFibGVkOiB0cnVlCiAgICBydW5Bc1VzZXI6IDEwMDIKICBwb2RTZWN1cml0eUNvbnRleHQ6CiAgICBlbmFibGVkOiB0cnVlCiAgICBmc0dyb3VwOiAxMDAyCiAgc2VydmljZUFjY291bnQ6CiAgICBjcmVhdGU6IHRydWUKICAgIGF1dG9tb3VudFNlcnZpY2VBY2NvdW50VG9rZW46IHRydWUKICByYmFjOgogICAgY3JlYXRlOiB0cnVlCiAgc2VydmljZToKICAgIHBvcnRzOgogICAgICBodHRwOiA4MDgyCnByb3h5OgogIHNlcnZpY2U6CiAgICBhcGk6CiAgICAgIHBvcnRzOgogICAgICAgIGh0dHA6IDgwMDAKICAgIHB1YmxpYzoKICAgICAgdHlwZTogTG9hZEJhbGFuY2VyCiAgICAgIHBvcnRzOgogICAgICAgIGh0dHA6IDgwCmltYWdlUHVsbGVyOgogIGVuYWJsZWQ6IHRydWUKc2luZ2xldXNlcjoKICBjb250YWluZXJTZWN1cml0eUNvbnRleHQ6CiAgICBlbmFibGVkOiB0cnVlCiAgICBydW5Bc1VzZXI6IDEwMDIKICBwb2RTZWN1cml0eUNvbnRleHQ6CiAgICBlbmFibGVkOiB0cnVlCiAgICBmc0dyb3VwOiAxMDAyCiAgcGVyc2lzdGVuY2U6CiAgICBlbmFibGVkOiB0cnVlCnBvc3RncmVzcWw6CiAgZW5hYmxlZDogdHJ1ZQogIGF1dGg6CiAgICB1c2VybmFtZTogYm5fdmliX2p1cHl0ZXJodWIKICAgIGRhdGFiYXNlOiBiaXRuYW1pX3ZpYl9qdXB5dGVyaHViCiAgc2VydmljZToKICAgIHBvcnRzOgogICAgICBwb3N0Z3Jlc3FsOiA1NDMy",
|
||||
"target_platform": {
|
||||
"target_platform_id": "{VIB_ENV_TARGET_PLATFORM}",
|
||||
"size": {
|
||||
"name": "S4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"action_id": "health-check",
|
||||
"params": {
|
||||
"endpoint": "lb-jupyterhub-proxy-public-http",
|
||||
"app_protocol": "HTTP"
|
||||
}
|
||||
},
|
||||
{
|
||||
"action_id": "goss",
|
||||
"params": {
|
||||
"resources": {
|
||||
"path": "/.vib/jupyterhub/goss"
|
||||
},
|
||||
"remote": {
|
||||
"workload": "deploy-jupyterhub-hub"
|
||||
},
|
||||
"vars_file": "vars.yaml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"action_id": "cypress",
|
||||
"params": {
|
||||
"resources": {
|
||||
"path": "/.vib/jupyterhub/cypress"
|
||||
},
|
||||
"endpoint": "lb-jupyterhub-proxy-public-http",
|
||||
"app_protocol": "HTTP",
|
||||
"env": {
|
||||
"username": "test_user",
|
||||
"password": "ComplicatedPassword123!4"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user