Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.utils.process_unittest.py @ 7578ab0a

History | View | Annotate | Download (22.8 kB)

1 a4ccecf6 Michael Hanselmann
#!/usr/bin/python
2 a4ccecf6 Michael Hanselmann
#
3 a4ccecf6 Michael Hanselmann
4 a4ccecf6 Michael Hanselmann
# Copyright (C) 2011 Google Inc.
5 a4ccecf6 Michael Hanselmann
#
6 a4ccecf6 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 a4ccecf6 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 a4ccecf6 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 a4ccecf6 Michael Hanselmann
# (at your option) any later version.
10 a4ccecf6 Michael Hanselmann
#
11 a4ccecf6 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 a4ccecf6 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a4ccecf6 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a4ccecf6 Michael Hanselmann
# General Public License for more details.
15 a4ccecf6 Michael Hanselmann
#
16 a4ccecf6 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 a4ccecf6 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 a4ccecf6 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a4ccecf6 Michael Hanselmann
# 02110-1301, USA.
20 a4ccecf6 Michael Hanselmann
21 a4ccecf6 Michael Hanselmann
22 a4ccecf6 Michael Hanselmann
"""Script for testing ganeti.utils.process"""
23 a4ccecf6 Michael Hanselmann
24 a4ccecf6 Michael Hanselmann
import unittest
25 a4ccecf6 Michael Hanselmann
import tempfile
26 a4ccecf6 Michael Hanselmann
import shutil
27 a4ccecf6 Michael Hanselmann
import os
28 a4ccecf6 Michael Hanselmann
import stat
29 a4ccecf6 Michael Hanselmann
import time
30 d6491981 René Nussbaumer
import select
31 a4ccecf6 Michael Hanselmann
import signal
32 a4ccecf6 Michael Hanselmann
33 a4ccecf6 Michael Hanselmann
from ganeti import constants
34 a4ccecf6 Michael Hanselmann
from ganeti import utils
35 a4ccecf6 Michael Hanselmann
from ganeti import errors
36 a4ccecf6 Michael Hanselmann
37 a4ccecf6 Michael Hanselmann
import testutils
38 a4ccecf6 Michael Hanselmann
39 a4ccecf6 Michael Hanselmann
40 a4ccecf6 Michael Hanselmann
class TestIsProcessAlive(unittest.TestCase):
41 a4ccecf6 Michael Hanselmann
  """Testing case for IsProcessAlive"""
42 a4ccecf6 Michael Hanselmann
43 a4ccecf6 Michael Hanselmann
  def testExists(self):
44 a4ccecf6 Michael Hanselmann
    mypid = os.getpid()
45 a4ccecf6 Michael Hanselmann
    self.assert_(utils.IsProcessAlive(mypid), "can't find myself running")
46 a4ccecf6 Michael Hanselmann
47 a4ccecf6 Michael Hanselmann
  def testNotExisting(self):
48 a4ccecf6 Michael Hanselmann
    pid_non_existing = os.fork()
49 a4ccecf6 Michael Hanselmann
    if pid_non_existing == 0:
50 a4ccecf6 Michael Hanselmann
      os._exit(0)
51 a4ccecf6 Michael Hanselmann
    elif pid_non_existing < 0:
52 a4ccecf6 Michael Hanselmann
      raise SystemError("can't fork")
53 a4ccecf6 Michael Hanselmann
    os.waitpid(pid_non_existing, 0)
54 a4ccecf6 Michael Hanselmann
    self.assertFalse(utils.IsProcessAlive(pid_non_existing),
55 a4ccecf6 Michael Hanselmann
                     "nonexisting process detected")
56 a4ccecf6 Michael Hanselmann
57 a4ccecf6 Michael Hanselmann
58 a4ccecf6 Michael Hanselmann
class TestGetProcStatusPath(unittest.TestCase):
59 a4ccecf6 Michael Hanselmann
  def test(self):
60 a4ccecf6 Michael Hanselmann
    self.assert_("/1234/" in utils.process._GetProcStatusPath(1234))
61 a4ccecf6 Michael Hanselmann
    self.assertNotEqual(utils.process._GetProcStatusPath(1),
62 a4ccecf6 Michael Hanselmann
                        utils.process._GetProcStatusPath(2))
63 a4ccecf6 Michael Hanselmann
64 a4ccecf6 Michael Hanselmann
65 a4ccecf6 Michael Hanselmann
class TestIsProcessHandlingSignal(unittest.TestCase):
66 a4ccecf6 Michael Hanselmann
  def setUp(self):
67 a4ccecf6 Michael Hanselmann
    self.tmpdir = tempfile.mkdtemp()
68 a4ccecf6 Michael Hanselmann
69 a4ccecf6 Michael Hanselmann
  def tearDown(self):
70 a4ccecf6 Michael Hanselmann
    shutil.rmtree(self.tmpdir)
71 a4ccecf6 Michael Hanselmann
72 a4ccecf6 Michael Hanselmann
  def testParseSigsetT(self):
73 a4ccecf6 Michael Hanselmann
    parse_sigset_t_fn = utils.process._ParseSigsetT
74 a4ccecf6 Michael Hanselmann
    self.assertEqual(len(parse_sigset_t_fn("0")), 0)
75 a4ccecf6 Michael Hanselmann
    self.assertEqual(parse_sigset_t_fn("1"), set([1]))
76 a4ccecf6 Michael Hanselmann
    self.assertEqual(parse_sigset_t_fn("1000a"), set([2, 4, 17]))
77 a4ccecf6 Michael Hanselmann
    self.assertEqual(parse_sigset_t_fn("810002"), set([2, 17, 24, ]))
78 a4ccecf6 Michael Hanselmann
    self.assertEqual(parse_sigset_t_fn("0000000180000202"),
79 a4ccecf6 Michael Hanselmann
                     set([2, 10, 32, 33]))
80 a4ccecf6 Michael Hanselmann
    self.assertEqual(parse_sigset_t_fn("0000000180000002"),
81 a4ccecf6 Michael Hanselmann
                     set([2, 32, 33]))
82 a4ccecf6 Michael Hanselmann
    self.assertEqual(parse_sigset_t_fn("0000000188000002"),
83 a4ccecf6 Michael Hanselmann
                     set([2, 28, 32, 33]))
84 a4ccecf6 Michael Hanselmann
    self.assertEqual(parse_sigset_t_fn("000000004b813efb"),
85 a4ccecf6 Michael Hanselmann
                     set([1, 2, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 17,
86 a4ccecf6 Michael Hanselmann
                          24, 25, 26, 28, 31]))
87 a4ccecf6 Michael Hanselmann
    self.assertEqual(parse_sigset_t_fn("ffffff"), set(range(1, 25)))
88 a4ccecf6 Michael Hanselmann
89 a4ccecf6 Michael Hanselmann
  def testGetProcStatusField(self):
