-
Notifications
You must be signed in to change notification settings - Fork 10
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
RHOAIENG-16055: new(tests): test to start a Workbench, by creating the Notebook CR directly #94
base: main
Are you sure you want to change the base?
Conversation
The following are automatically added/executed:
Available user actions:
Supported labels{'/hold', '/verified', '/lgtm', '/wip'} |
330e5e2
to
92744bb
Compare
f5edaa0
to
c1eddd8
Compare
tests/workbenches/conftest.py
Outdated
@@ -0,0 +1,309 @@ | |||
from __future__ import annotations | |||
|
|||
import logging |
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.
please use simple_logger
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.
fixed
tests/workbenches/conftest.py
Outdated
resource_manager.destroy() | ||
|
||
|
||
class KubeResourceManager: |
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.
please use ocpenshift python wrapper to CRUD resources
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.
done
tests/workbenches/conftest.py
Outdated
OPENSHIFT_DOMAIN = "openshift.io/" | ||
ODH_DOMAIN = "opendatahub.io/" |
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.
used in other places as well, please place under https://github.com/opendatahub-io/opendatahub-tests/blob/main/utilities/constants.py and re-use
tests/workbenches/conftest.py
Outdated
|
||
LABEL_DASHBOARD = ODH_DOMAIN + "dashboard" | ||
LABEL_ODH_MANAGED = ODH_DOMAIN + "odh-managed" | ||
LABEL_SIDECAR_ISTIO_INJECT = "sidecar.istio.io/inject" |
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.
ditto
tests/workbenches/conftest.py
Outdated
self.privileged_client = privileged_client | ||
self.resources: list[ocp_resources.resource.Resource] = [] | ||
|
||
def createResourceWithoutWait(self, client: DynamicClient, resource: ocp_resources.resource.Resource): |
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.
please use python naming conventions
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.
done
import kubernetes.client | ||
from kubernetes.dynamic import DynamicClient | ||
|
||
from tests.workbenches.conftest import OdhAnnotationsLabels, OdhConstants, PodUtils |
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.
under conftest place fixtures; functions and classes should be under utils.py
in the relevant dir
@classmethod | ||
@property | ||
@functools.cache | ||
def logger(cls): |
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.
please use simple_logger
), | ||
}, | ||
) | ||
def testCreateSimpleNotebook(self, function_resource_manager, admin_client, unprivileged_client): |
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.
all setup steps (e.g namespace, pvc) should be done in fixtures
please check existing fixtures and re-use
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.
done
# } | ||
|
||
|
||
def loadDefaultNotebook(client: DynamicClient, namespace: str, name: str, image: str) -> Notebook: |
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.
functions should go under utils.py
in the relevant dir
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.
done
@@ -0,0 +1,146 @@ | |||
apiVersion: kubeflow.org/v1 | |||
kind: Notebook |
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.
is there a template for this in the cluster?
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.
no, we don't have template for notebooks, the only template we have is hardcoded in odh-dashboard
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.
Why do we need the yaml? Can't we pass the arguments like any other resource?
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.
i like it this way, see no reason to rewrite it
|
||
with allure.step("Create Notebook CR"): | ||
# notebookImage: str = NotebookType.getNotebookImage(NotebookType.JUPYTER_MINIMAL_IMAGE, NotebookType.JUPYTER_MINIMAL_2023_2_TAG); | ||
notebookImage: str = "quay.io/modh/odh-minimal-notebook-container@sha256:615af25cfd4f3f2981b173e1a5ab24cb79f268ee72dabbddb6867ee1082eb902" |
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.
Can this be fetched dinamically from the cluster?
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.
yes, I changed the approach, thanks
notebookString = pathlib.Path( | ||
"/Users/jdanek/IdeaProjects/opendatahub-tests/tests/workbenches/notebook-controller/test_data/notebook.yaml" | ||
).read_text() |
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.
Pretty sure this won't work :)
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.
ofc, fixed now
afterTestSteps={ | ||
Step( | ||
value="Delete ODH operator and all created resources", | ||
expected="Operator is removed and all other resources as well", | ||
) | ||
}, |
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.
I don't think this has been functionally implemented but FWIW we don't plan to remove the operator after the test run
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.
fixed the doc comment, I never tried to implement operator removal here
tests/workbenches/docs.py
Outdated
@@ -0,0 +1,39 @@ | |||
from typing import Callable |
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.
What is this used for? does it just provide additional documentation for tests in e.g. https://github.com/opendatahub-io/opendatahub-tests/pull/94/files#diff-358f1122838e1ac22415822c5a85d419e2d111c64285e488695af1cf6f03d490R35 ?
IMHO if this is implemented we should use it across the repo to keep consistency, so this should go under a higher level directory, but it should probably be discussed beforehand. Can you attend the shift left wg meeting to do so?
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.
I'm not sure how useful this docs is going to be. Yes, it is only for structured comments. The Java version was able to render markdown docs from this, but I did not implement this in Python here.
IMO it's fine for now to only have this in the workbenches tests, and we (in workbenches team) need to decide if this is what we want to promote, or if we decide to delete this eventually.
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.
I would suggest using docstrings in general rather than trying to adapt to Java practices in this case: https://peps.python.org/pep-0257/
We haven't settled on a specific style and we're not yet rendering the documentation, but this seems to be the best bet to standardize across the repo
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.
ok then
@@ -0,0 +1,309 @@ | |||
from __future__ import annotations |
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.
I think the majority of these classes could be avoided if you instead used the wrapper library https://github.com/RedHatQE/openshift-python-wrapper
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.
used ocp_resources more, thanks
b956376
to
bf53997
Compare
12f966f
to
21ee191
Compare
tests/workbenches/docs.py
Outdated
@@ -0,0 +1,39 @@ | |||
from typing import Callable |
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.
I would suggest using docstrings in general rather than trying to adapt to Java practices in this case: https://peps.python.org/pep-0257/
We haven't settled on a specific style and we're not yet rendering the documentation, but this seems to be the best bet to standardize across the repo
tests/workbenches/resources.py
Outdated
class Notebook(NamespacedResource): | ||
api_group: str = "kubeflow.org" |
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.
IMHO this should be a class in ocp_resources itself
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.
+1
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.
allright, maybe if I start contributing to ocp_resources, I can try to do the work
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.
There is a tool that will auto-generate the class for ocp_resources, https://github.com/RedHatQE/openshift-python-wrapper/blob/main/class_generator/README.md
If you need any help with it feel free to ask any of us!
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.
tests/workbenches/utils.py
Outdated
GLOBAL_POLL_INTERVAL_MEDIUM = 10 | ||
|
||
|
||
class OcpResourceManager: |
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.
What is the specific goal you have with this class? if you use resources as classes from ocp_resources you will have their lifecycle handled by the wrapper library directly
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.
removed OcpResourceManager
tests/workbenches/utils.py
Outdated
raise RuntimeError(f"Exceptions during cleanup: {exceptions}") | ||
|
||
|
||
class PodUtils: |
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.
Same as above, if you use the Pod class you can already handle this without having to reimplement these checks
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.
done
utilities/infra.py
Outdated
@@ -44,6 +44,7 @@ def create_ns( | |||
teardown: bool = True, | |||
delete_timeout: int = 4 * 60, | |||
labels: Optional[dict[str, str]] = None, | |||
annotations: Optional[dict[str, str]] = None, |
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.
I think we want to move away from option and use the xx | yy
syntax by importing from future, see https://docs.python.org/3/library/stdtypes.html#types-union
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.
done
@@ -0,0 +1,146 @@ | |||
apiVersion: kubeflow.org/v1 | |||
kind: Notebook |
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.
Why do we need the yaml? Can't we pass the arguments like any other resource?
image_dict = {"jupyter-minimal-notebook": "jupyter-minimal-notebook"} | ||
else: | ||
image_dict = {"jupyter-minimal-notebook": "s2i-minimal-notebook"} | ||
return registry_path + "/" + controllers_namespace + "/" + image_dict[image_name] + ":" + image_tag |
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.
can we use fstring for better readability?
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.
done
@TestDoc( | ||
description=Desc("Create simple Notebook with all needed resources and see if Operator creates it properly"), | ||
contact=Contact(name="Jakub Stejskal", email="[email protected]"), | ||
steps={ | ||
Step( | ||
value="Create namespace for Notebook resources with proper name, labels and annotations", | ||
expected="Namespace is created", | ||
), | ||
Step(value="Create PVC with proper labels and data for Notebook", expected="PVC is created"), | ||
Step( | ||
value="Create Notebook resource with Jupyter Minimal image in pre-defined namespace", | ||
expected="Notebook resource is created", | ||
), | ||
Step( | ||
value="Wait for Notebook pods readiness", | ||
expected="Notebook pods are up and running, Notebook is in ready state", | ||
), | ||
}, | ||
) |
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.
I find this excessively verbose, but I'm open to use this format if we all agree.
|
||
nb = Notebook(yaml_file=io.StringIO(notebook_string)) | ||
|
||
return nb |
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.
no need to have nb variable, just return Notebook(yaml_file=io.StringIO(notebook_string))
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.
it's convenient to place breakpoint, if I ever wanted to do that, and look what's in nb
fixed now
tests/workbenches/resources.py
Outdated
class Notebook(NamespacedResource): | ||
api_group: str = "kubeflow.org" |
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.
+1
tests/workbenches/conftest.py
Outdated
name=request.param["name"], | ||
namespace=request.param["namespace"], | ||
label={constants.Dashboard.label: "true"}, | ||
accessmodes="ReadWriteOnce", |
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.
accessmodes="ReadWriteOnce", | |
accessmodes=PersistentVolumeClaim.AccessMode.RWO, |
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.
done
from utilities import constants | ||
|
||
|
||
@SuiteDoc( |
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.
please see @lugi0 comment above on dosctrings
@pytest.mark.parametrize( | ||
"users_namespace", | ||
[ | ||
pytest.param( | ||
{"name": NTB_NAMESPACE}, | ||
) | ||
], | ||
indirect=True, | ||
) | ||
@pytest.mark.parametrize( | ||
"users_persistent_volume_claim", | ||
[ | ||
pytest.param( | ||
{"name": NTB_NAME, "namespace": NTB_NAMESPACE}, | ||
) | ||
], | ||
indirect=True, | ||
) |
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.
iiuc all resources should be created together, so please use 1 set of parameters,
e,g
@pytest.mark.parametrize(
"users_namespace, users_persistent_volume_claim",
[
pytest.param(
{"name": NTB_NAMESPACE},
{"name": "xxx"},
)
],
indirect=True,
)
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.
done
|
||
|
||
@pytest.fixture(scope="function") | ||
def users_persistent_volume_claim( |
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.
call users_namespace
and then you can use it's attributes. e.g users_namespace.name
to set the namespace
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.
done
|
||
|
||
def _get_notebook_image(image_name: str, image_tag: str) -> str: | ||
registry_path = "image-registry.openshift-image-registry.svc:5000" |
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.
can we get it from the cluster?
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.
ended up following advice from @mwaykole and defined this as a constant
) | ||
|
||
|
||
def _get_notebook_image(image_name: str, image_tag: str) -> str: |
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.
please place functions under utils.py
file to keep the tests file only for tests
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.
done
notebook_string = notebook_string.replace("my-project", namespace).replace("my-workbench", name) | ||
# Set new Route url | ||
route_host: str = list( | ||
Route.get(client=client, name=constants.Dashboard.route_name, namespace=py_config["applications_namespace"]) |
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.
i think that client=client
should be dyn_client=....
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.
done
tests/workbenches/utils.py
Outdated
# | ||
from __future__ import annotations | ||
|
||
import logging |
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.
please use get_logger
from simple_logger
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.
fixed
tests/workbenches/utils.py
Outdated
import kubernetes.dynamic | ||
from kubernetes.dynamic import DynamicClient, ResourceField | ||
|
||
import ocp_resources.pod |
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.
when possible, please use explicit imports (i.e of only what is needed)
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.
from before I'm used to import packages, not individual names, as described for example in https://google.github.io/styleguide/pyguide.html#22-imports
ok, fixed
utilities/constants.py
Outdated
@@ -109,6 +112,19 @@ class StorageClassName: | |||
NFS: str = "nfs" | |||
|
|||
|
|||
class Dashboard: | |||
route_name = "odh-dashboard" if py_config.get("distribution") == "upstream" else "rhods-dashboard" | |||
label = OPENDATAHUB_IO + "/dashboard" |
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.
arg name should represent what it contains; please place under labels class
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.
done
from tests.workbenches.utils import step | ||
|
||
|
||
class TestNotebookST: |
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.
what is ST?
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.
I don't rightly know, that's how it was called in https://github.com/skodjob/odh-e2e/blob/main/src/test/java/io/odh/test/e2e/standard/NotebookST.java
will remove that suffix
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.
done
|
||
|
||
def _get_notebook_image(image_name: str, image_tag: str) -> str: | ||
registry_path = "image-registry.openshift-image-registry.svc:5000" |
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.
This can be added in constant files
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.
done
c4cfa99
to
f404037
Compare
f404037
to
6e68377
Compare
), | ||
""" | ||
with step("Create Notebook CR"): | ||
notebook_image: str = get_notebook_image("jupyter-minimal-notebook", "2024.2") |
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.
notebook_image: str
there is no need to declare type here when you call typed function get_notebook_image
Nit: It's better to call functions with arg=value
, if for some reason get_notebook_image
need to be refactored you will not be bound to positional arguments.
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.
well, https://github.com/RedHatQE/openshift-python-wrapper/pull/2331/files#diff-326458d10fbb8ff9e3b95dfec81f67dc7349f85a51d7539fa6c985072e4f9ab3R348-R351 has the types explicitly there too...
changed to use named parameter
|
||
with step("Wait for Notebook pod readiness"): | ||
with notebook: | ||
pods = Pod.get( |
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.
pods
can be empty list and your test will pass without test anything, please assert if not pods
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.
done
dyn_client=unprivileged_client, namespace=self.NTB_NAMESPACE, label_selector=f"app={self.NTB_NAME}" | ||
) | ||
for pod in pods: | ||
pod.wait_for_condition(condition="Ready", status="True") |
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.
All resources have condition
and status
please use them.
pod.wait_for_condition(condition=pod.Condition.READY, status=pod.Condition.Status.TRUE)
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.
done
tests/workbenches/utils.py
Outdated
|
||
|
||
def get_notebook_image(image_name: str, image_tag: str) -> str: | ||
controllers_namespace = py_config["applications_namespace"] |
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.
Simple way to do this will be:
image_name = "jupyter-minimal-notebook" if py_config.get("distribution") == "upstream" else "s2i-minimal-notebook"
return f"{INTERNAL_IMAGE_REGISTRY_PATH}/{py_config["applications_namespace"]}/{image_name}:{image_tag}"
And you can drop image_name
from the function args
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.
I'm not bothered by the extra argument, and i think that at callsite
notebook_image: str = get_notebook_image(image_name="jupyter-minimal-notebook", image_tag="2024.2")
makes more sense than if image_name parameter was omitted.
I could (eventually) have enum for the possible image names...
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.
Up to you, I would remove this function and just set the path in the test where it's needed. (only used in one place) and introduce more complicity without any reason.
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.
+1 to that; used once and should be set where used
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.
done
tests/workbenches/utils.py
Outdated
# Replace image | ||
notebook_string = notebook_string.replace("notebook_image_placeholder", image) | ||
|
||
return Notebook(yaml_file=io.StringIO(notebook_string)) |
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.
Resource accept kind_dict
, it's better to work with dict then with string.
You can load the YAML file with yaml
, change the needed values inside the dict and use it to create your resource.
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.
At that point I can just as well follow other recommendations here to have the file content be a python literal in code...
I guess I'll do that.
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.
went with the kind_dict, but kept using the yaml text file for the initial data
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.
and kept using string replacement, because modifying the dict selectively is way more work; I need to also update values inside long strings such as container args in the pod
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.
changed to using dict
tests/workbenches/utils.py
Outdated
notebook_string = notebook_string.replace("my-project", namespace).replace("my-workbench", name) | ||
# Set new Route url | ||
route_name = "odh-dashboard" if py_config.get("distribution") == "upstream" else "rhods-dashboard" | ||
route_host: str = list( |
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.
For better error handeling I think you should do:
route = Route(client=dyn_client, name=route_name, namespace=py_config["applications_namespace"])
if not route.exists:
assert .......
with the current code you will get IndexError: list index out of range
which say nothing.
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.
done
dbf7920
to
4c11ed8
Compare
) | ||
assert pods, "The expected notebook pods were not found" | ||
for pod in pods: | ||
pod.wait_for_condition(condition=pod.Condition.READY, status=pod.Condition.Status.TRUE) |
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.
right now you will fail of the first pod in wait_for_condition
, depends on what you want to test maybe it's better to collect the failed pods and assert once with all of them.
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.
thanks for the note; failing fast is what I want
tests/workbenches/utils.py
Outdated
|
||
|
||
def get_notebook_image(image_name: str, image_tag: str) -> str: | ||
controllers_namespace = py_config["applications_namespace"] |
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.
Up to you, I would remove this function and just set the path in the test where it's needed. (only used in one place) and introduce more complicity without any reason.
tests/workbenches/utils.py
Outdated
|
||
|
||
def load_default_notebook(dyn_client: DynamicClient, namespace: str, name: str, image: str) -> Notebook: | ||
notebook_string = (pathlib.Path(__file__).parent / "notebook-controller/test_data/notebook.yaml").read_text() |
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.
I think it's better to load the YAML here and work with dict which is python object and not with strings.
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.
ack, will see if I can get approvals from rhoai people without making the change; personally I don't want to make it
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.
please work with a dict; it is more readable and pythonic
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.
done
|
||
|
||
@pytest.fixture(scope="class") | ||
def users_namespace( |
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.
you can use unprivileged_model_namespace
https://github.com/opendatahub-io/opendatahub-tests/blob/main/tests/model_serving/model_server/authentication/conftest.py#L334 fixture; move it to upper conftest.
you can also add to create_ns
an new bool arg - add_dashboard_label
and apply the logic there
# | ||
# Copyright Skodjob authors. | ||
# License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). | ||
# |
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.
we currently do not have license info in our files; any reason to add it?
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.
saw no reason to remove it, more like; the code originally comes from odh-e2e repo
guess the world will not end in fire if I delete the header; deleted it now
# before_test_steps | ||
1. Step(value="Deploy Pipelines Operator", expected="Pipelines operator is available on the cluster"), | ||
2. Step(value="Deploy ServiceMesh Operator", expected="ServiceMesh operator is available on the cluster"), | ||
3. Step(value="Deploy Serverless Operator", expected="Serverless operator is available on the cluster"), | ||
4. Step(value="Install ODH operator", expected="Operator is up and running and is able to serve it's operands"), | ||
5. Step(value="Deploy DSCI", expected="DSCI is created and ready"), | ||
6. Step(value="Deploy DSC", expected="DSC is created and ready"), | ||
|
||
# after_test_steps | ||
1. Step(value="Delete all created resources", expected="All created resources are removed"), |
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.
this is not done in the tests so i am not sure why we need to include it here.
you can call skip_if_no_deployed_openshift_serverless
and skip_if_no_deployed_openshift_service_mesh
to skip the tests if these are not deployed or create new fixtures to fail if these are mandaotry
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.
removed
expected="Notebook pods are up and running, Notebook is in ready state", | ||
), | ||
""" | ||
with step("Create Notebook CR"): |
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.
can you please explain what is the value of using with step..
?
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.
just fancy documentation; deleted that part
expected="Notebook pods are up and running, Notebook is in ready state", | ||
), | ||
""" | ||
with step("Create Notebook CR"): |
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.
each step should either be a fixture (i.e setup for a test) or a test by itself. tests should verify one thing
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.
removed with step()
tests/workbenches/utils.py
Outdated
|
||
|
||
def get_notebook_image(image_name: str, image_tag: str) -> str: | ||
controllers_namespace = py_config["applications_namespace"] |
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.
+1 to that; used once and should be set where used
tests/workbenches/utils.py
Outdated
|
||
|
||
def load_default_notebook(dyn_client: DynamicClient, namespace: str, name: str, image: str) -> Notebook: | ||
notebook_string = (pathlib.Path(__file__).parent / "notebook-controller/test_data/notebook.yaml").read_text() |
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.
please work with a dict; it is more readable and pythonic
"""Gets the username for the client (see kubectl -v8 auth whoami)""" | ||
self_subject_review_resource: Resource = dyn_client.resources.get( | ||
api_version="authentication.k8s.io/v1", kind="SelfSubjectReview" | ||
) | ||
self_subject_review: ResourceInstance = dyn_client.create(self_subject_review_resource) | ||
username: str = self_subject_review.status.userInfo.username | ||
return username |
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.
wouldn'r running oc whoami
with run_command be easier?
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.
I don't think so, this way I should be able to use the same function with unpriviliged_client in some future test
tests/workbenches/utils.py
Outdated
@contextmanager | ||
def step(description: str) -> Generator[None, None, None]: | ||
yield |
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.
can you please explain why this is needed?
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.
so that with step() that I had in the test does not throw exception that step() is not defined
I've removed the definition and all usages now
utilities/constants.py
Outdated
@@ -107,6 +107,7 @@ class KserveAuth: | |||
|
|||
class OpenDataHubIo: | |||
MANAGED: str = "opendatahub.io/managed" | |||
SERVICE_MESH: str = "opendatahub.io/service-mesh" |
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.
please save opendatahub.io
and re-use
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.
done
…e test where it's needed
Description
This is a port of
How Has This Been Tested?
Merge criteria: