~joeborg/charm-helpers/apache-config

« back to all changes in this revision

Viewing changes to tests/contrib/openstack/test_openstack_utils.py

  • Committer: james.page at ubuntu
  • Date: 2017-05-25 13:46:14 UTC
  • mfrom: (618.3.25 charm-helpers)
  • Revision ID: james.page@ubuntu.com-20170525134614-nq74bhih9e9iquw2
[tinwood,r=*] Support for Ubuntu ports and refactoring of OpenStack utils to have a single source of truth for 'source' configuration options.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
import io
2
2
import os
3
 
import subprocess
4
 
import tempfile
5
3
import contextlib
6
4
import unittest
7
5
from copy import copy
 
6
from tests.helpers import patch_open
8
7
from testtools import TestCase
9
8
from mock import MagicMock, patch, call
10
9
 
 
10
from charmhelpers.fetch import ubuntu as fetch
11
11
import charmhelpers.contrib.openstack.utils as openstack
12
12
 
13
13
import six
123
123
 
124
124
# Mock python-dnspython resolver used by get_host_ip()
125
125
 
126
 
PGP_KEY_ASCII_ARMOR = """-----BEGIN PGP PUBLIC KEY BLOCK-----
127
 
Version: SKS 1.1.5
128
 
Comment: Hostname: keyserver.ubuntu.com
129
 
 
130
 
mI0EUCEyTAEEAMuUxyfiegCCwn4J/c0nw5PUTSJdn5FqiUTq6iMfij65xf1vl0g/Mxqw0gfg
131
 
AJIsCDvO9N9dloLAwF6FUBMg5My7WyhRPTAKF505TKJboyX3Pp4J1fU1LV8QFVOp87vUh1Rz
132
 
B6GU7cSglhnbL85gmbJTllkzkb3h4Yw7W+edjcQ/ABEBAAG0K0xhdW5jaHBhZCBQUEEgZm9y
133
 
IFVidW50dSBDbG91ZCBBcmNoaXZlIFRlYW2IuAQTAQIAIgUCUCEyTAIbAwYLCQgHAwIGFQgC
134
 
CQoLBBYCAwECHgECF4AACgkQimhEop9oEE7kJAP/eTBgq3Mhbvo0d8elMOuqZx3nmU7gSyPh
135
 
ep0zYIRZ5TJWl/7PRtvp0CJA6N6ZywYTQ/4ANHhpibcHZkh8K0AzUvsGXnJRSFoJeqyDbD91
136
 
EhoO+4ZfHs2HvRBQEDZILMa2OyuB497E5Mmyua3HDEOrG2cVLllsUZzpTFCx8NgeMHk=
137
 
=jLBm
138
 
-----END PGP PUBLIC KEY BLOCK-----
139
 
"""
140
 
 
141
126
 
142
127
class FakeAnswer(object):
 
128
 
143
129
    def __init__(self, ip):
144
130
        self.ip = ip
145
131
 
148
134
 
149
135
 
150
136
class FakeResolver(object):
 
137
 
151
138
    def __init__(self, ip):
152
139
        self.ip = ip
153
140
 
159
146
 
160
147
 
161
148
class FakeReverse(object):
 
149
 
162
150
    def from_address(self, address):
163
151
        return '156.94.189.91.in-addr.arpa'
164
152
 
165
153
 
166
154
class FakeDNSName(object):
 
155
 
167
156
    def __init__(self, dnsname):
168
157
        pass
169
158
 
170
159
 
171
160
class FakeDNS(object):
 
161
 
172
162
    def __init__(self, ip):
173
163
        self.resolver = FakeResolver(ip)
174
164
        self.reversename = FakeReverse()
177
167
 
178
168
 
179
169
class OpenStackHelpersTestCase(TestCase):
 
170
 
180
171
    def _apt_cache(self):
181
172
        # mocks out the apt cache
182
173
        def cache_get(package):
197
188
 