90 a4ccecf6 Michael Hanselmann
    for field in ["SigCgt", "Name", "FDSize"]:
91 a4ccecf6 Michael Hanselmann
      for value in ["", "0", "cat", "  1234 KB"]:
92 a4ccecf6 Michael Hanselmann
        pstatus = "\n".join([
93 a4ccecf6 Michael Hanselmann
          "VmPeak: 999 kB",
94 a4ccecf6 Michael Hanselmann
          "%s: %s" % (field, value),
95 a4ccecf6 Michael Hanselmann
          "TracerPid: 0",
96 a4ccecf6 Michael Hanselmann
          ])
97 a4ccecf6 Michael Hanselmann
        result = utils.process._GetProcStatusField(pstatus, field)
98 a4ccecf6 Michael Hanselmann
        self.assertEqual(result, value.strip())
99 a4ccecf6 Michael Hanselmann
100 a4ccecf6 Michael Hanselmann
  def test(self):
101 a4ccecf6 Michael Hanselmann
    sp = utils.PathJoin(self.tmpdir, "status")
102 a4ccecf6 Michael Hanselmann
103 a4ccecf6 Michael Hanselmann
    utils.WriteFile(sp, data="\n".join([
104 a4ccecf6 Michael Hanselmann
      "Name:   bash",
105 a4ccecf6 Michael Hanselmann
      "State:  S (sleeping)",
106 a4ccecf6 Michael Hanselmann
      "SleepAVG:       98%",
107 a4ccecf6 Michael Hanselmann
      "Pid:    22250",
108 a4ccecf6 Michael Hanselmann
      "PPid:   10858",
109 a4ccecf6 Michael Hanselmann
      "TracerPid:      0",
110 a4ccecf6 Michael Hanselmann
      "SigBlk: 0000000000010000",
111 a4ccecf6 Michael Hanselmann
      "SigIgn: 0000000000384004",
112 a4ccecf6 Michael Hanselmann
      "SigCgt: 000000004b813efb",
113 a4ccecf6 Michael Hanselmann
      "CapEff: 0000000000000000",
114 a4ccecf6 Michael Hanselmann
      ]))
115 a4ccecf6 Michael Hanselmann
116 a4ccecf6 Michael Hanselmann
    self.assert_(utils.IsProcessHandlingSignal(1234, 10, status_path=sp))
117 a4ccecf6 Michael Hanselmann
118 a4ccecf6 Michael Hanselmann
  def testNoSigCgt(self):
119 a4ccecf6 Michael Hanselmann
    sp = utils.PathJoin(self.tmpdir, "status")
120 a4ccecf6 Michael Hanselmann
121 a4ccecf6 Michael Hanselmann
    utils.WriteFile(sp, data="\n".join([
122 a4ccecf6 Michael Hanselmann
      "Name:   bash",
123 a4ccecf6 Michael Hanselmann
      ]))
124 a4ccecf6 Michael Hanselmann
125 a4ccecf6 Michael Hanselmann
    self.assertRaises(RuntimeError, utils.IsProcessHandlingSignal,
126 a4ccecf6 Michael Hanselmann
                      1234, 10, status_path=sp)
127 a4ccecf6 Michael Hanselmann
128 a4ccecf6 Michael Hanselmann
  def testNoSuchFile(self):
129 a4ccecf6 Michael Hanselmann
    sp = utils.PathJoin(self.tmpdir, "notexist")
130 a4ccecf6 Michael Hanselmann
131 a4ccecf6 Michael Hanselmann
    self.assertFalse(utils.IsProcessHandlingSignal(1234, 10, status_path=sp))
132 a4ccecf6 Michael Hanselmann
133 a4ccecf6 Michael Hanselmann
  @staticmethod
134 a4ccecf6 Michael Hanselmann
  def _TestRealProcess():
135 a4ccecf6 Michael Hanselmann
    signal.signal(signal.SIGUSR1, signal.SIG_DFL)
136 a4ccecf6 Michael Hanselmann
    if utils.IsProcessHandlingSignal(os.getpid(), signal.SIGUSR1):
137 a4ccecf6 Michael Hanselmann
      raise Exception("SIGUSR1 is handled when it should not be")
138 a4ccecf6 Michael Hanselmann
139 a4ccecf6 Michael Hanselmann
    signal.signal(signal.SIGUSR1, lambda signum, frame: None)
140 a4ccecf6 Michael Hanselmann
    if not utils.IsProcessHandlingSignal(os.getpid(), signal.SIGUSR1):
141 a4ccecf6 Michael Hanselmann
      raise Exception("SIGUSR1 is not handled when it should be")
142 a4ccecf6 Michael Hanselmann
143 a4ccecf6 Michael Hanselmann
    signal.signal(signal.SIGUSR1, signal.SIG_IGN)
144 a4ccecf6 Michael Hanselmann
    if utils.IsProcessHandlingSignal(os.getpid(), signal.SIGUSR1):
145 a4ccecf6 Michael Hanselmann
      raise Exception("SIGUSR1 is not handled when it should be")
146 a4ccecf6 Michael Hanselmann
147 a4ccecf6 Michael Hanselmann
    signal.signal(signal.SIGUSR1, signal.SIG_DFL)
148 a4ccecf6 Michael Hanselmann
    if utils.IsProcessHandlingSignal(os.getpid(), signal.SIGUSR1):
149 a4ccecf6 Michael Hanselmann
      raise Exception("SIGUSR1 is handled when it should not be")
150 a4ccecf6 Michael Hanselmann
151 a4ccecf6 Michael Hanselmann
    return True
152 a4ccecf6 Michael Hanselmann
153 a4ccecf6 Michael Hanselmann
  def testRealProcess(self):
154 a4ccecf6 Michael Hanselmann
    self.assert_(utils.RunInSeparateProcess(self._TestRealProcess))
155 a4ccecf6 Michael Hanselmann
156 a4ccecf6 Michael Hanselmann
157 d6491981 René Nussbaumer
class _PostforkProcessReadyHelper:
158 d6491981 René Nussbaumer
  """A helper to use with _postfork_fn in RunCmd.
159 d6491981 René Nussbaumer

160 d6491981 René Nussbaumer
  It makes sure a process has reached a certain state by reading from a fifo.
161 d6491981 René Nussbaumer

162 d6491981 René Nussbaumer
  @ivar write_fd: The fd number to write to
163 d6491981 René Nussbaumer

164 d6491981 René Nussbaumer
  """
165 d6491981 René Nussbaumer
  def __init__(self, timeout):
166 d6491981 René Nussbaumer
    """Initialize the helper.
167 d6491981 René Nussbaumer

168 d6491981 René Nussbaumer
    @param fifo_dir: The dir where we can create the fifo
169 d6491981 René Nussbaumer
    @param timeout: The time in seconds to wait before giving up
170 d6491981 René Nussbaumer

171 d6491981 René Nussbaumer
    """
