~charmers/charms/trusty/python-moinmoin/trunk

« back to all changes in this revision

Viewing changes to lib/charm-helpers/tests/core/test_hookenv.py

  • Committer: Marco Ceppi
  • Date: 2013-10-20 17:35:29 UTC
  • mfrom: (7.1.1 python-moinmoin)
  • Revision ID: marco@ceppi.net-20131020173529-w9qmyq0pjj1bc71f
Brad Marshall 2013-09-26 [merge] Rewritten in python using charm-helpers

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import json
 
2
 
 
3
import cPickle as pickle
 
4
from mock import patch, call, mock_open
 
5
from StringIO import StringIO
 
6
from mock import MagicMock
 
7
from testtools import TestCase
 
8
import yaml
 
9
 
 
10
from charmhelpers.core import hookenv
 
11
 
 
12
CHARM_METADATA = """name: testmock
 
13
summary: test mock summary
 
14
description: test mock description
 
15
requires:
 
16
    testreqs:
 
17
        interface: mock
 
18
provides:
 
19
    testprov:
 
20
        interface: mock
 
21
peers:
 
22
    testpeer:
 
23
        interface: mock
 
24
"""
 
25
 
 
26
 
 
27
class SerializableTest(TestCase):
 
28
    def test_serializes_object_to_json(self):
 
29
        foo = {
 
30
            'bar': 'baz',
 
31
        }
 
32
        wrapped = hookenv.Serializable(foo)
 
33
        self.assertEqual(wrapped.json(), json.dumps(foo))
 
34
 
 
35
    def test_serializes_object_to_yaml(self):
 
36
        foo = {
 
37
            'bar': 'baz',
 
38
        }
 
39
        wrapped = hookenv.Serializable(foo)
 
40
        self.assertEqual(wrapped.yaml(), yaml.dump(foo))
 
41
 
 
42
    def test_gets_attribute_from_inner_object_as_dict(self):
 
43
        foo = {
 
44
            'bar': 'baz',
 
45
        }
 
46
        wrapped = hookenv.Serializable(foo)
 
47
 
 
48
        self.assertEqual(wrapped.bar, 'baz')
 
49
 
 
50
    def test_raises_error_from_inner_object_as_dict(self):
 
51
        foo = {
 
52
            'bar': 'baz',
 
53
        }
 
54
        wrapped = hookenv.Serializable(foo)
 
55
 
 
56
        self.assertRaises(AttributeError, getattr, wrapped, 'baz')
 
57
 
 
58
    def test_dict_methods_from_inner_object(self):
 
59
        foo = {
 
60
            'bar': 'baz',
 
61
        }
 
62
        wrapped = hookenv.Serializable(foo)
 
63
        for meth in ('keys', 'values', 'items'):
 
64
            self.assertEqual(getattr(wrapped, meth)(), getattr(foo, meth)())
 
65
 
 
66
        for meth in ('iterkeys', 'itervalues', 'iteritems'):
 
67
            self.assertEqual(list(getattr(wrapped, meth)()),
 
68
                             list(getattr(foo, meth)()))
 
69
        self.assertEqual(wrapped.get('bar'), foo.get('bar'))
 
70
        self.assertEqual(wrapped.get('baz', 42), foo.get('baz', 42))
 
71
        self.assertIn('bar', wrapped)
 
72
 
 
73
    def test_get_gets_from_inner_object(self):
 
74
        foo = {
 
75
            'bar': 'baz',
 
76
        }
 
77
        wrapped = hookenv.Serializable(foo)
 
78
 
 
79
        self.assertEqual(wrapped.get('foo'), None)
 
80
        self.assertEqual(wrapped.get('bar'), 'baz')
 
81
        self.assertEqual(wrapped.get('zoo', 'bla'), 'bla')
 
82
 
 
83
    def test_gets_inner_object(self):
 
84
        foo = {
 
85
            'bar': 'baz',
 
86
        }
 
87
        wrapped = hookenv.Serializable(foo)
 
88
 
 
89
        self.assertIs(wrapped.data, foo)
 
90
 
 
91
    def test_pickle(self):
 
92
        foo = {'bar': 'baz'}
 
93
        wrapped = hookenv.Serializable(foo)
 
94
        pickled = pickle.dumps(wrapped)
 
95
        unpickled = pickle.loads(pickled)
 
96
 
 
97
        self.assert_(isinstance(unpickled, hookenv.Serializable))
 
98
        self.assertEqual(unpickled, foo)
 
99
 
 
100
    def test_boolean(self):
 
101
        true_dict = {'foo': 'bar'}
 
102
        false_dict = {}
 
