Skip to content

Commit 7fb3741

Browse files
Merge pull request opendatahub-io#24 from DharmitD/add-e2e-tests
Adding ML Pipelines' end-to-end tests
2 parents 4dd32b2 + 1d34b9c commit 7fb3741

File tree

14 files changed

+1229
-0
lines changed

14 files changed

+1229
-0
lines changed

tests/Dockerfile

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
FROM quay.io/centos/centos:stream8
2+
3+
# List of chromedriver versions for download - https://chromedriver.chromium.org/downloads
4+
ARG CHROMEDRIVER_VER=104.0.5112.79
5+
ARG ORG=opendatahub-io
6+
ARG BRANCH=master
7+
ARG ODS_CI_REPO=https://github.com/red-hat-data-services/ods-ci
8+
ARG ODS_CI_GITREF=releases/1.7.0-5
9+
ARG OC_CLI_URL=https://mirror.openshift.com/pub/openshift-v4/amd64/clients/ocp/latest/openshift-client-linux.tar.gz
10+
11+
ENV HOME /root
12+
WORKDIR /root
13+
14+
RUN dnf install -y bc git go-toolset python3-pip unzip && \
15+
git clone https://github.com/crobby/peak $HOME/peak && \
16+
cd $HOME/peak && \
17+
git submodule update --init
18+
19+
RUN dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm &&\
20+
echo -e "[google-chrome]\nname=google-chrome\nbaseurl=http://dl.google.com/linux/chrome/rpm/stable/x86_64\nenabled=1\ngpgcheck=1\ngpgkey=https://dl.google.com/linux/linux_signing_key.pub" > /etc/yum.repos.d/google-chrome.repo &&\
21+
dnf -y install "google-chrome-stable" &&\
22+
dnf clean all
23+
24+
# install jq to help with parsing json
25+
RUN curl -o /usr/local/bin/jq http://stedolan.github.io/jq/download/linux64/jq && \
26+
chmod +x /usr/local/bin/jq
27+
28+
RUN mkdir -p $HOME/src && \
29+
cd $HOME/src && \
30+
git clone --depth=1 --branch ${BRANCH} https://github.com/${ORG}/ml-pipelines && \
31+
# Clone ods-ci repo at specified git ref for the JupyterHub webUI tests
32+
git clone --depth=1 ${ODS_CI_REPO} ods-ci && cd ods-ci && \
33+
git fetch origin ${ODS_CI_GITREF} && git checkout FETCH_HEAD && \
34+
chmod -R 777 $HOME/src
35+
36+
# Use a specific destination file name in case the url dow download name changes
37+
ADD ${OC_CLI_URL} $HOME/peak/oc-cli.tar.gz
38+
RUN tar -C /usr/local/bin -xvf $HOME/peak/oc-cli.tar.gz && \
39+
chmod +x /usr/local/bin/oc
40+
41+
RUN curl -o /tmp/chromedriver_linux64.zip -L https://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VER}/chromedriver_linux64.zip &&\
42+
unzip /tmp/chromedriver_linux64.zip &&\
43+
cp chromedriver /usr/local/bin/chromedriver
44+
45+
COPY Pipfile Pipfile.lock $HOME/peak/
46+
47+
RUN pip3 install micropipenv &&\
48+
ln -s `which pip3` /usr/bin/pip &&\
49+
cd $HOME/peak &&\
50+
micropipenv install
51+
52+
COPY setup/operatorsetup scripts/install.sh scripts/installandtest.sh $HOME/peak/
53+
COPY resources $HOME/peak/operator-tests/odh-manifests/resources
54+
COPY util $HOME/peak/operator-tests/odh-manifests
55+
COPY setup/kfctl_openshift.yaml $HOME/kfdef/
56+
COPY basictests $HOME/peak/operator-tests/odh-manifests/basictests
57+
58+
RUN chmod -R 777 $HOME/kfdef && \
59+
mkdir -p $HOME/.kube && \
60+
chmod -R 777 $HOME/.kube && \
61+
chmod -R 777 $HOME/peak && \
62+
mkdir -p /peak && \
63+
chmod -R 777 $HOME && \
64+
ln -s $HOME/peak/installandtest.sh /peak/installandtest.sh
65+
66+
# For local testing, you can add your own kubeconfig to the image
67+
# Note: Do not push the image to a public repo with your kubeconfig
68+
# ADD kubeconfig /root/.kube/config
69+
70+
CMD $HOME/peak/installandtest.sh