172 d6491981 René Nussbaumer
    self.timeout = timeout
173 d6491981 René Nussbaumer
    (self.read_fd, self.write_fd) = os.pipe()
174 d6491981 René Nussbaumer
175 d6491981 René Nussbaumer
  def Ready(self, pid):
176 d6491981 René Nussbaumer
    """Waits until the process is ready.
177 d6491981 René Nussbaumer

178 d6491981 René Nussbaumer
    @param pid: The pid of the process
179 d6491981 René Nussbaumer

180 d6491981 René Nussbaumer
    """
181 d6491981 René Nussbaumer
    (read_ready, _, _) = select.select([self.read_fd], [], [], self.timeout)
182 d6491981 René Nussbaumer
183 d6491981 René Nussbaumer
    if not read_ready:
184 d6491981 René Nussbaumer
      # We hit the timeout
185 d6491981 René Nussbaumer
      raise AssertionError("Timeout %d reached while waiting for process %d"
186 d6491981 René Nussbaumer
                           " to become ready" % (self.timeout, pid))
187 d6491981 René Nussbaumer
188 d6491981 René Nussbaumer
  def Cleanup(self):
189 d6491981 René Nussbaumer
    """Cleans up the helper.
190 d6491981 René Nussbaumer

191 d6491981 René Nussbaumer
    """
192 d6491981 René Nussbaumer
    os.close(self.read_fd)
193 d6491981 René Nussbaumer
    os.close(self.write_fd)
194 d6491981 René Nussbaumer
195 d6491981 René Nussbaumer
196 a4ccecf6 Michael Hanselmann
class TestRunCmd(testutils.GanetiTestCase):
197 a4ccecf6 Michael Hanselmann
  """Testing case for the RunCmd function"""
198 a4ccecf6 Michael Hanselmann
199 a4ccecf6 Michael Hanselmann
  def setUp(self):
200 a4ccecf6 Michael Hanselmann
    testutils.GanetiTestCase.setUp(self)
201 a4ccecf6 Michael Hanselmann
    self.magic = time.ctime() + " ganeti test"
202 a4ccecf6 Michael Hanselmann
    self.fname = self._CreateTempFile()
203 a4ccecf6 Michael Hanselmann
    self.fifo_tmpdir = tempfile.mkdtemp()
204 a4ccecf6 Michael Hanselmann
    self.fifo_file = os.path.join(self.fifo_tmpdir, "ganeti_test_fifo")
205 a4ccecf6 Michael Hanselmann
    os.mkfifo(self.fifo_file)
206 a4ccecf6 Michael Hanselmann
207 d6491981 René Nussbaumer
    # If the process is not ready after 20 seconds we have bigger issues
208 d6491981 René Nussbaumer
    self.proc_ready_helper = _PostforkProcessReadyHelper(20)
209 d6491981 René Nussbaumer
210 a4ccecf6 Michael Hanselmann
  def tearDown(self):
211 d6491981 René Nussbaumer
    self.proc_ready_helper.Cleanup()
212 a4ccecf6 Michael Hanselmann
    shutil.rmtree(self.fifo_tmpdir)
213 a4ccecf6 Michael Hanselmann
    testutils.GanetiTestCase.tearDown(self)
214 a4ccecf6 Michael Hanselmann
215 a4ccecf6 Michael Hanselmann
  def testOk(self):
216 a4ccecf6 Michael Hanselmann
    """Test successful exit code"""
217 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd("/bin/sh -c 'exit 0'")
218 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.exit_code, 0)
219 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.output, "")
220 a4ccecf6 Michael Hanselmann
221 a4ccecf6 Michael Hanselmann
  def testFail(self):
222 a4ccecf6 Michael Hanselmann
    """Test fail exit code"""
223 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd("/bin/sh -c 'exit 1'")
224 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.exit_code, 1)
225 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.output, "")
226 a4ccecf6 Michael Hanselmann
227 a4ccecf6 Michael Hanselmann
  def testStdout(self):
228 a4ccecf6 Michael Hanselmann
    """Test standard output"""
229 a4ccecf6 Michael Hanselmann
    cmd = 'echo -n "%s"' % self.magic
230 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd("/bin/sh -c '%s'" % cmd)
231 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.stdout, self.magic)
232 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd("/bin/sh -c '%s'" % cmd, output=self.fname)
233 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.output, "")
234 a4ccecf6 Michael Hanselmann
    self.assertFileContent(self.fname, self.magic)
235 a4ccecf6 Michael Hanselmann
236 a4ccecf6 Michael Hanselmann
  def testStderr(self):
237 a4ccecf6 Michael Hanselmann
    """Test standard error"""
238 a4ccecf6 Michael Hanselmann
    cmd = 'echo -n "%s"' % self.magic
239 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd("/bin/sh -c '%s' 1>&2" % cmd)
240 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.stderr, self.magic)
241 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd("/bin/sh -c '%s' 1>&2" % cmd, output=self.fname)
242 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.output, "")
243 a4ccecf6 Michael Hanselmann
    self.assertFileContent(self.fname, self.magic)
244 a4ccecf6 Michael Hanselmann
245 a4ccecf6 Michael Hanselmann
  def testCombined(self):
246 a4ccecf6 Michael Hanselmann
    """Test combined output"""
247 a4ccecf6 Michael Hanselmann
    cmd = 'echo -n "A%s"; echo -n "B%s" 1>&2' % (self.magic, self.magic)
248 a4ccecf6 Michael Hanselmann
    expected = "A" + self.magic + "B" + self.magic
249 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd("/bin/sh -c '%s'" % cmd)
250 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.output, expected)
251 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd("/bin/sh -c '%s'" % cmd, output=self.fname)
252 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.output, "")
253 a4ccecf6 Michael Hanselmann
    self.assertFileContent(self.fname, expected)
254 a4ccecf6 Michael Hanselmann
255 a4ccecf6 Michael Hanselmann
  def testSignal(self):
256 a4ccecf6 Michael Hanselmann
    """Test signal"""
257 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd(["python", "-c",
258 a4ccecf6 Michael Hanselmann
                           "import os; os.kill(os.getpid(), 15)"])
259 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.signal, 15)
260 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.output, "")
261 a4ccecf6 Michael Hanselmann
262 a4ccecf6 Michael Hanselmann
  def testTimeoutClean(self):
263 d6491981 René Nussbaumer
    cmd = ("trap 'exit 0' TERM; echo >&%d; read < %s" %
264 d6491981 René Nussbaumer
           (self.proc_ready_helper.write_fd, self.fifo_file))