103
 
 
104
        self.assertIs(bool(hookenv.Serializable(true_dict)), True)
 
105
        self.assertIs(bool(hookenv.Serializable(false_dict)), False)
 
106
 
 
107
    def test_equality(self):
 
108
        foo = {'bar': 'baz'}
 
109
        bar = {'baz': 'bar'}
 
110
        wrapped_foo = hookenv.Serializable(foo)
 
111
 
 
112
        self.assertEqual(wrapped_foo, foo)
 
113
        self.assertEqual(wrapped_foo, wrapped_foo)
 
114
        self.assertNotEqual(wrapped_foo, bar)
 
115
 
 
116
 
 
117
class HelpersTest(TestCase):
 
118
    def setUp(self):
 
119
        super(HelpersTest, self).setUp()
 
120
        # Reset hookenv cache for each test
 
121
        hookenv.cache = {}
 
122
 
 
123
    @patch('subprocess.call')
 
124
    def test_logs_messages_to_juju_with_default_level(self, mock_call):
 
125
        hookenv.log('foo')
 
126
 
 
127
        mock_call.assert_called_with(['juju-log', 'foo'])
 
128
 
 
129
    @patch('subprocess.call')
 
130
    def test_logs_messages_with_alternative_levels(self, mock_call):
 
131
        alternative_levels = [
 
132
            hookenv.CRITICAL,
 
133
            hookenv.ERROR,
 
134
            hookenv.WARNING,
 
135
            hookenv.INFO,
 
136
        ]
 
137
 
 
138
        for level in alternative_levels:
 
139
            hookenv.log('foo', level)
 
140
            mock_call.assert_called_with(['juju-log', '-l', level, 'foo'])
 
141
 
 
142
    @patch('subprocess.check_output')
 
143
    def test_gets_charm_config_with_scope(self, check_output):
 
144
        config_data = 'bar'
 
145
        check_output.return_value = json.dumps(config_data)
 
146
 
 
147
        result = hookenv.config(scope='baz')
 
148
 
 
149
        self.assertEqual(result, 'bar')
 
150
        check_output.assert_called_with(['config-get', 'baz', '--format=json'])
 
151
 
 
152
        # The result can be used like a string
 
153
        self.assertEqual(result[1], 'a')
 
154
 
 
155
        # ... because the result is actually a string
 
156
        self.assert_(isinstance(result, basestring))
 
157
 
 
158
    @patch('subprocess.check_output')
 
159
    def test_gets_missing_charm_config_with_scope(self, check_output):
 
160
        check_output.return_value = ''
 
161
 
 
162
        result = hookenv.config(scope='baz')
 
163
 
 
164
        self.assertEqual(result, None)
 
165
        check_output.assert_called_with(['config-get', 'baz', '--format=json'])
 
166
 
 
167
    @patch('charmhelpers.core.hookenv.os')
 
168
    def test_gets_the_local_unit(self, os_):
 
169
        os_.environ = {
 
170
            'JUJU_UNIT_NAME': 'foo',
 
171
        }
 
172
 
 
173
        self.assertEqual(hookenv.local_unit(), 'foo')
 
174
 
 
175
    @patch('charmhelpers.core.hookenv.unit_get')
 
176
    def test_gets_unit_private_ip(self, _unitget):
 
177
        _unitget.return_value = 'foo'
 
178
        self.assertEqual("foo", hookenv.unit_private_ip())
 
179
        _unitget.assert_called_with('private-address')
 
180
 
 
181
    @patch('charmhelpers.core.hookenv.os')
 
182
    def test_checks_that_is_running_in_relation_hook(self, os_):
 
183
        os_.environ = {
 
184
            'JUJU_RELATION': 'foo',
 
185
        }
 
186
 
 
187
        self.assertTrue(hookenv.in_relation_hook())
 
188
 
 
189
    @patch('charmhelpers.core.hookenv.os')
 
190
    def test_checks_that_is_not_running_in_relation_hook(self, os_):
 
191
        os_.environ = {
 
192
            'bar': 'foo',
 
193
        }
 
194
 
 
195
        self.assertFalse(hookenv.in_relation_hook())
 
196
 
 
197
    @patch('charmhelpers.core.hookenv.os')
 
198
    def test_gets_the_relation_type(self, os_):
 
199
        os_.environ = {
 
200
            'JUJU_RELATION': 'foo',
 
201
        }
 
202
 
 
203
        self.assertEqual(hookenv.relation_type(), 'foo')
 
204
 
 
205
    @patch('charmhelpers.core.hookenv.os')
 
206
    def test_relation_type_none_if_not_in_environment(self, os_):
 
207
        os_.environ = {}
 
