c76cbce489b86fcdcf5a3e461529a0bf73f0a6cd
[ganeti-local] / test / py / qa.qa_config_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2012, 2013 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 """Script for testing qa.qa_config"""
23
24 import unittest
25 import tempfile
26 import shutil
27 import os
28 import operator
29
30 from ganeti import utils
31 from ganeti import serializer
32 from ganeti import constants
33 from ganeti import compat
34
35 from qa import qa_config
36 from qa import qa_error
37
38 import testutils
39
40
41 class TestTestEnabled(unittest.TestCase):
42   def testSimple(self):
43     for name in ["test", ["foobar"], ["a", "b"]]:
44       self.assertTrue(qa_config.TestEnabled(name, _cfg={}))
45
46     for default in [False, True]:
47       self.assertFalse(qa_config.TestEnabled("foo", _cfg={
48         "tests": {
49           "default": default,
50           "foo": False,
51           },
52         }))
53
54       self.assertTrue(qa_config.TestEnabled("bar", _cfg={
55         "tests": {
56           "default": default,
57           "bar": True,
58           },
59         }))
60
61   def testEitherWithDefault(self):
62     names = qa_config.Either("one")
63
64     self.assertTrue(qa_config.TestEnabled(names, _cfg={
65       "tests": {
66         "default": True,
67         },
68       }))
69
70     self.assertFalse(qa_config.TestEnabled(names, _cfg={
71       "tests": {
72         "default": False,
73         },
74       }))
75
76   def testEither(self):
77     names = [qa_config.Either(["one", "two"]),
78              qa_config.Either("foo"),
79              "hello",
80              ["bar", "baz"]]
81
82     self.assertTrue(qa_config.TestEnabled(names, _cfg={
83       "tests": {
84         "default": True,
85         },
86       }))
87
88     self.assertFalse(qa_config.TestEnabled(names, _cfg={
89       "tests": {
90         "default": False,
91         },
92       }))
93
94     for name in ["foo", "bar", "baz", "hello"]:
95       self.assertFalse(qa_config.TestEnabled(names, _cfg={
96         "tests": {
97           "default": True,
98           name: False,
99           },
100         }))
101
102     self.assertFalse(qa_config.TestEnabled(names, _cfg={
103       "tests": {
104         "default": True,
105         "one": False,
106         "two": False,
107         },
108       }))
109
110     self.assertTrue(qa_config.TestEnabled(names, _cfg={
111       "tests": {
112         "default": True,
113         "one": False,
114         "two": True,
115         },
116       }))
117
118     self.assertFalse(qa_config.TestEnabled(names, _cfg={
119       "tests": {
120         "default": True,
121         "one": True,
122         "two": True,
123         "foo": False,
124         },
125       }))
126
127   def testEitherNestedWithAnd(self):
128     names = qa_config.Either([["one", "two"], "foo"])
129
130     self.assertTrue(qa_config.TestEnabled(names, _cfg={
131       "tests": {
132         "default": True,
133         },
134       }))
135
136     for name in ["one", "two"]:
137       self.assertFalse(qa_config.TestEnabled(names, _cfg={
138         "tests": {
139           "default": True,
140           "foo": False,
141           name: False,
142           },
143         }))
144
145
146 class TestQaConfigLoad(unittest.TestCase):
147   def setUp(self):
148     self.tmpdir = tempfile.mkdtemp()
149
150   def tearDown(self):
151     shutil.rmtree(self.tmpdir)
152
153   def testLoadNonExistent(self):
154     filename = utils.PathJoin(self.tmpdir, "does.not.exist")
155     self.assertRaises(EnvironmentError, qa_config._QaConfig.Load, filename)
156
157   @staticmethod
158   def _WriteConfig(filename, data):
159     utils.WriteFile(filename, data=serializer.DumpJson(data))
160
161   def _CheckLoadError(self, filename, data, expected):
162     self._WriteConfig(filename, data)
163
164     try:
165       qa_config._QaConfig.Load(filename)
166     except qa_error.Error, err:
167       self.assertTrue(str(err).startswith(expected))
168     else:
169       self.fail("Exception was not raised")
170
171   def testFailsValidation(self):
172     filename = utils.PathJoin(self.tmpdir, "qa.json")
173     testconfig = {}
174
175     check_fn = compat.partial(self._CheckLoadError, filename, testconfig)
176
177     # No nodes
178     check_fn("Need at least one node")
179
180     testconfig["nodes"] = [
181       {
182         "primary": "xen-test-0",
183         "secondary": "192.0.2.1",
184         },
185       ]
186
187     # No instances
188     check_fn("Need at least one instance")
189
190     testconfig["instances"] = [
191       {
192         "name": "xen-test-inst1",
193         },
194       ]
195
196     # Missing "disk" and "disk-growth"
197     check_fn("Config options 'disk' and 'disk-growth' ")
198
199     testconfig["disk"] = []
200     testconfig["disk-growth"] = testconfig["disk"]
201
202     # Minimal accepted configuration
203     self._WriteConfig(filename, testconfig)
204     result = qa_config._QaConfig.Load(filename)
205     self.assertTrue(result.get("nodes"))
206
207     # Non-existent instance check script
208     testconfig[qa_config._INSTANCE_CHECK_KEY] = \
209       utils.PathJoin(self.tmpdir, "instcheck")
210     check_fn("Can't find instance check script")
211     del testconfig[qa_config._INSTANCE_CHECK_KEY]
212
213     # No enabled hypervisor
214     testconfig[qa_config._ENABLED_HV_KEY] = None
215     check_fn("No hypervisor is enabled")
216
217     # Unknown hypervisor
218     testconfig[qa_config._ENABLED_HV_KEY] = ["#unknownhv#"]
219     check_fn("Unknown hypervisor(s) enabled:")
220
221
222 class TestQaConfigWithSampleConfig(unittest.TestCase):
223   """Tests using C{qa-sample.json}.
224
225   This test case serves two purposes:
226
227     - Ensure shipped C{qa-sample.json} file is considered a valid QA
228       configuration
229     - Test some functions of L{qa_config._QaConfig} without having to
230       mock a whole configuration file
231
232   """
233   def setUp(self):
234     filename = "%s/qa/qa-sample.json" % testutils.GetSourceDir()
235
236     self.config = qa_config._QaConfig.Load(filename)
237
238   def testGetEnabledHypervisors(self):
239     self.assertEqual(self.config.GetEnabledHypervisors(),
240                      [constants.DEFAULT_ENABLED_HYPERVISOR])
241
242   def testGetDefaultHypervisor(self):
243     self.assertEqual(self.config.GetDefaultHypervisor(),
244                      constants.DEFAULT_ENABLED_HYPERVISOR)
245
246   def testGetInstanceCheckScript(self):
247     self.assertTrue(self.config.GetInstanceCheckScript() is None)
248
249   def testGetAndGetItem(self):
250     self.assertEqual(self.config["nodes"], self.config.get("nodes"))
251
252   def testGetMasterNode(self):
253     self.assertEqual(self.config.GetMasterNode(), self.config["nodes"][0])
254
255
256 class TestQaConfig(unittest.TestCase):
257   def setUp(self):
258     filename = \
259       testutils.TestDataFilename("qa-minimal-nodes-instances-only.json")
260
261     self.config = qa_config._QaConfig.Load(filename)
262
263   def testExclusiveStorage(self):
264     self.assertRaises(AssertionError, self.config.GetExclusiveStorage)
265
266     for value in [False, True, 0, 1, 30804, ""]:
267       self.config.SetExclusiveStorage(value)
268       self.assertEqual(self.config.GetExclusiveStorage(), bool(value))
269
270       for template in constants.DISK_TEMPLATES:
271         if value and template not in constants.DTS_EXCL_STORAGE:
272           self.assertFalse(self.config.IsTemplateSupported(template))
273         else:
274           self.assertTrue(self.config.IsTemplateSupported(template))
275
276   def testInstanceConversion(self):
277     self.assertTrue(isinstance(self.config["instances"][0],
278                                qa_config._QaInstance))
279
280   def testAcquireAndReleaseInstance(self):
281     self.assertFalse(compat.any(map(operator.attrgetter("used"),
282                                     self.config["instances"])))
283
284     inst = qa_config.AcquireInstance(_cfg=self.config)
285     self.assertTrue(inst.used)
286     self.assertTrue(inst.disk_template is None)
287
288     inst.Release()
289
290     self.assertFalse(inst.used)
291     self.assertTrue(inst.disk_template is None)
292
293     self.assertFalse(compat.any(map(operator.attrgetter("used"),
294                                     self.config["instances"])))
295
296   def testAcquireInstanceTooMany(self):
297     # Acquire all instances
298     for _ in range(len(self.config["instances"])):
299       inst = qa_config.AcquireInstance(_cfg=self.config)
300       self.assertTrue(inst.used)
301       self.assertTrue(inst.disk_template is None)
302
303     # The next acquisition must fail
304     self.assertRaises(qa_error.OutOfInstancesError,
305                       qa_config.AcquireInstance, _cfg=self.config)
306
307
308 if __name__ == "__main__":
309   testutils.GanetiTestProgram()