265 d6491981 René Nussbaumer
    result = utils.RunCmd(["/bin/sh", "-c", cmd], timeout=0.2,
266 d6491981 René Nussbaumer
                          noclose_fds=[self.proc_ready_helper.write_fd],
267 d6491981 René Nussbaumer
                          _postfork_fn=self.proc_ready_helper.Ready)
268 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.exit_code, 0)
269 a4ccecf6 Michael Hanselmann
270 a4ccecf6 Michael Hanselmann
  def testTimeoutKill(self):
271 d6491981 René Nussbaumer
    cmd = ["/bin/sh", "-c", "trap '' TERM; echo >&%d; read < %s" %
272 d6491981 René Nussbaumer
           (self.proc_ready_helper.write_fd, self.fifo_file)]
273 a4ccecf6 Michael Hanselmann
    timeout = 0.2
274 a4ccecf6 Michael Hanselmann
    (out, err, status, ta) = \
275 a4ccecf6 Michael Hanselmann
      utils.process._RunCmdPipe(cmd, {}, False, "/", False,
276 d6491981 René Nussbaumer
                                timeout, [self.proc_ready_helper.write_fd],
277 d6491981 René Nussbaumer
                                _linger_timeout=0.2,
278 d6491981 René Nussbaumer
                                _postfork_fn=self.proc_ready_helper.Ready)
279 a4ccecf6 Michael Hanselmann
    self.assert_(status < 0)
280 a4ccecf6 Michael Hanselmann
    self.assertEqual(-status, signal.SIGKILL)
281 a4ccecf6 Michael Hanselmann
282 a4ccecf6 Michael Hanselmann
  def testTimeoutOutputAfterTerm(self):
283 d6491981 René Nussbaumer
    cmd = ("trap 'echo sigtermed; exit 1' TERM; echo >&%d; read < %s" %
284 d6491981 René Nussbaumer
           (self.proc_ready_helper.write_fd, self.fifo_file))
285 d6491981 René Nussbaumer
    result = utils.RunCmd(["/bin/sh", "-c", cmd], timeout=0.2,
286 d6491981 René Nussbaumer
                          noclose_fds=[self.proc_ready_helper.write_fd],
287 d6491981 René Nussbaumer
                          _postfork_fn=self.proc_ready_helper.Ready)
288 a4ccecf6 Michael Hanselmann
    self.assert_(result.failed)
289 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.stdout, "sigtermed\n")
290 a4ccecf6 Michael Hanselmann
291 a4ccecf6 Michael Hanselmann
  def testListRun(self):
292 a4ccecf6 Michael Hanselmann
    """Test list runs"""
293 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd(["true"])
294 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.signal, None)
295 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.exit_code, 0)
296 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd(["/bin/sh", "-c", "exit 1"])
297 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.signal, None)
298 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.exit_code, 1)
299 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd(["echo", "-n", self.magic])
300 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.signal, None)
301 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.exit_code, 0)
302 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.stdout, self.magic)
303 a4ccecf6 Michael Hanselmann
304 a4ccecf6 Michael Hanselmann
  def testFileEmptyOutput(self):
305 a4ccecf6 Michael Hanselmann
    """Test file output"""
306 a4ccecf6 Michael Hanselmann
    result = utils.RunCmd(["true"], output=self.fname)
307 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.signal, None)
308 a4ccecf6 Michael Hanselmann
    self.assertEqual(result.exit_code, 0)
309 a4ccecf6 Michael Hanselmann
    self.assertFileContent(self.fname, "")
310 a4ccecf6 Michael Hanselmann
311 a4ccecf6 Michael Hanselmann
  def testLang(self):
312 a4ccecf6 Michael Hanselmann
    """Test locale environment"""
313 a4ccecf6 Michael Hanselmann
    old_env = os.environ.copy()
314 a4ccecf6 Michael Hanselmann
    try:
315 a4ccecf6 Michael Hanselmann
      os.environ["LANG"] = "en_US.UTF-8"
316 a4ccecf6 Michael Hanselmann
      os.environ["LC_ALL"] = "en_US.UTF-8"
317 a4ccecf6 Michael Hanselmann
      result = utils.RunCmd(["locale"])
318 a4ccecf6 Michael Hanselmann
      for line in result.output.splitlines():
319 a4ccecf6 Michael Hanselmann
        key, value = line.split("=", 1)
320 a4ccecf6 Michael Hanselmann
        # Ignore these variables, they're overridden by LC_ALL
321 a4ccecf6 Michael Hanselmann
        if key == "LANG" or key == "LANGUAGE":
322 a4ccecf6 Michael Hanselmann
          continue
323 a4ccecf6 Michael Hanselmann
        self.failIf(value and value != "C" and value != '"C"',
324 a4ccecf6 Michael Hanselmann
            "Variable %s is set to the invalid value '%s'" % (key, value))
325 a4ccecf6 Michael Hanselmann
    finally:
326 a4ccecf6 Michael Hanselmann
      os.environ = old_env
327 a4ccecf6 Michael Hanselmann
328 a4ccecf6 Michael Hanselmann
  def testDefaultCwd(self):
329 a4ccecf6 Michael Hanselmann
    """Test default working directory"""
330 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(utils.RunCmd(["pwd"]).stdout.strip(), "/")
331 a4ccecf6 Michael Hanselmann
332 a4ccecf6 Michael Hanselmann
  def testCwd(self):
333 a4ccecf6 Michael Hanselmann
    """Test default working directory"""
334 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(utils.RunCmd(["pwd"], cwd="/").stdout.strip(), "/")
335 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(utils.RunCmd(["pwd"], cwd="/tmp").stdout.strip(),
336 a4ccecf6 Michael Hanselmann
                         "/tmp")
337 a4ccecf6 Michael Hanselmann
    cwd = os.getcwd()
338 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(utils.RunCmd(["pwd"], cwd=cwd).stdout.strip(), cwd)
339 a4ccecf6 Michael Hanselmann
340 a4ccecf6 Michael Hanselmann
  def testResetEnv(self):
341 a4ccecf6 Michael Hanselmann
    """Test environment reset functionality"""
342 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(utils.RunCmd(["env"], reset_env=True).stdout.strip(),
343 a4ccecf6 Michael Hanselmann
                         "")
344 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(utils.RunCmd(["env"], reset_env=True,
345 a4ccecf6 Michael Hanselmann
                                      env={"FOO": "bar",}).stdout.strip(),
346 a4ccecf6 Michael Hanselmann
                         "FOO=bar")
347 a4ccecf6 Michael Hanselmann
348 a4ccecf6 Michael Hanselmann
  def testNoFork(self):
349 a4ccecf6 Michael Hanselmann
    """Test that nofork raise an error"""
350 a4ccecf6 Michael Hanselmann
    self.assertFalse(utils.process._no_fork)
351 a4ccecf6 Michael Hanselmann
    utils.DisableFork()
352 a4ccecf6 Michael Hanselmann
    try:
353 a4ccecf6 Michael Hanselmann
      self.assertTrue(utils.process._no_fork)
354 a4ccecf6 Michael Hanselmann
      self.assertRaises(errors.ProgrammerError, utils.RunCmd, ["true"])
355 a4ccecf6 Michael Hanselmann
    finally:
356 a4ccecf6 Michael Hanselmann
      utils.process._no_fork = False
357 a4ccecf6 Michael Hanselmann
    self.assertFalse(utils.process._no_fork)
358 a4ccecf6 Michael Hanselmann
359 a4ccecf6 Michael Hanselmann
  def testWrongParams(self):
360 a4ccecf6 Michael Hanselmann
    """Test wrong parameters"""
361 a4ccecf6 Michael Hanselmann
    self.assertRaises(errors.ProgrammerError, utils.RunCmd, ["true"],
362 a4ccecf6 Michael Hanselmann
                      output="/dev/null", interactive=True)
363 a4ccecf6 Michael Hanselmann
364 7b0bf9cd Apollon Oikonomopoulos
  def testNocloseFds(self):
365 7b0bf9cd Apollon Oikonomopoulos
    """Test selective fd retention (noclose_fds)"""
366 7b0bf9cd Apollon Oikonomopoulos
    temp = open(self.fname, "r+")
367 7b0bf9cd Apollon Oikonomopoulos
    try:
368 7b0bf9cd Apollon Oikonomopoulos
      temp.write("test")
369 7b0bf9cd Apollon Oikonomopoulos
      temp.seek(0)
370 7b0bf9cd Apollon Oikonomopoulos
      cmd = "read -u %d; echo $REPLY" % temp.fileno()
371 7b0bf9cd Apollon Oikonomopoulos
      result = utils.RunCmd(["/bin/bash", "-c", cmd])
372 7b0bf9cd Apollon Oikonomopoulos
      self.assertEqual(result.stdout.strip(), "")
373 7b0bf9cd Apollon Oikonomopoulos
      temp.seek(0)
374 7b0bf9cd Apollon Oikonomopoulos
      result = utils.RunCmd(["/bin/bash", "-c", cmd],
375 7b0bf9cd Apollon Oikonomopoulos
                            noclose_fds=[temp.fileno()])
376 7b0bf9cd Apollon Oikonomopoulos
      self.assertEqual(result.stdout.strip(), "test")
377 7b0bf9cd Apollon Oikonomopoulos
    finally:
378 7b0bf9cd Apollon Oikonomopoulos
      temp.close()
379 7b0bf9cd Apollon Oikonomopoulos
380 a4ccecf6 Michael Hanselmann
381 a4ccecf6 Michael Hanselmann
class TestRunParts(testutils.GanetiTestCase):
382 a4ccecf6 Michael Hanselmann
  """Testing case for the RunParts function"""
383 a4ccecf6 Michael Hanselmann
384 a4ccecf6 Michael Hanselmann
  def setUp(self):
385 a4ccecf6 Michael Hanselmann
    self.rundir = tempfile.mkdtemp(prefix="ganeti-test", suffix=".tmp")
386 a4ccecf6 Michael Hanselmann
387 a4ccecf6 Michael Hanselmann
  def tearDown(self):
388 a4ccecf6 Michael Hanselmann
    shutil.rmtree(self.rundir)
389 a4ccecf6 Michael Hanselmann
390 a4ccecf6 Michael Hanselmann
  def testEmpty(self):
391 a4ccecf6 Michael Hanselmann
    """Test on an empty dir"""
392 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(utils.RunParts(self.rundir, reset_env=True), [])
393 a4ccecf6 Michael Hanselmann
394 a4ccecf6 Michael Hanselmann
  def testSkipWrongName(self):
395 a4ccecf6 Michael Hanselmann
    """Test that wrong files are skipped"""
396 a4ccecf6 Michael Hanselmann
    fname = os.path.join(self.rundir, "00test.dot")
397 a4ccecf6 Michael Hanselmann
    utils.WriteFile(fname, data="")
398 a4ccecf6 Michael Hanselmann
    os.chmod(fname, stat.S_IREAD | stat.S_IEXEC)
399 a4ccecf6 Michael Hanselmann
    relname = os.path.basename(fname)
400 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(utils.RunParts(self.rundir, reset_env=True),
401 a4ccecf6 Michael Hanselmann
                         [(relname, constants.RUNPARTS_SKIP, None)])
402 a4ccecf6 Michael Hanselmann
403 a4ccecf6 Michael Hanselmann
  def testSkipNonExec(self):
404 a4ccecf6 Michael Hanselmann
    """Test that non executable files are skipped"""
405 a4ccecf6 Michael Hanselmann
    fname = os.path.join(self.rundir, "00test")
406 a4ccecf6 Michael Hanselmann
    utils.WriteFile(fname, data="")
407 a4ccecf6 Michael Hanselmann
    relname = os.path.basename(fname)
408 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(utils.RunParts(self.rundir, reset_env=True),
409 a4ccecf6 Michael Hanselmann
                         [(relname, constants.RUNPARTS_SKIP, None)])
410 a4ccecf6 Michael Hanselmann
411 a4ccecf6 Michael Hanselmann
  def testError(self):
412 a4ccecf6 Michael Hanselmann
    """Test error on a broken executable"""
413 a4ccecf6 Michael Hanselmann
    fname = os.path.join(self.rundir, "00test")
414 a4ccecf6 Michael Hanselmann
    utils.WriteFile(fname, data="")
415 a4ccecf6 Michael Hanselmann
    os.chmod(fname, stat.S_IREAD | stat.S_IEXEC)
416 a4ccecf6 Michael Hanselmann
    (relname, status, error) = utils.RunParts(self.rundir, reset_env=True)[0]
417 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(relname, os.path.basename(fname))
418 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(status, constants.RUNPARTS_ERR)
419 a4ccecf6 Michael Hanselmann
    self.failUnless(error)
420 a4ccecf6 Michael Hanselmann
421 a4ccecf6 Michael Hanselmann
  def testSorted(self):
422 a4ccecf6 Michael Hanselmann
    """Test executions are sorted"""
423 a4ccecf6 Michael Hanselmann
    files = []
424 a4ccecf6 Michael Hanselmann
    files.append(os.path.join(self.rundir, "64test"))
425 a4ccecf6 Michael Hanselmann
    files.append(os.path.join(self.rundir, "00test"))
426 a4ccecf6 Michael Hanselmann
    files.append(os.path.join(self.rundir, "42test"))
427 a4ccecf6 Michael Hanselmann
428 a4ccecf6 Michael Hanselmann
    for fname in files:
429 a4ccecf6 Michael Hanselmann
      utils.WriteFile(fname, data="")
