|  | # Copyright (C) 2017 Red Hat, Inc. | 
|  | # | 
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | # you may not use this file except in compliance with the License. | 
|  | # You may obtain a copy of the License at | 
|  | # | 
|  | #    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | 
|  | # implied. | 
|  | # | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  |  | 
|  | import os | 
|  | import shutil | 
|  | import tempfile | 
|  | import unittest | 
|  |  | 
|  | from devstack_local_conf import LocalConf | 
|  | from collections import OrderedDict | 
|  |  | 
|  | class TestDevstackLocalConf(unittest.TestCase): | 
|  |  | 
|  | @staticmethod | 
|  | def _init_localconf(p): | 
|  | lc = LocalConf(p.get('localrc'), | 
|  | p.get('local_conf'), | 
|  | p.get('base_services'), | 
|  | p.get('services'), | 
|  | p.get('plugins'), | 
|  | p.get('base_dir'), | 
|  | p.get('projects'), | 
|  | p.get('project'), | 
|  | p.get('tempest_plugins')) | 
|  | return lc | 
|  |  | 
|  | def setUp(self): | 
|  | self.tmpdir = tempfile.mkdtemp() | 
|  |  | 
|  | def tearDown(self): | 
|  | shutil.rmtree(self.tmpdir) | 
|  |  | 
|  | def test_plugins(self): | 
|  | "Test that plugins without dependencies work" | 
|  | localrc = {'test_localrc': '1'} | 
|  | local_conf = {'install': | 
|  | {'nova.conf': | 
|  | {'main': | 
|  | {'test_conf': '2'}}}} | 
|  | services = {'cinder': True} | 
|  | # We use ordereddict here to make sure the plugins are in the | 
|  | # *wrong* order for testing. | 
|  | plugins = OrderedDict([ | 
|  | ('bar', 'https://git.openstack.org/openstack/bar-plugin'), | 
|  | ('foo', 'https://git.openstack.org/openstack/foo-plugin'), | 
|  | ('baz', 'https://git.openstack.org/openstack/baz-plugin'), | 
|  | ]) | 
|  | p = dict(localrc=localrc, | 
|  | local_conf=local_conf, | 
|  | base_services=[], | 
|  | services=services, | 
|  | plugins=plugins, | 
|  | base_dir='./test', | 
|  | path=os.path.join(self.tmpdir, 'test.local.conf')) | 
|  | lc = self._init_localconf(p) | 
|  | lc.write(p['path']) | 
|  |  | 
|  | plugins = [] | 
|  | with open(p['path']) as f: | 
|  | for line in f: | 
|  | if line.startswith('enable_plugin'): | 
|  | plugins.append(line.split()[1]) | 
|  | self.assertEqual(['bar', 'baz', 'foo'], plugins) | 
|  |  | 
|  |  | 
|  | def test_plugin_deps(self): | 
|  | "Test that plugins with dependencies work" | 
|  | os.makedirs(os.path.join(self.tmpdir, 'foo-plugin', 'devstack')) | 
|  | os.makedirs(os.path.join(self.tmpdir, 'foo-plugin', '.git')) | 
|  | os.makedirs(os.path.join(self.tmpdir, 'bar-plugin', 'devstack')) | 
|  | os.makedirs(os.path.join(self.tmpdir, 'bar-plugin', '.git')) | 
|  | with open(os.path.join( | 
|  | self.tmpdir, | 
|  | 'foo-plugin', 'devstack', 'settings'), 'w') as f: | 
|  | f.write('define_plugin foo-plugin\n') | 
|  | with open(os.path.join( | 
|  | self.tmpdir, | 
|  | 'bar-plugin', 'devstack', 'settings'), 'w') as f: | 
|  | f.write('define_plugin bar-plugin\n') | 
|  | f.write('plugin_requires bar-plugin foo-plugin\n') | 
|  |  | 
|  | localrc = {'test_localrc': '1'} | 
|  | local_conf = {'install': | 
|  | {'nova.conf': | 
|  | {'main': | 
|  | {'test_conf': '2'}}}} | 
|  | services = {'cinder': True} | 
|  | # We use ordereddict here to make sure the plugins are in the | 
|  | # *wrong* order for testing. | 
|  | plugins = OrderedDict([ | 
|  | ('bar-plugin', 'https://git.openstack.org/openstack/bar-plugin'), | 
|  | ('foo-plugin', 'https://git.openstack.org/openstack/foo-plugin'), | 
|  | ]) | 
|  | p = dict(localrc=localrc, | 
|  | local_conf=local_conf, | 
|  | base_services=[], | 
|  | services=services, | 
|  | plugins=plugins, | 
|  | base_dir=self.tmpdir, | 
|  | path=os.path.join(self.tmpdir, 'test.local.conf')) | 
|  | lc = self._init_localconf(p) | 
|  | lc.write(p['path']) | 
|  |  | 
|  | plugins = [] | 
|  | with open(p['path']) as f: | 
|  | for line in f: | 
|  | if line.startswith('enable_plugin'): | 
|  | plugins.append(line.split()[1]) | 
|  | self.assertEqual(['foo-plugin', 'bar-plugin'], plugins) | 
|  |  | 
|  | def test_libs_from_git(self): | 
|  | "Test that LIBS_FROM_GIT is auto-generated" | 
|  | projects = { | 
|  | 'git.openstack.org/openstack/nova': { | 
|  | 'required': True, | 
|  | 'short_name': 'nova', | 
|  | }, | 
|  | 'git.openstack.org/openstack/oslo.messaging': { | 
|  | 'required': True, | 
|  | 'short_name': 'oslo.messaging', | 
|  | }, | 
|  | 'git.openstack.org/openstack/devstack-plugin': { | 
|  | 'required': False, | 
|  | 'short_name': 'devstack-plugin', | 
|  | }, | 
|  | } | 
|  | project = { | 
|  | 'short_name': 'glance', | 
|  | } | 
|  | p = dict(base_services=[], | 
|  | base_dir='./test', | 
|  | path=os.path.join(self.tmpdir, 'test.local.conf'), | 
|  | projects=projects, | 
|  | project=project) | 
|  | lc = self._init_localconf(p) | 
|  | lc.write(p['path']) | 
|  |  | 
|  | lfg = None | 
|  | with open(p['path']) as f: | 
|  | for line in f: | 
|  | if line.startswith('LIBS_FROM_GIT'): | 
|  | lfg = line.strip().split('=')[1] | 
|  | self.assertEqual('nova,oslo.messaging,glance', lfg) | 
|  |  | 
|  | def test_overridelibs_from_git(self): | 
|  | "Test that LIBS_FROM_GIT can be overridden" | 
|  | localrc = {'LIBS_FROM_GIT': 'oslo.db'} | 
|  | projects = { | 
|  | 'git.openstack.org/openstack/nova': { | 
|  | 'required': True, | 
|  | 'short_name': 'nova', | 
|  | }, | 
|  | 'git.openstack.org/openstack/oslo.messaging': { | 
|  | 'required': True, | 
|  | 'short_name': 'oslo.messaging', | 
|  | }, | 
|  | 'git.openstack.org/openstack/devstack-plugin': { | 
|  | 'required': False, | 
|  | 'short_name': 'devstack-plugin', | 
|  | }, | 
|  | } | 
|  | p = dict(localrc=localrc, | 
|  | base_services=[], | 
|  | base_dir='./test', | 
|  | path=os.path.join(self.tmpdir, 'test.local.conf'), | 
|  | projects=projects) | 
|  | lc = self._init_localconf(p) | 
|  | lc.write(p['path']) | 
|  |  | 
|  | lfg = None | 
|  | with open(p['path']) as f: | 
|  | for line in f: | 
|  | if line.startswith('LIBS_FROM_GIT'): | 
|  | lfg = line.strip().split('=')[1] | 
|  | self.assertEqual('"oslo.db"', lfg) | 
|  |  | 
|  | def test_avoid_double_quote(self): | 
|  | "Test that there a no duplicated quotes" | 
|  | localrc = {'TESTVAR': '"quoted value"'} | 
|  | p = dict(localrc=localrc, | 
|  | base_services=[], | 
|  | base_dir='./test', | 
|  | path=os.path.join(self.tmpdir, 'test.local.conf'), | 
|  | projects={}) | 
|  | lc = self._init_localconf(p) | 
|  | lc.write(p['path']) | 
|  |  | 
|  | testvar = None | 
|  | with open(p['path']) as f: | 
|  | for line in f: | 
|  | if line.startswith('TESTVAR'): | 
|  | testvar = line.strip().split('=')[1] | 
|  | self.assertEqual('"quoted value"', testvar) | 
|  |  | 
|  | def test_plugin_circular_deps(self): | 
|  | "Test that plugins with circular dependencies fail" | 
|  | os.makedirs(os.path.join(self.tmpdir, 'foo-plugin', 'devstack')) | 
|  | os.makedirs(os.path.join(self.tmpdir, 'foo-plugin', '.git')) | 
|  | os.makedirs(os.path.join(self.tmpdir, 'bar-plugin', 'devstack')) | 
|  | os.makedirs(os.path.join(self.tmpdir, 'bar-plugin', '.git')) | 
|  | with open(os.path.join( | 
|  | self.tmpdir, | 
|  | 'foo-plugin', 'devstack', 'settings'), 'w') as f: | 
|  | f.write('define_plugin foo\n') | 
|  | f.write('plugin_requires foo bar\n') | 
|  | with open(os.path.join( | 
|  | self.tmpdir, | 
|  | 'bar-plugin', 'devstack', 'settings'), 'w') as f: | 
|  | f.write('define_plugin bar\n') | 
|  | f.write('plugin_requires bar foo\n') | 
|  |  | 
|  | localrc = {'test_localrc': '1'} | 
|  | local_conf = {'install': | 
|  | {'nova.conf': | 
|  | {'main': | 
|  | {'test_conf': '2'}}}} | 
|  | services = {'cinder': True} | 
|  | # We use ordereddict here to make sure the plugins are in the | 
|  | # *wrong* order for testing. | 
|  | plugins = OrderedDict([ | 
|  | ('bar', 'https://git.openstack.org/openstack/bar-plugin'), | 
|  | ('foo', 'https://git.openstack.org/openstack/foo-plugin'), | 
|  | ]) | 
|  | p = dict(localrc=localrc, | 
|  | local_conf=local_conf, | 
|  | base_services=[], | 
|  | services=services, | 
|  | plugins=plugins, | 
|  | base_dir=self.tmpdir, | 
|  | path=os.path.join(self.tmpdir, 'test.local.conf')) | 
|  | with self.assertRaises(Exception): | 
|  | lc = self._init_localconf(p) | 
|  | lc.write(p['path']) | 
|  |  | 
|  | def _find_tempest_plugins_value(self, file_path): | 
|  | tp = None | 
|  | with open(file_path) as f: | 
|  | for line in f: | 
|  | if line.startswith('TEMPEST_PLUGINS'): | 
|  | found = line.strip().split('=')[1] | 
|  | self.assertIsNone(tp, | 
|  | "TEMPEST_PLUGIN ({}) found again ({})".format( | 
|  | tp, found)) | 
|  | tp = found | 
|  | return tp | 
|  |  | 
|  | def test_tempest_plugins(self): | 
|  | "Test that TEMPEST_PLUGINS is correctly populated." | 
|  | p = dict(base_services=[], | 
|  | base_dir='./test', | 
|  | path=os.path.join(self.tmpdir, 'test.local.conf'), | 
|  | tempest_plugins=['heat-tempest-plugin', 'sahara-tests']) | 
|  | lc = self._init_localconf(p) | 
|  | lc.write(p['path']) | 
|  |  | 
|  | tp = self._find_tempest_plugins_value(p['path']) | 
|  | self.assertEqual('"./test/heat-tempest-plugin ./test/sahara-tests"', tp) | 
|  | self.assertEqual(len(lc.warnings), 0) | 
|  |  | 
|  | def test_tempest_plugins_not_overridden(self): | 
|  | """Test that the existing value of TEMPEST_PLUGINS is not overridden | 
|  | by the user-provided value, but a warning is emitted.""" | 
|  | localrc = {'TEMPEST_PLUGINS': 'someplugin'} | 
|  | p = dict(localrc=localrc, | 
|  | base_services=[], | 
|  | base_dir='./test', | 
|  | path=os.path.join(self.tmpdir, 'test.local.conf'), | 
|  | tempest_plugins=['heat-tempest-plugin', 'sahara-tests']) | 
|  | lc = self._init_localconf(p) | 
|  | lc.write(p['path']) | 
|  |  | 
|  | tp = self._find_tempest_plugins_value(p['path']) | 
|  | self.assertEqual('"someplugin"', tp) | 
|  | self.assertEqual(len(lc.warnings), 1) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | unittest.main() |