~hazmat/charms/trusty/juju-gui/trunk

« back to all changes in this revision

Viewing changes to tests/test_backends.py

  • Committer: Francesco Banconi
  • Date: 2013-10-09 10:48:53 UTC
  • mfrom: (60.13.41 trunk)
  • Revision ID: francesco.banconi@canonical.com-20131009104853-6b8oxx4k1ycmv2yk
Tags: 0.11.0
MergedĀ juju-guiĀ trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
"""Backend tests."""
18
18
 
19
19
 
20
 
from collections import defaultdict
21
 
from contextlib import contextmanager
 
20
from contextlib import (
 
21
    contextmanager,
 
22
    nested,
 
23
)
 
24
import os
22
25
import shutil
23
26
import tempfile
24
27
import unittest
25
28
 
26
 
import charmhelpers
27
29
import mock
28
 
import shelltoolbox
29
30
 
30
31
import backend
31
32
import utils
32
33
 
33
34
 
34
 
def get_mixin_names(test_backend):
35
 
    return tuple(b.__class__.__name__ for b in test_backend.mixins)
36
 
 
37
 
 
38
 
class GotEmAllDict(defaultdict):
39
 
    """A dictionary that returns the same default value for all given keys."""
40
 
 
41
 
    def get(self, key, default=None):
42
 
        return self.default_factory()
 
35
EXPECTED_PYTHON_LEGACY_DEBS = ('apache2', 'curl', 'haproxy', 'openssl')
 
36
EXPECTED_GO_LEGACY_DEBS = (
 
37
    'apache2', 'curl', 'haproxy', 'openssl', 'python-yaml')
 
38
EXPECTED_PYTHON_BUILTIN_DEBS = (
 
39
    'curl', 'openssl', 'python-bzrlib', 'python-pip')
 
40
EXPECTED_GO_BUILTIN_DEBS = (
 
41
    'curl', 'openssl', 'python-bzrlib', 'python-pip', 'python-yaml')
 
42
 
 
43
simulate_pyjuju = mock.patch('utils.legacy_juju', mock.Mock(return_value=True))
 
44
simulate_juju_core = mock.patch(
 
45
    'utils.legacy_juju', mock.Mock(return_value=False))
43
46
 
44
47
 
45
48
class TestBackendProperties(unittest.TestCase):
46
49
    """Ensure the correct mixins and property values are collected."""
47
50
 
48
 
    simulate_pyjuju = mock.patch(
49
 
        'utils.legacy_juju', mock.Mock(return_value=True))
50
 
    simulate_juju_core = mock.patch(
51
 
        'utils.legacy_juju', mock.Mock(return_value=False))
 
51
    def assert_mixins(self, expected, backend):
 
52
        """Ensure the given backend includes the expected mixins."""
 
53
        obtained = tuple(mixin.__class__.__name__ for mixin in backend.mixins)
 
54
        self.assertEqual(tuple(expected), obtained)
 
55
 
 
56
    def assert_dependencies(self, expected_debs, expected_repository, backend):
 
57
        """Ensure the given backend includes the expected dependencies."""
 
58
        obtained_debs, obtained_repository = backend.get_dependencies()
 
59
        self.assertEqual(set(expected_debs), obtained_debs)
 
60
        self.assertEqual(expected_repository, obtained_repository)
52
61
 
53
62
    def check_sandbox_mode(self):
54
63
        """The backend includes the correct mixins when sandbox mode is active.
55
64
        """
56
 
        test_backend = backend.Backend(config={
57
 
            'sandbox': True, 'staging': False, 'builtin-server': False})
58
 
        mixin_names = get_mixin_names(test_backend)
59
 
        self.assertEqual(
60
 
            ('SandboxMixin', 'GuiMixin', 'HaproxyApacheMixin'),
61
 
            mixin_names)
62
 
        self.assertEqual(
63
 
            frozenset(('apache2', 'curl', 'haproxy', 'openssl')),
64
 
            test_backend.debs)
 
65
        expected_mixins = (
 
66
            'SetUpMixin', 'SandboxMixin', 'GuiMixin', 'HaproxyApacheMixin')
 
67
        config = {
 
68
            'builtin-server': False,
 
69
            'repository-location': 'ppa:my/location',
 
70
            'sandbox': True,
 
71
            'staging': False,
 
72
        }
 
73
        test_backend = backend.Backend(config=config)
 
74
        self.assert_mixins(expected_mixins, test_backend)
 
75
        self.assert_dependencies(
 
76
            EXPECTED_PYTHON_LEGACY_DEBS, 'ppa:my/location', test_backend)
65
77
 
66
78
    def test_python_staging_backend(self):
67
 
        with self.simulate_pyjuju:
68
 
            test_backend = backend.Backend(config={
69
 
                'sandbox': False, 'staging': True, 'builtin-server': False})
70
 
            mixin_names = get_mixin_names(test_backend)
71
 
            self.assertEqual(
72
 
                ('ImprovMixin', 'GuiMixin', 'HaproxyApacheMixin'),
73
 
                mixin_names)
74
 
            debs = ('apache2', 'curl', 'haproxy', 'openssl', 'zookeeper')
75
 
            self.assertEqual(frozenset(debs), test_backend.debs)
 
79
        expected_mixins = (
 
80
            'SetUpMixin', 'ImprovMixin', 'GuiMixin', 'HaproxyApacheMixin')
 
81
        config = {
 
82
            'builtin-server': False,
 
83
            'repository-location': 'ppa:my/location',
 
84
            'sandbox': False,
 
85
            'staging': True,
 
86
        }
 
87
        with simulate_pyjuju:
 
88
            test_backend = backend.Backend(config=config)
 
89
            self.assert_mixins(expected_mixins, test_backend)
 
90
            self.assert_dependencies(
 
91
                EXPECTED_PYTHON_LEGACY_DEBS + ('zookeeper',),
 
92
                'ppa:my/location', test_backend)
76
93
 
77
94
    def test_go_staging_backend(self):
78
95
        config = {'sandbox': False, 'staging': True, 'builtin-server': False}
79
 
        with self.simulate_juju_core:
 
96
        with simulate_juju_core:
80
97
            with self.assertRaises(ValueError) as context_manager:
81
98
                backend.Backend(config=config)
82
99
        error = str(context_manager.exception)
83
100
        self.assertEqual('Unable to use staging with go backend', error)
84
101
 
85
102
    def test_python_sandbox_backend(self):
86
 
        with self.simulate_pyjuju:
 
103
        with simulate_pyjuju:
87
104
            self.check_sandbox_mode()
88
105
 
89
106
    def test_go_sandbox_backend(self):
90
 
        with self.simulate_juju_core:
 
107
        with simulate_juju_core:
91
108
            self.check_sandbox_mode()
92
109
 
93
110
    def test_python_backend(self):
94
 
        with self.simulate_pyjuju:
95
 
            test_backend = backend.Backend(config={
96
 
                'sandbox': False, 'staging': False, 'builtin-server': False})
97
 
            mixin_names = get_mixin_names(test_backend)
98
 
            self.assertEqual(
99
 
                ('PythonMixin', 'GuiMixin', 'HaproxyApacheMixin'),
100
 
                mixin_names)
101
 
            self.assertEqual(
102
 
                frozenset(('apache2', 'curl', 'haproxy', 'openssl')),
103
 
                test_backend.debs)
 
111
        expected_mixins = (
 
112
            'SetUpMixin', 'PythonMixin', 'GuiMixin', 'HaproxyApacheMixin')
 
113
        config = {
 
114
            'builtin-server': False,
 
115
            'repository-location': 'ppa:my/location',
 
116
            'sandbox': False,
 
117
            'staging': False,
 
118
        }
 
119
        with simulate_pyjuju:
 
120
            test_backend = backend.Backend(config=config)
 
121
            self.assert_mixins(expected_mixins, test_backend)
 
122
            self.assert_dependencies(
 
123
                EXPECTED_PYTHON_LEGACY_DEBS, 'ppa:my/location', test_backend)
104
124
 
105
125
    def test_go_backend(self):
106
 
        with self.simulate_juju_core:
107
 
            test_backend = backend.Backend(config={
108
 
                'sandbox': False, 'staging': False, 'builtin-server': False})
109
 
            mixin_names = get_mixin_names(test_backend)
110
 
            self.assertEqual(
111
 
                ('GoMixin', 'GuiMixin', 'HaproxyApacheMixin'),
112
 
                mixin_names)
113
 
            self.assertEqual(
114
 
                frozenset(
115
 
                    ('apache2', 'curl', 'haproxy', 'openssl', 'python-yaml')),
116
 
                test_backend.debs)
117
 
 
118
 
    def test_builtin_server(self):
119
 
        expected_mixins = ('GoMixin', 'GuiMixin', 'BuiltinServerMixin')
120
 
        expected_debs = set([
121
 
            'python-pip', 'python-yaml', 'curl', 'openssl', 'python-bzrlib'])
122
 
        with self.simulate_juju_core:
123
 
            test_backend = backend.Backend(config={
124
 
                'sandbox': False, 'staging': False, 'builtin-server': True})
125
 
            mixin_names = get_mixin_names(test_backend)
126
 
            self.assertEqual(expected_mixins, mixin_names)
127
 
            self.assertEqual(expected_debs, test_backend.debs)
 