208
        self.assertEqual(hookenv.relation_type(), None)
 
209
 
 
210
    @patch('subprocess.check_output')
 
211
    @patch('charmhelpers.core.hookenv.relation_type')
 
212
    def test_gets_relation_ids(self, relation_type, check_output):
 
213
        ids = [1, 2, 3]
 
214
        check_output.return_value = json.dumps(ids)
 
215
        reltype = 'foo'
 
216
        relation_type.return_value = reltype
 
217
 
 
218
        result = hookenv.relation_ids()
 
219
 
 
220
        self.assertEqual(result, ids)
 
221
        check_output.assert_called_with(['relation-ids', '--format=json',
 
222
                                         reltype])
 
223
 
 
224
    @patch('subprocess.check_output')
 
225
    @patch('charmhelpers.core.hookenv.relation_type')
 
226
    def test_gets_relation_ids_empty_array(self, relation_type, check_output):
 
227
        ids = []
 
228
        check_output.return_value = json.dumps(None)
 
229
        reltype = 'foo'
 
230
        relation_type.return_value = reltype
 
231
 
 
232
        result = hookenv.relation_ids()
 
233
 
 
234
        self.assertEqual(result, ids)
 
235
        check_output.assert_called_with(['relation-ids', '--format=json',
 
236
                                         reltype])
 
237
 
 
238
    @patch('subprocess.check_output')
 
239
    @patch('charmhelpers.core.hookenv.relation_type')
 
240
    def test_relation_ids_no_relation_type(self, relation_type, check_output):
 
241
        ids = [1, 2, 3]
 
242
        check_output.return_value = json.dumps(ids)
 
243
        relation_type.return_value = None
 
244
 
 
245
        result = hookenv.relation_ids()
 
246
 
 
247
        self.assertEqual(result, [])
 
248
 
 
249
    @patch('subprocess.check_output')
 
250
    @patch('charmhelpers.core.hookenv.relation_type')
 
251
    def test_gets_relation_ids_for_type(self, relation_type, check_output):
 
252
        ids = [1, 2, 3]
 
253
        check_output.return_value = json.dumps(ids)
 
254
        reltype = 'foo'
 
255
 
 
256
        result = hookenv.relation_ids(reltype)
 
257
 
 
258
        self.assertEqual(result, ids)
 
259
        check_output.assert_called_with(['relation-ids', '--format=json',
 
260
                                         reltype])
 
261
        self.assertFalse(relation_type.called)
 
262
 
 
263
    @patch('subprocess.check_output')
 
264
    @patch('charmhelpers.core.hookenv.relation_id')
 
265
    def test_gets_related_units(self, relation_id, check_output):
 
266
        relid = 123
 
267
        units = ['foo', 'bar']
 
268
        relation_id.return_value = relid
 
269
        check_output.return_value = json.dumps(units)
 
270
 
 
271
        result = hookenv.related_units()
 
272
 
 
273
        self.assertEqual(result, units)
 
274
        check_output.assert_called_with(['relation-list', '--format=json',
 
275
                                         '-r', relid])
 
276
 
 
277
    @patch('subprocess.check_output')
 
278
    @patch('charmhelpers.core.hookenv.relation_id')
 
279
    def test_gets_related_units_empty_array(self, relation_id, check_output):
 
280
        relid = 123
 
281
        units = []
 
282
        relation_id.return_value = relid
 
283
        check_output.return_value = json.dumps(None)
 
284
 
 
285
        result = hookenv.related_units()
 
286
 
 
287
        self.assertEqual(result, units)
 
288
        check_output.assert_called_with(['relation-list', '--format=json',
 
289
                                         '-r', relid])
 
290
 
 
291
    @patch('subprocess.check_output')
 
292
    @patch('charmhelpers.core.hookenv.relation_id')
 
293
    def test_related_units_no_relation(self, relation_id, check_output):
 
294
        units = ['foo', 'bar']
 
295
        relation_id.return_value = None
 
296
        check_output.return_value = json.dumps(units)
 
297
 
 
298
        result = hookenv.related_units()
 
299
 
 
300
        self.assertEqual(result, units)
 
301
        check_output.assert_called_with(['relation-list', '--format=json'])
 
302
 
 
303
    @patch('subprocess.check_output')
 
304
    @patch('charmhelpers.core.hookenv.relation_id')
 
305
    def test_gets_related_units_for_id(self, relation_id, check_output):
 
306
        relid = 123
 
307
        units = ['foo', 'bar']
 
308
        check_output.return_value = json.dumps(units)
 
309
 
 
310
        result = hookenv.related_units(relid)
 
311
 
 
312
        self.assertEqual(result, units)
 
