~coreygoldberg/uci-engine/subunit-results

« back to all changes in this revision

Viewing changes to juju-deployer/test_deploy.py

Merge trunk, resolving conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# You should have received a copy of the GNU Affero General Public License
15
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
16
 
 
17
from distutils import dir_util
17
18
import os
18
 
import sys
19
19
import mock
20
20
import tempfile
21
21
import shutil
22
22
import subprocess
23
23
import unittest
 
24
import yaml
24
25
 
25
26
from novaclient import exceptions
26
27
import swiftclient
33
34
 
34
35
class TestCheckEnvironment(unittest.TestCase):
35
36
 
36
 
    DEFAULT_ENV =  {
 
37
    DEFAULT_ENV = {
37
38
        'OS_USERNAME': 'os-user',
 
39
        'GLANCE_OS_USERNAME': 'glance-os-user',
 
40
        'GLANCE_OS_AUTH_URL': 'glance-url',
 
41
        'GLANCE_OS_REGION_NAME': 'glance-region',
 
42
        'GLANCE_OS_TENANT_NAME': 'glance-tenant',
 
43
        'GLANCE_OS_PASSWORD': 'glance-password',
38
44
        'OS_AUTH_URL': 'something.stack',
39
45
        'CI_OAUTH_CONSUMER_KEY': 'key',
40
46
        'CI_OAUTH_TOKEN': 'token',
52
58
            'CI_CODE_SOURCE': None,
53
59
            'CI_PRIVATE_PPAS_ONLY': None,
54
60
            'CI_TEMPURL_EXPIRES': None,
 
61
            'CI_TEMPURL_SIGNING_KEY': None,
 
62
            'CI_KEYRING_URI': None,
 
63
            'CI_KEYSERVER_URL': None,
55
64
            'HP_ACCESS_KEY_ID': None,
56
65
            'HP_TENANT_ID': None,
57
 
            'HP_SECRET_KEY': None,
58
66
        }
59
67
        fixtures.isolate_from_env(self, ignored_env)
60
68
 
61
 
    def test_check_environment_defaults(self):
 
69
    @mock.patch('deploy.gen_random_key', return_value='RaMdOm_KeY')
 
70
    def test_check_environment_defaults(self, mocked_gen_key):
62
71
        # check that some of our values can be defaulted correctly:
63
72
        env_required = self.DEFAULT_ENV.copy()
64
73
        fixtures.isolate_from_env(self, env_required)
70
79
        self.assertEqual(os.environ['CI_KEYRING_URI'], '')
71
80
        self.assertEqual(
72
81
            os.environ['CI_KEYSERVER_URL'], 'keyserver.ubuntu.com')
73
 
        # HP_* variables are set empty if the deployment is not
 
82
        # CI_TEMPURL_SIGNING_KEY used for canonistack/prodstack TempURL
 
83
        # generation and `deploy.py` generated a new random HMAC-SHA1
 
84
        # (40 chars) key for each deployment.
 
85
        self.assertEqual(os.environ['CI_TEMPURL_SIGNING_KEY'], 'RaMdOm_KeY')
 
86
        # Other HP_* variables are set empty if the deployment is not
74
87
        # targeted to HPCloud.
75
 
        self.assertEqual(os.environ['HP_SECRET_KEY'], '')
76
88
        self.assertEqual(os.environ['HP_ACCESS_KEY_ID'], '')
77
89
        self.assertEqual(os.environ['HP_TENANT_ID'], '')
78
90
 
82
94
        hp_env = self.DEFAULT_ENV.copy()
83
95
        hp_env.update({
84
96
            'OS_AUTH_URL': 'something.hpcloud',
85
 
            'HP_SECRET_KEY': 'FROM_HORIZON',
 
97
            'CI_TEMPURL_SIGNING_KEY': 'FROM_HORIZON',
86
98
            'HP_ACCESS_KEY_ID': 'FROM_HORIZON',
87
99
            'HP_TENANT_ID': 'FROM_HORIZON',
88
100
        })
89
101
        fixtures.isolate_from_env(self, hp_env)
90
102
        deploy.check_environment()
91
103
 
 
104
    def test_check_environment_hp_signing_key(self):
 
105
        # check_environment bails out if it's a HPCloud deployment and
 
106
        # it can't find the required CI_TEMPURL_SIGNING_KEY.
 
107
        broken_hp_env = self.DEFAULT_ENV.copy()
 
108
        broken_hp_env.update({
 
109
            'OS_AUTH_URL': 'something.hpcloud',
 
110
            'HP_ACCESS_KEY_ID': 'FROM_HORIZON',
 
111
            'HP_TENANT_ID': 'FROM_HORIZON',
 
112
        })
 
113
        fixtures.isolate_from_env(self, broken_hp_env)
 
114
        with self.assertRaises(SystemExit) as cm:
 
115
            deploy.check_environment()
 
116
        self.assertEqual(
 
117
            'CI_TEMPURL_SIGNING_KEY has to be defined as your HP access '
 
118
            '\'secret_key\', which can be found in '
 
119
            'https://horizon.hpcloud.com/.',
 
120
            cm.exception.message)
 
121
 
92
122
    def test_check_environment_hp_fails(self):
93
123
        # check_environment bails out if it's a HPCloud deployment and
94
124
        # it can't find the required HP_* variables.
95
125
        broken_hp_env = self.DEFAULT_ENV.copy()
96
126
        broken_hp_env.update({
97
127
            'OS_AUTH_URL': 'something.hpcloud',
 
128
            'CI_TEMPURL_SIGNING_KEY': 'FROM_HORIZON',
98
129
        })
99
130
        fixtures.isolate_from_env(self, broken_hp_env)
100
 
        with self.assertRaises(SystemExit):
 
131
        with self.assertRaises(SystemExit) as cm:
101
132
            deploy.check_environment()
 
133
        self.assertEqual(
 
134
            ['',
 
135
             'ERROR: Missing required environment variables:',
 
136
             '  HP_TENANT_ID',
 
137
             '  HP_ACCESS_KEY_ID',
 
138
             'Please ensure the novarc file has been sourced.'],
 
139
            cm.exception.message.splitlines())
102
140
 
103
141
    def test_check_environment_fails(self):
104
142
        # check_environment bails out if a valid novarc isn't sourced.
107
145
            with self.assertRaises(SystemExit):
108
146
                deploy.check_environment()
109
147
 
 
148
    def test_gen_random_key(self):
 
149
        # `gen_random_key` generates random alphanumeric keys of a
 
150
        # specified length.
 
151
        key_hmac_sha1 = deploy.gen_random_key()
 
152
        self.assertTrue(key_hmac_sha1.isalnum())
 
153
        self.assertTrue(40, len(key_hmac_sha1))
 
154
        key_hmac_md5 = deploy.gen_random_key(length=32)
 
155
        self.assertTrue(key_hmac_md5.isalnum())
 
156
        self.assertTrue(32, len(key_hmac_md5))
 
157
 
110
158
 
111
159
class TestCheckDependencies(unittest.TestCase):
112
160
 
153
201
        super(TestInstallDeployer, self).setUp()
154
202
        fixtures.set_uniq_cwd(self)
155
203
 
156
 
    def test_install_deployer(self):
 
204
    @mock.patch('ci_utils.sourcecode.update_sourcecode')
 
205
    def test_install_deployer(self, mocked_us):
157
206
        fixtures.isolate_from_env(self, dict(PYTHONPATH=''))
158
 
        # FIXME: calling build_sourcedeps is heavyweight and yet another hint
159
 
        # the setup story needs love. -- vila 2014-04-29
 
207
 
 
208
        def local_us(*args, **kwargs):
 
209
            os.makedirs('juju-deployer/.bzr')
 
210
        mocked_us.side_effect = local_us
160
211
        deploy.build_sourcedeps('.')
161
212
        deployer_dir = deploy.install_deployer('.')
162
213
        self.addCleanup(shutil.rmtree, deployer_dir)
305
356
            open(os.path.join(user_dir, filename)).read(),
306
357
            'WORKING_DIR file was not overwritten.'
307
358
        )
 