126
        expected_mixins = (
 
127
            'SetUpMixin', 'GoMixin', 'GuiMixin', 'HaproxyApacheMixin')
 
128
        config = {
 
129
            'builtin-server': False,
 
130
            'repository-location': 'ppa:my/location',
 
131
            'sandbox': False,
 
132
            'staging': False,
 
133
        }
 
134
        with simulate_juju_core:
 
135
            test_backend = backend.Backend(config=config)
 
136
            self.assert_mixins(expected_mixins, test_backend)
 
137
            self.assert_dependencies(
 
138
                EXPECTED_GO_LEGACY_DEBS, 'ppa:my/location', test_backend)
 
139
 
 
140
    def test_go_builtin_server(self):
 
141
        config = {
 
142
            'builtin-server': True,
 
143
            'repository-location': 'ppa:my/location',
 
144
            'sandbox': False,
 
145
            'staging': False,
 
146
        }
 
147
        expected_mixins = (
 
148
            'SetUpMixin', 'GoMixin', 'GuiMixin', 'BuiltinServerMixin')
 
149
        with simulate_juju_core:
 
150
            test_backend = backend.Backend(config)
 
151
            self.assert_mixins(expected_mixins, test_backend)
 
152
            self.assert_dependencies(
 
153
                EXPECTED_GO_BUILTIN_DEBS, None, test_backend)
 
154
 
 
155
    def test_python_builtin_server(self):
 
156
        config = {
 
157
            'builtin-server': True,
 
158
            'repository-location': 'ppa:my/location',
 
159
            'sandbox': False,
 
160
            'staging': False,
 
161
        }
 
162
        expected_mixins = (
 
163
            'SetUpMixin', 'PythonMixin', 'GuiMixin', 'BuiltinServerMixin')
 
164
        with simulate_pyjuju:
 
165
            test_backend = backend.Backend(config)
 
166
            self.assert_mixins(expected_mixins, test_backend)
 
167
            self.assert_dependencies(
 
168
                EXPECTED_PYTHON_BUILTIN_DEBS, None, test_backend)
 
169
 
 
170
    def test_sandbox_builtin_server(self):
 
171
        config = {
 
172
            'builtin-server': True,
 
173
            'repository-location': 'ppa:my/location',
 
174
            'sandbox': True,
 
175
            'staging': False,
 
176
        }
 
177
        expected_mixins = (
 
178
            'SetUpMixin', 'SandboxMixin', 'GuiMixin', 'BuiltinServerMixin')
 
179
        with simulate_juju_core:
 
180
            test_backend = backend.Backend(config)
 
181
            self.assert_mixins(expected_mixins, test_backend)
 
182
            self.assert_dependencies(
 
183
                EXPECTED_PYTHON_BUILTIN_DEBS, None, test_backend)
128
184
 
129
185
 
130
186
class TestBackendCommands(unittest.TestCase):
131
187
 
132
188
    def setUp(self):
133
 
        self.called = {}
134
 
        self.alwaysFalse = GotEmAllDict(lambda: False)
135
 
        self.alwaysTrue = GotEmAllDict(lambda: True)
136
 
 
137
 
        # Monkeypatch functions.
138
 
        self.utils_mocks = {
139
 
            'compute_build_dir': utils.compute_build_dir,
140
 
            'fetch_api': utils.fetch_api,
141
 
            'fetch_gui_from_branch': utils.fetch_gui_from_branch,
142
 
            'fetch_gui_release': utils.fetch_gui_release,
143
 
            'find_missing_packages': utils.find_missing_packages,
144
 
            'get_api_address': utils.get_api_address,
145
 
            'get_npm_cache_archive_url': utils.get_npm_cache_archive_url,
146
 
            'install_builtin_server': utils.install_builtin_server,
147
 
            'parse_source': utils.parse_source,
148
 
            'prime_npm_cache': utils.prime_npm_cache,
149
 
            'remove_apache_setup': utils.remove_apache_setup,
150
 
            'remove_haproxy_setup': utils.remove_haproxy_setup,
151
 
            'save_or_create_certificates': utils.save_or_create_certificates,
152
 
            'setup_apache_config': utils.setup_apache_config,
153
 
            'setup_gui': utils.setup_gui,
154
 
            'setup_haproxy_config': utils.setup_haproxy_config,
155
 
            'start_agent': utils.start_agent,
156
 
            'start_improv': utils.start_improv,
157
 
            'write_builtin_server_startup': utils.write_builtin_server_startup,
158
 
            'write_gui_config': utils.write_gui_config,
159
 
        }
160
 
        self.charmhelpers_mocks = {
161
 
            'log': charmhelpers.log,
162
 
            'open_port': charmhelpers.open_port,
163
 
            'service_control': charmhelpers.service_control,
164
 
        }