313
        check_output.assert_called_with(['relation-list', '--format=json',
 
314
                                         '-r', relid])
 
315
        self.assertFalse(relation_id.called)
 
316
 
 
317
    @patch('charmhelpers.core.hookenv.os')
 
318
    def test_gets_the_remote_unit(self, os_):
 
319
        os_.environ = {
 
320
            'JUJU_REMOTE_UNIT': 'foo',
 
321
        }
 
322
 
 
323
        self.assertEqual(hookenv.remote_unit(), 'foo')
 
324
 
 
325
    @patch('charmhelpers.core.hookenv.remote_unit')
 
326
    @patch('charmhelpers.core.hookenv.relation_get')
 
327
    def test_gets_relation_for_unit(self, relation_get, remote_unit):
 
328
        unit = 'foo-unit'
 
329
        raw_relation = {
 
330
            'foo': 'bar',
 
331
        }
 
332
        remote_unit.return_value = unit
 
333
        relation_get.return_value = raw_relation
 
334
 
 
335
        result = hookenv.relation_for_unit()
 
336
 
 
337
        self.assertEqual(result['__unit__'], unit)
 
338
        self.assertEqual(result['foo'], 'bar')
 
339
        relation_get.assert_called_with(unit=unit, rid=None)
 
340
 
 
341
    @patch('charmhelpers.core.hookenv.remote_unit')
 
342
    @patch('charmhelpers.core.hookenv.relation_get')
 
343
    def test_gets_relation_for_unit_with_list(self, relation_get, remote_unit):
 
344
        unit = 'foo-unit'
 
345
        raw_relation = {
 
346
            'foo-list': 'one two three',
 
347
        }
 
348
        remote_unit.return_value = unit
 
349
        relation_get.return_value = raw_relation
 
350
 
 
351
        result = hookenv.relation_for_unit()
 
352
 
 
353
        self.assertEqual(result['__unit__'], unit)
 
354
        self.assertEqual(result['foo-list'], ['one', 'two', 'three'])
 
355
        relation_get.assert_called_with(unit=unit, rid=None)
 
356
 
 
357
    @patch('charmhelpers.core.hookenv.remote_unit')
 
358
    @patch('charmhelpers.core.hookenv.relation_get')
 
359
    def test_gets_relation_for_specific_unit(self, relation_get, remote_unit):
 
360
        unit = 'foo-unit'
 
361
        raw_relation = {
 
362
            'foo': 'bar',
 
363
        }
 
364
        relation_get.return_value = raw_relation
 
365
 
 
366
        result = hookenv.relation_for_unit(unit)
 
367
 
 
368
        self.assertEqual(result['__unit__'], unit)
 
369
        self.assertEqual(result['foo'], 'bar')
 
370
        relation_get.assert_called_with(unit=unit, rid=None)
 
371
        self.assertFalse(remote_unit.called)
 
372
 
 
373
    @patch('charmhelpers.core.hookenv.relation_ids')
 
374
    @patch('charmhelpers.core.hookenv.related_units')
 
375
    @patch('charmhelpers.core.hookenv.relation_for_unit')
 
376
    def test_gets_relations_for_id(self, relation_for_unit, related_units,
 
377
                                   relation_ids):
 
378
        relid = 123
 
379
        units = ['foo', 'bar']
 
380
        unit_data = [
 
381
            {'foo-item': 'bar-item'},
 
382
            {'foo-item2': 'bar-item2'},
 
383
        ]
 
384
        relation_ids.return_value = relid
 
385
        related_units.return_value = units
 
386
        relation_for_unit.side_effect = unit_data
 
387
 
 
388
        result = hookenv.relations_for_id()
 
389
 
 
390
        self.assertEqual(result[0]['__relid__'], relid)
 
391
        self.assertEqual(result[0]['foo-item'], 'bar-item')
 
392
        self.assertEqual(result[1]['__relid__'], relid)
 
393
        self.assertEqual(result[1]['foo-item2'], 'bar-item2')
 
394
        related_units.assert_called_with(relid)
 
395
        self.assertEqual(relation_for_unit.mock_calls, [
 
396
            call('foo', relid),
 
397
            call('bar', relid),
 
398
        ])
 
399
 
 
400
    @patch('charmhelpers.core.hookenv.relation_ids')
 
401
    @patch('charmhelpers.core.hookenv.related_units')
 
402
    @patch('charmhelpers.core.hookenv.relation_for_unit')
 
403
    def test_gets_relations_for_specific_id(self, relation_for_unit,
 
404
                                            related_units, relation_ids):
 
405
        relid = 123
 
406
        units = ['foo', 'bar']
 
