Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.hooks_unittest.py @ 87ed6b79

History | View | Annotate | Download (18.7 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2006, 2007 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 unittesting the hooks module"""
23

    
24

    
25
import unittest
26
import os
27
import time
28
import tempfile
29
import os.path
30

    
31
from ganeti import errors
32
from ganeti import opcodes
33
from ganeti import hooksmaster
34
from ganeti import backend
35
from ganeti import constants
36
from ganeti import cmdlib
37
from ganeti.rpc import node as rpc
38
from ganeti import compat
39
from ganeti import pathutils
40
from ganeti.constants import HKR_SUCCESS, HKR_FAIL, HKR_SKIP
41

    
42
from mocks import FakeConfig, FakeProc, FakeContext
43

    
44
import testutils
45

    
46

    
47
class FakeLU(cmdlib.LogicalUnit):
48
  HPATH = "test"
49

    
50
  def BuildHooksEnv(self):
51
    return {}
52

    
53
  def BuildHooksNodes(self):
54
    return ["a"], ["a"]
55

    
56

    
57
class TestHooksRunner(unittest.TestCase):
58
  """Testing case for HooksRunner"""
59
  def setUp(self):
60
    self.torm = []
61
    self.tmpdir = tempfile.mkdtemp()
62
    self.torm.append((self.tmpdir, True))
63
    self.logdir = tempfile.mkdtemp()
64
    self.torm.append((self.logdir, True))
65
    self.hpath = "fake"
66
    self.ph_dirs = {}
67
    for i in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
68
      dname = "%s/%s-%s.d" % (self.tmpdir, self.hpath, i)
69
      os.mkdir(dname)
70
      self.torm.append((dname, True))
71
      self.ph_dirs[i] = dname
72
    self.hr = backend.HooksRunner(hooks_base_dir=self.tmpdir)
73

    
74
  def tearDown(self):
75
    self.torm.reverse()
76
    for path, kind in self.torm:
77
      if kind:
78
        os.rmdir(path)
79
      else:
80
        os.unlink(path)
81

    
82
  def _rname(self, fname):
83
    return "/".join(fname.split("/")[-2:])
84

    
85
  def testEmpty(self):
86
    """Test no hooks"""
87
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
88
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}), [])
89

    
90
  def testSkipNonExec(self):
91
    """Test skip non-exec file"""
92
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
93
      fname = "%s/test" % self.ph_dirs[phase]
94
      f = open(fname, "w")
95
      f.close()
96
      self.torm.append((fname, False))
97
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
98
                           [(self._rname(fname), HKR_SKIP, "")])
99

    
100
  def testSkipInvalidName(self):
101
    """Test skip script with invalid name"""
102
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
103
      fname = "%s/a.off" % self.ph_dirs[phase]
104
      f = open(fname, "w")
105
      f.write("#!/bin/sh\nexit 0\n")
106
      f.close()
107
      os.chmod(fname, 0700)
108
      self.torm.append((fname, False))
109
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
110
                           [(self._rname(fname), HKR_SKIP, "")])
111

    
112
  def testSkipDir(self):
113
    """Test skip directory"""
114
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
115
      fname = "%s/testdir" % self.ph_dirs[phase]
116
      os.mkdir(fname)
117
      self.torm.append((fname, True))
118
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
119
                           [(self._rname(fname), HKR_SKIP, "")])
120

    
121
  def testSuccess(self):
122
    """Test success execution"""
123
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
124
      fname = "%s/success" % self.ph_dirs[phase]
125
      f = open(fname, "w")
126
      f.write("#!/bin/sh\nexit 0\n")
127
      f.close()
128
      self.torm.append((fname, False))
129
      os.chmod(fname, 0700)
130
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
131
                           [(self._rname(fname), HKR_SUCCESS, "")])
132

    
133
  def testSymlink(self):
134
    """Test running a symlink"""
135
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
136
      fname = "%s/success" % self.ph_dirs[phase]
137
      os.symlink("/bin/true", fname)
138
      self.torm.append((fname, False))
139
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
140
                           [(self._rname(fname), HKR_SUCCESS, "")])
141

    
142
  def testFail(self):
143
    """Test success execution"""
144
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
145
      fname = "%s/success" % self.ph_dirs[phase]
146
      f = open(fname, "w")
147
      f.write("#!/bin/sh\nexit 1\n")
148
      f.close()
149
      self.torm.append((fname, False))
150
      os.chmod(fname, 0700)
151
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}),
152
                           [(self._rname(fname), HKR_FAIL, "")])
153

    
154
  def testCombined(self):
155
    """Test success, failure and skip all in one test"""
156
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
157
      expect = []
158
      for fbase, ecode, rs in [("00succ", 0, HKR_SUCCESS),
159
                               ("10fail", 1, HKR_FAIL),
160
                               ("20inv.", 0, HKR_SKIP),
161
                               ]:
162
        fname = "%s/%s" % (self.ph_dirs[phase], fbase)
163
        f = open(fname, "w")
164
        f.write("#!/bin/sh\nexit %d\n" % ecode)
165
        f.close()
166
        self.torm.append((fname, False))
167
        os.chmod(fname, 0700)
168
        expect.append((self._rname(fname), rs, ""))
169
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}), expect)
170

    
171
  def testOrdering(self):
172
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
173
      expect = []
174
      for fbase in ["10s1",
175
                    "00s0",
176
                    "10sa",
177
                    "80sc",
178
                    "60sd",
179
                    ]:
180
        fname = "%s/%s" % (self.ph_dirs[phase], fbase)
181
        os.symlink("/bin/true", fname)
182
        self.torm.append((fname, False))
183
        expect.append((self._rname(fname), HKR_SUCCESS, ""))
184
      expect.sort()
185
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, {}), expect)
186

    
187
  def testEnv(self):
188
    """Test environment execution"""
189
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
190
      fbase = "success"
191
      fname = "%s/%s" % (self.ph_dirs[phase], fbase)
192
      os.symlink("/usr/bin/env", fname)
193
      self.torm.append((fname, False))
194
      env_snt = {"PHASE": phase}
195
      env_exp = "PHASE=%s" % phase
196
      self.failUnlessEqual(self.hr.RunHooks(self.hpath, phase, env_snt),
197
                           [(self._rname(fname), HKR_SUCCESS, env_exp)])
198

    
199

    
200
def FakeHooksRpcSuccess(node_list, hpath, phase, env):
201
  """Fake call_hooks_runner function.
202

203
  @rtype: dict of node -> L{rpc.RpcResult} with a successful script result
204
  @return: script execution from all nodes
205

206
  """
207
  rr = rpc.RpcResult
208
  return dict([(node, rr((True, [("utest", constants.HKR_SUCCESS, "ok")]),
209
                         node=node, call="FakeScriptOk"))
210
               for node in node_list])
211

    
212

    
213
class TestHooksMaster(unittest.TestCase):
214
  """Testing case for HooksMaster"""
215

    
216
  def _call_false(*args):
217
    """Fake call_hooks_runner function which returns False."""
218
    return False
219

    
220
  @staticmethod
221
  def _call_nodes_false(node_list, hpath, phase, env):
222
    """Fake call_hooks_runner function.
223

224
    @rtype: dict of node -> L{rpc.RpcResult} with an rpc error
225
    @return: rpc failure from all nodes
226

227
    """
228
    return dict([(node, rpc.RpcResult("error", failed=True,
229
                  node=node, call="FakeError")) for node in node_list])
230

    
231
  @staticmethod
232
  def _call_script_fail(node_list, hpath, phase, env):
233
    """Fake call_hooks_runner function.
234

235
    @rtype: dict of node -> L{rpc.RpcResult} with a failed script result
236
    @return: script execution failure from all nodes
237

238
    """
239
    rr = rpc.RpcResult
240
    return dict([(node, rr((True, [("utest", constants.HKR_FAIL, "err")]),
241
                           node=node, call="FakeScriptFail"))
242
                  for node in node_list])
243

    
244
  def setUp(self):
245
    self.op = opcodes.OpCode()
246
    self.context = FakeContext()
247
    # WARNING: here we pass None as RpcRunner instance since we know
248
    # our usage via HooksMaster will not use lu.rpc
249
    self.lu = FakeLU(FakeProc(), self.op, self.context, None, (123, "/foo/bar"),
250
                     None)
251

    
252
  def testTotalFalse(self):
253
    """Test complete rpc failure"""
254
    hm = hooksmaster.HooksMaster.BuildFromLu(self._call_false, self.lu)
255
    self.failUnlessRaises(errors.HooksFailure,
256
                          hm.RunPhase, constants.HOOKS_PHASE_PRE)
257
    hm.RunPhase(constants.HOOKS_PHASE_POST)
258

    
259
  def testIndividualFalse(self):
260
    """Test individual node failure"""
261
    hm = hooksmaster.HooksMaster.BuildFromLu(self._call_nodes_false, self.lu)
262
    hm.RunPhase(constants.HOOKS_PHASE_PRE)
263
    #self.failUnlessRaises(errors.HooksFailure,
264
    #                      hm.RunPhase, constants.HOOKS_PHASE_PRE)
265
    hm.RunPhase(constants.HOOKS_PHASE_POST)
266

    
267
  def testScriptFalse(self):
268
    """Test individual rpc failure"""
269
    hm = hooksmaster.HooksMaster.BuildFromLu(self._call_script_fail, self.lu)
270
    self.failUnlessRaises(errors.HooksAbort,
271
                          hm.RunPhase, constants.HOOKS_PHASE_PRE)
272
    hm.RunPhase(constants.HOOKS_PHASE_POST)
273

    
274
  def testScriptSucceed(self):
275
    """Test individual rpc failure"""
276
    hm = hooksmaster.HooksMaster.BuildFromLu(FakeHooksRpcSuccess, self.lu)
277
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
278
      hm.RunPhase(phase)
279

    
280

    
281
class FakeEnvLU(cmdlib.LogicalUnit):
282
  HPATH = "env_test_lu"
283
  HTYPE = constants.HTYPE_GROUP
284

    
285
  def __init__(self, *args):
286
    cmdlib.LogicalUnit.__init__(self, *args)
287
    self.hook_env = None
288

    
289
  def BuildHooksEnv(self):
290
    assert self.hook_env is not None
291
    return self.hook_env
292

    
293
  def BuildHooksNodes(self):
294
    return (["a"], ["a"])
295

    
296

    
297
class FakeNoHooksLU(cmdlib.NoHooksLU):
298
  pass
299

    
300

    
301
class TestHooksRunnerEnv(unittest.TestCase):
302
  def setUp(self):
303
    self._rpcs = []
304

    
305
    self.op = opcodes.OpTestDummy(result=False, messages=[], fail=False)
306
    self.lu = FakeEnvLU(FakeProc(), self.op, FakeContext(), None)
307

    
308
  def _HooksRpc(self, *args):
309
    self._rpcs.append(args)
310
    return FakeHooksRpcSuccess(*args)
311

    
312
  def _CheckEnv(self, env, phase, hpath):
313
    self.assertTrue(env["PATH"].startswith("/sbin"))
314
    self.assertEqual(env["GANETI_HOOKS_PHASE"], phase)
315
    self.assertEqual(env["GANETI_HOOKS_PATH"], hpath)
316
    self.assertEqual(env["GANETI_OP_CODE"], self.op.OP_ID)
317
    self.assertEqual(env["GANETI_HOOKS_VERSION"], str(constants.HOOKS_VERSION))
318
    self.assertEqual(env["GANETI_DATA_DIR"], pathutils.DATA_DIR)
319
    if "GANETI_OBJECT_TYPE" in env:
320
      self.assertEqual(env["GANETI_OBJECT_TYPE"], constants.HTYPE_GROUP)
321
    else:
322
      self.assertTrue(self.lu.HTYPE is None)
323

    
324
  def testEmptyEnv(self):
325
    # Check pre-phase hook
326
    self.lu.hook_env = {}
327
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
328
    hm.RunPhase(constants.HOOKS_PHASE_PRE)
329

    
330
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
331
    self.assertEqual(node_list, set(["node_a.example.com"]))
332
    self.assertEqual(hpath, self.lu.HPATH)
333
    self.assertEqual(phase, constants.HOOKS_PHASE_PRE)
334
    self._CheckEnv(env, constants.HOOKS_PHASE_PRE, self.lu.HPATH)
335

    
336
    # Check post-phase hook
337
    self.lu.hook_env = {}
338
    hm.RunPhase(constants.HOOKS_PHASE_POST)
339

    
340
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
341
    self.assertEqual(node_list, set(["node_a.example.com"]))
342
    self.assertEqual(hpath, self.lu.HPATH)
343
    self.assertEqual(phase, constants.HOOKS_PHASE_POST)
344
    self._CheckEnv(env, constants.HOOKS_PHASE_POST, self.lu.HPATH)
345

    
346
    self.assertRaises(IndexError, self._rpcs.pop)
347

    
348
  def testEnv(self):
349
    # Check pre-phase hook
350
    self.lu.hook_env = {
351
      "FOO": "pre-foo-value",
352
      }
353
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
354
    hm.RunPhase(constants.HOOKS_PHASE_PRE)
355

    
356
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
357
    self.assertEqual(node_list, set(["node_a.example.com"]))
358
    self.assertEqual(hpath, self.lu.HPATH)
359
    self.assertEqual(phase, constants.HOOKS_PHASE_PRE)
360
    self.assertEqual(env["GANETI_FOO"], "pre-foo-value")
361
    self.assertFalse(compat.any(key.startswith("GANETI_POST") for key in env))
362
    self._CheckEnv(env, constants.HOOKS_PHASE_PRE, self.lu.HPATH)
363

    
364
    # Check post-phase hook
365
    self.lu.hook_env = {
366
      "FOO": "post-value",
367
      "BAR": 123,
368
      }
369
    hm.RunPhase(constants.HOOKS_PHASE_POST)
370

    
371
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
372
    self.assertEqual(node_list, set(["node_a.example.com"]))
373
    self.assertEqual(hpath, self.lu.HPATH)
374
    self.assertEqual(phase, constants.HOOKS_PHASE_POST)
375
    self.assertEqual(env["GANETI_FOO"], "pre-foo-value")
376
    self.assertEqual(env["GANETI_POST_FOO"], "post-value")
377
    self.assertEqual(env["GANETI_POST_BAR"], "123")
378
    self.assertFalse("GANETI_BAR" in env)
379
    self._CheckEnv(env, constants.HOOKS_PHASE_POST, self.lu.HPATH)
380

    
381
    self.assertRaises(IndexError, self._rpcs.pop)
382

    
383
    # Check configuration update hook
384
    hm.RunConfigUpdate()
385
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
386
    self.assertEqual(set(node_list), set([self.lu.cfg.GetMasterNodeName()]))
387
    self.assertEqual(hpath, constants.HOOKS_NAME_CFGUPDATE)
388
    self.assertEqual(phase, constants.HOOKS_PHASE_POST)
389
    self._CheckEnv(env, constants.HOOKS_PHASE_POST,
390
                   constants.HOOKS_NAME_CFGUPDATE)
391
    self.assertFalse(compat.any(key.startswith("GANETI_POST") for key in env))
392
    self.assertEqual(env["GANETI_FOO"], "pre-foo-value")
393
    self.assertRaises(IndexError, self._rpcs.pop)
394

    
395
  def testConflict(self):
396
    for name in ["DATA_DIR", "OP_CODE"]:
397
      self.lu.hook_env = { name: "value" }
398

    
399
      # Test using a clean HooksMaster instance
400
      hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
401

    
402
      for phase in [constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST]:
403
        self.assertRaises(AssertionError, hm.RunPhase, phase)
404
        self.assertRaises(IndexError, self._rpcs.pop)
405

    
406
  def testNoNodes(self):
407
    self.lu.hook_env = {}
408
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
409
    hm.RunPhase(constants.HOOKS_PHASE_PRE, node_names=[])
410
    self.assertRaises(IndexError, self._rpcs.pop)
411

    
412
  def testSpecificNodes(self):
413
    self.lu.hook_env = {}
414

    
415
    nodes = [
416
      "node1.example.com",
417
      "node93782.example.net",
418
      ]
419

    
420
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
421

    
422
    for phase in [constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST]:
423
      hm.RunPhase(phase, node_names=nodes)
424

    
425
      (node_list, hpath, rpc_phase, env) = self._rpcs.pop(0)
426
      self.assertEqual(set(node_list), set(nodes))
427
      self.assertEqual(hpath, self.lu.HPATH)
428
      self.assertEqual(rpc_phase, phase)
429
      self._CheckEnv(env, phase, self.lu.HPATH)
430

    
431
      self.assertRaises(IndexError, self._rpcs.pop)
432

    
433
  def testRunConfigUpdateNoPre(self):
434
    self.lu.hook_env = {
435
      "FOO": "value",
436
      }
437

    
438
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
439
    hm.RunConfigUpdate()
440

    
441
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
442
    self.assertEqual(set(node_list), set([self.lu.cfg.GetMasterNodeName()]))
443
    self.assertEqual(hpath, constants.HOOKS_NAME_CFGUPDATE)
444
    self.assertEqual(phase, constants.HOOKS_PHASE_POST)
445
    self.assertEqual(env["GANETI_FOO"], "value")
446
    self.assertFalse(compat.any(key.startswith("GANETI_POST") for key in env))
447
    self._CheckEnv(env, constants.HOOKS_PHASE_POST,
448
                   constants.HOOKS_NAME_CFGUPDATE)
449

    
450
    self.assertRaises(IndexError, self._rpcs.pop)
451

    
452
  def testNoPreBeforePost(self):
453
    self.lu.hook_env = {
454
      "FOO": "value",
455
      }
456

    
457
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
458
    hm.RunPhase(constants.HOOKS_PHASE_POST)
459

    
460
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
461
    self.assertEqual(node_list, set(["node_a.example.com"]))
462
    self.assertEqual(hpath, self.lu.HPATH)
463
    self.assertEqual(phase, constants.HOOKS_PHASE_POST)
464
    self.assertEqual(env["GANETI_FOO"], "value")
465
    self.assertEqual(env["GANETI_POST_FOO"], "value")
466
    self._CheckEnv(env, constants.HOOKS_PHASE_POST, self.lu.HPATH)
467

    
468
    self.assertRaises(IndexError, self._rpcs.pop)
469

    
470
  def testNoHooksLU(self):
471
    self.lu = FakeNoHooksLU(FakeProc(), self.op, FakeContext(), None)
472
    self.assertRaises(AssertionError, self.lu.BuildHooksEnv)
473
    self.assertRaises(AssertionError, self.lu.BuildHooksNodes)
474

    
475
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
476
    self.assertEqual(hm.pre_env, {})
477
    self.assertRaises(IndexError, self._rpcs.pop)
478

    
479
    hm.RunPhase(constants.HOOKS_PHASE_PRE)
480
    self.assertRaises(IndexError, self._rpcs.pop)
481

    
482
    hm.RunPhase(constants.HOOKS_PHASE_POST)
483
    self.assertRaises(IndexError, self._rpcs.pop)
484

    
485
    hm.RunConfigUpdate()
486

    
487
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
488
    self.assertEqual(set(node_list), set([self.lu.cfg.GetMasterNodeName()]))
489
    self.assertEqual(hpath, constants.HOOKS_NAME_CFGUPDATE)
490
    self.assertEqual(phase, constants.HOOKS_PHASE_POST)
491
    self.assertFalse(compat.any(key.startswith("GANETI_POST") for key in env))
492
    self._CheckEnv(env, constants.HOOKS_PHASE_POST,
493
                   constants.HOOKS_NAME_CFGUPDATE)
494
    self.assertRaises(IndexError, self._rpcs.pop)
495

    
496
    assert isinstance(self.lu, FakeNoHooksLU), "LU was replaced"
497

    
498

    
499
class FakeEnvWithCustomPostHookNodesLU(cmdlib.LogicalUnit):
500
  HPATH = "env_test_lu"
501
  HTYPE = constants.HTYPE_GROUP
502

    
503
  def __init__(self, *args):
504
    cmdlib.LogicalUnit.__init__(self, *args)
505

    
506
  def BuildHooksEnv(self):
507
    return {}
508

    
509
  def BuildHooksNodes(self):
510
    return (["a"], ["a"])
511

    
512
  def PreparePostHookNodes(self, post_hook_node_uuids):
513
    return post_hook_node_uuids + ["b"]
514

    
515

    
516
class TestHooksRunnerEnv(unittest.TestCase):
517
  def setUp(self):
518
    self._rpcs = []
519

    
520
    self.op = opcodes.OpTestDummy(result=False, messages=[], fail=False)
521
    self.lu = FakeEnvWithCustomPostHookNodesLU(FakeProc(), self.op,
522
                                               FakeContext(), None,
523
                                               (123, "/foo/bar"),
524
                                               None)
525

    
526
  def _HooksRpc(self, *args):
527
    self._rpcs.append(args)
528
    return FakeHooksRpcSuccess(*args)
529

    
530
  def testEmptyEnv(self):
531
    # Check pre-phase hook
532
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
533
    hm.RunPhase(constants.HOOKS_PHASE_PRE)
534

    
535
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
536
    self.assertEqual(node_list, set(["a"]))
537

    
538
    # Check post-phase hook
539
    hm.RunPhase(constants.HOOKS_PHASE_POST)
540

    
541
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
542
    self.assertEqual(node_list, set(["a", "b"]))
543

    
544
    self.assertRaises(IndexError, self._rpcs.pop)
545

    
546

    
547
if __name__ == "__main__":
548
  testutils.GanetiTestProgram()