165
 
 
166
 
        def make_mock_function(name):
167
 
            def mock_function(*args, **kwargs):
168
 
                self.called[name] = True
169
 
                return (None, None)
170
 
            mock_function.__name__ = name
171
 
            return mock_function
172
 
 
173
 
        for name in self.utils_mocks.keys():
174
 
            setattr(utils, name, make_mock_function(name))
175
 
        for name in self.charmhelpers_mocks.keys():
176
 
            setattr(charmhelpers, name, make_mock_function(name))
177
 
 
178
 
        @contextmanager
179
 
        def mock_su(user):
180
 
            self.called['su'] = True
181
 
            yield
182
 
        self.orig_su = utils.su
183
 
        utils.su = mock_su
184
 
 
185
 
        def mock_apt_get_install(*debs):
186
 
            self.called['apt_get_install'] = True
187
 
        self.orig_apt_get_install = shelltoolbox.apt_get_install
188
 
        shelltoolbox.apt_get_install = mock_apt_get_install
189
 
 
190
 
        def mock_run(*debs):
191
 
            self.called['run'] = True
192
 
        self.orig_run = shelltoolbox.run
193
 
        shelltoolbox.run = mock_run
194
 
 
195
 
        # Monkeypatch directories.
196
 
        self.orig_juju_dir = utils.JUJU_DIR
197
 
        self.temp_dir = tempfile.mkdtemp()
198
 
        utils.JUJU_DIR = self.temp_dir
199
 
 
200
 
    def tearDown(self):
201
 
        # Cleanup directories.
202
 
        utils.JUJU_DIR = self.orig_juju_dir
203
 
        shutil.rmtree(self.temp_dir)
204
 
        # Undo the monkeypatching.
205
 
        shelltoolbox.run = self.orig_run
206
 
        shelltoolbox.apt_get_install = self.orig_apt_get_install
207
 
        utils.su = self.orig_su
208
 
        for name, orig_fun in self.charmhelpers_mocks.items():
209
 
            setattr(charmhelpers, name, orig_fun)
210
 
        for name, orig_fun in self.utils_mocks.items():
211
 
            setattr(utils, name, orig_fun)
212
 
 
213
 
    def test_install_python(self):
214
 
        test_backend = backend.Backend(config=self.alwaysFalse)
215
 
        test_backend.install()
216
 
        for mocked in (
217
 
            'apt_get_install', 'fetch_api', 'find_missing_packages',
218
 
        ):
219
 
            self.assertTrue(
220
 
                self.called.get(mocked), '{} was not called'.format(mocked))
221
 
 
222
 
    def test_install_improv_builtin(self):
223
 
        test_backend = backend.Backend(config=self.alwaysTrue)
224
 
        test_backend.install()
225
 
        for mocked in (
226
 
            'apt_get_install', 'fetch_api', 'find_missing_packages',
227
 
            'install_builtin_server',
228
 
        ):
229
 
            self.assertTrue(
230
 
                self.called.get(mocked), '{} was not called'.format(mocked))
231
 
 
232
 
    def test_start_agent(self):
233
 
        test_backend = backend.Backend(config=self.alwaysFalse)
234
 
        test_backend.start()
235
 
        for mocked in (
236
 
            'compute_build_dir', 'open_port', 'setup_apache_config',
237
 
            'setup_haproxy_config', 'start_agent', 'su', 'write_gui_config',
238
 
        ):
239
 
            self.assertTrue(
240
 
                self.called.get(mocked), '{} was not called'.format(mocked))
241
 
 
242
 
    def test_start_improv_builtin(self):
243
 
        test_backend = backend.Backend(config=self.alwaysTrue)
244
 
        test_backend.start()
245
 
        for mocked in (
246
 
            'compute_build_dir', 'open_port', 'start_improv', 'su',
247
 
            'write_builtin_server_startup', 'write_gui_config',
248
 
        ):
249
 
            self.assertTrue(
250
 
                self.called.get(mocked), '{} was not called'.format(mocked))
251
 
 
252
 
    def test_stop(self):
253
 
        test_backend = backend.Backend(config=self.alwaysFalse)
254
 
        test_backend.stop()
255
 
        self.assertTrue(self.called.get('su'), 'su was not called')
 
189
        # Set up directories.
 
190
        self.playground = tempfile.mkdtemp()
 
191
        self.addCleanup(shutil.rmtree, self.playground)
 
192
        self.base_dir = os.path.join(self.playground, 'juju-gui')
 
193
        self.command_log_file = os.path.join(self.playground, 'logs')
 
194
        self.juju_agent_dir = os.path.join(self.playground, 'juju-agent-dir')
 