407
        unit_data = [
 
408
            {'foo-item': 'bar-item'},
 
409
            {'foo-item2': 'bar-item2'},
 
410
        ]
 
411
        related_units.return_value = units
 
412
        relation_for_unit.side_effect = unit_data
 
413
 
 
414
        result = hookenv.relations_for_id(relid)
 
415
 
 
416
        self.assertEqual(result[0]['__relid__'], relid)
 
417
        self.assertEqual(result[0]['foo-item'], 'bar-item')
 
418
        self.assertEqual(result[1]['__relid__'], relid)
 
419
        self.assertEqual(result[1]['foo-item2'], 'bar-item2')
 
420
        related_units.assert_called_with(relid)
 
421
        self.assertEqual(relation_for_unit.mock_calls, [
 
422
            call('foo', relid),
 
423
            call('bar', relid),
 
424
        ])
 
425
        self.assertFalse(relation_ids.called)
 
426
 
 
427
    @patch('charmhelpers.core.hookenv.in_relation_hook')
 
428
    @patch('charmhelpers.core.hookenv.relation_type')
 
429
    @patch('charmhelpers.core.hookenv.relation_ids')
 
430
    @patch('charmhelpers.core.hookenv.relations_for_id')
 
431
    def test_gets_relations_for_type(self, relations_for_id, relation_ids,
 
432
                                     relation_type, in_relation_hook):
 
433
        reltype = 'foo-type'
 
434
        relids = [123, 234]
 
435
        relations = [
 
436
            [
 
437
                {'foo': 'bar'},
 
438
                {'foo2': 'bar2'},
 
439
            ],
 
440
            [
 
441
                {'FOO': 'BAR'},
 
442
                {'FOO2': 'BAR2'},
 
443
            ],
 
444
        ]
 
445
        is_in_relation = True
 
446
 
 
447
        relation_type.return_value = reltype
 
448
        relation_ids.return_value = relids
 
449
        relations_for_id.side_effect = relations
 
450
        in_relation_hook.return_value = is_in_relation
 
451
 
 
452
        result = hookenv.relations_of_type()
 
453
 
 
454
        self.assertEqual(result[0]['__relid__'], 123)
 
455
        self.assertEqual(result[0]['foo'], 'bar')
 
456
        self.assertEqual(result[1]['__relid__'], 123)
 
457
        self.assertEqual(result[1]['foo2'], 'bar2')
 
458
        self.assertEqual(result[2]['__relid__'], 234)
 
459
        self.assertEqual(result[2]['FOO'], 'BAR')
 
460
        self.assertEqual(result[3]['__relid__'], 234)
 
461
        self.assertEqual(result[3]['FOO2'], 'BAR2')
 
462
        relation_ids.assert_called_with(reltype)
 
463
        self.assertEqual(relations_for_id.mock_calls, [
 
464
            call(123),
 
465
            call(234),
 
466
        ])
 
467
 
 
468
    @patch('charmhelpers.core.hookenv.local_unit')
 
469
    @patch('charmhelpers.core.hookenv.relation_types')
 
470
    @patch('charmhelpers.core.hookenv.relation_ids')
 
471
    @patch('charmhelpers.core.hookenv.related_units')
 
472
    @patch('charmhelpers.core.hookenv.relation_get')
 
473
    def test_gets_relations(self, relation_get, related_units,
 
474
                            relation_ids, relation_types, local_unit):
 
475
        local_unit.return_value = 'u0'
 
476
        relation_types.return_value = ['t1', 't2']
 
477
        relation_ids.return_value = ['i1']
 
478
        related_units.return_value = ['u1', 'u2']
 
479
        relation_get.return_value = {'key': 'val'}
 
480
 
 
481
        result = hookenv.relations()
 
482
 
 
483
        self.assertEqual(result, {
 
484
            't1': {
 
485
                'i1': {
 
486
                    'u0': {'key': 'val'},
 
487
                    'u1': {'key': 'val'},
 
488
                    'u2': {'key': 'val'},
 
489
                },
 
490
            },
 
491
            't2': {
 
492
                'i1': {
 
493
                    'u0': {'key': 'val'},
 
494
                    'u1': {'key': 'val'},
 
495
                    'u2': {'key': 'val'},
 
496
                },
 
497
            },
 
498
        })
 
499
 
 
500
    @patch('charmhelpers.core.hookenv.config')
 
501
    @patch('charmhelpers.core.hookenv.relation_type')
 
502
    @patch('charmhelpers.core.hookenv.local_unit')
 
503
    @patch('charmhelpers.core.hookenv.relation_id')
 
504
    @patch('charmhelpers.core.hookenv.relations')
 