tests/Makefile

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
IMAGE=odh-manifests-test
2+
GIT_ORG=opendatahub-io
3+
GIT_BRANCH=master
4+
ODHPROJECT=opendatahub
5+
# Specify the repo and git ref/branch to use for cloning ods-ci
6+
ODS_CI_REPO=https://github.com/red-hat-data-services/ods-ci
7+
ODS_CI_GITREF=master
8+
OC_CLI_URL=https://mirror.openshift.com/pub/openshift-v4/amd64/clients/ocp/latest/openshift-client-linux.tar.gz
9+
OPENSHIFT_USER=
10+
OPENSHIFT_PASS=
11+
OPENSHIFT_LOGIN_PROVIDER=
12+
# Setting SKIP_INSTALL will let you run the tests against an ODH instance that is already setup
13+
SKIP_INSTALL=
14+
# Setting TESTS_REGEX will allow you to change which tests are going to be run
15+
TESTS_REGEX=
16+
# Location inside the container where CI system will retrieve files after a test run
17+
ARTIFACT_DIR=/tmp/artifacts
18+
LOCAL_ARTIFACT_DIR="${PWD}/artifacts"
19+
20+
all: test
21+
test: build run clean
22+
23+
build:
24+
podman build -t $(IMAGE) --build-arg ORG=$(GIT_ORG) --build-arg BRANCH=$(GIT_BRANCH) --build-arg ODS_CI_REPO=$(ODS_CI_REPO) --build-arg ODS_CI_GITREF=$(ODS_CI_GITREF) --build-arg OC_CLI_URL=$(OC_CLI_URL) .
25+
26+
run:
27+
# Confirm that we have a directory for storing any screenshots from selenium tests
28+
mkdir -p ${LOCAL_ARTIFACT_DIR}/screenshots
29+
oc config view --flatten --minify > /tmp/tests-kubeconfig
30+
podman run -e SKIP_INSTALL=$(SKIP_INSTALL) -e TESTS_REGEX=$(TESTS_REGEX) -e SKIP_OPERATOR_INSTALL=$(SKIP_OPERATOR_INSTALL) \
31+
-e SKIP_KFDEF_INSTALL=$(SKIP_KFDEF_INSTALL) -e ODHPROJECT=$(ODHPROJECT) \
32+
-e OPENSHIFT_USER="$(OPENSHIFT_USER)" -e OPENSHIFT_PASS="$(OPENSHIFT_PASS)" -e OPENSHIFT_LOGIN_PROVIDER=$(OPENSHIFT_LOGIN_PROVIDER) -e ARTIFACT_DIR=$(ARTIFACT_DIR) \
33+
-it -v ${LOCAL_ARTIFACT_DIR}/:$(ARTIFACT_DIR):z -v /tmp/tests-kubeconfig:/tmp/kubeconfig:z $(IMAGE)
34+
35+
clean:
36+
oc delete -n $(ODHPROJECT) kfdef opendatahub || true
37+
oc delete project $(ODHPROJECT) || echo -e "\n\n==> If the project deletion failed, you can try to use this script to force it: https://raw.githubusercontent.com/jefferyb/useful-scripts/master/openshift/force-delete-openshift-project\n\n"
38+
#Clean up openshift-operators namespace
39+
oc get csv -n openshift-operators -o name | grep strimzi-cluster-operator | xargs oc delete -n openshift-operators || true
40+
oc get csv -n openshift-operators -o name | grep opendatahub-operator | xargs oc delete -n openshift-operators || true
41+
oc delete subscription -n openshift-operators -l peak.test.subscription=opendatahub-operator
42+
oc get mutatingwebhookconfiguration -o name | grep katib | grep $(ODHPROJECT) | xargs oc delete || true
43+
oc get validatingwebhookconfiguration -o name | grep katib | grep $(ODHPROJECT) | xargs oc delete || true

tests/Pipfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[[source]]
2+
name = "pypi"
3+
url = "https://pypi.org/simple"
4+
verify_ssl = true
5+
6+
[dev-packages]
7+
8+
[packages]
9+
selenium = "*"
10+
11+
[requires]
12+
python_version = "3.6"

