Merge branch 'stable-2.7' into stable-2.8
[ganeti-local] / test / py / ganeti.masterd.iallocator_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2012 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 ganeti.masterd.iallocator"""
23
24 import unittest
25
26 from ganeti import compat
27 from ganeti import constants
28 from ganeti import errors
29 from ganeti import objects
30 from ganeti import ht
31 from ganeti.masterd import iallocator
32
33 import testutils
34
35
36 class _StubIAllocator(object):
37   def __init__(self, success):
38     self.success = success
39
40
41 class TestIAReqMultiInstanceAlloc(unittest.TestCase):
42   def testResult(self):
43     good_results = [
44       # First result (all instances "allocate")
45       [
46         [["foo", ["a", "b"]],
47          ["bar", ["c"]],
48          ["baz", []]],
49         []
50       ],
51       # Second result (partial "allocate", partial "fail")
52       [
53         [["bar", ["c", "b"]],
54          ["baz", ["a"]]],
55         ["foo"]
56       ],
57       # Third result (all instances "fail")
58       [
59         [],
60         ["foo", "bar", "baz"]
61       ],
62       ]
63     bad_results = [
64       "foobar",
65       1234,
66       [],
67       [[]],
68       [[], [], []],
69       ]
70
71     result_fn = iallocator.IAReqMultiInstanceAlloc.REQ_RESULT
72
73     self.assertTrue(compat.all(map(result_fn, good_results)))
74     self.assertFalse(compat.any(map(result_fn, bad_results)))
75
76
77 class TestIARequestBase(unittest.TestCase):
78   def testValidateResult(self):
79     class _StubReqBase(iallocator.IARequestBase):
80       MODE = constants.IALLOCATOR_MODE_ALLOC
81       REQ_RESULT = ht.TBool
82
83     stub = _StubReqBase()
84     stub.ValidateResult(_StubIAllocator(True), True)
85     self.assertRaises(errors.ResultValidationError, stub.ValidateResult,
86                       _StubIAllocator(True), "foo")
87     stub.ValidateResult(_StubIAllocator(False), True)
88     # We don't validate the result if the iallocation request was not successful
89     stub.ValidateResult(_StubIAllocator(False), "foo")
90
91
92 class _FakeConfigWithNdParams:
93   def GetNdParams(self, _):
94     return None
95
96
97 class TestComputeBasicNodeData(unittest.TestCase):
98   def setUp(self):
99     self.fn = compat.partial(iallocator.IAllocator._ComputeBasicNodeData,
100                              _FakeConfigWithNdParams())
101
102   def testEmpty(self):
103     self.assertEqual(self.fn({}, None), {})
104
105   def testSimple(self):
106     node1 = objects.Node(name="node1",
107                          primary_ip="192.0.2.1",
108                          secondary_ip="192.0.2.2",
109                          offline=False,
110                          drained=False,
111                          master_candidate=True,
112                          master_capable=True,
113                          group="11112222",
114                          vm_capable=False)
115
116     node2 = objects.Node(name="node2",
117                          primary_ip="192.0.2.3",
118                          secondary_ip="192.0.2.4",
119                          offline=True,
120                          drained=False,
121                          master_candidate=False,
122                          master_capable=False,
123                          group="11112222",
124                          vm_capable=True)
125
126     assert node1 != node2
127
128     ninfo = {
129       "#unused-1#": node1,
130       "#unused-2#": node2,
131       }
132
133     self.assertEqual(self.fn(ninfo, None), {
134       "node1": {
135         "tags": [],
136         "primary_ip": "192.0.2.1",
137         "secondary_ip": "192.0.2.2",
138         "offline": False,
139         "drained": False,
140         "master_candidate": True,
141         "group": "11112222",
142         "master_capable": True,
143         "vm_capable": False,
144         "ndparams": None,
145         },
146       "node2": {
147         "tags": [],
148         "primary_ip": "192.0.2.3",
149         "secondary_ip": "192.0.2.4",
150         "offline": True,
151         "drained": False,
152         "master_candidate": False,
153         "group": "11112222",
154         "master_capable": False,
155         "vm_capable": True,
156         "ndparams": None,
157         },
158       })
159
160   def testOfflineNode(self):
161     for whitelist in [None, [], set(), ["node1"], ["node2"]]:
162       result = self.fn({
163         "node1": objects.Node(name="node1", offline=True)
164         }, whitelist)
165       self.assertEqual(len(result), 1)
166       self.assertTrue(result["node1"]["offline"])
167
168   def testWhitelist(self):
169     for whitelist in [None, [], set(), ["node1"], ["node2"]]:
170       result = self.fn({
171         "node1": objects.Node(name="node1", offline=False)
172         }, whitelist)
173       self.assertEqual(len(result), 1)
174
175       if whitelist is None or "node1" in whitelist:
176         self.assertFalse(result["node1"]["offline"])
177       else:
178         self.assertTrue(result["node1"]["offline"])
179
180
181 if __name__ == "__main__":
182   testutils.GanetiTestProgram()