195
        self.ssl_cert_path = os.path.join(self.playground, 'ssl-cert-path')
 
196
        # Set up default values.
 
197
        self.juju_api_branch = 'lp:juju-api'
 
198
        self.juju_gui_source = 'stable'
 
199
        self.repository_location = 'ppa:my/location'
 
200
        self.parse_source_return_value = ('stable', None)
 
201
 
 
202
    def make_config(self, options=None):
 
203
        """Create and return a backend configuration dict."""
 
204
        config = {
 
205
            'builtin-server': True,
 
206
            'builtin-server-logging': 'info',
 
207
            'charmworld-url': 'http://charmworld.example.com',
 
208
            'command-log-file': self.command_log_file,
 
209
            'default-viewmode': 'sidebar',
 
210
            'ga-key': 'my-key',
 
211
            'juju-api-branch': self.juju_api_branch,
 
212
            'juju-gui-debug': False,
 
213
            'juju-gui-console-enabled': False,
 
214
            'juju-gui-source': self.juju_gui_source,
 
215
            'login-help': 'login-help',
 
216
            'read-only': False,
 
217
            'repository-location': self.repository_location,
 
218
            'sandbox': False,
 
219
            'secure': True,
 
220
            'serve-tests': False,
 
221
            'show-get-juju-button': False,
 
222
            'ssl-cert-path': self.ssl_cert_path,
 
223
            'staging': False,
 
224
        }
 
225
        if options is not None:
 
226
            config.update(options)
 
227
        return config
 
228
 
 
229
    @contextmanager
 
230
    def mock_all(self):
 
231
        """Mock all the extrenal functions used by the backend framework."""
 
232
        mock_parse_source = mock.Mock(
 
233
            return_value=self.parse_source_return_value)
 
234
        mocks = {
 
235
            'base_dir': mock.patch('backend.utils.BASE_DIR', self.base_dir),
 
236
            'compute_build_dir': mock.patch('backend.utils.compute_build_dir'),
 
237
            'fetch_api': mock.patch('backend.utils.fetch_api'),
 
238
            'fetch_gui_from_branch': mock.patch(
 
239
                'backend.utils.fetch_gui_from_branch'),
 
240
            'fetch_gui_release': mock.patch('backend.utils.fetch_gui_release'),
 
241
            'install_builtin_server': mock.patch(
 
242
                'backend.utils.install_builtin_server'),
 
243
            'install_missing_packages': mock.patch(
 
244
                'backend.utils.install_missing_packages'),
 
245
            'juju_agent_dir': mock.patch(
 
246
                'backend.utils.JUJU_AGENT_DIR', self.juju_agent_dir),
 
247
            'log': mock.patch('backend.log'),
 
248
            'open_port': mock.patch('backend.open_port'),
 
249
            'parse_source': mock.patch(
 
250
                'backend.utils.parse_source', mock_parse_source),
 
251
            'save_or_create_certificates': mock.patch(
 
252
                'backend.utils.save_or_create_certificates'),
 
253
            'setup_gui': mock.patch('backend.utils.setup_gui'),
 
254
            'start_agent': mock.patch('backend.utils.start_agent'),
 
255
            'start_builtin_server': mock.patch(
 
256
                'backend.utils.start_builtin_server'),
 
257
            'start_haproxy_apache': mock.patch(
 
258
                'backend.utils.start_haproxy_apache'),
 
259
            'stop_agent': mock.patch('backend.utils.stop_agent'),
 
260
            'stop_builtin_server': mock.patch(
 
261
                'backend.utils.stop_builtin_server'),
 
262
            'stop_haproxy_apache': mock.patch(
 
263
                'backend.utils.stop_haproxy_apache'),
 
264
            'write_gui_config': mock.patch('backend.utils.write_gui_config'),
 
265
        }
 
266
        # Note: nested is deprecated for good reasons which do not apply here.
 
267
        # Used here to easily nest a dynamically generated list of context
 
268
        # managers.
 
269
        with nested(*mocks.values()) as context_managers:
 
270
            object_dict = dict(zip(mocks.keys(), context_managers))
 
271
            yield type('Mocks', (object,), object_dict)
 
272
 
 
273
    def assert_write_gui_config_called(self, mocks, config):
 
274
        """Ensure the mocked write_gui_config has been properly called."""
 
275
        mocks.write_gui_config.assert_called_once_with(
 
276
            config['juju-gui-console-enabled'], config['login-help'],
 
277
            config['read-only'], config['staging'], config['charmworld-url'],
 
278
            mocks.compute_build_dir(), secure=config['secure'],
 
279
            sandbox=config['sandbox'], ga_key=config['ga-key'],
 
280
            default_viewmode=config['default-viewmode'],
 
281
            show_get_juju_button=config['show-get-juju-button'], password=None)
 