198
189
    @patch('charmhelpers.contrib.openstack.utils.lsb_release')
199
190
    def test_os_codename_from_install_source(self, mocked_lsb):
200
 
        '''Test mapping install source to OpenStack release name'''
 
191
        """Test mapping install source to OpenStack release name"""
201
192
        mocked_lsb.return_value = FAKE_RELEASE
202
193
 
203
194
        # the openstack release shipped with respective ubuntu/lsb release.
236
227
 
237
228
    @patch('charmhelpers.contrib.openstack.utils.lsb_release')
238
229
    def test_os_codename_from_bad_install_source(self, mocked_lsb):
239
 
        '''Test mapping install source to OpenStack release name'''
 
230
        """Test mapping install source to OpenStack release name"""
240
231
        _fake_release = copy(FAKE_RELEASE)
241
232
        _fake_release['DISTRIB_CODENAME'] = 'natty'
242
233
 
249
240
            mocked_err.assert_called_with(_er)
250
241
 
251
242
    def test_os_codename_from_version(self):
252
 
        '''Test mapping OpenStack numerical versions to code name'''
 
243
        """Test mapping OpenStack numerical versions to code name"""
253
244
        self.assertEquals(openstack.get_os_codename_version('2013.1'),
254
245
                          'grizzly')
255
246
 
256
247
    @patch('charmhelpers.contrib.openstack.utils.error_out')
257
248
    def test_os_codename_from_bad_version(self, mocked_error):
258
 
        '''Test mapping a bad OpenStack numerical versions to code name'''
 
249
        """Test mapping a bad OpenStack numerical versions to code name"""
259
250
        openstack.get_os_codename_version('2014.5.5')
260
251
        expected_err = ('Could not determine OpenStack codename for '
261
252
                        'version 2014.5.5')
262
253
        mocked_error.assert_called_with(expected_err)
263
254
 
264
255
    def test_os_version_from_codename(self):
265
 
        '''Test mapping a OpenStack codename to numerical version'''
 
256
        """Test mapping a OpenStack codename to numerical version"""
266
257
        self.assertEquals(openstack.get_os_version_codename('folsom'),
267
258
                          '2012.2')
268
259
 
269
260
    @patch('charmhelpers.contrib.openstack.utils.error_out')
270
261
    def test_os_version_from_bad_codename(self, mocked_error):
271
 
        '''Test mapping a bad OpenStack codename to numerical version'''
 
262
        """Test mapping a bad OpenStack codename to numerical version"""
272
263
        openstack.get_os_version_codename('foo')
273
264
        expected_err = 'Could not derive OpenStack version for codename: foo'
274
265
        mocked_error.assert_called_with(expected_err)
275
266
 
276
267
    def test_os_version_swift_from_codename(self):
277
 
        '''Test mapping a swift codename to numerical version'''
 
268
        """Test mapping a swift codename to numerical version"""
278
269
        self.assertEquals(openstack.get_os_version_codename_swift('liberty'),
279
270
                          '2.5.0')
280
271
 
283
274
 
284
275
    @patch('charmhelpers.contrib.openstack.utils.error_out')
285
276
    def test_os_version_swift_from_bad_codename(self, mocked_error):
286
 
        '''Test mapping a bad swift codename to numerical version'''
 
277
        """Test mapping a bad swift codename to numerical version"""
287
278
        openstack.get_os_version_codename_swift('foo')
288
279
        expected_err = 'Could not derive swift version for codename: foo'
289
280
        mocked_error.assert_called_with(expected_err)
302
293
        self.assertEquals(openstack.get_swift_codename('1.2.3'), None)
303
294
 
304
295
    def test_os_codename_from_package(self):
305
 
        '''Test deriving OpenStack codename from an installed package'''
 
296
        """Test deriving OpenStack codename from an installed package"""
306
297
        with patch('apt_pkg.Cache') as cache:
307
298
            cache.return_value = self._apt_cache()