359
        self.assertEquals(user_dir, working_dir)
308
360
 
309
361
 
310
362
class TestPopulateTemplates(unittest.TestCase):
355
407
        fixtures.set_uniq_cwd(self)
356
408
 
357
409
    def test_build_charms(self):
358
 
        charmsdir = tempfile.mkdtemp()
359
 
        self.addCleanup(shutil.rmtree, charmsdir)
360
 
        p = os.path.join(charmsdir, 'precise')
 
410
        # `build_charms` builds tree charms, copies them to the working-dir
 
411
        # and sets JUJU_REPOSITORY.
 
412
        charms_dir = tempfile.mkdtemp()
 
413
        self.addCleanup(shutil.rmtree, charms_dir)
 
414
        working_dir = tempfile.mkdtemp()
 
415
        self.addCleanup(shutil.rmtree, working_dir)
 
416
        # Creates 'tree' fake-charms directories.
 
417
        # - precise
 
418
        # | - charm1 (empty)
 
419
        # | - charm2 (Makefile for creating 'make_called')
 
420
        p = os.path.join(charms_dir, 'precise')
361
421
        os.mkdir(p)
362
422
        charm1 = os.path.join(p, 'charm1')
363
423
        os.mkdir(charm1)
365
425
        os.mkdir(charm2)
366
426
        with open(os.path.join(charm2, 'Makefile'), 'w') as f:
367
427
            f.write('all:\n')
368
 
            f.write('\tmkdir ../build_charms_should_delete\n')
369
 
            # webui is precious and should not be deleted
370
 
            f.write('\tmkdir ../webui\n')
371
 
            f.write('\ttouch make_called\n')
372
 
 
373
 
        clean = deploy.build_charms(charmsdir)
374
 
        clean()
375
 
 
376
 
        self.assertTrue(os.path.exists(os.path.join(charm2, 'make_called')))
377
 
        self.assertItemsEqual(['charm1', 'charm2', 'webui'], os.listdir(p))
 
428
            f.write('\t@touch make_called\n')
 