282
 
 
283
    def test_base_dir_created(self):
 
284
        # The base Juju GUI directory is correctly created.
 
285
        config = self.make_config()
 
286
        test_backend = backend.Backend(config=config)
 
287
        with self.mock_all():
 
288
            test_backend.install()
 
289
        self.assertTrue(os.path.isdir(self.base_dir))
 
290
 
 
291
    def test_base_dir_removed(self):
 
292
        # The base Juju GUI directory is correctly removed.
 
293
        config = self.make_config()
 
294
        test_backend = backend.Backend(config=config)
 
295
        with self.mock_all():
 
296
            test_backend.install()
 
297
            test_backend.destroy()
 
298
        self.assertFalse(os.path.exists(utils.BASE_DIR), utils.BASE_DIR)
 
299
 
 
300
    def test_install_python_legacy_stable(self):
 
301
        # Install a pyJuju backend with legacy server and stable release.
 
302
        config = self.make_config({'builtin-server': False})
 
303
        with simulate_pyjuju:
 
304
            test_backend = backend.Backend(config=config)
 
305
            with self.mock_all() as mocks:
 
306
                test_backend.install()
 
307
        mocks.install_missing_packages.assert_called_once_with(
 
308
            set(EXPECTED_PYTHON_LEGACY_DEBS),
 
309
            repository=self.repository_location)
 
310
        mocks.fetch_api.assert_called_once_with(self.juju_api_branch)
 
311
        mocks.parse_source.assert_called_once_with(self.juju_gui_source)
 
312
        mocks.fetch_gui_release.assert_called_once_with(
 
313
            *self.parse_source_return_value)
 
314
        self.assertFalse(mocks.fetch_gui_from_branch.called)
 
315
        mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_release())
 
316
        self.assertFalse(mocks.install_builtin_server.called)
 
317
 
 
318
    def test_install_go_legacy_stable(self):
 
319
        # Install a juju-core backend with legacy server and stable release.
 
320
        config = self.make_config({'builtin-server': False})
 
321
        with simulate_juju_core:
 
322
            test_backend = backend.Backend(config=config)
 
323
            with self.mock_all() as mocks:
 
324
                test_backend.install()
 
325
        mocks.install_missing_packages.assert_called_once_with(
 
326
            set(EXPECTED_GO_LEGACY_DEBS), repository=self.repository_location)
 
327
        self.assertFalse(mocks.fetch_api.called)
 
328
        mocks.parse_source.assert_called_once_with(self.juju_gui_source)
 
329
        mocks.fetch_gui_release.assert_called_once_with(
 
330
            *self.parse_source_return_value)
 
331
        self.assertFalse(mocks.fetch_gui_from_branch.called)
 
332
        mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_release())
 
333
        self.assertFalse(mocks.install_builtin_server.called)
 
334
 
 
335
    def test_install_python_builtin_stable(self):
 
336
        # Install a pyJuju backend with builtin server and stable release.
 
337
        config = self.make_config({'builtin-server': True})
 
338
        with simulate_pyjuju:
 
339
            test_backend = backend.Backend(config=config)
 
340
            with self.mock_all() as mocks:
 
341
                test_backend.install()
 
342
        mocks.install_missing_packages.assert_called_once_with(
 
343
            set(EXPECTED_PYTHON_BUILTIN_DEBS), repository=None)
 
344
        mocks.fetch_api.assert_called_once_with(self.juju_api_branch)
 
345
        mocks.parse_source.assert_called_once_with(self.juju_gui_source)
 
346
        mocks.fetch_gui_release.assert_called_once_with(
 
347
            *self.parse_source_return_value)
 
348
        self.assertFalse(mocks.fetch_gui_from_branch.called)
 
349
        mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_release())
 
350
        mocks.install_builtin_server.assert_called_once_with()
 
351
 
 
352
    def test_install_go_builtin_stable(self):
 
353
        # Install a juju-core backend with builtin server and stable release.
 
354
        config = self.make_config({'builtin-server': True})
 
355
        with simulate_juju_core:
 
356
            test_backend = backend.Backend(config=config)
 
357
            with self.mock_all() as mocks:
 
358
                test_backend.install()
 
359
        mocks.install_missing_packages.assert_called_once_with(
 
360
            set(EXPECTED_GO_BUILTIN_DEBS), repository=None)
 
361
        self.assertFalse(mocks.fetch_api.called)
 
362
        mocks.parse_source.assert_called_once_with(self.juju_gui_source)
 
363
        mocks.fetch_gui_release.assert_called_once_with(
 
364
            *self.parse_source_return_value)
 
365
        self.assertFalse(mocks.fetch_gui_from_branch.called)
 
