1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# Ubuntu CI Engine
# Copyright 2014 Canonical Ltd.
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License version 3, as
# published by the Free Software Foundation.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import mock
import os
import unittest
import shutil
import tempfile
import base64
import yaml
import hooks
PATCHES = [
'charmhelpers.core.hookenv.config',
'charmhelpers.core.hookenv.log',
'charmhelpers.core.hookenv.relations_of_type',
'charmhelpers.core.hookenv.remote_unit',
'charmhelpers.core.host.mkdir',
]
class JujuTestCase(unittest.TestCase):
def setUp(self):
"""Setup a testing hook environment.
Patches the required charmhelper and intercom objects and
initializes few mocks for tests.
"""
super(JujuTestCase, self).setUp()
self.tmpdir = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, self.tmpdir)
for spec in PATCHES:
attr_name = spec.split('.')[-1]
_m = mock.patch(spec)
setattr(self, attr_name, _m.start())
self.addCleanup(_m.stop)
self.unit_name = 'bazinga/0'
self.service_dir = os.path.join(self.tmpdir, 'bazinga')
self.keys_dir = os.path.join(self.service_dir, 'keys')
self.remote_unit.return_value = self.unit_name
self.relations_of_type.side_effect = (
lambda rel_type: [{'__unit__': self.unit_name}])
self.mkdir.side_effect = lambda d, perms=None: os.mkdir(d)
self._set_default_config()
def _set_default_config(self):
defaults = {}
config = os.path.join(os.path.dirname(__file__), '../config.yaml')
if os.path.exists(config):
with open(config) as f:
config = yaml.safe_load(f)
for name, option in config['options'].iteritems():
defaults[name] = option.get('default')
defaults['install_root'] = self.tmpdir
self.config.return_value = defaults
def test_service_dir(self):
# Unit names get sanitized before discovering its service name.
expected = os.path.join(self.tmpdir, 'bazinga')
self.assertEqual(expected, hooks._service_dir(self.unit_name))
expected = os.path.join(self.tmpdir, 'foo-bar_x')
self.assertEqual(expected, hooks._service_dir('foo-bar:x/42'))
def test_config_changed_no_container(self):
# Configuration changes have not effect until the subordinate
# charm gets a container (parent).
self.relations_of_type.side_effect = lambda rel_type: []
os.mkdir(self.service_dir)
hooks.hooks.execute(['hooks/config-changed'])
self.assertEqual([], os.listdir(self.service_dir))
def test_config_changed_full(self):
# Configuration changes have immediate effect on bound charms
# and existing 'keys' directory is removed and a new one is created
# with configured key contents.
# Fake and previous 'keys' directory.
os.makedirs(self.keys_dir)
with open(os.path.join(self.keys_dir, 'deleted'), 'w') as fd:
fd.write('gone!')
# Set of keys for this test.
config = {
'ssh-private-key': base64.b64encode('secret!'),
'ssh-public-key': base64.b64encode('public?'),
'gpg-secret-keyring': base64.b64encode('secret!'),
'gpg-public-keyring': base64.b64encode('public?'),
'launchpad-credentials': base64.b64encode('launchpad!'),
}
self.config.return_value.update(config)
hooks.hooks.execute(['hooks/config-changed'])
self.assertEqual(['keys'], os.listdir(self.service_dir))
keys = sorted(os.listdir(self.keys_dir))
self.assertEqual(
['gpg.pub', 'gpg.sec', 'id_rsa', 'id_rsa.pub',
'launchpad.credentials'], keys)
def test_juju_info_joined(self):
# Keys are placed immediately when the subordinate charm is bound.
os.makedirs(self.service_dir)
self.config.return_value['ssh-private-key'] = base64.b64encode(
'secret!')
hooks.hooks.execute(['hooks/juju-info-relation-joined'])
self.assertEqual(['keys'], os.listdir(self.service_dir))
self.assertEqual(['id_rsa'], os.listdir(self.keys_dir))
|