diff --git a/tests/.gitignore b/tests/.gitignore index b592560018..ae4758b7fe 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -11,3 +11,7 @@ results.xml __pycache__/ *.py[cod] .pytest_cache + +# Pytest HTML report +*.html +*.css diff --git a/tests/data/virtual-server-route-status/route-multiple-invalid-prefixed-path.yaml b/tests/data/virtual-server-route-status/route-multiple-invalid-prefixed-path.yaml new file mode 100644 index 0000000000..28463fe353 --- /dev/null +++ b/tests/data/virtual-server-route-status/route-multiple-invalid-prefixed-path.yaml @@ -0,0 +1,20 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: backends +spec: + host: virtual-server-route.example.com + upstreams: + - name: backend1 + service: backend1-svc + port: 80 + - name: backend3 + service: backend3-svc + port: 80 + subroutes: + - path: /backends/backend8 + action: + pass: backend1 + - path: /backends/backend9 + action: + pass: backend3 \ No newline at end of file diff --git a/tests/data/virtual-server-route-status/route-multiple-invalid.yaml b/tests/data/virtual-server-route-status/route-multiple-invalid.yaml new file mode 100644 index 0000000000..c02d0265ad --- /dev/null +++ b/tests/data/virtual-server-route-status/route-multiple-invalid.yaml @@ -0,0 +1,20 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: backends +spec: + host: virtual-server-route.example.com + upstreams: + - name: backend1 + service: backend1-svc + port: 80 + - name: backend3 + service: backend3-svc + port: 80 + subroutes: + - path: backends/backend1 + action: + pass: backend1 + - path: backends/backend3 + action: + pass: backend3 \ No newline at end of file diff --git a/tests/data/virtual-server-route-status/route-multiple.yaml b/tests/data/virtual-server-route-status/route-multiple.yaml new file mode 100644 index 0000000000..240c8a5c57 --- /dev/null +++ b/tests/data/virtual-server-route-status/route-multiple.yaml @@ -0,0 +1,20 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: backends +spec: + host: virtual-server-route.example.com + upstreams: + - name: backend1 + service: backend1-svc + port: 80 + - name: backend3 + service: backend3-svc + port: 80 + subroutes: + - path: /backends/backend1 + action: + pass: backend1 + - path: /backends/backend3 + action: + pass: backend3 \ No newline at end of file diff --git a/tests/data/virtual-server-route-status/route-single-invalid-prefixed-path.yaml b/tests/data/virtual-server-route-status/route-single-invalid-prefixed-path.yaml new file mode 100644 index 0000000000..d095ea70a1 --- /dev/null +++ b/tests/data/virtual-server-route-status/route-single-invalid-prefixed-path.yaml @@ -0,0 +1,14 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: backend2 +spec: + host: virtual-server-route.example.com + upstreams: + - name: backend2 + service: backend2-svc + port: 80 + subroutes: + - path: /backend6 + action: + pass: backend2 \ No newline at end of file diff --git a/tests/data/virtual-server-route-status/route-single-invalid.yaml b/tests/data/virtual-server-route-status/route-single-invalid.yaml new file mode 100644 index 0000000000..aef0241704 --- /dev/null +++ b/tests/data/virtual-server-route-status/route-single-invalid.yaml @@ -0,0 +1,14 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: backend2 +spec: + host: virtual-server-route.example.com + upstreams: + - name: backend2 + service: backend2-svc + port: 80 + subroutes: + - path: backend2 + action: + pass: backend2 \ No newline at end of file diff --git a/tests/data/virtual-server-route-status/route-single.yaml b/tests/data/virtual-server-route-status/route-single.yaml new file mode 100644 index 0000000000..fe7702fa7e --- /dev/null +++ b/tests/data/virtual-server-route-status/route-single.yaml @@ -0,0 +1,14 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: backend2 +spec: + host: virtual-server-route.example.com + upstreams: + - name: backend2 + service: backend2-svc + port: 80 + subroutes: + - path: /backend2 + action: + pass: backend2 \ No newline at end of file diff --git a/tests/data/virtual-server-route-status/standard/virtual-server.yaml b/tests/data/virtual-server-route-status/standard/virtual-server.yaml new file mode 100644 index 0000000000..b98d4cf0a2 --- /dev/null +++ b/tests/data/virtual-server-route-status/standard/virtual-server.yaml @@ -0,0 +1,11 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServer +metadata: + name: virtual-server-route +spec: + host: virtual-server-route.example.com + routes: + - path: /backends + route: backends-namespace/backends + - path: /backend2 + route: backend2-namespace/backend2 \ No newline at end of file diff --git a/tests/data/virtual-server-route-status/virtual-server-invalid.yaml b/tests/data/virtual-server-route-status/virtual-server-invalid.yaml new file mode 100644 index 0000000000..bd47e5ea29 --- /dev/null +++ b/tests/data/virtual-server-route-status/virtual-server-invalid.yaml @@ -0,0 +1,11 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServer +metadata: + name: virtual-server-route +spec: + host: virtual-server-route.example.com + routes: + - path: /backend_x + route: backends-namespace/backend_x + - path: /backend_y + route: backend2-namespace/backend_y \ No newline at end of file diff --git a/tests/data/virtual-server-status/invalid-state.yaml b/tests/data/virtual-server-status/invalid-state.yaml new file mode 100644 index 0000000000..8c9c324f41 --- /dev/null +++ b/tests/data/virtual-server-status/invalid-state.yaml @@ -0,0 +1,20 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServer +metadata: + name: virtual-server-status +spec: + host: virtual-server-status.example.com + upstreams: + - name: backend2 + service: backend2-svc + port: 80 + - name: backend1 + service: backend1-svc + port: 80 + routes: + - path: backend1 + action: + pass: backend1 + - path: backend2 + action: + pass: backend2 \ No newline at end of file diff --git a/tests/data/virtual-server-status/standard/virtual-server.yaml b/tests/data/virtual-server-status/standard/virtual-server.yaml new file mode 100644 index 0000000000..971bac17b1 --- /dev/null +++ b/tests/data/virtual-server-status/standard/virtual-server.yaml @@ -0,0 +1,20 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServer +metadata: + name: virtual-server-status +spec: + host: virtual-server-status.example.com + upstreams: + - name: backend2 + service: backend2-svc + port: 80 + - name: backend1 + service: backend1-svc + port: 80 + routes: + - path: /backend1 + action: + pass: backend1 + - path: /backend2 + action: + pass: backend2 \ No newline at end of file diff --git a/tests/data/virtual-server-status/warning-state.yaml b/tests/data/virtual-server-status/warning-state.yaml new file mode 100644 index 0000000000..ad2c076e19 --- /dev/null +++ b/tests/data/virtual-server-status/warning-state.yaml @@ -0,0 +1,22 @@ +apiVersion: k8s.nginx.org/v1 +kind: VirtualServer +metadata: + name: virtual-server-status +spec: + host: virtual-server-status.example.com + upstreams: + - name: backend2 + service: backend2-svc + lb-method: random + slow-start: 1m + port: 80 + - name: backend1 + service: backend1-svc + port: 80 + routes: + - path: /backend1 + action: + pass: backend1 + - path: /backend2 + action: + pass: backend2 \ No newline at end of file diff --git a/tests/requirements.txt b/tests/requirements.txt index 1a646fdec4..40ddfd3c9f 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -7,4 +7,5 @@ ipaddress==1.0.22 # >= 1.0.17 cffi==1.12.3 pyopenssl==19.0.0 certifi==2019.6.16 -urllib3==1.25.3 \ No newline at end of file +urllib3==1.25.3 +pytest-html==2.1.1 \ No newline at end of file diff --git a/tests/suite/custom_resources_utils.py b/tests/suite/custom_resources_utils.py index 2f58f43f88..24a2234ece 100644 --- a/tests/suite/custom_resources_utils.py +++ b/tests/suite/custom_resources_utils.py @@ -1,7 +1,9 @@ """Describe methods to utilize the kubernetes-client.""" import pytest import yaml +import logging +from pprint import pprint from kubernetes.client import CustomObjectsApi, ApiextensionsV1beta1Api, CoreV1Api from kubernetes import client from kubernetes.client.rest import ApiException @@ -23,13 +25,15 @@ def create_crd(api_extensions_v1_beta1: ApiextensionsV1beta1Api, body) -> None: # ApiException(f"An unexpected exception occurred: {api_ex}", reason=api_ex.reason) except Exception as ex: # https://github.com/kubernetes-client/python/issues/376 - if ex.args[0] == 'Invalid value for `conditions`, must not be `None`': + if ex.args[0] == "Invalid value for `conditions`, must not be `None`": print("There was an insignificant exception during the CRD creation. Continue...") else: pytest.fail(f"An unexpected exception {ex} occurred. Exiting...") -def create_crd_from_yaml(api_extensions_v1_beta1: ApiextensionsV1beta1Api, name, yaml_manifest) -> None: +def create_crd_from_yaml( + api_extensions_v1_beta1: ApiextensionsV1beta1Api, name, yaml_manifest +) -> None: """ Create a specific CRD based on yaml file. @@ -41,7 +45,7 @@ def create_crd_from_yaml(api_extensions_v1_beta1: ApiextensionsV1beta1Api, name, with open(yaml_manifest) as f: docs = yaml.safe_load_all(f) for dep in docs: - if dep['metadata']['name'] == name: + if dep["metadata"]["name"] == name: create_crd(api_extensions_v1_beta1, dep) print("CRD was created") @@ -61,7 +65,32 @@ def delete_crd(api_extensions_v1_beta1: ApiextensionsV1beta1Api, name) -> None: print(f"CRD was removed with name '{name}'") -def create_virtual_server_from_yaml(custom_objects: CustomObjectsApi, yaml_manifest, namespace) -> str: +def read_crd(custom_objects: CustomObjectsApi, namespace, plural, name) -> object: + """ + Get CRD information (kubectl describe output) + + :param custom_objects: CustomObjectsApi + :param namespace: The custom resource's namespace + :param plural: the custom resource's plural name + :param name: the custom object's name + :return: object + """ + print(f"Getting info for {name} in namespace {namespace}") + try: + response = custom_objects.get_namespaced_custom_object( + "k8s.nginx.org", "v1", namespace, plural, name + ) + pprint(response) + return response + + except ApiException as ex: + logging.exception(f"Exception occured: {ex} while getting reading CRD") + raise + + +def create_virtual_server_from_yaml( + custom_objects: CustomObjectsApi, yaml_manifest, namespace +) -> str: """ Create a VirtualServer based on yaml file. @@ -73,10 +102,17 @@ def create_virtual_server_from_yaml(custom_objects: CustomObjectsApi, yaml_manif print("Create a VirtualServer:") with open(yaml_manifest) as f: dep = yaml.safe_load(f) - - custom_objects.create_namespaced_custom_object("k8s.nginx.org", "v1", namespace, "virtualservers", dep) - print(f"VirtualServer created with name '{dep['metadata']['name']}'") - return dep['metadata']['name'] + try: + custom_objects.create_namespaced_custom_object( + "k8s.nginx.org", "v1", namespace, "virtualservers", dep + ) + print(f"VirtualServer created with name '{dep['metadata']['name']}'") + return dep["metadata"]["name"] + except ApiException as ex: + logging.exception( + f"Exception: {ex} occured while creating VirtualServer: {dep['metadata']['name']}" + ) + raise def delete_virtual_server(custom_objects: CustomObjectsApi, name, namespace) -> None: @@ -90,14 +126,24 @@ def delete_virtual_server(custom_objects: CustomObjectsApi, name, namespace) -> """ print(f"Delete a VirtualServer: {name}") delete_options = client.V1DeleteOptions() - custom_objects.delete_namespaced_custom_object("k8s.nginx.org", - "v1", namespace, "virtualservers", name, delete_options) - ensure_item_removal(custom_objects.get_namespaced_custom_object, - "k8s.nginx.org", "v1", namespace, "virtualservers", name) + + custom_objects.delete_namespaced_custom_object( + "k8s.nginx.org", "v1", namespace, "virtualservers", name, delete_options + ) + ensure_item_removal( + custom_objects.get_namespaced_custom_object, + "k8s.nginx.org", + "v1", + namespace, + "virtualservers", + name, + ) print(f"VirtualServer was removed with name '{name}'") -def patch_virtual_server_from_yaml(custom_objects: CustomObjectsApi, name, yaml_manifest, namespace) -> None: +def patch_virtual_server_from_yaml( + custom_objects: CustomObjectsApi, name, yaml_manifest, namespace +) -> None: """ Patch a VS based on yaml manifest @@ -111,8 +157,14 @@ def patch_virtual_server_from_yaml(custom_objects: CustomObjectsApi, name, yaml_ with open(yaml_manifest) as f: dep = yaml.safe_load(f) - custom_objects.patch_namespaced_custom_object("k8s.nginx.org", "v1", namespace, "virtualservers", name, dep) - print(f"VirtualServer updated with name '{dep['metadata']['name']}'") + try: + custom_objects.patch_namespaced_custom_object( + "k8s.nginx.org", "v1", namespace, "virtualservers", name, dep + ) + print(f"VirtualServer updated with name '{dep['metadata']['name']}'") + except ApiException as ex: + logging.exception(f"Failed with exception {ex} while patching VirtualServer: {name}") + raise def patch_virtual_server(custom_objects: CustomObjectsApi, name, namespace, body) -> str: @@ -126,12 +178,16 @@ def patch_virtual_server(custom_objects: CustomObjectsApi, name, namespace, body :return: str """ print("Update a VirtualServer:") - custom_objects.patch_namespaced_custom_object("k8s.nginx.org", "v1", namespace, "virtualservers", name, body) + custom_objects.patch_namespaced_custom_object( + "k8s.nginx.org", "v1", namespace, "virtualservers", name, body + ) print(f"VirtualServer updated with a name '{body['metadata']['name']}'") - return body['metadata']['name'] + return body["metadata"]["name"] -def patch_v_s_route_from_yaml(custom_objects: CustomObjectsApi, name, yaml_manifest, namespace) -> None: +def patch_v_s_route_from_yaml( + custom_objects: CustomObjectsApi, name, yaml_manifest, namespace +) -> None: """ Update a VirtualServerRoute based on yaml manifest @@ -144,12 +200,19 @@ def patch_v_s_route_from_yaml(custom_objects: CustomObjectsApi, name, yaml_manif print(f"Update a VirtualServerRoute: {name}") with open(yaml_manifest) as f: dep = yaml.safe_load(f) - - custom_objects.patch_namespaced_custom_object("k8s.nginx.org", "v1", namespace, "virtualserverroutes", name, dep) - print(f"VirtualServerRoute updated with name '{dep['metadata']['name']}'") - - -def get_vs_nginx_template_conf(v1: CoreV1Api, vs_namespace, vs_name, pod_name, pod_namespace) -> str: + try: + custom_objects.patch_namespaced_custom_object( + "k8s.nginx.org", "v1", namespace, "virtualserverroutes", name, dep + ) + print(f"VirtualServerRoute updated with name '{dep['metadata']['name']}'") + except ApiException as ex: + logging.exception(f"Failed with exception {ex} while patching VirtualServerRoute: {name}") + raise + + +def get_vs_nginx_template_conf( + v1: CoreV1Api, vs_namespace, vs_name, pod_name, pod_namespace +) -> str: """ Get contents of /etc/nginx/conf.d/vs_{namespace}_{vs_name}.conf in the pod. @@ -177,9 +240,11 @@ def create_v_s_route_from_yaml(custom_objects: CustomObjectsApi, yaml_manifest, with open(yaml_manifest) as f: dep = yaml.safe_load(f) - custom_objects.create_namespaced_custom_object("k8s.nginx.org", "v1", namespace, "virtualserverroutes", dep) + custom_objects.create_namespaced_custom_object( + "k8s.nginx.org", "v1", namespace, "virtualserverroutes", dep + ) print(f"VirtualServerRoute created with a name '{dep['metadata']['name']}'") - return dep['metadata']['name'] + return dep["metadata"]["name"] def patch_v_s_route(custom_objects: CustomObjectsApi, name, namespace, body) -> str: @@ -193,9 +258,11 @@ def patch_v_s_route(custom_objects: CustomObjectsApi, name, namespace, body) -> :return: str """ print("Update a VirtualServerRoute:") - custom_objects.patch_namespaced_custom_object("k8s.nginx.org", "v1", namespace, "virtualserverroutes", name, body) + custom_objects.patch_namespaced_custom_object( + "k8s.nginx.org", "v1", namespace, "virtualserverroutes", name, body + ) print(f"VirtualServerRoute updated with a name '{body['metadata']['name']}'") - return body['metadata']['name'] + return body["metadata"]["name"] def delete_v_s_route(custom_objects: CustomObjectsApi, name, namespace) -> None: @@ -209,10 +276,17 @@ def delete_v_s_route(custom_objects: CustomObjectsApi, name, namespace) -> None: """ print(f"Delete a VirtualServerRoute: {name}") delete_options = client.V1DeleteOptions() - custom_objects.delete_namespaced_custom_object("k8s.nginx.org", - "v1", namespace, "virtualserverroutes", name, delete_options) - ensure_item_removal(custom_objects.get_namespaced_custom_object, - "k8s.nginx.org", "v1", namespace, "virtualserverroutes", name) + custom_objects.delete_namespaced_custom_object( + "k8s.nginx.org", "v1", namespace, "virtualserverroutes", name, delete_options + ) + ensure_item_removal( + custom_objects.get_namespaced_custom_object, + "k8s.nginx.org", + "v1", + namespace, + "virtualserverroutes", + name, + ) print(f"VirtualServerRoute was removed with the name '{name}'") @@ -227,6 +301,6 @@ def generate_item_with_upstream_options(yaml_manifest, options) -> dict: """ with open(yaml_manifest) as f: dep = yaml.safe_load(f) - for upstream in dep['spec']['upstreams']: + for upstream in dep["spec"]["upstreams"]: upstream.update(options) return dep diff --git a/tests/suite/test_v_s_route_status.py b/tests/suite/test_v_s_route_status.py new file mode 100644 index 0000000000..3afba96f21 --- /dev/null +++ b/tests/suite/test_v_s_route_status.py @@ -0,0 +1,272 @@ +import pytest +from kubernetes.client.rest import ApiException +from suite.resources_utils import wait_before_test +from suite.custom_resources_utils import ( + read_crd, + patch_virtual_server_from_yaml, + patch_v_s_route_from_yaml, + delete_virtual_server, + create_virtual_server_from_yaml, +) +from settings import TEST_DATA + +@pytest.mark.vsr +@pytest.mark.parametrize( + "crd_ingress_controller, v_s_route_setup", + [ + ( + {"type": "complete", "extra_args": [f"-enable-custom-resources"],}, + {"example": "virtual-server-route-status"}, + ) + ], + indirect=True, +) +class TestVirtualServerRouteStatus: + def patch_valid_vsr(self, kube_apis, v_s_route_setup) -> None: + """ + Function to revert vsr deployments to valid state + """ + patch_src_m = f"{TEST_DATA}/virtual-server-route-status/route-multiple.yaml" + patch_v_s_route_from_yaml( + kube_apis.custom_objects, + v_s_route_setup.route_m.name, + patch_src_m, + v_s_route_setup.route_m.namespace, + ) + wait_before_test() + patch_src_s = f"{TEST_DATA}/virtual-server-route-status/route-single.yaml" + patch_v_s_route_from_yaml( + kube_apis.custom_objects, + v_s_route_setup.route_s.name, + patch_src_s, + v_s_route_setup.route_s.namespace, + ) + wait_before_test() + + def patch_valid_vs(self, kube_apis, v_s_route_setup) -> None: + """ + Function to revert vs deployment to valid state + """ + patch_src = f"{TEST_DATA}/virtual-server-route-status/standard/virtual-server.yaml" + patch_virtual_server_from_yaml( + kube_apis.custom_objects, v_s_route_setup.vs_name, patch_src, v_s_route_setup.namespace, + ) + wait_before_test() + + @pytest.mark.smoke + def test_status_valid( + self, kube_apis, crd_ingress_controller, v_s_route_setup, v_s_route_app_setup + ): + """ + Test VirtualServerRoute status with a valid fields in yaml + """ + response_m = read_crd( + kube_apis.custom_objects, + v_s_route_setup.route_m.namespace, + "virtualserverroutes", + v_s_route_setup.route_m.name, + ) + response_s = read_crd( + kube_apis.custom_objects, + v_s_route_setup.route_s.namespace, + "virtualserverroutes", + v_s_route_setup.route_s.name, + ) + assert ( + response_m["status"] + and response_m["status"]["reason"] == "AddedOrUpdated" + and response_m["status"]["referencedBy"] + and response_m["status"]["state"] == "Valid" + ) + + assert ( + response_s["status"] + and response_s["status"]["reason"] == "AddedOrUpdated" + and response_s["status"]["referencedBy"] + and response_s["status"]["state"] == "Valid" + ) + + def test_status_invalid( + self, kube_apis, crd_ingress_controller, v_s_route_setup, v_s_route_app_setup + ): + """ + Test VirtualServerRoute status with a invalid paths in vsr yaml + """ + patch_src_m = f"{TEST_DATA}/virtual-server-route-status/route-multiple-invalid.yaml" + patch_v_s_route_from_yaml( + kube_apis.custom_objects, + v_s_route_setup.route_m.name, + patch_src_m, + v_s_route_setup.route_m.namespace, + ) + wait_before_test() + patch_src_s = f"{TEST_DATA}/virtual-server-route-status/route-single-invalid.yaml" + patch_v_s_route_from_yaml( + kube_apis.custom_objects, + v_s_route_setup.route_s.name, + patch_src_s, + v_s_route_setup.route_s.namespace, + ) + wait_before_test() + + response_m = read_crd( + kube_apis.custom_objects, + v_s_route_setup.route_m.namespace, + "virtualserverroutes", + v_s_route_setup.route_m.name, + ) + response_s = read_crd( + kube_apis.custom_objects, + v_s_route_setup.route_s.namespace, + "virtualserverroutes", + v_s_route_setup.route_s.name, + ) + + self.patch_valid_vsr(kube_apis, v_s_route_setup) + assert ( + response_m["status"] + and response_m["status"]["reason"] == "Rejected" + and response_m["status"]["referencedBy"] + and response_m["status"]["state"] == "Invalid" + ) + + assert ( + response_s["status"] + and response_s["status"]["reason"] == "Rejected" + and response_s["status"]["referencedBy"] + and response_s["status"]["state"] == "Invalid" + ) + + def test_status_invalid_prefix( + self, kube_apis, crd_ingress_controller, v_s_route_setup, v_s_route_app_setup + ): + """ + Test VirtualServerRoute status with a invalid path /prefix in vsr yaml + i.e. referring to non-existing path + """ + patch_src_m = f"{TEST_DATA}/virtual-server-route-status/route-multiple-invalid-prefixed-path.yaml" + patch_v_s_route_from_yaml( + kube_apis.custom_objects, + v_s_route_setup.route_m.name, + patch_src_m, + v_s_route_setup.route_m.namespace, + ) + wait_before_test() + patch_src_s = f"{TEST_DATA}/virtual-server-route-status/route-single-invalid-prefixed-path.yaml" + patch_v_s_route_from_yaml( + kube_apis.custom_objects, + v_s_route_setup.route_s.name, + patch_src_s, + v_s_route_setup.route_s.namespace, + ) + wait_before_test() + + response_m = read_crd( + kube_apis.custom_objects, + v_s_route_setup.route_m.namespace, + "virtualserverroutes", + v_s_route_setup.route_m.name, + ) + response_s = read_crd( + kube_apis.custom_objects, + v_s_route_setup.route_s.namespace, + "virtualserverroutes", + v_s_route_setup.route_s.name, + ) + + self.patch_valid_vsr(kube_apis, v_s_route_setup) + assert ( + response_m["status"] + and response_m["status"]["reason"] == "AddedOrUpdated" + and response_m["status"]["referencedBy"] + and response_m["status"]["state"] == "Valid" + ) + + assert ( + response_s["status"] + and response_s["status"]["reason"] == "AddedOrUpdated" + and response_s["status"]["referencedBy"] + and response_s["status"]["state"] == "Valid" + ) + + @pytest.mark.skip + def test_status_invalid_vs( + self, kube_apis, crd_ingress_controller, v_s_route_setup, v_s_route_app_setup + ): + """ + Test VirtualServerRoute status with invalid reference in vs yaml + """ + + patch_src = f"{TEST_DATA}/virtual-server-route-status/virtual-server-invalid.yaml" + patch_virtual_server_from_yaml( + kube_apis.custom_objects, v_s_route_setup.vs_name, patch_src, v_s_route_setup.namespace, + ) + wait_before_test() + + response_m = read_crd( + kube_apis.custom_objects, + v_s_route_setup.route_m.namespace, + "virtualserverroutes", + v_s_route_setup.route_m.name, + ) + response_s = read_crd( + kube_apis.custom_objects, + v_s_route_setup.route_s.namespace, + "virtualserverroutes", + v_s_route_setup.route_s.name, + ) + self.patch_valid_vs(kube_apis, v_s_route_setup) + assert ( + response_m["status"] + and response_m["status"]["reason"] == "Rejected" + and not response_m["status"]["referencedBy"] + and response_m["status"]["state"] == "Invalid" + ) + + assert ( + response_s["status"] + and response_s["status"]["reason"] == "Rejected" + and not response_s["status"]["referencedBy"] + and response_s["status"]["state"] == "Invalid" + ) + + @pytest.mark.skip + def test_status_remove_vs( + self, kube_apis, crd_ingress_controller, v_s_route_setup, v_s_route_app_setup + ): + """ + Test VirtualServerRoute status after deleting referenced VirtualServer + """ + delete_virtual_server( + kube_apis.custom_objects, v_s_route_setup.vs_name, v_s_route_setup.namespace, + ) + + response_m = read_crd( + kube_apis.custom_objects, + v_s_route_setup.route_m.namespace, + "virtualserverroutes", + v_s_route_setup.route_m.name, + ) + response_s = read_crd( + kube_apis.custom_objects, + v_s_route_setup.route_s.namespace, + "virtualserverroutes", + v_s_route_setup.route_s.name, + ) + + vs_src = f"{TEST_DATA}/virtual-server-route-status/standard/virtual-server.yaml" + create_virtual_server_from_yaml(kube_apis.custom_objects, vs_src, v_s_route_setup.namespace) + + assert ( + response_m["status"] + and response_m["status"]["reason"] == "Rejected" + and not response_m["status"]["referencedBy"] + and response_m["status"]["state"] == "Invalid" + ) + + assert ( + response_s["status"] + and response_s["status"]["reason"] == "Rejected" + and not response_s["status"]["referencedBy"] + and response_s["status"]["state"] == "Invalid" + ) diff --git a/tests/suite/test_v_s_route_upstream_options.py b/tests/suite/test_v_s_route_upstream_options.py index 91c9382cb0..3fe89ec08c 100644 --- a/tests/suite/test_v_s_route_upstream_options.py +++ b/tests/suite/test_v_s_route_upstream_options.py @@ -222,7 +222,7 @@ def test_v_s_r_overrides_config_map(self, kube_apis, replace_configmap_from_yaml(kube_apis.v1, config_map_name, ingress_controller_prerequisites.namespace, f"{TEST_DATA}/virtual-server-route-upstream-options/configmap-with-keys.yaml") - wait_before_test(2) + wait_before_test() ic_pod_name = get_first_pod_name(kube_apis.v1, ingress_controller_prerequisites.namespace) config = get_vs_nginx_template_conf(kube_apis.v1, v_s_route_setup.namespace, diff --git a/tests/suite/test_virtual_server_status.py b/tests/suite/test_virtual_server_status.py new file mode 100644 index 0000000000..0892e0c730 --- /dev/null +++ b/tests/suite/test_virtual_server_status.py @@ -0,0 +1,107 @@ +import pytest +from kubernetes.client.rest import ApiException +from suite.resources_utils import wait_before_test +from suite.custom_resources_utils import ( + read_crd, + patch_virtual_server_from_yaml, +) +from settings import TEST_DATA + +@pytest.mark.vs +@pytest.mark.parametrize( + "crd_ingress_controller, virtual_server_setup", + [ + ( + {"type": "complete", "extra_args": [f"-enable-custom-resources"],}, + {"example": "virtual-server-status", "app_type": "simple",}, + ) + ], + indirect=True, +) +class TestVirtualServerStatus: + + def patch_valid_vs(self, kube_apis, virtual_server_setup) -> None: + """ + Function to revert vs deployment to valid state + """ + patch_src = f"{TEST_DATA}/virtual-server-status/standard/virtual-server.yaml" + patch_virtual_server_from_yaml( + kube_apis.custom_objects, + virtual_server_setup.vs_name, + patch_src, + virtual_server_setup.namespace, + ) + + @pytest.mark.smoke + def test_status_valid( + self, kube_apis, crd_ingress_controller, virtual_server_setup, + ): + """ + Test VirtualServer status with a valid fields in yaml + """ + response = read_crd( + kube_apis.custom_objects, + virtual_server_setup.namespace, + "virtualservers", + virtual_server_setup.vs_name, + ) + assert ( + response["status"] + and response["status"]["reason"] == "AddedOrUpdated" + and response["status"]["state"] == "Valid" + ) + + def test_status_invalid( + self, kube_apis, crd_ingress_controller, virtual_server_setup, + ): + """ + Test VirtualServer status with a invalid path pattern + """ + patch_src = f"{TEST_DATA}/virtual-server-status/invalid-state.yaml" + patch_virtual_server_from_yaml( + kube_apis.custom_objects, + virtual_server_setup.vs_name, + patch_src, + virtual_server_setup.namespace, + ) + wait_before_test() + response = read_crd( + kube_apis.custom_objects, + virtual_server_setup.namespace, + "virtualservers", + virtual_server_setup.vs_name, + ) + self.patch_valid_vs(kube_apis, virtual_server_setup) + assert ( + response["status"] + and response["status"]["reason"] == "Rejected" + and response["status"]["state"] == "Invalid" + ) + + @pytest.mark.skip_for_nginx_oss + def test_status_warning( + self, kube_apis, crd_ingress_controller, virtual_server_setup, + ): + """ + Test VirtualServer status with conflicting Upstream fields + Only for N+ since Slow-start isn + """ + patch_src = f"{TEST_DATA}/virtual-server-status/warning-state.yaml" + patch_virtual_server_from_yaml( + kube_apis.custom_objects, + virtual_server_setup.vs_name, + patch_src, + virtual_server_setup.namespace, + ) + wait_before_test() + response = read_crd( + kube_apis.custom_objects, + virtual_server_setup.namespace, + "virtualservers", + virtual_server_setup.vs_name, + ) + assert ( + response["status"] + and response["status"]["reason"] == "AddedOrUpdatedWithWarning" + and response["status"]["state"] == "Warning" + )