366
        mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_release())
 
367
        mocks.install_builtin_server.assert_called_once_with()
 
368
 
 
369
    def test_install_go_builtin_branch(self):
 
370
        # Install a juju-core backend with builtin server and branch release.
 
371
        self.parse_source_return_value = ('branch', ('lp:juju-gui', 42))
 
372
        expected_calls = [
 
373
            mock.call(set(EXPECTED_GO_BUILTIN_DEBS), repository=None),
 
374
            mock.call(
 
375
                utils.DEB_BUILD_DEPENDENCIES,
 
376
                repository=self.repository_location,
 
377
            ),
 
378
        ]
 
379
        config = self.make_config({'builtin-server': True})
 
380
        with simulate_juju_core:
 
381
            test_backend = backend.Backend(config=config)
 
382
            with self.mock_all() as mocks:
 
383
                test_backend.install()
 
384
        mocks.install_missing_packages.assert_has_calls(expected_calls)
 
385
        self.assertFalse(mocks.fetch_api.called)
 
386
        mocks.parse_source.assert_called_once_with(self.juju_gui_source)
 
387
        mocks.fetch_gui_from_branch.assert_called_once_with(
 
388
            'lp:juju-gui', 42, self.command_log_file)
 
389
        self.assertFalse(mocks.fetch_gui_release.called)
 
390
        mocks.setup_gui.assert_called_once_with(mocks.fetch_gui_from_branch())
 
391
        mocks.install_builtin_server.assert_called_once_with()
 
392
 
 
393
    def test_start_python_legacy(self):
 
394
        # Start a pyJuju backend with legacy server.
 
395
        config = self.make_config({'builtin-server': False})
 
396
        with simulate_pyjuju:
 
397
            test_backend = backend.Backend(config=config)
 
398
            with self.mock_all() as mocks:
 
399
                test_backend.start()
 
400
        mocks.start_agent.assert_called_once_with(self.ssl_cert_path)
 
401
        mocks.compute_build_dir.assert_called_with(
 
402
            config['juju-gui-debug'], config['serve-tests'])
 
403
        self.assert_write_gui_config_called(mocks, config)
 
404
        mocks.open_port.assert_has_calls([mock.call(80), mock.call(443)])
 
405
        mocks.start_haproxy_apache.assert_called_once_with(
 
406
            mocks.compute_build_dir(), config['serve-tests'],
 
407
            self.ssl_cert_path, config['secure'])
 
408
        self.assertFalse(mocks.start_builtin_server.called)
 
409
 
 
410
    def test_start_go_legacy(self):
 
411
        # Start a juju-core backend with legacy server.
 
412
        config = self.make_config({'builtin-server': False})
 
413
        with simulate_juju_core:
 
414
            test_backend = backend.Backend(config=config)
 
415
            with self.mock_all() as mocks:
 
416
                test_backend.start()
 
417
        self.assertFalse(mocks.start_agent.called)
 
418
        mocks.compute_build_dir.assert_called_with(
 
419
            config['juju-gui-debug'], config['serve-tests'])
 
420
        self.assert_write_gui_config_called(mocks, config)
 
421
        mocks.open_port.assert_has_calls([mock.call(80), mock.call(443)])
 
422
        mocks.start_haproxy_apache.assert_called_once_with(
 
423
            mocks.compute_build_dir(), config['serve-tests'],
 
424
            self.ssl_cert_path, config['secure'])
 
425
        self.assertFalse(mocks.start_builtin_server.called)
 
426
 
 
427
    def test_start_python_builtin(self):
 
428
        # Start a pyJuju backend with builtin server.
 
429
        config = self.make_config({'builtin-server': True})
 
430
        with simulate_pyjuju:
 
431
            test_backend = backend.Backend(config=config)
 
432
            with self.mock_all() as mocks:
 
433
                test_backend.start()
 
434
        mocks.start_agent.assert_called_once_with(self.ssl_cert_path)
 
435
        mocks.compute_build_dir.assert_called_with(
 
436
            config['juju-gui-debug'], config['serve-tests'])
 
437
        self.assert_write_gui_config_called(mocks, config)
 
438
        mocks.open_port.assert_has_calls([mock.call(80), mock.call(443)])
 
439
        mocks.start_builtin_server.assert_called_once_with(
 
440
            mocks.compute_build_dir(), self.ssl_cert_path,
 
441
            config['serve-tests'], config['sandbox'],
 
442
            config['builtin-server-logging'], not config['secure'])
 
443
        self.assertFalse(mocks.start_haproxy_apache.called)
 
444
 
 
445
    def test_start_go_builtin(self):
 
446
        # Start a juju-core backend with builtin server.
 
447
        config = self.make_config({'builtin-server': True})
 