430 a4ccecf6 Michael Hanselmann
431 a4ccecf6 Michael Hanselmann
    results = utils.RunParts(self.rundir, reset_env=True)
432 a4ccecf6 Michael Hanselmann
433 a4ccecf6 Michael Hanselmann
    for fname in sorted(files):
434 a4ccecf6 Michael Hanselmann
      self.failUnlessEqual(os.path.basename(fname), results.pop(0)[0])
435 a4ccecf6 Michael Hanselmann
436 a4ccecf6 Michael Hanselmann
  def testOk(self):
437 a4ccecf6 Michael Hanselmann
    """Test correct execution"""
438 a4ccecf6 Michael Hanselmann
    fname = os.path.join(self.rundir, "00test")
439 a4ccecf6 Michael Hanselmann
    utils.WriteFile(fname, data="#!/bin/sh\n\necho -n ciao")
440 a4ccecf6 Michael Hanselmann
    os.chmod(fname, stat.S_IREAD | stat.S_IEXEC)
441 a4ccecf6 Michael Hanselmann
    (relname, status, runresult) = \
442 a4ccecf6 Michael Hanselmann
      utils.RunParts(self.rundir, reset_env=True)[0]
443 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(relname, os.path.basename(fname))
444 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(status, constants.RUNPARTS_RUN)
445 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(runresult.stdout, "ciao")
446 a4ccecf6 Michael Hanselmann
447 a4ccecf6 Michael Hanselmann
  def testRunFail(self):
448 a4ccecf6 Michael Hanselmann
    """Test correct execution, with run failure"""
449 a4ccecf6 Michael Hanselmann
    fname = os.path.join(self.rundir, "00test")
450 a4ccecf6 Michael Hanselmann
    utils.WriteFile(fname, data="#!/bin/sh\n\nexit 1")
451 a4ccecf6 Michael Hanselmann
    os.chmod(fname, stat.S_IREAD | stat.S_IEXEC)
452 a4ccecf6 Michael Hanselmann
    (relname, status, runresult) = \
453 a4ccecf6 Michael Hanselmann
      utils.RunParts(self.rundir, reset_env=True)[0]
454 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(relname, os.path.basename(fname))
455 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(status, constants.RUNPARTS_RUN)
456 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(runresult.exit_code, 1)
457 a4ccecf6 Michael Hanselmann
    self.failUnless(runresult.failed)
458 a4ccecf6 Michael Hanselmann
459 a4ccecf6 Michael Hanselmann
  def testRunMix(self):
460 a4ccecf6 Michael Hanselmann
    files = []
461 a4ccecf6 Michael Hanselmann
    files.append(os.path.join(self.rundir, "00test"))
462 a4ccecf6 Michael Hanselmann
    files.append(os.path.join(self.rundir, "42test"))
463 a4ccecf6 Michael Hanselmann
    files.append(os.path.join(self.rundir, "64test"))
464 a4ccecf6 Michael Hanselmann
    files.append(os.path.join(self.rundir, "99test"))
465 a4ccecf6 Michael Hanselmann
466 a4ccecf6 Michael Hanselmann
    files.sort()
467 a4ccecf6 Michael Hanselmann
468 a4ccecf6 Michael Hanselmann
    # 1st has errors in execution
469 a4ccecf6 Michael Hanselmann
    utils.WriteFile(files[0], data="#!/bin/sh\n\nexit 1")
470 a4ccecf6 Michael Hanselmann
    os.chmod(files[0], stat.S_IREAD | stat.S_IEXEC)
471 a4ccecf6 Michael Hanselmann
472 a4ccecf6 Michael Hanselmann
    # 2nd is skipped
473 a4ccecf6 Michael Hanselmann
    utils.WriteFile(files[1], data="")
474 a4ccecf6 Michael Hanselmann
475 a4ccecf6 Michael Hanselmann
    # 3rd cannot execute properly
476 a4ccecf6 Michael Hanselmann
    utils.WriteFile(files[2], data="")
477 a4ccecf6 Michael Hanselmann
    os.chmod(files[2], stat.S_IREAD | stat.S_IEXEC)
478 a4ccecf6 Michael Hanselmann
479 a4ccecf6 Michael Hanselmann
    # 4th execs
480 a4ccecf6 Michael Hanselmann
    utils.WriteFile(files[3], data="#!/bin/sh\n\necho -n ciao")
481 a4ccecf6 Michael Hanselmann
    os.chmod(files[3], stat.S_IREAD | stat.S_IEXEC)
482 a4ccecf6 Michael Hanselmann
483 a4ccecf6 Michael Hanselmann
    results = utils.RunParts(self.rundir, reset_env=True)
484 a4ccecf6 Michael Hanselmann
485 a4ccecf6 Michael Hanselmann
    (relname, status, runresult) = results[0]
486 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(relname, os.path.basename(files[0]))
487 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(status, constants.RUNPARTS_RUN)
488 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(runresult.exit_code, 1)
489 a4ccecf6 Michael Hanselmann
    self.failUnless(runresult.failed)
490 a4ccecf6 Michael Hanselmann
491 a4ccecf6 Michael Hanselmann
    (relname, status, runresult) = results[1]
492 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(relname, os.path.basename(files[1]))
493 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(status, constants.RUNPARTS_SKIP)
494 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(runresult, None)
495 a4ccecf6 Michael Hanselmann
496 a4ccecf6 Michael Hanselmann
    (relname, status, runresult) = results[2]
497 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(relname, os.path.basename(files[2]))
498 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(status, constants.RUNPARTS_ERR)
499 a4ccecf6 Michael Hanselmann
    self.failUnless(runresult)
500 a4ccecf6 Michael Hanselmann
501 a4ccecf6 Michael Hanselmann
    (relname, status, runresult) = results[3]
502 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(relname, os.path.basename(files[3]))
503 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(status, constants.RUNPARTS_RUN)
504 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(runresult.output, "ciao")
505 a4ccecf6 Michael Hanselmann
    self.failUnlessEqual(runresult.exit_code, 0)
506 a4ccecf6 Michael Hanselmann
    self.failUnless(not runresult.failed)
507 a4ccecf6 Michael Hanselmann
508 a4ccecf6 Michael Hanselmann
  def testMissingDirectory(self):
509 a4ccecf6 Michael Hanselmann
    nosuchdir = utils.PathJoin(self.rundir, "no/such/directory")
510 a4ccecf6 Michael Hanselmann
    self.assertEqual(utils.RunParts(nosuchdir), [])
511 a4ccecf6 Michael Hanselmann
512 a4ccecf6 Michael Hanselmann
513 a4ccecf6 Michael Hanselmann
class TestStartDaemon(testutils.GanetiTestCase):
514 a4ccecf6 Michael Hanselmann
  def setUp(self):
515 a4ccecf6 Michael Hanselmann
    self.tmpdir = tempfile.mkdtemp(prefix="ganeti-test")
