1 # ============LICENSE_START=======================================================
3 # ================================================================================
4 # Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
5 # ================================================================================
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 # ============LICENSE_END=========================================================
19 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
21 # -*- coding: utf-8 -*-
23 Tests the mock catalog
28 from dcae_cli.catalog.mock.schema import validate_component, validate_format,apply_defaults_docker_config, apply_defaults
29 from dcae_cli.catalog.mock import schema
30 from dcae_cli.util.exc import DcaeException
36 "name": "asimov.format.integerClassification",
38 "description": "Represents a single classification from a machine learning model - just a test version"
40 "dataformatversion": "1.0.0",
42 "$schema": "http://json-schema.org/draft-04/schema#",
49 "additionalProperties": false
59 "name": "asimov.component.kpi_anomaly",
60 "description": "Classifies VNF KPI data as anomalous",
61 "component_type": "docker"
66 "format": "dcae.vnf.kpi",
72 "format":"std.format_one",
75 "type": "message router"
80 "format": "asimov.format.integerClassification",
82 "config_key": "prediction",
86 "format":"std.format_one",
89 "type": "message router"
97 "route": "/score-vnf",
99 "format": "dcae.vnf.kpi",
103 "format": "asimov.format.integerClassification",
113 "description": "Probability threshold to exceed to be anomalous"
118 "uri": "somedockercontainerpath",
119 "type": "docker image"
125 "endpoint": "/health"
131 cdap_component_test = r'''
134 "name":"std.cdap_comp",
136 "description":"cdap test component",
137 "component_type":"cdap"
142 "format":"std.format_one",
148 "format":"std.format_one",
151 "type": "message router"
156 "format":"std.format_two",
162 "format":"std.format_one",
165 "type": "message router"
176 "format":"std.format_one",
180 "format":"std.format_two",
183 "service_name":"baphomet",
184 "service_endpoint":"rises",
194 "uri": "somecdapjarurl",
200 "artifact_name" : "HelloWorld",
201 "artifact_version" : "3.4.3",
203 {"program_type" : "flows", "program_id" : "WhoFlow"},
204 {"program_type" : "services", "program_id" : "Greeting"}
213 validate_component(json.loads(component_test))
214 validate_format(json.loads(format_test))
215 validate_component(json.loads(cdap_component_test))
217 # Test with DR publishes for cdap
218 dr_publishes = { "format":"std.format_one", "version":"1.0.0",
219 "config_key":"pub3", "type": "data router" }
220 cdap_valid = json.loads(cdap_component_test)
221 cdap_valid["streams"]["publishes"].append(dr_publishes)
223 # Test with DR subscribes for cdap
224 cdap_invalid = json.loads(cdap_component_test)
225 ss = cdap_invalid["streams"]["subscribes"][0]
226 ss["type"] = "data_router"
227 ss["config_key"] = "nada"
228 cdap_invalid["streams"]["subscribes"][0] = ss
230 with pytest.raises(DcaeException):
231 validate_component(cdap_invalid)
235 def test_validate_docker_config():
237 def compose_spec(config):
238 spec = json.loads(component_test)
239 spec["auxilary"] = config
242 good_docker_configs = [
246 "endpoint": "/health",
254 "script": "curl something"
258 for good_config in good_docker_configs:
259 spec = compose_spec(good_config)
260 assert validate_component(spec) == None
262 bad_docker_configs = [
279 for bad_config in bad_docker_configs:
280 with pytest.raises(DcaeException):
281 spec = compose_spec(bad_config)
282 validate_component(spec)
285 def test_validate_cdap_config():
287 def compose_spec(config):
288 spec = json.loads(cdap_component_test)
289 spec["auxilary"] = config
292 good_cdap_configs = [
294 "streamname":"streamname",
295 "artifact_version":"6.6.6",
296 "artifact_name" : "testname",
300 "streamname":"streamname",
301 "artifact_version":"6.6.6",
302 "artifact_name" : "testname",
303 "programs" : [{"program_type" : "flows", "program_id" : "flow_id"}],
304 "program_preferences" : [{"program_type" : "flows", "program_id" : "flow_id", "program_pref" : {"he" : "shall rise"}}],
305 "namespace" : "this should be an optional field",
306 "app_preferences" : {"he" : "shall rise"}
310 for good_config in good_cdap_configs:
311 spec = compose_spec(good_config)
312 assert validate_component(spec) == None
316 {"YOU HAVE" : "ALWAYS FAILED ME"}
319 for bad_config in bad_cdap_configs:
320 with pytest.raises(DcaeException):
321 spec = compose_spec(bad_config)
322 validate_component(bad_config)
325 def test_apply_defaults():
326 definition = { "length": { "default": 10 }, "duration": { "default": "10s" } }
328 # Test: Add expected properties
330 actual = apply_defaults(definition, properties)
331 assert actual == { "length": 10, "duration": "10s" }
333 # Test: Don't mess with existing values
334 properties = { "length": 100, "duration": "100s" }
335 actual = apply_defaults(definition, properties)
336 assert actual == properties
338 # Test: No defaults to apply
339 definition = { "length": {}, "duration": {} }
340 properties = { "width": 100 }
341 actual = apply_defaults(definition, properties)
342 assert actual == properties
344 # Test: Nested object
345 definition = { "length": { "default": 10 }, "duration": { "default": "10s" },
346 "location": { "properties": { "lat": { "default": "40" },
347 "long": { "default": "75" }, "alt": {} } } }
348 actual = apply_defaults(definition, {})
349 assert actual == {'duration': '10s', 'length': 10,
350 'location': {'lat': '40', 'long': '75'}}
353 def test_apply_defaults_docker_config():
354 # Test: Adding of missing expected properties for http
355 dc = { "healthcheck": { "type": "http", "endpoint": "/foo" } }
356 actual = apply_defaults_docker_config(dc)
358 assert "interval" in actual["healthcheck"]
359 assert "timeout" in actual["healthcheck"]
361 # Test: Adding of missing expected properties for script
362 dc = { "healthcheck": { "type": "script", "script": "/bin/do-something" } }
363 actual = apply_defaults_docker_config(dc)
365 assert "interval" in actual["healthcheck"]
366 assert "timeout" in actual["healthcheck"]
368 # Test: Expected properties already exist
369 dc = { "healthcheck": { "type": "http", "endpoint": "/foo",
370 "interval": "10000s", "timeout": "100000s" } }
371 actual = apply_defaults_docker_config(dc)
374 # Test: Never should happen
375 dc = { "healthcheck": { "type": "bogus" } }
376 actual = apply_defaults_docker_config(dc)
382 "$schema": "http://json-schema.org/draft-04/schema#",
383 "title": "Test schema",
386 "foo": { "type": "string" },
387 "bar": { "type": "integer" }
389 "required": ["foo", "bar"]
392 good_path = "/correct_path"
394 def fetch_schema(path):
395 if path == good_path:
398 raise schema.FetchSchemaError("Schema not found")
402 good_instance = { "foo": "hello", "bar": 1776 }
404 schema._validate(fetch_schema, good_path, good_instance)
406 # Error from validating
410 with pytest.raises(DcaeException):
411 schema._validate(fetch_schema, good_path, bad_instance)
413 # Error from fetching
415 bad_path = "/wrong_path"
417 with pytest.raises(DcaeException):
418 schema._validate(fetch_schema, bad_path, good_instance)