Make tox work in a fresh scenario
[dcaegen2/platform/cli.git] / dcae-cli / dcae_cli / catalog / mock / tests / test_mock_catalog.py
1 # ============LICENSE_START=======================================================
2 # org.onap.dcae
3 # ================================================================================
4 # Copyright (c) 2017-2018 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
9 #
10 #      http://www.apache.org/licenses/LICENSE-2.0
11 #
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=========================================================
18 #
19 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
20
21 # -*- coding: utf-8 -*-
22 '''
23 Tests the mock catalog
24 '''
25 import json
26 from copy import deepcopy
27 from functools import partial
28
29 import pytest
30
31 from sqlalchemy.exc import IntegrityError
32
33 from dcae_cli.catalog.mock.catalog import MockCatalog, MissingEntry, DuplicateEntry, _get_unique_format_things
34 from dcae_cli.catalog.mock import catalog
35
36
37 _c1_spec = {'self': {'name': 'std.comp_one',
38                     'version': '1.0.0',
39                     'description': 'comp1',
40                     'component_type': 'docker'},
41           'streams': {'publishes': [{'format': 'std.format_one',
42                                      'version': '1.0.0',
43                                      'config_key': 'pub1',
44                                      'type': 'http'}],
45                       'subscribes': [{'format': 'std.format_one',
46                                       'version': '1.0.0',
47                                       'route': '/sub1',
48                                       'type': 'http'}]},
49           'services': {'calls': [{'request': {'format': 'std.format_one',
50                                               'version': '1.0.0'},
51                                   'response': {'format': 'std.format_one',
52                                                'version': '1.0.0'},
53                                   'config_key': 'call1'}],
54                        'provides': [{'request': {'format': 'std.format_one',
55                                                  'version': '1.0.0'},
56                                      'response': {'format': 'std.format_one',
57                                                   'version': '1.0.0'},
58                                      'route': '/prov1'}]},
59           'parameters': [{"name": "foo",
60                           "value": 1,
61                           "description": "the foo thing"},
62                          {"name": "bar",
63                           "value": 2,
64                           "description": "the bar thing"}
65                           ],
66           'artifacts': [{ "uri": "foo-image", "type": "docker image" }],
67           'auxilary': {
68             "healthcheck": {
69                 "type": "http",
70                 "endpoint": "/health",
71                 "interval": "15s",
72                 "timeout": "1s"
73                 }
74               }
75            }
76
77 _c2_spec = {'self': {'name': 'std.comp_two',
78                           'version': '1.0.0',
79                           'description': 'comp2',
80                           'component_type': 'docker'},
81           'streams': {'publishes': [],
82                       'subscribes': [{'format': 'std.format_one',
83                                       'version': '1.0.0',
84                                       'route': '/sub1',
85                                       'type': 'http'}]},
86           'services': {'calls': [],
87                        'provides': [{'request': {'format': 'std.format_one',
88                                                  'version': '1.0.0'},
89                                      'response': {'format': 'std.format_one',
90                                                   'version': '1.0.0'},
91                                      'route': '/prov1'}]},
92           'parameters': [],
93           'artifacts': [{ "uri": "bar-image", "type": "docker image" }],
94           'auxilary': {
95             "healthcheck": {
96                 "type": "http",
97                 "endpoint": "/health",
98                 "interval": "15s",
99                 "timeout": "1s"
100                 }
101               }
102            }
103
104
105 _c2v2_spec = {'self': {'name': 'std.comp_two',
106                           'version': '2.0.0',
107                           'description': 'comp2',
108                           'component_type': 'docker'},
109           'streams': {'publishes': [],
110                       'subscribes': [{'format': 'std.format_one',
111                                       'version': '1.0.0',
112                                       'route': '/sub1',
113                                       'type': 'http'}]},
114           'services': {'calls': [],
115                        'provides': [{'request': {'format': 'std.format_one',
116                                                  'version': '1.0.0'},
117                                      'response': {'format': 'std.format_one',
118                                                   'version': '1.0.0'},
119                                      'route': '/prov1'}]},
120           'parameters': [],
121           'artifacts': [{ "uri": "baz-image", "type": "docker image" }],
122           'auxilary': {
123             "healthcheck": {
124                 "type": "http",
125                 "endpoint": "/health",
126                 "interval": "15s",
127                 "timeout": "1s"
128                 }
129               }
130            }
131
132
133 _c3_spec = {'self': {'name': 'std.comp_three',
134                           'version': '3.0.0',
135                           'description': 'comp3',
136                           'component_type': 'docker'},
137           'streams': {'publishes': [],
138                       'subscribes': [{'format': 'std.format_two',
139                                       'version': '1.5.0',
140                                       'route': '/sub1',
141                                       'type': 'http'}]},
142           'services': {'calls': [],
143                        'provides': [{'request': {'format': 'std.format_one',
144                                                  'version': '1.0.0'},
145                                      'response': {'format': 'std.format_two',
146                                                   'version': '1.5.0'},
147                                      'route': '/prov1'}]},
148           'parameters': [],
149           'artifacts': [{ "uri": "bazinga-image", "type": "docker image" }],
150           'auxilary': {
151             "healthcheck": {
152                 "type": "http",
153                 "endpoint": "/health",
154                 "interval": "15s",
155                 "timeout": "1s"
156                 }
157               }
158            }
159
160
161 _df1_spec = {
162           "self": {
163               "name": "std.format_one",
164               "version": "1.0.0",
165               "description": "df1"
166           },
167           "dataformatversion": "1.0.0",
168           "jsonschema": {
169               "$schema": "http://json-schema.org/draft-04/schema#",
170                       "type": "object",
171               "properties": {
172                   "raw-text": {
173                       "type": "string"
174                   }
175               },
176               "required": ["raw-text"],
177               "additionalProperties": False
178           }
179         }
180 _df2_spec = {
181           "self": {
182               "name": "std.format_two",
183               "version": "1.5.0",
184               "description": "df2"
185           },
186           "dataformatversion": "1.0.0",
187           "jsonschema": {
188               "$schema": "http://json-schema.org/draft-04/schema#",
189                       "type": "object",
190               "properties": {
191                   "raw-text": {
192                       "type": "string"
193                   }
194               },
195               "required": ["raw-text"],
196               "additionalProperties": False
197           }
198        }
199 _df2v2_spec  = {
200           "self": {
201               "name": "std.format_two",
202               "version": "2.0.0",
203               "description": "df2"
204           },
205           "dataformatversion": "1.0.0",
206           "jsonschema": {
207               "$schema": "http://json-schema.org/draft-04/schema#",
208                       "type": "object",
209               "properties": {
210                   "raw-text": {
211                       "type": "string"
212                   }
213               },
214               "required": ["raw-text"],
215               "additionalProperties": False
216           }
217             }
218
219 _cdap_spec={
220    "self":{
221       "name":"std.cdap_comp",
222       "version":"0.0.0",
223       "description":"cdap test component",
224       "component_type":"cdap"
225    },
226    "streams":{
227       "publishes":[
228          {
229             "format":"std.format_one",
230             "version":"1.0.0",
231             "config_key":"pub1",
232             "type": "http"
233          }
234       ],
235       "subscribes":[
236          {
237             "format":"std.format_two",
238             "version":"1.5.0",
239             "route":"/sub1",
240             "type": "http"
241          }
242       ]
243    },
244    "services":{
245       "calls":[
246
247       ],
248       "provides":[
249          {
250             "request":{
251                "format":"std.format_one",
252                "version":"1.0.0"
253             },
254             "response":{
255                "format":"std.format_two",
256                "version":"1.5.0"
257             },
258             "service_name":"baphomet",
259             "service_endpoint":"rises",
260             "verb":"GET"
261          }
262       ]
263    },
264    "parameters": {
265        "app_config" : [],
266        "app_preferences" : [],
267        "program_preferences" : []
268    },
269    "artifacts": [{"uri": "bahpomet.com", "type": "jar"}],
270    "auxilary": {
271         "streamname":"streamname",
272         "artifact_version":"6.6.6",
273         "artifact_name": "test_name",
274         "programs" : [{"program_type" : "flows", "program_id" : "flow_id"}]
275         }
276
277 }
278
279
280 def test_component_basic(mock_cli_config, catalog=None):
281     '''Tests basic component usage of MockCatalog'''
282     if catalog is None:
283         mc = MockCatalog(db_name='dcae_cli.test.db', purge_existing=True, enforce_image=False)
284     else:
285         mc = catalog
286
287     c1_spec = deepcopy(_c1_spec)
288     df1_spec = deepcopy(_df1_spec)
289     df2_spec = deepcopy(_df2_spec)
290
291     user = "test_component_basic"
292
293     # success
294     mc.add_format(df2_spec, user)
295
296     # duplicate
297     with pytest.raises(DuplicateEntry):
298         mc.add_format(df2_spec, user)
299
300     # component relies on df1_spec which hasn't been added
301     with pytest.raises(MissingEntry):
302         mc.add_component(user, c1_spec)
303
304     # add df1 and comp1
305     mc.add_format(df1_spec, user)
306     mc.add_component(user, c1_spec)
307
308     with pytest.raises(DuplicateEntry):
309         mc.add_component(user, c1_spec)
310
311     cname, cver = mc.verify_component('std.comp_one', version=None)
312     assert cver == '1.0.0'
313
314
315 def test_format_basic(mock_cli_config, catalog=None):
316     '''Tests basic data format usage of MockCatalog'''
317     if catalog is None:
318         mc = MockCatalog(db_name='dcae_cli.test.db', purge_existing=True)
319     else:
320         mc = catalog
321
322     user = "test_format_basic"
323
324     df1_spec = deepcopy(_df1_spec)
325     df2_spec = deepcopy(_df2_spec)
326
327     # success
328     mc.add_format(df1_spec, user)
329
330     # duplicate is bad
331     with pytest.raises(DuplicateEntry):
332         mc.add_format(df1_spec, user)
333
334     # allow update of same version
335     new_descr = 'a new description'
336     df1_spec['self']['description'] = new_descr
337     mc.add_format(df1_spec, user, update=True)
338
339     # adding a new version is kosher
340     new_ver = '2.0.0'
341     df1_spec['self']['version'] = new_ver
342     mc.add_format(df1_spec, user)
343
344     # can't update a format that doesn't exist
345     with pytest.raises(MissingEntry):
346         mc.add_format(df2_spec, user, update=True)
347
348     # get spec and make sure it's updated
349     spec = mc.get_format_spec(df1_spec['self']['name'], version=None)
350     assert spec['self']['version'] == new_ver
351     assert spec['self']['description'] == new_descr
352
353
354 def test_discovery(mock_cli_config, catalog=None):
355     '''Tests creation of discovery objects'''
356     if catalog is None:
357         mc = MockCatalog(db_name='dcae_cli.test.db', purge_existing=True, enforce_image=False)
358     else:
359         mc = catalog
360
361     user = "test_discovery"
362
363     c1_spec = deepcopy(_c1_spec)
364     df1_spec = deepcopy(_df1_spec)
365     c2_spec = deepcopy(_c2_spec)
366
367     mc.add_format(df1_spec, user)
368     mc.add_component(user, c1_spec)
369     mc.add_component(user, c2_spec)
370
371     params, interfaces = mc.get_discovery_for_docker(c1_spec['self']['name'], c1_spec['self']['version'])
372     assert params == {'bar': 2, 'foo': 1}
373     assert interfaces == {'call1': [('std.comp_two', '1.0.0')], 'pub1': [('std.comp_two', '1.0.0')]}
374
375
376 def _spec_tuple(dd):
377     '''Returns a (name, version, component type) tuple from a given component spec dict'''
378     return dd['self']['name'], dd['self']['version'], dd['self']['component_type']
379
380
381 def _comp_tuple_set(*dds):
382     '''Runs a set of component spec tuples'''
383     return set(map(_spec_tuple, dds))
384
385
386 def _format_tuple(dd):
387     '''Returns a (name, version) tuple from a given data format spec dict'''
388     return dd['self']['name'], dd['self']['version']
389
390
391 def _format_tuple_set(*dds):
392     '''Runs a set of data format spec tuples'''
393     return set(map(_format_tuple, dds))
394
395
396 def test_comp_list(mock_cli_config, catalog=None):
397     '''Tests the list functionality of the catalog'''
398     if catalog is None:
399         mc = MockCatalog(db_name='dcae_cli.test.db', purge_existing=True, enforce_image=False)
400     else:
401         mc = catalog
402
403     user = "test_comp_list"
404
405     df1_spec = deepcopy(_df1_spec)
406     df2_spec = deepcopy(_df2_spec)
407     df2v2_spec = deepcopy(_df2v2_spec)
408
409     c1_spec = deepcopy(_c1_spec)
410     c2_spec = deepcopy(_c2_spec)
411     c2v2_spec = deepcopy(_c2v2_spec)
412     c3_spec = deepcopy(_c3_spec)
413
414     mc.add_format(df1_spec, user)
415     mc.add_format(df2_spec, user)
416     mc.add_format(df2v2_spec, user)
417     mc.add_component(user, c1_spec)
418     mc.add_component(user, c2_spec)
419     mc.add_component(user, c2v2_spec)
420     mc.add_component(user, c3_spec)
421
422     mc.add_component(user,_cdap_spec)
423
424     def components_to_specs(components):
425         return [ json.loads(c["spec"]) for c in components ]
426
427     # latest by default. only v2 of c2
428     components = mc.list_components()
429     specs = components_to_specs(components)
430     assert _comp_tuple_set(*specs) == _comp_tuple_set(c1_spec, c2v2_spec, c3_spec, _cdap_spec)
431
432     # all components
433     components = mc.list_components(latest=False)
434     specs = components_to_specs(components)
435     assert _comp_tuple_set(*specs) == _comp_tuple_set(c1_spec, c2_spec, c2v2_spec, c3_spec, _cdap_spec)
436
437     components = mc.list_components(subscribes=[('std.format_one', None)])
438     specs = components_to_specs(components)
439     assert _comp_tuple_set(*specs) == _comp_tuple_set(c1_spec, c2v2_spec)
440
441     # no comps subscribe to latest std.format_two
442     components = mc.list_components(subscribes=[('std.format_two', None)])
443     assert not components
444
445     components = mc.list_components(subscribes=[('std.format_two', '1.5.0')])
446     specs = components_to_specs(components)
447     assert _comp_tuple_set(*specs) == _comp_tuple_set(c3_spec, _cdap_spec)
448
449     # raise if format doesn't exist
450     with pytest.raises(MissingEntry):
451         mc.list_components(subscribes=[('std.format_two', '5.0.0')])
452
453     components = mc.list_components(publishes=[('std.format_one', None)])
454     specs = components_to_specs(components)
455     assert _comp_tuple_set(*specs) == _comp_tuple_set(c1_spec, _cdap_spec)
456
457     components = mc.list_components(calls=[(('std.format_one', None), ('std.format_one', None)), ])
458     specs = components_to_specs(components)
459     assert _comp_tuple_set(*specs) == _comp_tuple_set(c1_spec)
460
461     # raise if format doesn't exist
462     with pytest.raises(MissingEntry):
463         mc.list_components(calls=[(('std.format_one', '5.0.0'), ('std.format_one', None)), ])
464
465     components = mc.list_components(provides=[(('std.format_one', '1.0.0'), ('std.format_two', '1.5.0')), ])
466     specs = components_to_specs(components)
467     assert _comp_tuple_set(*specs) == _comp_tuple_set(c3_spec, _cdap_spec)
468
469     # test for listing published components
470
471     name_pub = c1_spec["self"]["name"]
472     version_pub = c1_spec["self"]["version"]
473     mc.publish_component(user, name_pub, version_pub)
474     components = mc.list_components(only_published=True)
475     specs = components_to_specs(components)
476     assert _comp_tuple_set(*specs) == _comp_tuple_set(c1_spec)
477
478     components = mc.list_components(only_published=False)
479     assert len(components) == 4
480
481
482 def test_format_list(mock_cli_config, catalog=None):
483     '''Tests the list functionality of the catalog'''
484     if catalog is None:
485         mc = MockCatalog(db_name='dcae_cli.test.db', purge_existing=True, enforce_image=False)
486     else:
487         mc = catalog
488
489     user = "test_format_list"
490
491     df1_spec = deepcopy(_df1_spec)
492     df2_spec = deepcopy(_df2_spec)
493     df2v2_spec = deepcopy(_df2v2_spec)
494
495     mc.add_format(df1_spec, user)
496     mc.add_format(df2_spec, user)
497     mc.add_format(df2v2_spec, user)
498
499     def formats_to_specs(components):
500         return [ json.loads(c["spec"]) for c in components ]
501
502     # latest by default. ensure only v2 of df2 makes it
503     formats = mc.list_formats()
504     specs = formats_to_specs(formats)
505     assert _format_tuple_set(*specs) == _format_tuple_set(df1_spec, df2v2_spec)
506
507     # list all
508     formats = mc.list_formats(latest=False)
509     specs = formats_to_specs(formats)
510     assert _format_tuple_set(*specs) == _format_tuple_set(df1_spec, df2_spec, df2v2_spec)
511
512     # test listing of published formats
513
514     name_pub = df1_spec["self"]["name"]
515     version_pub = df1_spec["self"]["version"]
516
517     mc.publish_format(user, name_pub, version_pub)
518     formats = mc.list_formats(only_published=True)
519     specs = formats_to_specs(formats)
520     assert _format_tuple_set(*specs) == _format_tuple_set(df1_spec)
521
522     formats = mc.list_formats(only_published=False)
523     assert len(formats) == 2
524
525
526 def test_component_add_cdap(mock_cli_config, catalog=None):
527     '''Adds a mock CDAP application'''
528     if catalog is None:
529         mc = MockCatalog(db_name='dcae_cli.test.db', purge_existing=True)
530     else:
531         mc = catalog
532
533     user = "test_component_add_cdap"
534
535     df1_spec = deepcopy(_df1_spec)
536     df2_spec = deepcopy(_df2_spec)
537
538     mc.add_format(df1_spec, user)
539     mc.add_format(df2_spec, user)
540
541     mc.add_component(user, _cdap_spec)
542
543     name, version, _ = _spec_tuple(_cdap_spec)
544     jar_out, cdap_config_out, spec_out = mc.get_cdap(name, version)
545
546     assert _cdap_spec["artifacts"][0]["uri"] == jar_out
547     assert _cdap_spec["auxilary"] == cdap_config_out
548     assert _cdap_spec == spec_out
549
550
551 def test_get_discovery_from_spec(mock_cli_config):
552     mc = MockCatalog(db_name='dcae_cli.test.db', purge_existing=True,
553             enforce_image=False)
554
555     user = "test_get_discovery_from_spec"
556
557     c1_spec_updated = deepcopy(_c1_spec)
558     c1_spec_updated["streams"]["publishes"][0] = {
559             'format': 'std.format_one',
560             'version': '1.0.0',
561             'config_key': 'pub1',
562             'type': 'http'
563             }
564     c1_spec_updated["streams"]["subscribes"][0] = {
565             'format': 'std.format_one',
566             'version': '1.0.0',
567             'route': '/sub1',
568             'type': 'http'
569             }
570
571     # Case when c1 doesn't exist
572
573     mc.add_format(_df1_spec, user)
574     mc.add_component(user, _c2_spec)
575     actual_params, actual_interface_map, actual_dmaap_config_keys \
576             = mc.get_discovery_from_spec(user, c1_spec_updated, None)
577
578     assert actual_params == {'bar': 2, 'foo': 1}
579     assert actual_interface_map == { 'pub1': [('std.comp_two', '1.0.0')],
580             'call1': [('std.comp_two', '1.0.0')] }
581     assert actual_dmaap_config_keys == ([], [])
582
583     # Case when c1 already exist
584
585     mc.add_component(user,_c1_spec)
586
587     c1_spec_updated["services"]["calls"][0]["config_key"] = "callme"
588     actual_params, actual_interface_map, actual_dmaap_config_keys \
589             = mc.get_discovery_from_spec(user, c1_spec_updated, None)
590
591     assert actual_params == {'bar': 2, 'foo': 1}
592     assert actual_interface_map == { 'pub1': [('std.comp_two', '1.0.0')],
593             'callme': [('std.comp_two', '1.0.0')] }
594     assert actual_dmaap_config_keys == ([], [])
595
596     # Case where add in dmaap streams
597     # TODO: Add in subscribes test case after spec gets pushed
598
599     c1_spec_updated["streams"]["publishes"][0] = {
600             'format': 'std.format_one',
601             'version': '1.0.0',
602             'config_key': 'pub1',
603             'type': 'message router'
604             }
605
606     actual_params, actual_interface_map, actual_dmaap_config_keys \
607             = mc.get_discovery_from_spec(user, c1_spec_updated, None)
608
609     assert actual_params == {'bar': 2, 'foo': 1}
610     assert actual_interface_map == { 'callme': [('std.comp_two', '1.0.0')] }
611     assert actual_dmaap_config_keys == (["pub1"], [])
612
613     # Case when cdap spec doesn't exist
614
615     cdap_spec = deepcopy(_cdap_spec)
616     cdap_spec["streams"]["publishes"][0] = {
617             'format': 'std.format_one',
618             'version': '1.0.0',
619             'config_key': 'pub1',
620             'type': 'http'
621             }
622     cdap_spec["streams"]["subscribes"][0] = {
623             'format': 'std.format_two',
624             'version': '1.5.0',
625             'route': '/sub1',
626             'type': 'http'
627             }
628
629     mc.add_format(_df2_spec, user)
630     actual_params, actual_interface_map, actual_dmaap_config_keys \
631             = mc.get_discovery_from_spec(user, cdap_spec, None)
632
633     assert actual_params == {'program_preferences': [], 'app_config': {}, 'app_preferences': {}}
634     assert actual_interface_map == {'pub1': [('std.comp_two', '1.0.0'), ('std.comp_one', '1.0.0')]}
635     assert actual_dmaap_config_keys == ([], [])
636
637
638 def test_get_unpublished_formats(mock_cli_config, catalog=None):
639     if catalog is None:
640         mc = MockCatalog(db_name='dcae_cli.test.db', purge_existing=True, enforce_image=False)
641     else:
642         mc = catalog
643
644     user = "test_get_unpublished_formats"
645
646     mc.add_format(_df1_spec, user)
647     mc.add_component(user, _c1_spec)
648
649     # detect unpublished formats
650
651     name_to_pub = _c1_spec["self"]["name"]
652     version_to_pub = _c1_spec["self"]["version"]
653     formats = mc.get_unpublished_formats(name_to_pub, version_to_pub)
654     assert [('std.format_one', '1.0.0')] == formats
655
656     # all formats published
657
658     mc.publish_format(user, _df1_spec["self"]["name"], _df1_spec["self"]["version"])
659     formats = mc.get_unpublished_formats(name_to_pub, version_to_pub)
660     assert len(formats) == 0
661
662
663 def test_get_unique_format_things():
664     def create_tuple(entry):
665         return (entry["name"], entry["version"])
666
667     def get_orm(name, version):
668         return ("ORM", name, version)
669
670     entries = [{"name": "abc", "version": 123},
671             {"name": "abc", "version": 123},
672             {"name": "abc", "version": 123},
673             {"name": "def", "version": 456},
674             {"name": "def", "version": 456}]
675
676     get_unique_fake_format = partial(_get_unique_format_things, create_tuple,
677             get_orm)
678     expected = [("ORM", "abc", 123), ("ORM", "def", 456)]
679
680     assert sorted(expected) == sorted(get_unique_fake_format(entries))
681
682
683 def test_filter_latest():
684     orms = [('std.empty.get', '1.0.0'), ('std.unknown', '1.0.0'),
685             ('std.unknown', '1.0.1'), ('std.empty.get', '1.0.1')]
686
687     assert list(catalog._filter_latest(orms)) == [('std.empty.get', '1.0.1'), \
688             ('std.unknown', '1.0.1')]
689
690
691 def test_raise_if_duplicate():
692     class FakeOrig(object):
693         args = ["unique", "duplicate"]
694
695     url = "sqlite"
696     orig = FakeOrig()
697     error = IntegrityError("Error about uniqueness", None, orig)
698
699     with pytest.raises(catalog.DuplicateEntry):
700         catalog._raise_if_duplicate(url, error)
701
702     # Couldn't find psycopg2.IntegrityError constructor nor way
703     # to set pgcode so decided to mock it.
704     class FakeOrigPostgres(object):
705         pgcode = "23505"
706
707     url = "postgres"
708     orig = FakeOrigPostgres()
709     error = IntegrityError("Error about uniqueness", None, orig)
710
711     with pytest.raises(catalog.DuplicateEntry):
712         catalog._raise_if_duplicate(url, error)
713
714
715 def test_get_docker_image_from_spec():
716     assert "foo-image" == catalog._get_docker_image_from_spec(_c1_spec)
717
718 def test_get_cdap_jar_from_spec():
719     assert "bahpomet.com" == catalog._get_cdap_jar_from_spec(_cdap_spec)
720
721
722 def test_build_config_keys_map():
723     stub_spec = {
724           'streams': {
725               'publishes': [
726                   {'format': 'std.format_one', 'version': '1.0.0',
727                       'config_key': 'pub1', 'type': 'http'},
728                   {'format': 'std.format_one', 'version': '1.0.0',
729                       'config_key': 'pub2', 'type': 'message_router'}
730                   ],
731               'subscribes': [
732                   {'format': 'std.format_one', 'version': '1.0.0', 'route': '/sub1',
733                       'type': 'http'},
734                   {'format': 'std.format_one', 'version': '1.0.0',
735                       'config_key': 'sub2', 'type': 'message_router'}
736                   ]
737               },
738           'services': {
739               'calls': [
740                   {'request': {'format': 'std.format_one', 'version': '1.0.0'},
741                    'response': {'format': 'std.format_one', 'version': '1.0.0'},
742                    'config_key': 'call1'}
743                   ],
744               'provides': [
745                   {'request': {'format': 'std.format_one', 'version': '1.0.0'},
746                    'response': {'format': 'std.format_one', 'version': '1.0.0'},
747                    'route': '/prov1'}
748                   ]
749               }
750           }
751
752     grouping = catalog.build_config_keys_map(stub_spec)
753     expected = {'call1': {'group': 'services_calls'}, 'pub1': {'type': 'http', 'group': 'streams_publishes'}, 'sub2': {'type': 'message_router', 'group': 'streams_subscribes'}, 'pub2': {'type': 'message_router', 'group': 'streams_publishes'}}
754     assert expected == grouping
755
756
757 def test_get_data_router_subscriber_route():
758     spec = {"streams": {"subscribes": [ { "type": "data_router", "config_key":
759         "alpha", "route": "/alpha" }, { "type": "message_router", "config_key":
760         "beta" } ]}}
761
762     assert "/alpha" == catalog.get_data_router_subscriber_route(spec, "alpha")
763
764     with pytest.raises(catalog.MissingEntry):
765         catalog.get_data_router_subscriber_route(spec, "beta")
766
767     with pytest.raises(catalog.MissingEntry):
768         catalog.get_data_router_subscriber_route(spec, "gamma")
769
770
771 if __name__ == '__main__':
772     '''Test area'''
773     pytest.main([__file__, ])