505
    @patch('charmhelpers.core.hookenv.relation_get')
 
506
    @patch('charmhelpers.core.hookenv.os')
 
507
    def test_gets_execution_environment(self, os_, relations_get,
 
508
                                        relations, relation_id, local_unit,
 
509
                                        relation_type, config):
 
510
        config.return_value = 'some-config'
 
511
        relation_type.return_value = 'some-type'
 
512
        local_unit.return_value = 'some-unit'
 
513
        relation_id.return_value = 'some-id'
 
514
        relations.return_value = 'all-relations'
 
515
        relations_get.return_value = 'some-relations'
 
516
        os_.environ = 'some-environment'
 
517
 
 
518
        result = hookenv.execution_environment()
 
519
 
 
520
        self.assertEqual(result, {
 
521
            'conf': 'some-config',
 
522
            'reltype': 'some-type',
 
523
            'unit': 'some-unit',
 
524
            'relid': 'some-id',
 
525
            'rel': 'some-relations',
 
526
            'rels': 'all-relations',
 
527
            'env': 'some-environment',
 
528
        })
 
529
 
 
530
    @patch('charmhelpers.core.hookenv.config')
 
531
    @patch('charmhelpers.core.hookenv.relation_type')
 
532
    @patch('charmhelpers.core.hookenv.local_unit')
 
533
    @patch('charmhelpers.core.hookenv.relation_id')
 
534
    @patch('charmhelpers.core.hookenv.relations')
 
535
    @patch('charmhelpers.core.hookenv.relation_get')
 
536
    @patch('charmhelpers.core.hookenv.os')
 
537
    def test_gets_execution_environment_no_relation(
 
538
            self, os_, relations_get, relations, relation_id,
 
539
            local_unit, relation_type, config):
 
540
        config.return_value = 'some-config'
 
541
        relation_type.return_value = 'some-type'
 
542
        local_unit.return_value = 'some-unit'
 
543
        relation_id.return_value = None
 
544
        relations.return_value = 'all-relations'
 
545
        relations_get.return_value = 'some-relations'
 
546
        os_.environ = 'some-environment'
 
547
 
 
548
        result = hookenv.execution_environment()
 
549
 
 
550
        self.assertEqual(result, {
 
551
            'conf': 'some-config',
 
552
            'unit': 'some-unit',
 
553
            'rels': 'all-relations',
 
554
            'env': 'some-environment',
 
555
        })
 
556
 
 
557
    @patch('charmhelpers.core.hookenv.os')
 
558
    def test_gets_the_relation_id(self, os_):
 
559
        os_.environ = {
 
560
            'JUJU_RELATION_ID': 'foo',
 
561
        }
 
562
 
 
563
        self.assertEqual(hookenv.relation_id(), 'foo')
 
564
 
 
565
    @patch('charmhelpers.core.hookenv.os')
 
566
    def test_relation_id_none_if_no_env(self, os_):
 
567
        os_.environ = {}
 
568
        self.assertEqual(hookenv.relation_id(), None)
 
569
 
 
570
    @patch('subprocess.check_output')
 
571
    def test_gets_relation(self, check_output):
 
572
        data = {"foo": "BAR"}
 
573
        check_output.return_value = json.dumps(data)
 
574
        result = hookenv.relation_get()
 
575
 
 
576
        self.assertEqual(result['foo'], 'BAR')
 
577
        check_output.assert_called_with(['relation-get', '--format=json', '-'])
 
578
 
 
579
    @patch('charmhelpers.core.hookenv.subprocess')
 
580
    def test_relation_get_none(self, mock_subprocess):
 
581
        mock_subprocess.check_output.return_value = 'null'
 
582
 
 
583
        result = hookenv.relation_get()
 
584
 
 
585
        self.assertIsNone(result)
 
586
 
 
587
    @patch('subprocess.check_output')
 
588
    def test_gets_relation_with_scope(self, check_output):
 
589
        check_output.return_value = json.dumps('bar')
 
590
 
 
591
        result = hookenv.relation_get(attribute='baz-scope')
 
592
 
 
593
        self.assertEqual(result, 'bar')
 
594
        check_output.assert_called_with(['relation-get', '--format=json',
 
595
                                         'baz-scope'])
 
596
 
 
597
    @patch('subprocess.check_output')
 
598
    def test_gets_missing_relation_with_scope(self, check_output):
 
599
        check_output.return_value = ""
 
600
 
 
601
        result = hookenv.relation_get(attribute='baz-scope')
 
602
 
 
603
        self.assertEqual(result, None)
 
604
        check_output.assert_called_with(['relation-get', '--format=json',
 
605
                                         'baz-scope'])
 