516 a4ccecf6 Michael Hanselmann
    self.tmpfile = os.path.join(self.tmpdir, "test")
517 a4ccecf6 Michael Hanselmann
518 a4ccecf6 Michael Hanselmann
  def tearDown(self):
519 a4ccecf6 Michael Hanselmann
    shutil.rmtree(self.tmpdir)
520 a4ccecf6 Michael Hanselmann
521 a4ccecf6 Michael Hanselmann
  def testShell(self):
522 a4ccecf6 Michael Hanselmann
    utils.StartDaemon("echo Hello World > %s" % self.tmpfile)
523 a4ccecf6 Michael Hanselmann
    self._wait(self.tmpfile, 60.0, "Hello World")
524 a4ccecf6 Michael Hanselmann
525 a4ccecf6 Michael Hanselmann
  def testShellOutput(self):
526 a4ccecf6 Michael Hanselmann
    utils.StartDaemon("echo Hello World", output=self.tmpfile)
527 a4ccecf6 Michael Hanselmann
    self._wait(self.tmpfile, 60.0, "Hello World")
528 a4ccecf6 Michael Hanselmann
529 a4ccecf6 Michael Hanselmann
  def testNoShellNoOutput(self):
530 a4ccecf6 Michael Hanselmann
    utils.StartDaemon(["pwd"])
531 a4ccecf6 Michael Hanselmann
532 a4ccecf6 Michael Hanselmann
  def testNoShellNoOutputTouch(self):
533 a4ccecf6 Michael Hanselmann
    testfile = os.path.join(self.tmpdir, "check")
534 a4ccecf6 Michael Hanselmann
    self.failIf(os.path.exists(testfile))
535 a4ccecf6 Michael Hanselmann
    utils.StartDaemon(["touch", testfile])
536 a4ccecf6 Michael Hanselmann
    self._wait(testfile, 60.0, "")
537 a4ccecf6 Michael Hanselmann
538 a4ccecf6 Michael Hanselmann
  def testNoShellOutput(self):
539 a4ccecf6 Michael Hanselmann
    utils.StartDaemon(["pwd"], output=self.tmpfile)
540 a4ccecf6 Michael Hanselmann
    self._wait(self.tmpfile, 60.0, "/")
541 a4ccecf6 Michael Hanselmann
542 a4ccecf6 Michael Hanselmann
  def testNoShellOutputCwd(self):
543 a4ccecf6 Michael Hanselmann
    utils.StartDaemon(["pwd"], output=self.tmpfile, cwd=os.getcwd())
544 a4ccecf6 Michael Hanselmann
    self._wait(self.tmpfile, 60.0, os.getcwd())
545 a4ccecf6 Michael Hanselmann
546 a4ccecf6 Michael Hanselmann
  def testShellEnv(self):
547 a4ccecf6 Michael Hanselmann
    utils.StartDaemon("echo \"$GNT_TEST_VAR\"", output=self.tmpfile,
548 a4ccecf6 Michael Hanselmann
                      env={ "GNT_TEST_VAR": "Hello World", })
549 a4ccecf6 Michael Hanselmann
    self._wait(self.tmpfile, 60.0, "Hello World")
550 a4ccecf6 Michael Hanselmann
551 a4ccecf6 Michael Hanselmann
  def testNoShellEnv(self):
552 a4ccecf6 Michael Hanselmann
    utils.StartDaemon(["printenv", "GNT_TEST_VAR"], output=self.tmpfile,
553 a4ccecf6 Michael Hanselmann
                      env={ "GNT_TEST_VAR": "Hello World", })
554 a4ccecf6 Michael Hanselmann
    self._wait(self.tmpfile, 60.0, "Hello World")
555 a4ccecf6 Michael Hanselmann
556 a4ccecf6 Michael Hanselmann
  def testOutputFd(self):
557 a4ccecf6 Michael Hanselmann
    fd = os.open(self.tmpfile, os.O_WRONLY | os.O_CREAT)
558 a4ccecf6 Michael Hanselmann
    try:
559 a4ccecf6 Michael Hanselmann
      utils.StartDaemon(["pwd"], output_fd=fd, cwd=os.getcwd())
560 a4ccecf6 Michael Hanselmann
    finally:
561 a4ccecf6 Michael Hanselmann
      os.close(fd)
562 a4ccecf6 Michael Hanselmann
    self._wait(self.tmpfile, 60.0, os.getcwd())
563 a4ccecf6 Michael Hanselmann
564 a4ccecf6 Michael Hanselmann
  def testPid(self):
565 a4ccecf6 Michael Hanselmann
    pid = utils.StartDaemon("echo $$ > %s" % self.tmpfile)
566 a4ccecf6 Michael Hanselmann
    self._wait(self.tmpfile, 60.0, str(pid))
567 a4ccecf6 Michael Hanselmann
568 a4ccecf6 Michael Hanselmann
  def testPidFile(self):
569 a4ccecf6 Michael Hanselmann
    pidfile = os.path.join(self.tmpdir, "pid")
570 a4ccecf6 Michael Hanselmann
    checkfile = os.path.join(self.tmpdir, "abort")
571 a4ccecf6 Michael Hanselmann
572 a4ccecf6 Michael Hanselmann
    pid = utils.StartDaemon("while sleep 5; do :; done", pidfile=pidfile,
573 a4ccecf6 Michael Hanselmann
                            output=self.tmpfile)
574 a4ccecf6 Michael Hanselmann
    try:
575 a4ccecf6 Michael Hanselmann
      fd = os.open(pidfile, os.O_RDONLY)
576 a4ccecf6 Michael Hanselmann
      try:
577 a4ccecf6 Michael Hanselmann
        # Check file is locked
578 a4ccecf6 Michael Hanselmann
        self.assertRaises(errors.LockError, utils.LockFile, fd)
579 a4ccecf6 Michael Hanselmann
580 a4ccecf6 Michael Hanselmann
        pidtext = os.read(fd, 100)
581 a4ccecf6 Michael Hanselmann
      finally:
582 a4ccecf6 Michael Hanselmann
        os.close(fd)
583 a4ccecf6 Michael Hanselmann
584 a4ccecf6 Michael Hanselmann
      self.assertEqual(int(pidtext.strip()), pid)
585 a4ccecf6 Michael Hanselmann
586 a4ccecf6 Michael Hanselmann
      self.assert_(utils.IsProcessAlive(pid))
587 a4ccecf6 Michael Hanselmann
    finally:
588 a4ccecf6 Michael Hanselmann
      # No matter what happens, kill daemon
589 a4ccecf6 Michael Hanselmann
      utils.KillProcess(pid, timeout=5.0, waitpid=False)
590 a4ccecf6 Michael Hanselmann
      self.failIf(utils.IsProcessAlive(pid))