tests/Pipfile.lock

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/README.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Running containerized tests
2+
3+
Running the tests this way assumes that you have an active kubeadmin login
4+
on the cluster that you want to run the tests against and that you have podman
5+
installed. (If you prefer docker, you can edit the Makefile to replace podman
6+
with docker).
7+
8+
Run the following:
9+
10+
```sh
11+
cd tests
12+
make build
13+
make run
14+
```
15+
16+
## Cleaning up after your test run (optional)
17+
18+
Only run the following if you want to eliminate your Open Data Hub installation.
19+
20+
To cleanup the Open Data Hub installation after a test run, you can run `make clean`.
21+
Running `make clean` **will wipe your Open Data Hub installation** and delete the project.
22+
23+
24+
## Customizing test behavior
25+
26+
Without changes, the test image will run `$HOME/peak/installandtest.sh` which
27+
handles setting up the opendatahub-operator and then creating the KfDef found in
28+
`tests/setup/kfctl_openshift.yaml`. If you want to modify your test run, you
29+
might want to change those files to get the behavior that you're looking for.
30+
After you make changes, you will need to rebuild the test image with `make build`.
31+
32+
If you'd like to run the tests against an instance that already has Open Data Hub installed,
33+
you set `SKIP_INSTALL=true` and that will cause the test run
34+
to skip the installation process and will only run the tests. example: `make run SKIP_INSTALL=true`
35+
36+
If you'd like to run the tests against an instance that already has a KfDef created,
37+
you set `SKIP_KFDEF_INSTALL=true` and that will cause the test run
38+
to skip the step of creating the default KfDef. example: `make run SKIP_KFDEF_INSTALL=true`
39+
40+
If you'd like to run a single test instead of all tests, you can
41+
set the TESTS_REGEX variable `TESTS_REGEX=<name of the test to run>`. That will
42+
only run the test that you specify instead of all of the tests. example: `make run TESTS_REGEX=grafana`
43+
44+
If you have a local instance already running the operator and you'd like to skip that part
45+
of the install process, you can set `SKIP_OPERATOR_INSTALL=true` and that will bypass installation
46+
of the operator, but will still install the authentication for the jupyterhub tests.
47+
48+
For other possible configurations, you can look in the Makefile. There are a set of
49+
variables at the top that you could change to meet the needs of your particular test run.
50+
51+
## Test Artifacts
52+
The environment variable `ARTIFACT_DIR` specifies the root directory where all test artifacts should be
53+
stored for retrieval at the end of a test run. Any files created should be uniquely named to prevent
54+
a test from overwriting an artifact generated by another test.
55+
56+
# Running tests manually
57+
58+
Manual running of the tests relies on the test
59+
runner [located here](https://github.com/AICoE/peak).
60+
See the README.md there for more detailed information on how it works.
61+
62+
Note when running on a **mac** you may need to do the following:
63+
64+
```sh
65+
brew install coreutils
66+
ln -s /usr/local/bin/greadlink /usr/local/bin/readlink
67+
```
68+
69+
Make sure you have an OpenShift login, then do the following:
70+
71+
```sh
72+
git clone https://github.com/AICoE/peak
73+
cd peak
74+
git submodule update --init
75+
echo opendatahub-kubeflow nil https://github.com/opendatahub-io/odh-manifests > my-list
76+
./setup.sh -t my-list
77+
./run.sh operator-tests/opendatahub-kubeflow/tests/basictests
78+
```
79+
80+
Note, if you're looking to test another repo and/or branch, you can change the "echo" command from above to something of the following form where "your branch" is optional:
81+
82+
```sh
83+
echo opendatahub-kubeflow nil <your repo> <your branch> > my-list
84+
```
85+
86+
If your installation is not in the opendatahub project, you will need to modify
87+
the export line in tests/util to set the value of ODHPROJECT to match name of the project you are using.
88+
89+
You can run tests individually by passing a substring to run.sh to match:
90+
91+
```sh
92+
./run.sh ailibrary.sh
93+
```
94+
95+
# Basic test
96+
97+
These tests are in the basictests directory. This set of tests assumes that you have opendatahub (Kubeflow-based) isntalled. It then goes through each module and tests
98+
to be sure that the expected pods are all in the running state. This is meant to be the barebones basic smoke tests for an installation.
99+
The steps to run this test are:
100+
101+
* Run the tests
102+
103+
```sh
104+
./run.sh tests/basictests
105+
```

tests/TESTING.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
## Overivew
2+
3+
The aim was to set ourselves up with a test system that would give us an automated way to run tests against our PRs. At the outset of this, our repo had no tests of any sort, so the first task became getting some basic tests running against the bits in our repo.
4+
5+
Our tests are based on the utilities found in https://github.com/openshift/origin/tree/master/hack/lib which are a set of bash functions and scripts that facilitate a reasonably fast way to develop and run a set of tests against either OpenShift itself or, in our case, a set of applications running on OpenShift. Those tests were adapted for use in radanalytics and then re-adapted them for testing operators running in OpenShift. We have borrowed their test runner (our fork is [here](https://github.com/crobby/peak)) that will search a subdirectory tree for scripts that match a given regular expression (ie: ‘tests’ would find all scripts that have ‘tests’ anywhere in their full path or name), so it is easy to run a single test or a large group of tests.
6+
7+
Each test script has a small amount of boilerplate code followed by a series of bash tests. Each test could call out to another utility/language/whatever. The utilities available in the testing library can check for specific results in text/exit code/etc of each call. Any test lines that produce a failed result are tabulated and reported at the end of the test runs. Of course, the stdout/stderr of each failed call is also available in addition to whatever other logging your test call might produce. Here’s what I would call the main building block of the tests: https://github.com/openshift/origin/blob/master/hack/lib/cmd.sh It defines what amount to wrappers around whatever calls you want to make in your tests and handles the parsing of the result text/exit codes.
8+
9+
## Integration with OpenShift-CI:
10+
11+
The first step toward integrating with [OpenShift CI](https://github.com/openshift/release) is granting access to the OpenShift CI Robot and the OpenShift Merge Robot entities in the settings of the repo. Once that is complete, you can contact the openshift-ci team and they will set up the necessary webhooks in the target repo.
12+
13+
Next is the prow configuration. The configuration files are kept in the https://github.com/openshift/release repository. Under the `core_services/prow` directory, you’ll need to modify `_config.yaml` and `_plugins.yaml` in order to have your repository included in the configuration. Submit a PR to that repo and when it merges, you’re all set. As for the contents of your changes, unless you know exactly what you want, it might be useful to start by adding your repo with settings copied from another repository already in the config.
14+
15+
Lastly, and perhaps the most important is defining the configuration that will run your tests. These files are also in the openshift/release repo. To define your test job, you can create a config file like ours which is defined [here](https://github.com/openshift/release/blob/master/ci-operator/config/opendatahub-io/odh-manifests/opendatahub-io-odh-manifests-master.yaml). The job defines the following items:
16+
1) An image that can be built to run your tests (your tests run inside a container)
17+
2) Instructions on how to build that test image and
18+
3) A workflow that has your test or tests in the “tests” portion of the workflow definition. In our case, we are using the ipi-aws workflow which will spin-up a fresh OpenShift cluster in AWS where our tests will run (our test container will start with an admin KUBECONFIG for that cluster)
19+
20+
For greater detail on any of the steps, you can refer to the [OpenShift relase README](https://github.com/openshift/release/blob/master/README.md)

tests/basictests/ml-pipelines.sh

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/bin/bash
2+
3+
source $TEST_DIR/common
4+
5+
MY_DIR=$(readlink -f `dirname "${BASH_SOURCE[0]}"`)
6+
7+
source ${MY_DIR}/../util
8+
RESOURCEDIR="${MY_DIR}/../resources"
9+
10+
os::test::junit::declare_suite_start "$MY_SCRIPT"
11+
12+
function check_resources() {
13+
header "Testing ML pipelines installation"
14+
os::cmd::expect_success "oc project ${ODHPROJECT}"
15+
os::cmd::try_until_text "oc get crd pipelineruns.tekton.dev " "pipelineruns.tekton.dev" $odhdefaulttimeout $odhdefaultinterval
16+
os::cmd::try_until_text "oc get pods -l application-crd-id=kubeflow-pipelines --field-selector='status.phase!=Running,status.phase!=Completed' -o jsonpath='{$.items[*].metadata.name}' | wc -w" "0" $odhdefaulttimeout $odhdefaultinterval
17+
running_pods=$(oc get pods -l application-crd-id=kubeflow-pipelines --field-selector='status.phase=Running' -o jsonpath='{$.items[*].metadata.name}' | wc -w)
18+
os::cmd::expect_success "if [ "$running_pods" -gt "0" ]; then exit 0; else exit 1; fi"
19+
}
20+
21+
function check_ui_overlay() {
22+
header "Checking UI overlay Kfdef deploys the UI"
23+
os::cmd::try_until_text "oc get pods -l app=ml-pipeline-ui --field-selector='status.phase=Running' -o jsonpath='{$.items[*].metadata.name}' | wc -w" "1" $odhdefaulttimeout $odhdefaultinterval
24+
}
25+
26+
function create_pipeline() {
27+
header "Creating a pipeline"
28+
route=`oc get route ml-pipeline || echo ""`
29+
if [[ -z $route ]]; then
30+
oc expose service ml-pipeline
31+
fi
32+
ROUTE=$(oc get route ml-pipeline --template={{.spec.host}})
33+
PIPELINE_ID=$(curl -s -F "uploadfile=@${RESOURCEDIR}/ml-pipelines/test-pipeline-run.yaml" ${ROUTE}/apis/v1beta1/pipelines/upload | jq -r .id)
34+
os::cmd::try_until_not_text "curl -s ${ROUTE}/apis/v1beta1/pipelines/${PIPELINE_ID} | jq" "null" $odhdefaulttimeout $odhdefaultinterval
35+
}
36+
37+
function list_pipelines() {
38+
header "Listing pipelines"
39+
os::cmd::try_until_text "curl -s ${ROUTE}/apis/v1beta1/pipelines | jq '.total_size'" "2" $odhdefaulttimeout $odhdefaultinterval
40+
}
41+
42+
function create_run() {
43+
header "Creating a run"
44+
RUN_ID=$(curl -s -H "Content-Type: application/json" -X POST ${ROUTE}/apis/v1beta1/runs -d "{\"name\":\"test-pipeline-run_run\", \"pipeline_spec\":{\"pipeline_id\":\"${PIPELINE_ID}\"}}" | jq -r .run.id)
45+
os::cmd::try_until_not_text "curl -s ${ROUTE}/apis/v1beta1/runs/${RUN_ID} | jq '" "null" $odhdefaulttimeout $odhdefaultinterval
46+
}
47+
48+
function list_runs() {
49+
header "Listing runs"
50+
os::cmd::try_until_text "curl -s ${ROUTE}/apis/v1beta1/runs | jq '.total_size'" "1" $odhdefaulttimeout $odhdefaultinterval
51+
}
52+
53+
function check_run_status() {
54+
header "Checking run status"
55+
os::cmd::try_until_text "curl -s ${ROUTE}/apis/v1beta1/runs/${RUN_ID} | jq '.run.status'" "Completed" $odhdefaulttimeout $odhdefaultinterval
56+
}
57+
58+
function setup_monitoring() {
59+
header "Enabling User Workload Monitoring on the cluster"
60+
oc apply -f ${RESOURCEDIR}/ml-pipelines/enable-uwm.yaml
61+
}
62+
63+
function test_metrics() {
64+
header "Checking metrics for total number of runs, should be 1 since we have spun up 1 run"
65+
## On OCP 4.11, get-token is removed
66+
cluster_version=`oc get -o json clusterversion | jq '.items[0].status.desired.version' | grep "4.11" || echo ""`
67+
if [[ -z $cluster_version ]]; then
68+
monitoring_token=`oc sa get-token prometheus-k8s -n openshift-monitoring`
69+
else
70+
monitoring_token=`oc create token prometheus-k8s -n openshift-monitoring`
71+
fi
72+
os::cmd::try_until_text "oc -n openshift-monitoring exec -c prometheus prometheus-k8s-0 -- curl -k -H \"Authorization: Bearer $monitoring_token\" 'https://thanos-querier.openshift-monitoring:9091/api/v1/query?query=run_server_run_count' | jq '.data.result[0].value[1]'" "1" $odhdefaulttimeout $odhdefaultinterval
73+
}
74+
75+
function delete_runs() {
76+
header "Deleting runs"
77+
os::cmd::try_until_text "curl -s -X DELETE ${ROUTE}/apis/v1beta1/runs/${RUN_ID} | jq" "" $odhdefaulttimeout $odhdefaultinterval
78+
os::cmd::try_until_text "curl -s ${ROUTE}/apis/v1beta1/runs/${RUN_ID} | jq '.code'" "5" $odhdefaulttimeout $odhdefaultinterval
79+
}
80+
81+
function delete_pipeline() {
82+
header "Deleting the pipeline"
83+
os::cmd::try_until_text "curl -s -X DELETE ${ROUTE}/apis/v1beta1/pipelines/${PIPELINE_ID} | jq" "" $odhdefaulttimeout $odhdefaultinterval
84+
}
85+
86+
check_resources
87+
check_ui_overlay
88+
create_pipeline
89+
list_pipelines
90+
create_run
91+
list_runs
92+
check_run_status
93+
setup_monitoring
94+
test_metrics
95+
delete_runs
96+
delete_pipeline
97+
oc delete route ml-pipeline
98+
99+
os::test::junit::declare_suite_end

0 commit comments

Comments
 (0)