448
        with simulate_juju_core:
 
449
            test_backend = backend.Backend(config=config)
 
450
            with self.mock_all() as mocks:
 
451
                test_backend.start()
 
452
        self.assertFalse(mocks.start_agent.called)
 
453
        mocks.compute_build_dir.assert_called_with(
 
454
            config['juju-gui-debug'], config['serve-tests'])
 
455
        self.assert_write_gui_config_called(mocks, config)
 
456
        mocks.open_port.assert_has_calls([mock.call(80), mock.call(443)])
 
457
        mocks.start_builtin_server.assert_called_once_with(
 
458
            mocks.compute_build_dir(), self.ssl_cert_path,
 
459
            config['serve-tests'], config['sandbox'],
 
460
            config['builtin-server-logging'], not config['secure'])
 
461
        self.assertFalse(mocks.start_haproxy_apache.called)
 
462
 
 
463
    def test_stop_python_legacy(self):
 
464
        # Stop a pyJuju backend with legacy server.
 
465
        config = self.make_config({'builtin-server': False})
 
466
        with simulate_pyjuju:
 
467
            test_backend = backend.Backend(config=config)
 
468
            with self.mock_all() as mocks:
 
469
                test_backend.stop()
 
470
        mocks.stop_agent.assert_called_once_with()
 
471
        mocks.stop_haproxy_apache.assert_called_once_with()
 
472
        self.assertFalse(mocks.stop_builtin_server.called)
 
473
 
 
474
    def test_stop_go_legacy(self):
 
475
        # Stop a juju-core backend with legacy server.
 
476
        config = self.make_config({'builtin-server': False})
 
477
        with simulate_juju_core:
 
478
            test_backend = backend.Backend(config=config)
 
479
            with self.mock_all() as mocks:
 
480
                test_backend.stop()
 
481
        self.assertFalse(mocks.stop_agent.called)
 
482
        mocks.stop_haproxy_apache.assert_called_once_with()
 
483
        self.assertFalse(mocks.stop_builtin_server.called)
 
484
 
 
485
    def test_stop_python_builtin(self):
 
486
        # Stop a pyJuju backend with builtin server.
 
487
        config = self.make_config({'builtin-server': True})
 
488
        with simulate_pyjuju:
 
489
            test_backend = backend.Backend(config=config)
 
490
            with self.mock_all() as mocks:
 
491
                test_backend.stop()
 
492
        mocks.stop_agent.assert_called_once_with()
 
493
        mocks.stop_builtin_server.assert_called_once_with()
 
494
        self.assertFalse(mocks.stop_haproxy_apache.called)
 
495
 
 
496
    def test_stop_go_builtin(self):
 
497
        # Stop a juju-core backend with builtin server.
 
498
        config = self.make_config({'builtin-server': True})
 
499
        with simulate_juju_core:
 
500
            test_backend = backend.Backend(config=config)
 
501
            with self.mock_all() as mocks:
 
502
                test_backend.stop()
 
503
        self.assertFalse(mocks.stop_agent.called)
 
504
        mocks.stop_builtin_server.assert_called_once_with()
 
505
        self.assertFalse(mocks.stop_haproxy_apache.called)
256
506
 
257
507
 
258
508
class TestBackendUtils(unittest.TestCase):
276
526
        )
277
527
        self.assertTrue(test_backend.different('sandbox'))
278
528
        self.assertFalse(test_backend.different('staging'))
 
529
 
 
530
 
 
531
class TestCallMethods(unittest.TestCase):
 
532
 
 
533
    def setUp(self):
 
534
        self.called = []
 
535
        self.objects = [self.make_object('Obj1'), self.make_object('Obj2')]
 
536
 
 
537
    def make_object(self, name, has_method=True):
 
538
        """Create and return an test object with the given name."""
 
539
        def method(obj, *args):
 
540
            self.called.append([obj.__class__.__name__, args])
 
541
        object_dict = {'method': method} if has_method else {}
 
542
        return type(name, (object,), object_dict)()
 
543
 
 
544
    def test_call(self):
 
545
        # The methods are correctly called.
 
546
        backend.call_methods(self.objects, 'method', 'arg1', 'arg2')
 
547
        expected = [['Obj1', ('arg1', 'arg2')], ['Obj2', ('arg1', 'arg2')]]
 
548
        self.assertEqual(expected, self.called)
 
549
 
 
550
    def test_no_method(self):
 
551
        # An object without the method is ignored.
 
552
        self.objects.append(self.make_object('Obj3', has_method=False))
 
553
        backend.call_methods(self.objects, 'method')
 
554
        expected = [['Obj1', ()], ['Obj2', ()]]
 
555
        self.assertEqual(expected, self.called)