308
299
            for pkg, vers in six.iteritems(FAKE_REPO):
316
307
 
317
308
    @patch('charmhelpers.contrib.openstack.utils.error_out')
318
309
    def test_os_codename_from_bad_package_version(self, mocked_error):
319
 
        '''Test deriving OpenStack codename for a poorly versioned package'''
 
310
        """Test deriving OpenStack codename for a poorly versioned package"""
320
311
        with patch('apt_pkg.Cache') as cache:
321
312
            cache.return_value = self._apt_cache()
322
313
            openstack.get_os_codename_package('bad-version')
325
316
 
326
317
    @patch('charmhelpers.contrib.openstack.utils.error_out')
327
318
    def test_os_codename_from_bad_package(self, mocked_error):
328
 
        '''Test deriving OpenStack codename from an unavailable package'''
 
319
        """Test deriving OpenStack codename from an unavailable package"""
329
320
        with patch('apt_pkg.Cache') as cache:
330
321
            cache.return_value = self._apt_cache()
331
322
            try:
339
330
            mocked_error.assert_called_with(e)
340
331
 
341
332
    def test_os_codename_from_bad_package_nonfatal(self):
342
 
        '''Test OpenStack codename from an unavailable package is non-fatal'''
 
333
        """Test OpenStack codename from an unavailable package is non-fatal"""
343
334
        with patch('apt_pkg.Cache') as cache:
344
335
            cache.return_value = self._apt_cache()
