Skip to content

Commit

Permalink
tests: enable bundle functional tests for v2 compiled pipelines (#383)
Browse files Browse the repository at this point in the history
* tests: enable bundle functional tests for v2 compiled pipelines

The recent upgrades in kubeflow pipelines introduced a new version of the SDK that is
compatible with the newer backend (pipelines 2.0.3). This commits ensures that the CI
tests both a pipeline v1 and v2 to ensure good coverage.
  • Loading branch information
DnPlas authored Nov 20, 2023
1 parent c8ebd79 commit 1572e69
Show file tree
Hide file tree
Showing 11 changed files with 387 additions and 187 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/integrate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,11 @@ jobs:
test-bundle:
name: Test the bundle
runs-on: ubuntu-20.04

strategy:
matrix:
sdk:
- v1
- v2
steps:
# This is a workaround for https://github.com/canonical/kfp-operators/issues/250
# Ideally we'd use self-hosted runners, but this effort is still not stable
Expand Down Expand Up @@ -145,7 +149,7 @@ jobs:
# Run integration tests against the 1.7 generic install bundle definition
# Using destructive mode because of https://github.com/canonical/charmcraft/issues/1132
# and https://github.com/canonical/charmcraft/issues/1138
sg snap_microk8s -c "tox -e bundle-integration -- --model kubeflow --bundle=./tests/integration/bundles/kfp_latest_edge.yaml.j2 --destructive-mode"
sg snap_microk8s -c "tox -e bundle-integration-${{ matrix.sdk }} -- --model kubeflow --bundle=./tests/integration/bundles/kfp_latest_edge.yaml.j2 --destructive-mode"
- name: Get all
run: kubectl get all -A
Expand Down
2 changes: 0 additions & 2 deletions requirements-integration.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ aiohttp
jsonschema<4.18
# Pinning to <4.0 due to compatibility with the 3.1 controller version
juju<4.0
# Need this version of kfp to work with kfp 2.0.0-alpha.7
kfp==1.8.22
lightkube
pytest
pytest-operator
Expand Down
108 changes: 5 additions & 103 deletions requirements-integration.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
#
# pip-compile requirements-integration.in
#
absl-py==1.4.0
# via kfp
aiohttp==3.8.5
# via -r requirements-integration.in
aiosignal==1.3.1
Expand All @@ -30,7 +28,6 @@ certifi==2023.7.22
# via
# httpcore
# httpx
# kfp-server-api
# kubernetes
# requests
cffi==1.15.1
Expand All @@ -41,71 +38,28 @@ charset-normalizer==3.2.0
# via
# aiohttp
# requests
click==8.1.7
# via
# kfp
# typer
cloudpickle==2.2.1
# via kfp
cryptography==41.0.3
# via paramiko
decorator==5.1.1
# via
# ipdb
# ipython
deprecated==1.2.14
# via kfp
docstring-parser==0.15
# via kfp
exceptiongroup==1.1.3
# via
# anyio
# pytest
executing==1.2.0
# via stack-data
fire==0.5.0
# via kfp
frozenlist==1.4.0
# via
# aiohttp
# aiosignal
google-api-core==2.11.1
# via
# google-api-python-client
# google-cloud-core
# google-cloud-storage
# kfp
google-api-python-client==1.12.11
# via kfp
google-auth==2.22.0
# via
# google-api-core
# google-api-python-client
# google-auth-httplib2
# google-cloud-core
# google-cloud-storage
# kfp
# kubernetes
google-auth-httplib2==0.1.0
# via google-api-python-client
google-cloud-core==2.3.3
# via google-cloud-storage
google-cloud-storage==2.10.0
# via kfp
google-crc32c==1.5.0
# via google-resumable-media
google-resumable-media==2.6.0
# via google-cloud-storage
googleapis-common-protos==1.60.0
# via google-api-core
# via kubernetes
h11==0.14.0
# via httpcore
httpcore==0.17.3
# via httpx
httplib2==0.22.0
# via
# google-api-python-client
# google-auth-httplib2
httpx==0.24.1
# via lightkube
hvac==1.2.0
Expand All @@ -129,23 +83,13 @@ jedi==0.19.0
jinja2==3.1.2
# via pytest-operator
jsonschema==4.17.3
# via
# -r requirements-integration.in
# kfp
# via -r requirements-integration.in
juju==3.2.2
# via
# -r requirements-integration.in
# pytest-operator
kfp==1.8.22
# via -r requirements-integration.in
kfp-pipeline-spec==0.1.16
# via kfp
kfp-server-api==1.8.5
# via kfp
kubernetes==25.3.0
# via
# juju
# kfp
# via juju
lightkube==0.14.0
# via -r requirements-integration.in
lightkube-models==1.28.1.4
Expand Down Expand Up @@ -181,12 +125,7 @@ pluggy==1.3.0
prompt-toolkit==3.0.39
# via ipython
protobuf==3.20.3
# via
# google-api-core
# googleapis-common-protos
# kfp
# kfp-pipeline-spec
# macaroonbakery
# via macaroonbakery
ptyprocess==0.7.0
# via pexpect
pure-eval==0.2.2
Expand All @@ -200,8 +139,6 @@ pyasn1-modules==0.3.0
# via google-auth
pycparser==2.21
# via cffi
pydantic==1.10.12
# via kfp
pygments==2.16.1
# via ipython
pyhcl==0.4.5
Expand All @@ -213,8 +150,6 @@ pynacl==1.5.0
# macaroonbakery
# paramiko
# pymacaroons
pyparsing==3.1.1
# via httplib2
pyrfc3339==1.1
# via
# juju
Expand All @@ -231,42 +166,30 @@ pytest-asyncio==0.21.1
pytest-operator==0.29.0
# via -r requirements-integration.in
python-dateutil==2.8.2
# via
# kfp-server-api
# kubernetes
# via kubernetes
pytz==2023.3.post1
# via pyrfc3339
pyyaml==6.0.1
# via
# -r requirements-integration.in
# juju
# kfp
# kubernetes
# lightkube
# pytest-operator
requests==2.31.0
# via
# google-api-core
# google-cloud-storage
# hvac
# kubernetes
# macaroonbakery
# requests-oauthlib
# requests-toolbelt
requests-oauthlib==1.3.1
# via kubernetes
requests-toolbelt==0.10.1
# via kfp
rsa==4.9
# via google-auth
six==1.16.0
# via
# asttokens
# fire
# google-api-python-client
# google-auth
# google-auth-httplib2
# kfp-server-api
# kubernetes
# macaroonbakery
# paramiko
Expand All @@ -279,14 +202,8 @@ sniffio==1.3.0
# httpx
stack-data==0.6.2
# via ipython
strip-hints==0.1.10
# via kfp
tabulate==0.9.0
# via kfp
tenacity==8.2.3
# via -r requirements-integration.in
termcolor==2.3.0
# via fire
tomli==2.0.1
# via
# ipdb
Expand All @@ -297,26 +214,15 @@ traitlets==5.9.0
# via
# ipython
# matplotlib-inline
typer==0.9.0
# via kfp
typing-extensions==4.7.1
# via
# ipython
# kfp
# pydantic
# typer
# typing-inspect
typing-inspect==0.9.0
# via juju
uritemplate==3.0.1
# via
# google-api-python-client
# kfp
urllib3==1.26.16
# via
# google-auth
# kfp
# kfp-server-api
# kubernetes
# requests
wcwidth==0.2.6
Expand All @@ -325,10 +231,6 @@ websocket-client==1.6.2
# via kubernetes
websockets==8.1
# via juju
wheel==0.41.2
# via strip-hints
wrapt==1.15.0
# via deprecated
yarl==1.9.2
# via aiohttp
zipp==3.16.2
Expand Down
5 changes: 2 additions & 3 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ This directory has the following structure:
│   ├── k8s_resources.py
│   └── localize_bundle.py
├── kfp_globals.py
├── pipelines
│   ├── sample_pipeline.yaml
│   └── sample_pipeline_execution_order.py
├── pipelines/
│   └── ... # Sample pipelines
├── profile
│   └── profile.yaml
├── test_kfp_functional.py
Expand Down
34 changes: 5 additions & 29 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
KUBEFLOW_USER_NAME = PROFILE_FILE["spec"]["owner"]["name"]


@pytest.fixture(scope="module")
@pytest.fixture(scope="session")
def forward_kfp_ui():
"""Port forward the kfp-ui service."""
kfp_ui_process = subprocess.Popen(
Expand All @@ -46,7 +46,7 @@ def forward_kfp_ui():
kfp_ui_process.terminate()


@pytest.fixture(scope="module")
@pytest.fixture(scope="session")
def apply_profile(lightkube_client):
"""Apply a Profile simulating a user."""
# Create a Viewer namespaced resource
Expand All @@ -59,7 +59,7 @@ def apply_profile(lightkube_client):

yield

# Remove namespace
# Remove profile
read_yaml = Path(PROFILE_FILE_PATH).read_text()
yaml_loaded = codecs.load_all_yaml(read_yaml)
for obj in yaml_loaded:
Expand All @@ -73,7 +73,7 @@ def apply_profile(lightkube_client):
raise api_error


@pytest.fixture(scope="module")
@pytest.fixture(scope="session")
def kfp_client(apply_profile, forward_kfp_ui) -> kfp.Client:
"""Returns a KFP Client that can talk to the KFP API Server."""
# Instantiate the KFP Client
Expand All @@ -82,37 +82,13 @@ def kfp_client(apply_profile, forward_kfp_ui) -> kfp.Client:
return client


@pytest.fixture(scope="module")
@pytest.fixture(scope="session")
def lightkube_client() -> lightkube.Client:
"""Returns a lightkube Client that can talk to the K8s API."""
client = lightkube.Client(field_manager="kfp-operators")
return client


@pytest.fixture(scope="function")
def upload_and_clean_pipeline(kfp_client: kfp.Client):
"""Upload an arbitrary pipeline and remove after test case execution."""
pipeline_upload_response = kfp_client.pipeline_uploads.upload_pipeline(
uploadfile=SAMPLE_PIPELINE, name=SAMPLE_PIPELINE_NAME
)

yield pipeline_upload_response

kfp_client.delete_pipeline(pipeline_id=pipeline_upload_response.id)


@pytest.fixture(scope="function")
def create_and_clean_experiment(kfp_client: kfp.Client):
"""Create an experiment and remove after test case execution."""
experiment_response = kfp_client.create_experiment(
name="test-experiment", namespace=KUBEFLOW_PROFILE_NAMESPACE
)

yield experiment_response

kfp_client.delete_experiment(experiment_id=experiment_response.id)


def pytest_addoption(parser: Parser):
parser.addoption(
"--bundle",
Expand Down
9 changes: 7 additions & 2 deletions tests/integration/kfp_globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@
]

# Variables for uploading/creating pipelines/experiments/runs
SAMPLE_PIPELINE = f"{basedir}/tests/integration/pipelines/sample_pipeline.yaml"
SAMPLE_PIPELINE_NAME = "sample-pipeline-2"
SAMPLE_PIPELINES_PATH = f"{basedir}/tests/integration/pipelines"
SAMPLE_PIPELINE = {
"v1": f"{SAMPLE_PIPELINES_PATH}/sample_pipeline.yaml",
"v2": f"{SAMPLE_PIPELINES_PATH}/pipeline_container_no_input.yaml",
}

SAMPLE_PIPELINE_NAME = "sample-pipeline"

# Variables for creating a viewer
SAMPLE_VIEWER = f"{basedir}/tests/integration/viewer/mnist.yaml"
Expand Down
Loading

0 comments on commit 1572e69

Please sign in to comment.