606
 
 
607
    @patch('subprocess.check_output')
 
608
    def test_gets_relation_with_unit_name(self, check_output):
 
609
        check_output.return_value = json.dumps('BAR')
 
610
 
 
611
        result = hookenv.relation_get(attribute='baz-scope', unit='baz-unit')
 
612
 
 
613
        self.assertEqual(result, 'BAR')
 
614
        check_output.assert_called_with(['relation-get', '--format=json',
 
615
                                         'baz-scope', 'baz-unit'])
 
616
 
 
617
    @patch('charmhelpers.core.hookenv.local_unit')
 
618
    @patch('subprocess.check_call')
 
619
    @patch('subprocess.check_output')
 
620
    def test_relation_set_flushes_local_unit_cache(self, check_output,
 
621
                                                   check_call, local_unit):
 
622
        check_output.return_value = json.dumps('BAR')
 
623
        local_unit.return_value = 'baz_unit'
 
624
        hookenv.relation_get(attribute='baz_scope', unit='baz_unit')
 
625
        hookenv.relation_get(attribute='bar_scope')
 
626
        self.assertTrue(len(hookenv.cache) == 2)
 
627
        hookenv.relation_set(baz_scope='hello')
 
628
        # relation_set should flush any entries for local_unit
 
629
        self.assertTrue(len(hookenv.cache) == 1)
 
630
 
 
631
    @patch('subprocess.check_output')
 
632
    def test_gets_relation_with_relation_id(self, check_output):
 
633
        check_output.return_value = json.dumps('BAR')
 
634
 
 
635
        result = hookenv.relation_get(attribute='baz-scope', unit='baz-unit',
 
636
                                      rid=123)
 
637
 
 
638
        self.assertEqual(result, 'BAR')
 
639
        check_output.assert_called_with(['relation-get', '--format=json', '-r',
 
640
                                         123, 'baz-scope', 'baz-unit'])
 
641
 
 
642
    @patch('subprocess.check_call')
 
643
    def test_sets_relation_with_kwargs(self, check_call_):
 
644
        hookenv.relation_set(foo="bar")
 
645
        check_call_.assert_called_with(['relation-set', 'foo=bar'])
 
646
 
 
647
    @patch('subprocess.check_call')
 
648
    def test_sets_relation_with_dict(self, check_call_):
 
649
        hookenv.relation_set(relation_settings={"foo": "bar"})
 
650
        check_call_.assert_called_with(['relation-set', 'foo=bar'])
 
651
 
 
652
    @patch('subprocess.check_call')
 
653
    def test_sets_relation_with_relation_id(self, check_call_):
 
654
        hookenv.relation_set(relation_id="foo", bar="baz")
 
655
        check_call_.assert_called_with(['relation-set', '-r', 'foo',
 
656
                                        'bar=baz'])
 
657
 
 
658
    @patch('subprocess.check_call')
 
659
    def test_sets_relation_with_missing_value(self, check_call_):
 
660
        hookenv.relation_set(foo=None)
 
661
        check_call_.assert_called_with(['relation-set', 'foo='])
 
662
 
 
663
    def test_lists_relation_types(self):
 
664
        open_ = mock_open()
 
665
        open_.return_value = StringIO(CHARM_METADATA)
 
666
        with patch('charmhelpers.core.hookenv.open', open_, create=True):
 
667
            with patch.dict('os.environ', {'CHARM_DIR': '/var/empty'}):
 
668
                reltypes = set(hookenv.relation_types())
 
669
        open_.assert_called_once_with('/var/empty/metadata.yaml')
 
670
        self.assertEqual(set(('testreqs', 'testprov', 'testpeer')), reltypes)
 
671
 
 
672
    @patch('subprocess.check_call')
 
673
    def test_opens_port(self, check_call_):
 
674
        hookenv.open_port(443, "TCP")
 
675
        hookenv.open_port(80)
 
676
        hookenv.open_port(100, "UDP")
 
677
        calls = [
 
678
            call(['open-port', '443/TCP']),
 
679
            call(['open-port', '80/TCP']),
 
680
            call(['open-port', '100/UDP']),
 
681
        ]
 
682
        check_call_.assert_has_calls(calls)
 
683
 
 
684
    @patch('subprocess.check_call')
 
685
    def test_closes_port(self, check_call_):
 
686
        hookenv.close_port(443, "TCP")
 
687
        hookenv.close_port(80)
 
688
        hookenv.close_port(100, "UDP")
 
689
        calls = [
 
690
            call(['close-port', '443/TCP']),
 
691
            call(['close-port', '80/TCP']),
 
692
            call(['close-port', '100/UDP']),
 
693
        ]
 