429
        # Copy the unbuilt tree for simulating a pre-existing working_dir.
 
430
        charms_copy = os.path.join(working_dir, 'charms')
 
431
        dir_util.copy_tree(charms_dir, charms_copy)
 
432
        # Track charm built indicators. Both tree and working-dir are unbuilt.
 
433
        built_path = 'precise/charm2/make_called'
 
434
        tree_built = os.path.join(charms_dir, built_path)
 
435
        copy_built = os.path.join(charms_copy, built_path)
 
436
        self.assertFalse(os.path.exists(tree_built))
 
437
        self.assertFalse(os.path.exists(copy_built))
 
438
 
 
439
        deploy.build_charms(working_dir, charms_dir)
 
440
 
 
441
        self.assertTrue(os.path.exists(tree_built))
 
442
        self.assertTrue(os.path.exists(copy_built))
 
443
        self.assertItemsEqual(['charms'], os.listdir(working_dir))
 
444
        self.assertItemsEqual(os.listdir(charms_dir), os.listdir(charms_copy))
 
445
        self.assertEquals(
 
446
            os.path.join(charms_copy), os.environ['JUJU_REPOSITORY'])
378
447
 
379
448
 
380
449
class TestPrivateIP(unittest.TestCase):
395
464
        self.assertTrue(deploy.private_IP('192.168.0.16'))
396
465
 
397
466
 
398
 
class TestInstallAmulet(unittest.TestCase):
399
 
 
400
 
    def setUp(self):
401
 
        super(TestInstallAmulet, self).setUp()
402
 
        fixtures.set_uniq_cwd(self)
403
 
 
404
 
    def test_install_amulet(self):
405
 
        fixtures.override_env(self, 'PYTHONPATH', '')
406
 
        # FIXME: calling build_sourcedeps is heavyweight and yet another hint
407
 
        # the setup story needs love. -- vila 2014-04-29
408
 
        deploy.build_sourcedeps('.')
409
 
        deploy.install_amulet('.')
410
 
        self.assertTrue(os.path.exists(os.path.join('amulet', '.bzr')))
411
 
        self.assertEqual(os.path.join(self.uniq_dir, 'amulet'),
412
 
                         os.environ['PYTHONPATH'])
413
 
 
414
 
 
415
467
class TestNeedsBotstrap(unittest.TestCase):
416
468
 
417
469
    @mock.patch('deploy._get_control_bucket',
439
491
                dcb.assert_called_with()
440
492
 
441
493
 
 
494
class TestGetEnvironment(unittest.TestCase):
 
495
    def setUp(self):
 
496
        super(TestGetEnvironment, self).setUp()
 
497
        fixtures.set_uniq_cwd(self)
 
498
        fixtures.isolate_from_env(
 
499
            self, dict(HOME=self.uniq_dir, JUJU_HOME=None, JUJU_ENV=None))
 
500
        os.mkdir('.juju')
 
501
        self.juju_home = os.path.join(os.environ['HOME'], '.juju')
 
502
 
 
503
    def test_get_juju_home(self):
 
504
        juju_home = '~/.juju/'
 
505
        os.environ['JUJU_HOME'] = juju_home
 
506
        self.assertEquals(juju_home, deploy._get_juju_home())
 
507
 
 
508
    def test_get_juju_home_unset(self):
 
509
        self.assertEquals(self.juju_home, deploy._get_juju_home())
 
510
 
 
511
    def test_get_juju_env_os_environ_set(self):
 
512
        env = 'hp'
 
513
        os.environ['JUJU_ENV'] = env
 
514
        self.assertEquals(env, deploy._get_juju_env())
 
515
 
 
516
    def test_get_juju_env_current_env(self):
 
517
        env = 'hpcloud'
 
518
        with open(os.path.join(
 
519
                  self.juju_home, 'current-environment'), 'w') as fp:
 
520
            fp.write(env)
 
521
        self.assertEquals(env, deploy._get_juju_env())
 
522
 
 
523
    def test_get_juju_env_default(self):
 
524
        env = {
 
525
            'default': 'hp',
 
526
            'environments': {
 
527
                'hp': {
 
528
                    'type': 'openstack',
 
529
                    'default-series': 'precise',
 
530
                    'use-floating-ip': False,
 
531
                },
 
532
            },
 
533
        }
 
534
        with open(os.path.join(
 
535
                  self.juju_home, 'environments.yaml'), 'w') as f:
 
536
            yaml.safe_dump(env, f)
 
537
        self.assertEquals('hp', deploy._get_juju_env())
 
538
 
 
539
 
 
540
class TestUtilityFunctions(unittest.TestCase):
 
541
 
 
542
    def test_juju_status(self):
 
543
        mocked = {'environment': 'local', 'machines': {}, 'services': {}}
 
544
        mocked = yaml.safe_dump(mocked)
 
545
        with mock.patch('subprocess.check_output', return_value=mocked):
 
546
            status = deploy.juju_status()
 
547
            self.assertEqual('local', status['environment'])
 
548
 
 
549
 
442
550
if __name__ == '__main__':
443
551
    unittest.main()