diff options
Diffstat (limited to 'k8s/tests')
-rw-r--r-- | k8s/tests/conftest.py | 34 | ||||
-rw-r--r-- | k8s/tests/test_decorators.py | 34 | ||||
-rw-r--r-- | k8s/tests/test_discovery.py | 71 | ||||
-rw-r--r-- | k8s/tests/test_tasks.py | 293 | ||||
-rw-r--r-- | k8s/tests/test_utils.py | 33 |
5 files changed, 465 insertions, 0 deletions
diff --git a/k8s/tests/conftest.py b/k8s/tests/conftest.py new file mode 100644 index 0000000..572a510 --- /dev/null +++ b/k8s/tests/conftest.py @@ -0,0 +1,34 @@ +# ============LICENSE_START======================================================= +# org.onap.dcae +# ================================================================================ +# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. + +import pytest + +@pytest.fixture() +def mockconfig(monkeypatch): + """ Override the regular configure() routine that reads a file and calls Consul""" + def altconfig(): + return { + "consul_host": "consul", + "namespace":"dcae", + "consul_dns_name" : "consul", + "image_pull_secrets" : [] + } + from configure import configure + monkeypatch.setattr(configure, 'configure', altconfig)
\ No newline at end of file diff --git a/k8s/tests/test_decorators.py b/k8s/tests/test_decorators.py new file mode 100644 index 0000000..552fa4b --- /dev/null +++ b/k8s/tests/test_decorators.py @@ -0,0 +1,34 @@ +# ============LICENSE_START======================================================= +# org.onap.dcae +# ================================================================================ +# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. + +def test_wrapper_merge_inputs(mockconfig): + from k8splugin import decorators as dec + + properties = { "app_config": {"nested": { "a": 123, "b": 456 }, "foo": "duh"}, + "image": "some-docker-image" } + kwargs = { "app_config": {"nested": {"a": 789, "c": "zyx"}} } + + def task_func(**inputs): + return inputs + + expected = { "app_config": {"nested": { "a": 789, "b": 456, "c": "zyx" }, + "foo": "duh"}, "image": "some-docker-image" } + + assert expected == dec._wrapper_merge_inputs(task_func, properties, **kwargs)
\ No newline at end of file diff --git a/k8s/tests/test_discovery.py b/k8s/tests/test_discovery.py new file mode 100644 index 0000000..24e45ee --- /dev/null +++ b/k8s/tests/test_discovery.py @@ -0,0 +1,71 @@ +# ============LICENSE_START======================================================= +# org.onap.dcae +# ================================================================================ +# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. + +import pytest +from functools import partial +import requests + +def test_wrap_consul_call(mockconfig): + from k8splugin import discovery as dis + + def foo(a, b, c="default"): + return " ".join([a, b, c]) + + wrapped_foo = partial(dis._wrap_consul_call, foo) + assert wrapped_foo("hello", "world") == "hello world default" + assert wrapped_foo("hello", "world", c="new masters") == "hello world new masters" + + def foo_connection_error(a, b, c): + raise requests.exceptions.ConnectionError("simulate failed connection") + + wrapped_foo = partial(dis._wrap_consul_call, foo_connection_error) + with pytest.raises(dis.DiscoveryConnectionError): + wrapped_foo("a", "b", "c") + +def test_generate_service_component_name(mockconfig): + from k8splugin import discovery as dis + + component_type = "some-component-type" + name = dis.generate_service_component_name(component_type) + assert name.split("-", 1)[1] == component_type + +def test_find_matching_services(mockconfig): + from k8splugin import discovery as dis + + services = { "component_dockerhost_1": ["foo", "bar"], + "platform_dockerhost": [], "component_dockerhost_2": ["baz"] } + assert sorted(["component_dockerhost_1", "component_dockerhost_2"]) \ + == sorted(dis._find_matching_services(services, "component_dockerhost", [])) + + assert ["component_dockerhost_1"] == dis._find_matching_services(services, \ + "component_dockerhost", ["foo", "bar"]) + + assert ["component_dockerhost_1"] == dis._find_matching_services(services, \ + "component_dockerhost", ["foo"]) + + assert [] == dis._find_matching_services(services, "unknown", ["foo"]) + +def test_is_healthy_pure(mockconfig): + from k8splugin import discovery as dis + + def fake_is_healthy(name): + return 0, [{ "Checks": [{"Status": "passing"}] }] + + assert True == dis._is_healthy_pure(fake_is_healthy, "some-component")
\ No newline at end of file diff --git a/k8s/tests/test_tasks.py b/k8s/tests/test_tasks.py new file mode 100644 index 0000000..4d0aa90 --- /dev/null +++ b/k8s/tests/test_tasks.py @@ -0,0 +1,293 @@ +# ============LICENSE_START======================================================= +# org.onap.dcae +# ================================================================================ +# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. + +import copy +import pytest +from cloudify.exceptions import NonRecoverableError, RecoverableError + + +def test_generate_component_name(mockconfig): + from k8splugin import tasks + kwargs = { "service_component_type": "doodle", + "service_component_name_override": None } + + assert "doodle" in tasks._generate_component_name(**kwargs)["name"] + + kwargs["service_component_name_override"] = "yankee" + + assert "yankee" == tasks._generate_component_name(**kwargs)["name"] + + +def test_parse_streams(monkeypatch, mockconfig): + import k8splugin + from k8splugin import tasks + # Good case for streams_publishes + test_input = { "streams_publishes": [{"name": "topic00", "type": "message_router"}, + {"name": "feed00", "type": "data_router"}], + "streams_subscribes": {} } + + expected = {'feed00': {'type': 'data_router', 'name': 'feed00'}, + 'streams_publishes': [{'type': 'message_router', 'name': 'topic00'}, + {'type': 'data_router', 'name': 'feed00'}], + 'streams_subscribes': {}, + 'topic00': {'type': 'message_router', 'name': 'topic00'} + } + + assert expected == tasks._parse_streams(**test_input) + + # Good case for streams_subscribes (password provided) + test_input = { "streams_publishes": {}, + "streams_subscribes": [{"name": "topic01", "type": "message_router"}, + {"name": "feed01", "type": "data_router", "username": "hero", + "password": "123456"}] } + + expected = {'feed01': {'type': 'data_router', 'name': 'feed01', + 'username': 'hero', 'password': '123456'}, + 'streams_publishes': {}, + 'streams_subscribes': [{'type': 'message_router', 'name': 'topic01'}, + {'type': 'data_router', 'name': 'feed01', 'username': 'hero', + 'password': '123456'}], + 'topic01': {'type': 'message_router', 'name': 'topic01'}} + + assert expected == tasks._parse_streams(**test_input) + + # Good case for streams_subscribes (password generated) + test_input = { "streams_publishes": {}, + "streams_subscribes": [{"name": "topic01", "type": "message_router"}, + {"name": "feed01", "type": "data_router", "username": None, + "password": None}] } + + def not_so_random(n): + return "nosurprise" + + monkeypatch.setattr(k8splugin.utils, "random_string", not_so_random) + + expected = {'feed01': {'type': 'data_router', 'name': 'feed01', + 'username': 'nosurprise', 'password': 'nosurprise'}, + 'streams_publishes': {}, + 'streams_subscribes': [{'type': 'message_router', 'name': 'topic01'}, + {'type': 'data_router', 'name': 'feed01', 'username': None, + 'password': None}], + 'topic01': {'type': 'message_router', 'name': 'topic01'}} + + assert expected == tasks._parse_streams(**test_input) + + +def test_setup_for_discovery(monkeypatch, mockconfig): + import k8splugin + from k8splugin import tasks + + test_input = { "name": "some-name", + "application_config": { "one": "a", "two": "b" } } + + def fake_push_config(conn, name, application_config): + return + + monkeypatch.setattr(k8splugin.discovery, "push_service_component_config", + fake_push_config) + + assert test_input == tasks._setup_for_discovery(**test_input) + + def fake_push_config_connection_error(conn, name, application_config): + raise k8splugin.discovery.DiscoveryConnectionError("Boom") + + monkeypatch.setattr(k8splugin.discovery, "push_service_component_config", + fake_push_config_connection_error) + + with pytest.raises(RecoverableError): + tasks._setup_for_discovery(**test_input) + + +def test_setup_for_discovery_streams(monkeypatch, mockconfig): + import k8splugin + from k8splugin import tasks + test_input = {'feed01': {'type': 'data_router', 'name': 'feed01', + 'username': 'hero', 'password': '123456', 'location': 'Bedminster'}, + 'streams_publishes': {}, + 'streams_subscribes': [{'type': 'message_router', 'name': 'topic01'}, + {'type': 'data_router', 'name': 'feed01', 'username': 'hero', + 'password': '123456', 'location': 'Bedminster'}], + 'topic01': {'type': 'message_router', 'name': 'topic01'}} + test_input["name"] = "some-foo-service-component" + + # Good case + def fake_add_to_entry(conn, key, add_name, add_value): + """ + This fake method will check all the pieces that are used to make store + details in Consul + """ + if key != test_input["name"] + ":dmaap": + return None + if add_name != "feed01": + return None + if add_value != {"location": "Bedminster", "delivery_url": None, + "username": "hero", "password": "123456", "subscriber_id": None}: + return None + + return "SUCCESS!" + + monkeypatch.setattr(k8splugin.discovery, "add_to_entry", + fake_add_to_entry) + + assert tasks._setup_for_discovery_streams(**test_input) == test_input + + # Good case - no data router subscribers + test_input = {"streams_publishes": [{"name": "topic00", "type": "message_router"}], + 'streams_subscribes': [{'type': 'message_router', 'name': 'topic01'}]} + test_input["name"] = "some-foo-service-component" + + assert tasks._setup_for_discovery_streams(**test_input) == test_input + + # Bad case - something happened from the Consul call + test_input = {'feed01': {'type': 'data_router', 'name': 'feed01', + 'username': 'hero', 'password': '123456', 'location': 'Bedminster'}, + 'streams_publishes': {}, + 'streams_subscribes': [{'type': 'message_router', 'name': 'topic01'}, + {'type': 'data_router', 'name': 'feed01', 'username': 'hero', + 'password': '123456', 'location': 'Bedminster'}], + 'topic01': {'type': 'message_router', 'name': 'topic01'}} + test_input["name"] = "some-foo-service-component" + + def barf(conn, key, add_name, add_value): + raise RuntimeError("Barf") + + monkeypatch.setattr(k8splugin.discovery, "add_to_entry", + barf) + + with pytest.raises(NonRecoverableError): + tasks._setup_for_discovery_streams(**test_input) + + +def test_lookup_service(monkeypatch, mockconfig): + import k8splugin + from k8splugin import tasks + def fake_lookup(conn, scn): + return [{"ServiceAddress": "192.168.1.1", "ServicePort": "80"}] + + monkeypatch.setattr(k8splugin.discovery, "lookup_service", + fake_lookup) + + assert "192.168.1.1" == tasks._lookup_service("some-component") + assert "192.168.1.1:80" == tasks._lookup_service("some-component", + with_port=True) + + +def test_verify_container(monkeypatch, mockconfig): + from k8sclient import k8sclient + from k8splugin import tasks + from k8splugin.exceptions import DockerPluginDeploymentError + + def fake_is_available_success(ch, scn): + return True + + monkeypatch.setattr(k8sclient, "is_available", + fake_is_available_success) + + assert tasks._verify_container("some-name", 3) + + def fake_is_available_never_good(ch, scn): + return False + + monkeypatch.setattr(k8sclient, "is_available", + fake_is_available_never_good) + + with pytest.raises(DockerPluginDeploymentError): + tasks._verify_container("some-name", 2) + + +def test_update_delivery_url(monkeypatch, mockconfig): + import k8splugin + from k8splugin import tasks + test_input = {'feed01': {'type': 'data_router', 'name': 'feed01', + 'username': 'hero', 'password': '123456', 'location': 'Bedminster', + 'route': 'some-path'}, + 'streams_publishes': {}, + 'streams_subscribes': [{'type': 'message_router', 'name': 'topic01'}, + {'type': 'data_router', 'name': 'feed01', 'username': 'hero', + 'password': '123456', 'location': 'Bedminster', + 'route': 'some-path'}], + 'topic01': {'type': 'message_router', 'name': 'topic01'}} + test_input["service_component_name"] = "some-foo-service-component" + + def fake_lookup_service(name, with_port=False): + if with_port: + return "10.100.1.100:8080" + else: + return + + monkeypatch.setattr(k8splugin.tasks, "_lookup_service", + fake_lookup_service) + + expected = copy.deepcopy(test_input) + expected["feed01"]["delivery_url"] = "http://10.100.1.100:8080/some-path" + + assert tasks._update_delivery_url(**test_input) == expected + + +def test_enhance_docker_params(mockconfig): + from k8splugin import tasks + # Good - Test empty docker config + + test_kwargs = { "docker_config": {}, "service_id": None } + actual = tasks._enhance_docker_params(**test_kwargs) + + assert actual == {'envs': {"SERVICE_TAGS": ""}, 'docker_config': {}, "service_id": None } + + # Good - Test just docker config ports and volumes + + test_kwargs = { "docker_config": { "ports": ["1:1", "2:2"], + "volumes": [{"container": "somewhere", "host": "somewhere else"}] }, + "service_id": None } + actual = tasks._enhance_docker_params(**test_kwargs) + + assert actual == {'envs': {"SERVICE_TAGS": ""}, 'docker_config': {'ports': ['1:1', '2:2'], + 'volumes': [{'host': 'somewhere else', 'container': 'somewhere'}]}, + 'ports': ['1:1', '2:2'], 'volumes': [{'host': 'somewhere else', + 'container': 'somewhere'}], "service_id": None} + + # Good - Test just docker config ports and volumes with overrrides + + test_kwargs = { "docker_config": { "ports": ["1:1", "2:2"], + "volumes": [{"container": "somewhere", "host": "somewhere else"}] }, + "ports": ["3:3", "4:4"], "volumes": [{"container": "nowhere", "host": + "nowhere else"}], + "service_id": None } + actual = tasks._enhance_docker_params(**test_kwargs) + + assert actual == {'envs': {"SERVICE_TAGS": ""}, 'docker_config': {'ports': ['1:1', '2:2'], + 'volumes': [{'host': 'somewhere else', 'container': 'somewhere'}]}, + 'ports': ['1:1', '2:2', '3:3', '4:4'], 'volumes': [{'host': 'somewhere else', + 'container': 'somewhere'}, {'host': 'nowhere else', 'container': + 'nowhere'}], "service_id": None} + + # Good + + test_kwargs = { "docker_config": {}, "service_id": "zed", + "deployment_id": "abc" } + actual = tasks._enhance_docker_params(**test_kwargs) + + assert actual["envs"] == {"SERVICE_TAGS": "abc,zed"} + + +def test_notify_container(mockconfig): + from k8splugin import tasks + + test_input = { "docker_config": { "trigger_type": "unknown" } } + assert test_input == tasks._notify_container(**test_input)
\ No newline at end of file diff --git a/k8s/tests/test_utils.py b/k8s/tests/test_utils.py new file mode 100644 index 0000000..0b7cba4 --- /dev/null +++ b/k8s/tests/test_utils.py @@ -0,0 +1,33 @@ +# ============LICENSE_START======================================================= +# org.onap.dcae +# ================================================================================ +# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. + +def test_random_string(mockconfig): + from k8splugin import utils + + target_length = 10 + assert len(utils.random_string(target_length)) == target_length + + +def test_update_dict(mockconfig): + from k8splugin import utils + + d = { "a": 1, "b": 2 } + u = { "a": 2, "b": 3 } + assert utils.update_dict(d, u) == u |