694
        check_call_.assert_has_calls(calls)
 
695
 
 
696
    @patch('subprocess.check_output')
 
697
    def test_gets_unit_attribute(self, check_output_):
 
698
        check_output_.return_value = json.dumps('bar')
 
699
        self.assertEqual(hookenv.unit_get('foo'), 'bar')
 
700
        check_output_.assert_called_with(['unit-get', '--format=json', 'foo'])
 
701
 
 
702
    @patch('subprocess.check_output')
 
703
    def test_gets_missing_unit_attribute(self, check_output_):
 
704
        check_output_.return_value = ""
 
705
        self.assertEqual(hookenv.unit_get('foo'), None)
 
706
        check_output_.assert_called_with(['unit-get', '--format=json', 'foo'])
 
707
 
 
708
    def test_cached_decorator(self):
 
709
        calls = []
 
710
        values = {
 
711
            'hello': 'world',
 
712
            'foo': 'bar',
 
713
            'baz': None
 
714
            }
 
715
 
 
716
        @hookenv.cached
 
717
        def cache_function(attribute):
 
718
            calls.append(attribute)
 
719
            return values[attribute]
 
720
 
 
721
        self.assertEquals(cache_function('hello'), 'world')
 
722
        self.assertEquals(cache_function('hello'), 'world')
 
723
        self.assertEquals(cache_function('foo'), 'bar')
 
724
        self.assertEquals(cache_function('baz'), None)
 
725
        self.assertEquals(cache_function('baz'), None)
 
726
        self.assertEquals(calls, ['hello', 'foo', 'baz'])
 
727
 
 
728
    def test_gets_charm_dir(self):
 
729
        with patch.dict('os.environ', {'CHARM_DIR': '/var/empty'}):
 
730
            self.assertEqual(hookenv.charm_dir(), '/var/empty')
 
731
 
 
732
 
 
733
class HooksTest(TestCase):
 
734
    def test_runs_a_registered_function(self):
 
735
        foo = MagicMock()
 
736
        hooks = hookenv.Hooks()
 
737
        hooks.register('foo', foo)
 
738
 
 
739
        hooks.execute(['foo', 'some', 'other', 'args'])
 
740
 
 
741
        foo.assert_called_with()
 
742
 
 
743
    def test_cannot_run_unregistered_function(self):
 
744
        foo = MagicMock()
 
745
        hooks = hookenv.Hooks()
 
746
        hooks.register('foo', foo)
 
747
 
 
748
        self.assertRaises(hookenv.UnregisteredHookError, hooks.execute,
 
749
                          ['bar'])
 
750
 
 
751
    def test_can_run_a_decorated_function_as_one_or_more_hooks(self):
 
752
        execs = []
 
753
        hooks = hookenv.Hooks()
 
754
 
 
755
        @hooks.hook('bar', 'baz')
 
756
        def func():
 
757
            execs.append(True)
 
758
 
 
759
        hooks.execute(['bar'])
 
760
        hooks.execute(['baz'])
 
761
        self.assertRaises(hookenv.UnregisteredHookError, hooks.execute,
 
762
                          ['brew'])
 
763
        self.assertEqual(execs, [True, True])
 
764
 
 
765
    def test_can_run_a_decorated_function_as_itself(self):
 
766
        execs = []
 
767
        hooks = hookenv.Hooks()
 
768
 
 
769
        @hooks.hook()
 
770
        def func():
 
771
            execs.append(True)
 
772
 
 
773
        hooks.execute(['func'])
 
774
        self.assertRaises(hookenv.UnregisteredHookError, hooks.execute,
 
775
                          ['brew'])
 
776
        self.assertEqual(execs, [True])
 
777
 
 
778
    def test_magic_underscores(self):
 
779
        # Juju hook names use hypens as separators. Python functions use
 
780
        # underscores. If explicit names have not been provided, hooks
 
781
        # are registered with both the function name and the function
 
782
        # name with underscores replaced with hypens for convenience.
 
783
        execs = []
 
784
        hooks = hookenv.Hooks()
 
785
 
 
786
        @hooks.hook()
 
787
        def call_me_maybe():
 
788
            execs.append(True)
 
789
 
 
790
        hooks.execute(['call-me-maybe'])
 
791
        hooks.execute(['call_me_maybe'])
 
792
        self.assertEqual(execs, [True, True])
 
793
 
 
794
    @patch('charmhelpers.core.hookenv.local_unit')
 
795
    def test_gets_service_name(self, _unit):
 
796
        _unit.return_value = 'mysql/3'
 
797
        self.assertEqual(hookenv.service_name(), 'mysql')