591 a4ccecf6 Michael Hanselmann
592 a4ccecf6 Michael Hanselmann
    self.assertEqual(utils.ReadFile(self.tmpfile), "")
593 a4ccecf6 Michael Hanselmann
594 a4ccecf6 Michael Hanselmann
  def _wait(self, path, timeout, expected):
595 a4ccecf6 Michael Hanselmann
    # Due to the asynchronous nature of daemon processes, polling is necessary.
596 a4ccecf6 Michael Hanselmann
    # A timeout makes sure the test doesn't hang forever.
597 a4ccecf6 Michael Hanselmann
    def _CheckFile():
598 a4ccecf6 Michael Hanselmann
      if not (os.path.isfile(path) and
599 a4ccecf6 Michael Hanselmann
              utils.ReadFile(path).strip() == expected):
600 a4ccecf6 Michael Hanselmann
        raise utils.RetryAgain()
601 a4ccecf6 Michael Hanselmann
602 a4ccecf6 Michael Hanselmann
    try:
603 a4ccecf6 Michael Hanselmann
      utils.Retry(_CheckFile, (0.01, 1.5, 1.0), timeout)
604 a4ccecf6 Michael Hanselmann
    except utils.RetryTimeout:
605 a4ccecf6 Michael Hanselmann
      self.fail("Apparently the daemon didn't run in %s seconds and/or"
606 a4ccecf6 Michael Hanselmann
                " didn't write the correct output" % timeout)
607 a4ccecf6 Michael Hanselmann
608 a4ccecf6 Michael Hanselmann
  def testError(self):
609 a4ccecf6 Michael Hanselmann
    self.assertRaises(errors.OpExecError, utils.StartDaemon,
610 a4ccecf6 Michael Hanselmann
                      ["./does-NOT-EXIST/here/0123456789"])
611 a4ccecf6 Michael Hanselmann
    self.assertRaises(errors.OpExecError, utils.StartDaemon,
612 a4ccecf6 Michael Hanselmann
                      ["./does-NOT-EXIST/here/0123456789"],
613 a4ccecf6 Michael Hanselmann
                      output=os.path.join(self.tmpdir, "DIR/NOT/EXIST"))
614 a4ccecf6 Michael Hanselmann
    self.assertRaises(errors.OpExecError, utils.StartDaemon,
615 a4ccecf6 Michael Hanselmann
                      ["./does-NOT-EXIST/here/0123456789"],
616 a4ccecf6 Michael Hanselmann
                      cwd=os.path.join(self.tmpdir, "DIR/NOT/EXIST"))
617 a4ccecf6 Michael Hanselmann
    self.assertRaises(errors.OpExecError, utils.StartDaemon,
618 a4ccecf6 Michael Hanselmann
                      ["./does-NOT-EXIST/here/0123456789"],
619 a4ccecf6 Michael Hanselmann
                      output=os.path.join(self.tmpdir, "DIR/NOT/EXIST"))
620 a4ccecf6 Michael Hanselmann
621 a4ccecf6 Michael Hanselmann
    fd = os.open(self.tmpfile, os.O_WRONLY | os.O_CREAT)
622 a4ccecf6 Michael Hanselmann
    try:
623 a4ccecf6 Michael Hanselmann
      self.assertRaises(errors.ProgrammerError, utils.StartDaemon,
624 a4ccecf6 Michael Hanselmann
                        ["./does-NOT-EXIST/here/0123456789"],
625 a4ccecf6 Michael Hanselmann
                        output=self.tmpfile, output_fd=fd)
626 a4ccecf6 Michael Hanselmann
    finally:
627 a4ccecf6 Michael Hanselmann
      os.close(fd)
628 a4ccecf6 Michael Hanselmann
629 a4ccecf6 Michael Hanselmann
630 a4ccecf6 Michael Hanselmann
class RunInSeparateProcess(unittest.TestCase):
631 a4ccecf6 Michael Hanselmann
  def test(self):
632 a4ccecf6 Michael Hanselmann
    for exp in [True, False]:
633 a4ccecf6 Michael Hanselmann
      def _child():
634 a4ccecf6 Michael Hanselmann
        return exp
635 a4ccecf6 Michael Hanselmann
636 a4ccecf6 Michael Hanselmann
      self.assertEqual(exp, utils.RunInSeparateProcess(_child))
637 a4ccecf6 Michael Hanselmann
638 a4ccecf6 Michael Hanselmann
  def testArgs(self):
639 a4ccecf6 Michael Hanselmann
    for arg in [0, 1, 999, "Hello World", (1, 2, 3)]:
640 a4ccecf6 Michael Hanselmann
      def _child(carg1, carg2):
641 a4ccecf6 Michael Hanselmann
        return carg1 == "Foo" and carg2 == arg
642 a4ccecf6 Michael Hanselmann
643 a4ccecf6 Michael Hanselmann
      self.assert_(utils.RunInSeparateProcess(_child, "Foo", arg))
644 a4ccecf6 Michael Hanselmann
645 a4ccecf6 Michael Hanselmann
  def testPid(self):
646 a4ccecf6 Michael Hanselmann
    parent_pid = os.getpid()
647 a4ccecf6 Michael Hanselmann
648 a4ccecf6 Michael Hanselmann
    def _check():
649 a4ccecf6 Michael Hanselmann
      return os.getpid() == parent_pid
650 a4ccecf6 Michael Hanselmann
651 a4ccecf6 Michael Hanselmann
    self.failIf(utils.RunInSeparateProcess(_check))
652 a4ccecf6 Michael Hanselmann
653 a4ccecf6 Michael Hanselmann
  def testSignal(self):
654 a4ccecf6 Michael Hanselmann
    def _kill():
655 a4ccecf6 Michael Hanselmann
      os.kill(os.getpid(), signal.SIGTERM)
656 a4ccecf6 Michael Hanselmann
657 a4ccecf6 Michael Hanselmann
    self.assertRaises(errors.GenericError,
658 a4ccecf6 Michael Hanselmann
                      utils.RunInSeparateProcess, _kill)
659 a4ccecf6 Michael Hanselmann
660 a4ccecf6 Michael Hanselmann
  def testException(self):
661 a4ccecf6 Michael Hanselmann
    def _exc():
662 a4ccecf6 Michael Hanselmann
      raise errors.GenericError("This is a test")
663 a4ccecf6 Michael Hanselmann
664 a4ccecf6 Michael Hanselmann
    self.assertRaises(errors.GenericError,
665 a4ccecf6 Michael Hanselmann
                      utils.RunInSeparateProcess, _exc)
666 a4ccecf6 Michael Hanselmann
667 a4ccecf6 Michael Hanselmann
668 a4ccecf6 Michael Hanselmann
if __name__ == "__main__":
669 a4ccecf6 Michael Hanselmann
  testutils.GanetiTestProgram()