Tommy Carpenter | 81b9ed7 | 2017-08-23 11:21:44 -0400 | [diff] [blame] | 1 | # org.onap.dcae |
| 2 | # ================================================================================ |
| 3 | # Copyright (c) 2017 AT&T Intellectual Property. All rights reserved. |
| 4 | # ================================================================================ |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | # ============LICENSE_END========================================================= |
| 17 | # |
| 18 | # ECOMP is a trademark and service mark of AT&T Intellectual Property. |
| 19 | |
Michael Hwang | e11be5d | 2017-09-21 12:19:32 -0400 | [diff] [blame] | 20 | import six, json, logging |
Tommy Carpenter | 81b9ed7 | 2017-08-23 11:21:44 -0400 | [diff] [blame] | 21 | # http://stackoverflow.com/questions/9623114/check-if-two-unordered-lists-are-equal |
| 22 | from collections import Counter |
| 23 | from functools import partial |
| 24 | import pytest |
| 25 | import requests |
| 26 | from discovery_client import discovery as dis |
| 27 | |
| 28 | |
| 29 | def test_get_connection_types(): |
| 30 | config = { "x": "say something", "y": 123, "z": "{{some-analytics}}" } |
| 31 | expected = [(("z", ), "some-analytics"), ] |
| 32 | actual = dis._get_connection_types(config) |
| 33 | assert Counter(expected) == Counter(actual) |
| 34 | |
| 35 | # Whitespaces ok |
| 36 | config = { "x": "say something", "y": 123, "z": "{{ some-analytics }}" } |
| 37 | expected = [(("z", ), "some-analytics"), ] |
| 38 | actual = dis._get_connection_types(config) |
| 39 | assert Counter(expected) == Counter(actual) |
| 40 | |
| 41 | # Paul wanted the ability to include version so match on more than just one |
| 42 | # subfield |
| 43 | config = { "x": "say something", "y": 123, "z": "{{1-0-0.some-analytics}}" } |
| 44 | expected = [(("z", ), "1-0-0.some-analytics"), ] |
| 45 | actual = dis._get_connection_types(config) |
| 46 | assert Counter(expected) == Counter(actual) |
| 47 | |
| 48 | # Need double parantheses |
| 49 | config = { "x": "say something", "y": 123, "z": "{some-analytics}" } |
| 50 | actual = dis._get_connection_types(config) |
| 51 | assert Counter([]) == Counter(actual) |
| 52 | |
| 53 | # Nested in dict dict |
| 54 | config = { "x": "say something", "y": 123, |
| 55 | "z": { "aa": { "bbb": "{{some-analytics}}" } } } |
| 56 | expected = [(("z", "aa", "bbb"), "some-analytics"), ] |
| 57 | actual = dis._get_connection_types(config) |
| 58 | assert Counter(expected) == Counter(actual) |
| 59 | |
| 60 | # Nested in list dict |
| 61 | config = { "x": "say something", "y": 123, |
| 62 | "z": [ "no-op", { "bbb": "{{some-analytics}}" } ] } |
| 63 | expected = [(("z", 1, "bbb"), "some-analytics"), ] |
| 64 | actual = dis._get_connection_types(config) |
| 65 | assert Counter(expected) == Counter(actual) |
| 66 | |
| 67 | # Force strings to be unicode, test for Python2 compatibility |
Michael Hwang | e11be5d | 2017-09-21 12:19:32 -0400 | [diff] [blame] | 68 | config = { "x": six.u("say something"), "y": 123, |
| 69 | "z": six.u("{{some-analytics}}") } |
Tommy Carpenter | 81b9ed7 | 2017-08-23 11:21:44 -0400 | [diff] [blame] | 70 | expected = [(("z", ), "some-analytics"), ] |
| 71 | actual = dis._get_connection_types(config) |
| 72 | assert Counter(expected) == Counter(actual) |
| 73 | |
| 74 | |
| 75 | def test_resolve_connection_types(): |
| 76 | upstream = "b243b0b8-8a24-4f88-add7-9b530c578149.laika.foobar.rework-central.dcae.ecomp.com" |
| 77 | downstream = "839b0b31-f13d-4bfc-9adf-450d34071304.laika.foobar.rework-central.dcae.ecomp.com" |
| 78 | |
| 79 | connection_types = [("downstream-laika", "laika"),] |
| 80 | relationships = [downstream] |
| 81 | expected = [("downstream-laika", [downstream])] |
| 82 | actual = dis._resolve_connection_types(upstream, connection_types, relationships) |
| 83 | assert sorted(actual) == sorted(expected) |
| 84 | |
| 85 | # NOTE: Removed test that tested the scenario where the name stems don't |
| 86 | # match up. This name stem matching was causing grief to others so lifted the |
| 87 | # constraint. |
| 88 | |
| 89 | |
| 90 | def test_resolve_name_for_platform(): |
| 91 | def fake_lookup(fixture, service_name): |
| 92 | if service_name == fixture["ServiceName"]: |
| 93 | return [fixture] |
| 94 | |
| 95 | # Good case. Grabbed from Consul call |
| 96 | fixture = { 'Node': 'agent-one', 'ModifyIndex': 2892, 'Address': '127.0.0.1', |
| 97 | 'ServiceName': 'e9526e08-f9b8-42c4-99a3-443cd4deeac1.platform-laika.foobar.rework-central.dcae.ecomp.com', |
| 98 | 'ServicePort': 12708, 'CreateIndex': 2825, 'ServiceAddress': '196.207.143.67', |
| 99 | 'ServiceTags': [], 'ServiceEnableTagOverride': False, |
| 100 | 'ServiceID': 'e9526e08-f9b8-42c4-99a3-443cd4deeac1.platform-laika.foobar.rework-central.dcae.ecomp.com'} |
| 101 | |
| 102 | expected = ["{0}:{1}".format(fixture["ServiceAddress"], |
| 103 | fixture["ServicePort"])] |
| 104 | assert dis._resolve_name(partial(fake_lookup, fixture), fixture["ServiceName"]) == expected |
| 105 | |
| 106 | # Fail case. When Registrator is misconfigured and ServiceAddress is not set |
| 107 | fixture = { 'Node': 'agent-one', 'ModifyIndex': 2892, 'Address': '127.0.0.1', |
| 108 | 'ServiceName': 'e9526e08-f9b8-42c4-99a3-443cd4deeac1.platform-laika.foobar.rework-central.dcae.ecomp.com', |
| 109 | 'ServicePort': 12708, 'CreateIndex': 2825, 'ServiceAddress': '', |
| 110 | 'ServiceTags': [], 'ServiceEnableTagOverride': False, |
| 111 | 'ServiceID': 'e9526e08-f9b8-42c4-99a3-443cd4deeac1.platform-laika.foobar.rework-central.dcae.ecomp.com'} |
| 112 | |
| 113 | with pytest.raises(dis.DiscoveryResolvingNameError): |
| 114 | dis._resolve_name(partial(fake_lookup, fixture), fixture["ServiceName"]) |
| 115 | |
| 116 | # Fail case. When lookup just blows up for some reason |
| 117 | def fake_lookup_blows(service_name): |
| 118 | raise RuntimeError("Thar she blows") |
| 119 | |
| 120 | with pytest.raises(dis.DiscoveryResolvingNameError): |
| 121 | dis._resolve_name(fake_lookup_blows, fixture["ServiceName"]) |
| 122 | |
| 123 | |
| 124 | def test_resolve_name_for_docker(): |
| 125 | def fake_lookup(fixture, service_name): |
| 126 | if service_name == fixture["ServiceName"]: |
| 127 | return [fixture] |
| 128 | |
| 129 | # Good case. Grabbed from Consul call |
| 130 | fixture = { 'Node': 'agent-one', 'ModifyIndex': 2892, 'Address': '127.0.0.1', |
| 131 | 'ServiceName': 'e9526e08-f9b8-42c4-99a3-443cd4deeac1.laika.foobar.rework-central.dcae.ecomp.com', |
| 132 | 'ServicePort': 12708, 'CreateIndex': 2825, 'ServiceAddress': '196.207.143.67', |
| 133 | 'ServiceTags': [], 'ServiceEnableTagOverride': False, |
| 134 | 'ServiceID': 'e9526e08-f9b8-42c4-99a3-443cd4deeac1.laika.foobar.rework-central.dcae.ecomp.com'} |
| 135 | |
| 136 | expected = ["{0}:{1}".format(fixture["ServiceAddress"], |
| 137 | fixture["ServicePort"])] |
| 138 | assert dis._resolve_name(partial(fake_lookup, fixture), fixture["ServiceName"]) == expected |
| 139 | |
| 140 | # Fail case. When Registrator is misconfigured and ServiceAddress is not set |
| 141 | fixture = { 'Node': 'agent-one', 'ModifyIndex': 2892, 'Address': '127.0.0.1', |
| 142 | 'ServiceName': 'e9526e08-f9b8-42c4-99a3-443cd4deeac1.laika.foobar.rework-central.dcae.ecomp.com', |
| 143 | 'ServicePort': 12708, 'CreateIndex': 2825, 'ServiceAddress': '', |
| 144 | 'ServiceTags': [], 'ServiceEnableTagOverride': False, |
| 145 | 'ServiceID': 'e9526e08-f9b8-42c4-99a3-443cd4deeac1.laika.foobar.rework-central.dcae.ecomp.com'} |
| 146 | |
| 147 | with pytest.raises(dis.DiscoveryResolvingNameError): |
| 148 | dis._resolve_name(partial(fake_lookup, fixture), fixture["ServiceName"]) |
| 149 | |
| 150 | # Fail case. When lookup just blows up for some reason |
| 151 | def fake_lookup_blows(service_name): |
| 152 | raise RuntimeError("Thar she blows") |
| 153 | |
| 154 | with pytest.raises(dis.DiscoveryResolvingNameError): |
| 155 | dis._resolve_name(fake_lookup_blows, fixture["ServiceName"]) |
| 156 | |
| 157 | |
| 158 | def test_resolve_name_for_cdap(monkeypatch): |
| 159 | def fake_lookup(fixture, service_name): |
| 160 | if service_name == fixture["ServiceName"]: |
| 161 | return [fixture] |
| 162 | |
| 163 | # Good case. Handle CDAP apps |
| 164 | fixture = { |
| 165 | "Node":"agent-one", "Address":"10.170.2.17", |
| 166 | "ServiceID": "00b6210b71e445cdaadf76e620ebffcfhelloworldcdapappfoobardcaereworkdcaeecompcom", |
| 167 | "ServiceName": "00b6210b71e445cdaadf76e620ebffcfhelloworldcdapappfoobardcaereworkdcaeecompcom", |
| 168 | "ServiceTags":[], |
| 169 | "ServiceAddress": "196.207.143.116", |
| 170 | "ServicePort": 7777, "ServiceEnableTagOverride": False, "CreateIndex": 144733, "ModifyIndex":145169 } |
| 171 | |
| 172 | class FakeRequestsResponse(object): |
| 173 | def __init__(self, url, broker_json): |
| 174 | self.url = url |
| 175 | self.broker_json = broker_json |
| 176 | |
| 177 | def raise_for_status(self): |
| 178 | expected_broker_url = "http://{0}:{1}/application/{2}".format( |
| 179 | fixture["ServiceAddress"], fixture["ServicePort"], |
| 180 | fixture["ServiceName"]) |
| 181 | if self.url == expected_broker_url: |
| 182 | return True |
| 183 | else: |
| 184 | raise RuntimeError("Mismatching address") |
| 185 | |
| 186 | def json(self): |
| 187 | return self.broker_json |
| 188 | |
| 189 | # Simulate the call to the CDAP broker |
| 190 | broker_json = { |
| 191 | "appname":"00b6210b71e445cdaadf76e620ebffcfhelloworldcdapappfoobardcaereworkdcaeecompcom", |
| 192 | "healthcheckurl":"http://196.207.143.116:7777/application/00b6210b71e445cdaadf76e620ebffcfhelloworldcdapappfoobardcaereworkdcaeecompcom/healthcheck", |
| 193 | "metricsurl":"http://196.207.143.116:7777/application/00b6210b71e445cdaadf76e620ebffcfhelloworldcdapappfoobardcaereworkdcaeecompcom/metrics", |
| 194 | "url":"http://196.207.143.116:7777/application/00b6210b71e445cdaadf76e620ebffcfhelloworldcdapappfoobardcaereworkdcaeecompcom", |
| 195 | "connectionurl":"http://196.207.160.159:10000/v3/namespaces/default/streams/foo", |
| 196 | "serviceendpoints": "something" } |
| 197 | |
| 198 | monkeypatch.setattr(requests, "get", lambda url: FakeRequestsResponse(url, broker_json)) |
| 199 | |
| 200 | expected = [{ key: broker_json[key] |
| 201 | for key in ["connectionurl", "serviceendpoints"] }] |
| 202 | assert dis._resolve_name(partial(fake_lookup, fixture), fixture["ServiceName"]) == expected |
| 203 | |
| 204 | |
| 205 | def test_resolve_configuration_dict(monkeypatch): |
| 206 | service_name = "123.current-node-type.some-service.some-location.com" |
| 207 | target_service_name = "456.target-node-type.some-service.some-location.com" |
| 208 | |
| 209 | # Fake the Consul calls |
| 210 | |
| 211 | def fake_get_relationship(ch, service_name): |
| 212 | return [ target_service_name ] |
| 213 | |
| 214 | monkeypatch.setattr(dis, "_get_relationships_from_consul", |
| 215 | fake_get_relationship) |
| 216 | |
| 217 | fixture = [{ 'Node': 'agent-one', 'ModifyIndex': 2892, 'Address': '127.0.0.1', |
| 218 | 'ServiceName': target_service_name, |
| 219 | 'ServicePort': 12708, 'CreateIndex': 2825, 'ServiceAddress': '196.207.143.67', |
| 220 | 'ServiceTags': [], 'ServiceEnableTagOverride': False, |
| 221 | 'ServiceID': target_service_name }] |
| 222 | |
| 223 | def fake_lookup(ch, service_name): |
| 224 | return fixture |
| 225 | |
| 226 | monkeypatch.setattr(dis, "_lookup_with_consul", fake_lookup) |
| 227 | |
| 228 | # Simple config case |
| 229 | test_config = { "target-node": "{{ target-node-type }}", "other-param": 123 } |
| 230 | |
| 231 | expected = dict(test_config) |
| 232 | expected["target-node"] = ["196.207.143.67:12708"] |
| 233 | actual = dis._resolve_configuration_dict(None, service_name, test_config) |
| 234 | assert Counter(actual) == Counter(expected) |
| 235 | |
| 236 | # Nested config case |
| 237 | test_config = { "output_formats": { "target-node": "{{ target-node-type }}" }, |
| 238 | "other-param": 123 } |
| 239 | |
| 240 | expected = dict(test_config) |
| 241 | expected["output_formats"]["target-node"] = "196.207.143.67:12708" |
| 242 | actual = dis._resolve_configuration_dict(None, service_name, test_config) |
| 243 | assert Counter(actual) == Counter(expected) |
| 244 | |
| 245 | |
| 246 | def test_get_consul_host(monkeypatch): |
| 247 | with pytest.raises(dis.DiscoveryInitError): |
| 248 | dis.get_consul_hostname() |
| 249 | |
| 250 | monkeypatch.setenv("CONSUL_HOST", "i-am-consul-host") |
| 251 | assert "i-am-consul-host" == dis.get_consul_hostname() |
| 252 | |
| 253 | assert "no-i-am" == dis.get_consul_hostname("no-i-am") |