345
336
            self.assertEquals(
349
340
 
350
341
    @patch('charmhelpers.contrib.openstack.utils.error_out')
351
342
    def test_os_codename_from_uninstalled_package(self, mock_error):
352
 
        '''Test OpenStack codename from an available but uninstalled pkg'''
 
343
        """Test OpenStack codename from an available but uninstalled pkg"""
353
344
        with patch('apt_pkg.Cache') as cache:
354
345
            cache.return_value = self._apt_cache()
355
346
            try:
361
352
            mock_error.assert_called_with(e)
362
353
 
363
354
    def test_os_codename_from_uninstalled_package_nonfatal(self):
364
 
        '''Test OpenStack codename from avail uninstalled pkg is non fatal'''
 
355
        """Test OpenStack codename from avail uninstalled pkg is non fatal"""
365
356
        with patch('apt_pkg.Cache') as cache:
366
357
            cache.return_value = self._apt_cache()
367
358
            self.assertEquals(
371
362
 
372
363
    @patch('charmhelpers.contrib.openstack.utils.error_out')
373
364
    def test_os_version_from_package(self, mocked_error):
374
 
        '''Test deriving OpenStack version from an installed package'''
 
365
        """Test deriving OpenStack version from an installed package"""
375
366
        with patch('apt_pkg.Cache') as cache:
376
367
            cache.return_value = self._apt_cache()
377
368
            for pkg, vers in six.iteritems(FAKE_REPO):
384
375
 
385
376
    @patch('charmhelpers.contrib.openstack.utils.error_out')
386
377
    def test_os_version_from_bad_package(self, mocked_error):
387
 
        '''Test deriving OpenStack version from an uninstalled package'''
 
378
        """Test deriving OpenStack version from an uninstalled package"""
388
379
        with patch('apt_pkg.Cache') as cache:
389
380
            cache.return_value = self._apt_cache()
390
381
            try:
398
389
            mocked_error.assert_called_with(e)
399
390
 
400
391
    def test_os_version_from_bad_package_nonfatal(self):
401
 
        '''Test OpenStack version from an uninstalled package is non-fatal'''
 
392
        """Test OpenStack version from an uninstalled package is non-fatal"""
402
393
        with patch('apt_pkg.Cache') as cache:
403
394
            cache.return_value = self._apt_cache()
404
395
            self.assertEquals(
410
401
    @patch.object(openstack, 'git_os_codename_install_source')
411
402
    @patch('charmhelpers.contrib.openstack.utils.config')
412
403
    def test_os_release_uncached(self, config, git_cn, get_cn):
413
 
        openstack.os_rel = None
 
404
        openstack._os_rel = None
414
405
        get_cn.return_value = 'folsom'
415
406
        git_cn.return_value = None
416
407
 
420
411
        self.assertEquals('folsom', openstack.os_release('nova-common'))
421
412
 
422
413
    def test_os_release_cached(self):
423
 
        openstack.os_rel = 'foo'
 
414
        openstack._os_rel = 'foo'
424
415
        self.assertEquals('foo', openstack.os_release('nova-common'))
425
416
 
426
417
    @patch.object(openstack, 'juju_log')
427
418
    @patch('sys.exit')
428
419
    def test_error_out(self, mocked_exit, juju_log):
429
 
        '''Test erroring out'''
 
420
        """Test erroring out"""
430
421
        openstack.error_out('Everything broke.')
431
422
        _log = 'FATAL ERROR: Everything broke.'
432
423
        juju_log.assert_called_with(_log, level='ERROR')
433
424
        mocked_exit.assert_called_with(1)
434
425
 
 
426
    def test_get_source_and_pgp_key(self):
 
427
        tests = {
 
428
            "source|key": ('source', 'key'),
 
429
            "source|": ('source', None),
 
430
            "|key": ('', 'key'),
 
431
            "source": ('source', None),
 
432
        }
 
433
        for k, v in six.iteritems(tests):
 
434
            self.assertEqual(openstack.get_source_and_pgp_key(k), v)
 
435
 
 
436
    # These should still work, even though the bulk of the functionality has
 
437
    # moved to charmhelpers.fetch.add_source()
435
438
    def test_configure_install_source_distro(self):
436
 
        '''Test configuring installation from distro'''
 
439
        """Test configuring installation from distro"""
437
440
        self.assertIsNone(openstack.configure_installation_source('distro'))
438
441
 
439
442
    def test_configure_install_source_ppa(self):
440
 
        '''Test configuring installation source from PPA'''
 
443
        """Test configuring installation source from PPA"""
441
444
        with patch('subprocess.check_call') as mock:
442
445
            src = 'ppa:gandelman-a/openstack'
443
446
            openstack.configure_installation_source(src)
444
 
            ex_cmd = ['add-apt-repository', '-y', 'ppa:gandelman-a/openstack']
 
447
            ex_cmd = [
 
448
                'add-apt-repository', '--yes', 'ppa:gandelman-a/openstack']
445
449
            mock.assert_called_with(ex_cmd)
446
450
 
447
 
    @patch(builtin_open)
448
 
    @patch('charmhelpers.contrib.openstack.utils.juju_log')
449
 
    @patch('charmhelpers.contrib.openstack.utils.import_key')
450
 
    def test_configure_install_source_deb_url(self, _import, _log, _open):
451
 
        '''Test configuring installation source from deb repo url'''
452
 
        _file = MagicMock(spec=io.FileIO)
453
 
        _open.return_value = _file
 
451
    @patch('subprocess.check_call')
 
452
    @patch.object(fetch, 'import_key')
 
453
    def test_configure_install_source_deb_url(self, _import, _spcc):
 
454
        """Test configuring installation source from deb repo url"""
454
455
        src = ('deb http://ubuntu-cloud.archive.canonical.com/ubuntu '
455
456
               'precise-havana main|KEYID')
456
457
        openstack.configure_installation_source(src)
457
458
        _import.assert_called_with('KEYID')
458
 
        _file.__enter__().write.assert_called_with(src.split('|')[0])
459
 
        src = ('deb http://ubuntu-cloud.archive.canonical.com/ubuntu '
460
 
               'precise-havana main')
461
 
        openstack.configure_installation_source(src)
462
 
        _file.__enter__().write.assert_called_with(src)
 
459
        _spcc.assert_called_once_with(
 
460
            ['add-apt-repository', '--yes',
 
461
             'deb http://ubuntu-cloud.archive.canonical.com/ubuntu '
 
462
             'precise-havana main'])
463
463
 
464
 
    @patch('charmhelpers.contrib.openstack.utils.lsb_release')
 
464
    @patch.object(fetch, 'lsb_release')
465
465
    @patch(builtin_open)
466
 
    @patch('charmhelpers.contrib.openstack.utils.juju_log')
467
 
    def test_configure_install_source_distro_proposed(self, _log, _open, _lsb):
468
 
        '''Test configuring installation source from deb repo url'''
 
466
    @patch('subprocess.check_call')
 
467
    def test_configure_install_source_distro_proposed(
 
468
            self, _spcc, _open, _lsb):
 
469
        """Test configuring installation source from deb repo url"""
469
470
        _lsb.return_value = FAKE_RELEASE
470
471
        _file = MagicMock(spec=io.FileIO)
471
472
        _open.return_value = _file
472
473
        openstack.configure_installation_source('distro-proposed')
 
474
        _file.__enter__().write.assert_called_once_with(
 
475
            '# Proposed\ndeb http://archive.ubuntu.com/ubuntu '
 
476
            'precise-proposed main universe multiverse restricted\n')
473
477
        src = ('deb http://archive.ubuntu.com/ubuntu/ precise-proposed '
474
478
               'restricted main multiverse universe')
475
479
        openstack.configure_installation_source(src)
476
 
        _file.__enter__().write.assert_called_with(src)
 
480
        _spcc.assert_called_once_with(
 
481
            ['add-apt-repository', '--yes',
 
482
             'deb http://archive.ubuntu.com/ubuntu/ precise-proposed '
 
483
             'restricted main multiverse universe'])
 
484
 
 
485
    @patch('charmhelpers.fetch.filter_installed_packages')
 
486
    @patch('charmhelpers.fetch.apt_install')
 
487
    @patch.object(openstack, 'error_out')
 
488
    @patch.object(openstack, 'juju_log')
 
489
    def test_add_source_cloud_invalid_pocket(self, _log, _out,
 
490
                                             apt_install, filter_pkg):
 
491
        openstack.configure_installation_source("cloud:havana-updates")
 
492
        _e = ('Invalid Cloud Archive release specified: '
 
493
              'havana-updates on this Ubuntuversion')
 
494
        _s = _out.call_args[0][0]
 
495
        self.assertTrue(_s.startswith(_e))
 
496
 
 
497
    @patch.object(fetch, 'filter_installed_packages')
 
498
    @patch.object(fetch, 'apt_install')
 
499
    @patch.object(fetch, 'lsb_release')
 
500
    def test_add_source_cloud_pocket_style(self, lsb_release,
 
501
                                           apt_install, filter_pkg):
 
502
        source = "cloud:precise-updates/havana"
 
503
        lsb_release.return_value = {'DISTRIB_CODENAME': 'precise'}
 
504
        result = (
 
505
            "# Ubuntu Cloud Archive\n"
 
506
            "deb http://ubuntu-cloud.archive.canonical.com/ubuntu "
 
507
            "precise-updates/havana main\n")
 
508
        with patch_open() as (mock_open, mock_file):
 
509
            openstack.configure_installation_source(source)
 
510
            mock_file.write.assert_called_with(result)
 
511
        filter_pkg.assert_called_with(['ubuntu-cloud-keyring'])
 
512
 
 
513
    @patch.object(fetch, 'filter_installed_packages')
 
514
    @patch.object(fetch, 'apt_install')
 
515
    @patch.object(fetch, 'lsb_release')
 
516
    def test_add_source_cloud_os_style(self, lsb_release,
 
517
                                       apt_install, filter_pkg):
 
518
        source = "cloud:precise-havana"
 
519
        lsb_release.return_value = {'DISTRIB_CODENAME': 'precise'}
 
520
        result = (
 
521
            "# Ubuntu Cloud Archive\n"
 
522
            "deb http://ubuntu-cloud.archive.canonical.com/ubuntu "
 
523
            "precise-updates/havana main\n")
 
524
        with patch_open() as (mock_open, mock_file):
 
525
            openstack.configure_installation_source(source)
 
526
            mock_file.write.assert_called_with(result)
 
527
        filter_pkg.assert_called_with(['ubuntu-cloud-keyring'])
 
528
 
 
529
    @patch.object(fetch, 'filter_installed_packages')
 
530
    @patch.object(fetch, 'apt_install')
 
531
    def test_add_source_cloud_distroless_style(self, apt_install, filter_pkg):
 
532
        source = "cloud:havana"
 
533
        result = (
 
534
            "# Ubuntu Cloud Archive\n"
 
535
            "deb http://ubuntu-cloud.archive.canonical.com/ubuntu "
 
536
            "precise-updates/havana main\n")
 
537
        with patch_open() as (mock_open, mock_file):
 
538
            openstack.configure_installation_source(source)
 
539
            mock_file.write.assert_called_with(result)
 
540
        filter_pkg.assert_called_with(['ubuntu-cloud-keyring'])
477
541
 
478
542
    @patch('charmhelpers.contrib.openstack.utils.error_out')
479
543
    def test_configure_bad_install_source(self, _error):
480
544
        openstack.configure_installation_source('foo')
481
 
        _error.assert_called_with('Invalid openstack-release specified: foo')
 
545
        _error.assert_called_with("Unknown source: 'foo'")
482
546
 
483
 
    @patch('charmhelpers.contrib.openstack.utils.lsb_release')
 
547
    @patch.object(fetch, 'lsb_release')
484
548
    def test_configure_install_source_uca_staging(self, _lsb):
485
 
        '''Test configuring installation source from UCA staging sources'''
 
549
        """Test configuring installation source from UCA staging sources"""
486
550
        _lsb.return_value = FAKE_RELEASE
487
551
        # staging pockets are configured as PPAs
488
552
        with patch('subprocess.check_call') as _subp:
493
557
            _subp.assert_called_with(cmd)
494
558
 
495
559
    @patch(builtin_open)
496
 
    @patch('charmhelpers.contrib.openstack.utils.apt_install')
497
 
    @patch('charmhelpers.contrib.openstack.utils.lsb_release')
498
 
    def test_configure_install_source_uca_repos(self, _lsb, _install, _open):
499
 
        '''Test configuring installation source from UCA sources'''
 
560
    @patch.object(fetch, 'apt_install')
 
561
    @patch.object(fetch, 'lsb_release')
 
562
    @patch.object(fetch, 'filter_installed_packages')
 
563
    def test_configure_install_source_uca_repos(
 
564
            self, _fip, _lsb, _install, _open):
 
565
        """Test configuring installation source from UCA sources"""
500
566
        _lsb.return_value = FAKE_RELEASE
501
567
        _file = MagicMock(spec=io.FileIO)
502
568
        _open.return_value = _file
 
569
        _fip.side_effect = lambda x: x
503
570
        for src, url in UCA_SOURCES:
 
571
            actual_url = "# Ubuntu Cloud Archive\n{}\n".format(url)
504
572
            openstack.configure_installation_source(src)
505
 
            _install.assert_called_with('ubuntu-cloud-keyring',
 
573
            _install.assert_called_with(['ubuntu-cloud-keyring'],
506
574
                                        fatal=True)
507
575
            _open.assert_called_with(
508
576
                '/etc/apt/sources.list.d/cloud-archive.list',
509
577
                'w'
510
578
            )
511
 
            _file.__enter__().write.assert_called_with(url)
 
579
            _file.__enter__().write.assert_called_with(actual_url)
512
580
 
513
581
    @patch('charmhelpers.contrib.openstack.utils.error_out')
514
582
    def test_configure_install_source_bad_uca(self, mocked_error):
515
 
        '''Test configuring installation source from bad UCA source'''
 
583
        """Test configuring installation source from bad UCA source"""
516
584
        try:
517
585
            openstack.configure_installation_source('cloud:foo-bar')
518
586
        except:
519
587
            # ignore exceptions that raise when error_out is mocked
520
588
            # and doesn't sys.exit(1)
521
589
            pass
522
 
        _e = 'Invalid Cloud Archive release specified: foo-bar'
523
 
        mocked_error.assert_called_with(_e)
524
 
 
525
 
    @patch.object(openstack, 'juju_log', lambda *args, **kwargs: None)
526
 
    def test_import_apt_key_radix(self):
527
 
        '''Ensure shell out apt-key during key import'''
528
 
        with patch('subprocess.check_call') as _subp:
529
 
            openstack.import_key('foo')
530
 
            cmd = ['apt-key', 'adv', '--keyserver',
531
 
                   'hkp://keyserver.ubuntu.com:80', '--recv-keys', 'foo']
532
 
            _subp.assert_called_with(cmd)
533
 
 
534
 
    @patch.object(openstack, 'juju_log', lambda *args, **kwargs: None)
535
 
    def test_import_apt_key_ascii_armor(self):
536
 
        with tempfile.NamedTemporaryFile() as tmp:
537
 
            with patch.object(openstack, 'tempfile') as \
538
 
                    mock_tmpfile:
539
 
                tmpfile = mock_tmpfile.NamedTemporaryFile.return_value
540
 
                tmpfile.__enter__.return_value = tmpfile
541
 
                tmpfile.name = tmp.name
542
 
                with patch('subprocess.check_call') as _subp:
543
 
                    openstack.import_key(PGP_KEY_ASCII_ARMOR)
544
 
                    cmd = ['apt-key', 'add', tmp.name]
545
 
                    _subp.assert_called_with(cmd)
546
 
 
547
 
    @patch.object(openstack, 'juju_log', lambda *args, **kwargs: None)
548
 
    @patch('charmhelpers.contrib.openstack.utils.error_out')
549
 
    def test_import_bad_apt_key(self, mocked_error):
550
 
        '''Ensure error when importing apt key fails'''
551
 
        with patch('subprocess.check_call') as _subp:
552
 
            cmd = ['apt-key', 'adv', '--keyserver',
553
 
                   'hkp://keyserver.ubuntu.com:80', '--recv-keys', 'foo']
554
 
            _subp.side_effect = subprocess.CalledProcessError(1, cmd, '')
555
 
            openstack.import_key('foo')
556
 
            cmd = ['apt-key', 'adv', '--keyserver',
557
 
                   'hkp://keyserver.ubuntu.com:80', '--recv-keys', 'foo']
558
 
        mocked_error.assert_called_with("Error importing PGP key 'foo'")
 
590
        _e = ('Invalid Cloud Archive release specified: foo-bar'
 
591
              ' on this Ubuntuversion')
 
592
        _s = mocked_error.call_args[0][0]
 
593
        self.assertTrue(_s.startswith(_e))
 
594
 
 
595
    @patch.object(openstack, 'fetch_import_key')
 
596
    def test_import_key_calls_fetch_import_key(self, fetch_import_key):
 
597
        openstack.import_key('random-string')
 
598
        fetch_import_key.assert_called_once_with('random-string')
 
599
 
 
600
    @patch.object(openstack, 'fetch_import_key')
 
601
    @patch.object(openstack, 'sys')
 
602
    def test_import_key_calls_sys_exit_on_error(self, mock_sys,
 
603
                                                fetch_import_key):
 
604
 
 
605
        def raiser(_):
 
606
            raise openstack.GPGKeyError("an error occurred")
 
607
        fetch_import_key.side_effect = raiser
 
608
        openstack.import_key('random failure')
 
609
        mock_sys.exit.assert_called_once_with(1)
559
610
 
560
611
    @patch('os.mkdir')
561
612
    @patch('os.path.exists')
562
613
    @patch('charmhelpers.contrib.openstack.utils.charm_dir')
563
614
    @patch(builtin_open)
564
615
    def test_save_scriptrc(self, _open, _charm_dir, _exists, _mkdir):
565
 
        '''Test generation of scriptrc from environment'''
 
616
        """Test generation of scriptrc from environment"""
566
617
        scriptrc = ['#!/bin/bash\n',
567
618
                    'export setting1=foo\n',
568
619
                    'export setting2=bar\n']
618
669
    @patch.object(openstack, 'is_block_device')
619
670
    @patch.object(openstack, 'error_out')
620
671
    def test_ensure_block_device_bad_config(self, err, is_bd):
621
 
        '''Test it doesn't prepare storage with bad config'''
 
672
        """Test it doesn't prepare storage with bad config"""
622
673
        openstack.ensure_block_device(block_device='none')
623
674
        self.assertTrue(err.called)
624
675
 
625
676
    @patch.object(openstack, 'is_block_device')
626
677
    @patch.object(openstack, 'ensure_loopback_device')
627
678
    def test_ensure_block_device_loopback(self, ensure_loopback, is_bd):
628
 
        '''Test it ensures loopback device when checking block device'''
 
679
        """Test it ensures loopback device when checking block device"""
629
680
        defsize = openstack.DEFAULT_LOOPBACK_SIZE
630
681
        is_bd.return_value = True
631
682
 
641
692
 
642
693
    @patch.object(openstack, 'is_block_device')
643
694
    def test_ensure_standard_block_device(self, is_bd):
644
 
        '''Test it looks for storage at both relative and full device path'''
 
695
        """Test it looks for storage at both relative and full device path"""
645
696
        for dev in ['vdb', '/dev/vdb']:
646
697
            openstack.ensure_block_device(dev)
647
698
            is_bd.assert_called_with('/dev/vdb')
649
700
    @patch.object(openstack, 'is_block_device')
650
701
    @patch.object(openstack, 'error_out')
651
702
    def test_ensure_nonexistent_block_device(self, error_out, is_bd):
652
 
        '''Test it will not ensure a non-existant block device'''
 
703
        """Test it will not ensure a non-existant block device"""
653
704
        is_bd.return_value = False
654
705
        openstack.ensure_block_device(block_device='foo')
655
706
        self.assertTrue(error_out.called)
660
711
    @patch.object(openstack, 'zap_disk')
661
712
    @patch.object(openstack, 'is_lvm_physical_volume')
662
713
    def test_clean_storage_unmount(self, is_pv, zap_disk, mounts, umount, log):
663
 
        '''Test it unmounts block device when cleaning storage'''
 
714
        """Test it unmounts block device when cleaning storage"""
664
715
        is_pv.return_value = False
665
716
        zap_disk.return_value = True
666
717
        mounts.return_value = MOUNTS
673
724
    @patch.object(openstack, 'mounts')
674
725
    @patch.object(openstack, 'is_lvm_physical_volume')
675
726
    def test_clean_storage_lvm_wipe(self, is_pv, mounts, rm_lv, rm_vg, log):
676
 
        '''Test it removes traces of LVM when cleaning storage'''
 
727
        """Test it removes traces of LVM when cleaning storage"""
677
728
        mounts.return_value = []
678
729
        is_pv.return_value = True
679
730
        openstack.clean_storage('/dev/vdb')
684
735
    @patch.object(openstack, 'is_lvm_physical_volume')
685
736
    @patch.object(openstack, 'mounts')
686
737
    def test_clean_storage_zap_disk(self, mounts, is_pv, zap_disk):
687
 
        '''It removes traces of LVM when cleaning storage'''
 
738
        """It removes traces of LVM when cleaning storage"""
688
739
        mounts.return_value = []
689
740
        is_pv.return_value = False
690
741
        openstack.clean_storage('/dev/vdb')