1 # -*- coding: utf-8 -*-
3 from twisted.trial import unittest
5 from twisted.python import usage, runtime
6 from twisted.internet import utils
7 import os.path, re, sys
8 from cStringIO import StringIO
9 from allmydata.util import fileutil, pollmixin
10 from allmydata.util.encodingutil import unicode_to_argv, unicode_to_output, get_filesystem_encoding
11 from allmydata.scripts import runner
13 from allmydata.test import common_util
18 srcfile = allmydata.__file__
19 srcdir = os.path.dirname(os.path.dirname(os.path.realpath(srcfile)))
20 if os.path.normcase(srcdir).endswith('.egg'):
21 srcdir = os.path.dirname(srcdir)
22 elif os.path.normcase(os.path.basename(srcdir)) == 'site-packages':
23 srcdir = os.path.dirname(srcdir)
24 if re.search(r'python.+\..+', os.path.normcase(os.path.basename(srcdir))):
25 srcdir = os.path.dirname(srcdir)
26 if os.path.normcase(os.path.basename(srcdir)) == 'lib':
27 srcdir = os.path.dirname(srcdir)
29 rootdir = os.path.dirname(srcdir)
31 bintahoe = os.path.join(rootdir, 'bin', 'tahoe')
32 if sys.platform == "win32":
33 bintahoe += ".pyscript"
34 if not os.path.exists(bintahoe):
35 alt_bintahoe = os.path.join(rootdir, 'Scripts', 'tahoe.pyscript')
36 if os.path.exists(alt_bintahoe):
37 bintahoe = alt_bintahoe
41 def skip_if_cannot_run_bintahoe(self):
42 if "cygwin" in sys.platform.lower():
43 raise unittest.SkipTest("We don't know how to make this test work on cygwin: spawnProcess seems to hang forever. We don't know if 'bin/tahoe start' can be run on cygwin.")
44 if not os.path.exists(bintahoe):
45 raise unittest.SkipTest("The bin/tahoe script isn't to be found in the expected location (%s), and I don't want to test a 'tahoe' executable that I find somewhere else, in case it isn't the right executable for this version of Tahoe. Perhaps running 'setup.py build' again will help." % (bintahoe,))
47 def skip_if_cannot_daemonize(self):
48 self.skip_if_cannot_run_bintahoe()
49 if runtime.platformType == "win32":
50 # twistd on windows doesn't daemonize. cygwin should work normally.
51 raise unittest.SkipTest("twistd does not fork under windows")
54 class BinTahoe(common_util.SignalMixin, unittest.TestCase, SkipMixin):
55 def test_the_right_code(self):
57 root_from_cwd = os.path.normcase(os.path.normpath(os.path.join(cwd, "..")))
58 root_from_test = os.path.normcase(os.path.normpath(rootdir))
60 same = (root_from_cwd == root_from_test)
63 same = os.path.samefile(root_from_cwd, root_from_test)
64 except AttributeError, e:
68 msg = ("We seem to be testing the code at %r,\n"
69 "(according to the source filename %r),\n"
70 "but expected to be testing the code at %r.\n"
71 % (root_from_test, srcfile, root_from_cwd))
72 if (not isinstance(cwd, unicode) and
73 (os.path.normcase(os.path.normpath(cwd))).decode(get_filesystem_encoding(), 'replace')
74 != os.path.normcase(os.path.normpath(os.getcwdu()))):
75 msg += ("However, this may be a false alarm because the current directory path\n"
76 "is not representable in the filesystem encoding. Please run the tests\n"
77 "from the root of the Tahoe-LAFS distribution at a non-Unicode path.")
78 raise unittest.SkipTest(msg)
80 msg += "Please run the tests from the root of the Tahoe-LAFS distribution."
84 self.skip_if_cannot_run_bintahoe()
85 d = utils.getProcessOutputAndValue(bintahoe, args=["--version-and-path"], env=os.environ)
87 out, err, rc_or_sig = res
88 self.failUnlessEqual(rc_or_sig, 0, str(res))
90 # Fail unless the package is *this* version *and* was loaded from *this* source directory.
91 required_ver_and_path = "%s: %s (%s)" % (allmydata.__appname__, allmydata.__version__, srcdir)
92 self.failUnless(out.startswith(required_ver_and_path),
93 str((out, err, rc_or_sig, required_ver_and_path)))
95 self.failIfEqual(allmydata.__version__, "unknown",
96 "We don't know our version, because this distribution didn't come "
97 "with a _version.py and 'setup.py darcsver' hasn't been run.")
101 def test_unicode_arguments_and_output(self):
102 self.skip_if_cannot_run_bintahoe()
106 tricky_arg = unicode_to_argv(tricky, mangle=True)
107 tricky_out = unicode_to_output(tricky)
108 except UnicodeEncodeError:
109 raise unittest.SkipTest("A non-ASCII argument/output could not be encoded on this platform.")
111 d = utils.getProcessOutputAndValue(bintahoe, args=[tricky_arg], env=os.environ)
113 out, err, rc_or_sig = res
114 self.failUnlessEqual(rc_or_sig, 1, str(res))
115 self.failUnlessIn("Unknown command: "+tricky_out, out)
119 def test_run_with_python_options(self):
120 self.skip_if_cannot_run_bintahoe()
122 # -t is a harmless option that warns about tabs.
123 d = utils.getProcessOutputAndValue(sys.executable, args=['-t', bintahoe, '--version'],
126 out, err, rc_or_sig = res
127 self.failUnlessEqual(rc_or_sig, 0, str(res))
128 self.failUnless(out.startswith(allmydata.__appname__+':'), str(res))
132 def test_version_no_noise(self):
133 self.skip_if_cannot_run_bintahoe()
136 pkg_resources.require("Twisted>=9.0.0")
137 except pkg_resources.VersionConflict:
138 raise unittest.SkipTest("We pass this test only with Twisted >= v9.0.0")
140 d = utils.getProcessOutputAndValue(bintahoe, args=["--version"], env=os.environ)
142 out, err, rc_or_sig = res
143 self.failUnlessEqual(rc_or_sig, 0, str(res))
144 self.failUnless(out.startswith(allmydata.__appname__+':'), str(res))
145 self.failIfIn("DeprecationWarning", out, str(res))
146 self.failUnlessEqual(err, "", str(res))
151 class CreateNode(unittest.TestCase):
152 # exercise "tahoe create-node", create-introducer,
153 # create-key-generator, and create-stats-gatherer, by calling the
154 # corresponding code as a subroutine.
156 def workdir(self, name):
157 basedir = os.path.join("test_runner", "CreateNode", name)
158 fileutil.make_dirs(basedir)
161 def run_tahoe(self, argv):
162 out,err = StringIO(), StringIO()
163 rc = runner.runner(argv, stdout=out, stderr=err)
164 return rc, out.getvalue(), err.getvalue()
166 def do_create(self, kind):
167 basedir = self.workdir("test_" + kind)
168 command = "create-" + kind
169 is_client = kind in ("node", "client")
170 tac = is_client and "tahoe-client.tac" or ("tahoe-" + kind + ".tac")
172 n1 = os.path.join(basedir, command + "-n1")
173 argv = ["--quiet", command, "--basedir", n1]
174 rc, out, err = self.run_tahoe(argv)
175 self.failUnlessEqual(err, "")
176 self.failUnlessEqual(out, "")
177 self.failUnlessEqual(rc, 0)
178 self.failUnless(os.path.exists(n1))
179 self.failUnless(os.path.exists(os.path.join(n1, tac)))
182 # tahoe.cfg should exist, and should have storage enabled for
183 # 'create-node', and disabled for 'create-client'.
184 tahoe_cfg = os.path.join(n1, "tahoe.cfg")
185 self.failUnless(os.path.exists(tahoe_cfg))
186 content = open(tahoe_cfg).read()
188 self.failUnless("\n[storage]\nenabled = false\n" in content)
190 self.failUnless("\n[storage]\nenabled = true\n" in content)
192 # creating the node a second time should be rejected
193 rc, out, err = self.run_tahoe(argv)
194 self.failIfEqual(rc, 0, str((out, err, rc)))
195 self.failUnlessEqual(out, "")
196 self.failUnless("is not empty." in err)
198 # Fail if there is a non-empty line that doesn't end with a
200 for line in err.splitlines():
201 self.failIf(re.search("[\S][^\.!?]$", line), (line,))
203 # test that the non --basedir form works too
204 n2 = os.path.join(basedir, command + "-n2")
205 argv = ["--quiet", command, n2]
206 rc, out, err = self.run_tahoe(argv)
207 self.failUnlessEqual(err, "")
208 self.failUnlessEqual(out, "")
209 self.failUnlessEqual(rc, 0)
210 self.failUnless(os.path.exists(n2))
211 self.failUnless(os.path.exists(os.path.join(n2, tac)))
213 # test the --node-directory form
214 n3 = os.path.join(basedir, command + "-n3")
215 argv = ["--quiet", command, "--node-directory", n3]
216 rc, out, err = self.run_tahoe(argv)
217 self.failUnlessEqual(err, "")
218 self.failUnlessEqual(out, "")
219 self.failUnlessEqual(rc, 0)
220 self.failUnless(os.path.exists(n3))
221 self.failUnless(os.path.exists(os.path.join(n3, tac)))
223 # test the --multiple form
224 n4 = os.path.join(basedir, command + "-n4")
225 n5 = os.path.join(basedir, command + "-n5")
226 argv = ["--quiet", command, "--multiple", n4, n5]
227 rc, out, err = self.run_tahoe(argv)
228 self.failUnlessEqual(err, "")
229 self.failUnlessEqual(out, "")
230 self.failUnlessEqual(rc, 0)
231 self.failUnless(os.path.exists(n4))
232 self.failUnless(os.path.exists(os.path.join(n4, tac)))
233 self.failUnless(os.path.exists(n5))
234 self.failUnless(os.path.exists(os.path.join(n5, tac)))
236 # make sure it rejects too many arguments without --multiple
237 argv = [command, "basedir", "extraarg"]
238 self.failUnlessRaises(usage.UsageError,
242 # when creating a non-client, there is no default for the basedir
245 self.failUnlessRaises(usage.UsageError,
251 self.do_create("node")
253 def test_client(self):
254 # create-client should behave like create-node --no-storage.
255 self.do_create("client")
257 def test_introducer(self):
258 self.do_create("introducer")
260 def test_key_generator(self):
261 self.do_create("key-generator")
263 def test_stats_gatherer(self):
264 self.do_create("stats-gatherer")
266 def test_subcommands(self):
267 # no arguments should trigger a command listing, via UsageError
268 self.failUnlessRaises(usage.UsageError,
274 class RunNode(common_util.SignalMixin, unittest.TestCase, pollmixin.PollMixin,
276 # exercise "tahoe start", for both introducer, client node, and
277 # key-generator, by spawning "tahoe start" as a subprocess. This doesn't
278 # get us figleaf-based line-level coverage, but it does a better job of
279 # confirming that the user can actually run "./bin/tahoe start" and
280 # expect it to work. This verifies that bin/tahoe sets up PYTHONPATH and
281 # the like correctly.
283 # This doesn't work on cygwin (it hangs forever), so we skip this test
284 # when we're on cygwin. It is likely that "tahoe start" itself doesn't
285 # work on cygwin: twisted seems unable to provide a version of
286 # spawnProcess which really works there.
288 def workdir(self, name):
289 basedir = os.path.join("test_runner", "RunNode", name)
290 fileutil.make_dirs(basedir)
293 def test_introducer(self):
294 self.skip_if_cannot_daemonize()
295 basedir = self.workdir("test_introducer")
296 c1 = os.path.join(basedir, "c1")
297 HOTLINE_FILE = os.path.join(c1, "suicide_prevention_hotline")
298 TWISTD_PID_FILE = os.path.join(c1, "twistd.pid")
299 INTRODUCER_FURL_FILE = os.path.join(c1, "introducer.furl")
301 d = utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "create-introducer", "--basedir", c1], env=os.environ)
303 out, err, rc_or_sig = res
304 self.failUnlessEqual(rc_or_sig, 0)
305 # by writing this file, we get ten seconds before the node will
306 # exit. This insures that even if the test fails (and the 'stop'
307 # command doesn't work), the client should still terminate.
308 open(HOTLINE_FILE, "w").write("")
309 # now it's safe to start the node
312 def _then_start_the_node(res):
313 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "start", c1], env=os.environ)
314 d.addCallback(_then_start_the_node)
317 out, err, rc_or_sig = res
319 open(HOTLINE_FILE, "w").write("")
320 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
321 self.failUnlessEqual(rc_or_sig, 0, errstr)
322 self.failUnlessEqual(out, "", errstr)
323 # self.failUnlessEqual(err, "", errstr) # See test_client_no_noise -- for now we ignore noise.
325 # the parent (twistd) has exited. However, twistd writes the pid
326 # from the child, not the parent, so we can't expect twistd.pid
327 # to exist quite yet.
329 # the node is running, but it might not have made it past the
330 # first reactor turn yet, and if we kill it too early, it won't
331 # remove the twistd.pid file. So wait until it does something
332 # that we know it won't do until after the first turn.
335 def _node_has_started():
336 return os.path.exists(INTRODUCER_FURL_FILE)
337 d.addCallback(lambda res: self.poll(_node_has_started))
340 open(HOTLINE_FILE, "w").write("")
341 self.failUnless(os.path.exists(TWISTD_PID_FILE))
342 # rm this so we can detect when the second incarnation is ready
343 os.unlink(INTRODUCER_FURL_FILE)
344 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "restart", c1], env=os.environ)
345 d.addCallback(_started)
348 out, err, rc_or_sig = res
349 open(HOTLINE_FILE, "w").write("")
350 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
351 self.failUnlessEqual(rc_or_sig, 0, errstr)
352 self.failUnlessEqual(out, "", errstr)
353 # self.failUnlessEqual(err, "", errstr) # See test_client_no_noise -- for now we ignore noise.
356 # again, the second incarnation of the node might not be ready yet,
357 # so poll until it is
358 d.addCallback(lambda res: self.poll(_node_has_started))
360 # now we can kill it. TODO: On a slow machine, the node might kill
361 # itself before we get a chance too, especially if spawning the
362 # 'tahoe stop' command takes a while.
364 open(HOTLINE_FILE, "w").write("")
365 self.failUnless(os.path.exists(TWISTD_PID_FILE))
367 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "stop", c1], env=os.environ)
370 def _after_stopping(res):
371 out, err, rc_or_sig = res
372 open(HOTLINE_FILE, "w").write("")
373 # the parent has exited by now
374 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
375 self.failUnlessEqual(rc_or_sig, 0, errstr)
376 self.failUnlessEqual(out, "", errstr)
377 # self.failUnlessEqual(err, "", errstr) # See test_client_no_noise -- for now we ignore noise.
378 # the parent was supposed to poll and wait until it sees
379 # twistd.pid go away before it exits, so twistd.pid should be
381 self.failIf(os.path.exists(TWISTD_PID_FILE))
382 d.addCallback(_after_stopping)
384 def _remove_hotline(res):
385 os.unlink(HOTLINE_FILE)
387 d.addBoth(_remove_hotline)
389 test_introducer.timeout = 480 # This hit the 120-second timeout on "François Lenny-armv5tel", then it hit a 240-second timeout on our feisty2.5 buildslave: http://allmydata.org/buildbot/builders/feisty2.5/builds/2381/steps/test/logs/test.log
391 def test_client_no_noise(self):
392 self.skip_if_cannot_daemonize()
395 pkg_resources.require("Twisted>=9.0.0")
396 except pkg_resources.VersionConflict:
397 raise unittest.SkipTest("We pass this test only with Twisted >= v9.0.0")
398 basedir = self.workdir("test_client_no_noise")
399 c1 = os.path.join(basedir, "c1")
400 HOTLINE_FILE = os.path.join(c1, "suicide_prevention_hotline")
401 TWISTD_PID_FILE = os.path.join(c1, "twistd.pid")
402 PORTNUMFILE = os.path.join(c1, "client.port")
404 d = utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "create-client", "--basedir", c1, "--webport", "0"], env=os.environ)
406 out, err, rc_or_sig = res
407 errstr = "cc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
408 assert rc_or_sig == 0, errstr
409 self.failUnlessEqual(rc_or_sig, 0)
410 # By writing this file, we get forty seconds before the client will exit. This insures
411 # that even if the 'stop' command doesn't work (and the test fails), the client should
413 open(HOTLINE_FILE, "w").write("")
414 open(os.path.join(c1, "introducer.furl"), "w").write("pb://xrndsskn2zuuian5ltnxrte7lnuqdrkz@127.0.0.1:55617/introducer\n")
415 # now it's safe to start the node
419 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "start", c1], env=os.environ)
420 d.addCallback(_start)
423 out, err, rc_or_sig = res
424 errstr = "cc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
425 open(HOTLINE_FILE, "w").write("")
426 self.failUnlessEqual(rc_or_sig, 0, errstr)
427 self.failUnlessEqual(out, "", errstr) # If you emit noise, you fail this test.
428 self.failUnlessEqual(err, "", errstr)
430 # the parent (twistd) has exited. However, twistd writes the pid
431 # from the child, not the parent, so we can't expect twistd.pid
432 # to exist quite yet.
434 # the node is running, but it might not have made it past the
435 # first reactor turn yet, and if we kill it too early, it won't
436 # remove the twistd.pid file. So wait until it does something
437 # that we know it won't do until after the first turn.
440 def _node_has_started():
441 return os.path.exists(PORTNUMFILE)
442 d.addCallback(lambda res: self.poll(_node_has_started))
444 # now we can kill it. TODO: On a slow machine, the node might kill
445 # itself before we get a chance too, especially if spawning the
446 # 'tahoe stop' command takes a while.
448 self.failUnless(os.path.exists(TWISTD_PID_FILE), (TWISTD_PID_FILE, os.listdir(os.path.dirname(TWISTD_PID_FILE))))
449 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "stop", c1], env=os.environ)
453 def test_client(self):
454 self.skip_if_cannot_daemonize()
455 basedir = self.workdir("test_client")
456 c1 = os.path.join(basedir, "c1")
457 HOTLINE_FILE = os.path.join(c1, "suicide_prevention_hotline")
458 TWISTD_PID_FILE = os.path.join(c1, "twistd.pid")
459 PORTNUMFILE = os.path.join(c1, "client.port")
461 d = utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "create-node", "--basedir", c1, "--webport", "0"], env=os.environ)
463 out, err, rc_or_sig = res
464 self.failUnlessEqual(rc_or_sig, 0)
465 # By writing this file, we get sixty seconds before the client will exit. This insures
466 # that even if the 'stop' command doesn't work (and the test fails), the client should
468 open(HOTLINE_FILE, "w").write("")
469 open(os.path.join(c1, "introducer.furl"), "w").write("pb://xrndsskn2zuuian5ltnxrte7lnuqdrkz@127.0.0.1:55617/introducer\n")
470 # now it's safe to start the node
474 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "start", c1], env=os.environ)
475 d.addCallback(_start)
478 out, err, rc_or_sig = res
479 open(HOTLINE_FILE, "w").write("")
480 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
481 self.failUnlessEqual(rc_or_sig, 0, errstr)
482 self.failUnlessEqual(out, "", errstr)
483 # self.failUnlessEqual(err, "", errstr) # See test_client_no_noise -- for now we ignore noise.
485 # the parent (twistd) has exited. However, twistd writes the pid
486 # from the child, not the parent, so we can't expect twistd.pid
487 # to exist quite yet.
489 # the node is running, but it might not have made it past the
490 # first reactor turn yet, and if we kill it too early, it won't
491 # remove the twistd.pid file. So wait until it does something
492 # that we know it won't do until after the first turn.
495 def _node_has_started():
496 return os.path.exists(PORTNUMFILE)
497 d.addCallback(lambda res: self.poll(_node_has_started))
500 open(HOTLINE_FILE, "w").write("")
501 self.failUnless(os.path.exists(TWISTD_PID_FILE))
502 # rm this so we can detect when the second incarnation is ready
503 os.unlink(PORTNUMFILE)
505 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "restart", c1], env=os.environ)
506 d.addCallback(_started)
509 out, err, rc_or_sig = res
511 open(HOTLINE_FILE, "w").write("")
512 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
513 self.failUnlessEqual(rc_or_sig, 0, errstr)
514 self.failUnlessEqual(out, "", errstr)
515 # self.failUnlessEqual(err, "", errstr) # See test_client_no_noise -- for now we ignore noise.
518 # again, the second incarnation of the node might not be ready yet,
519 # so poll until it is
520 d.addCallback(lambda res: self.poll(_node_has_started))
522 # now we can kill it. TODO: On a slow machine, the node might kill
523 # itself before we get a chance too, especially if spawning the
524 # 'tahoe stop' command takes a while.
526 open(HOTLINE_FILE, "w").write("")
527 self.failUnless(os.path.exists(TWISTD_PID_FILE), (TWISTD_PID_FILE, os.listdir(os.path.dirname(TWISTD_PID_FILE))))
528 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "stop", c1], env=os.environ)
532 out, err, rc_or_sig = res
534 open(HOTLINE_FILE, "w").write("")
535 # the parent has exited by now
536 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
537 self.failUnlessEqual(rc_or_sig, 0, errstr)
538 self.failUnlessEqual(out, "", errstr)
539 # self.failUnlessEqual(err, "", errstr) # See test_client_no_noise -- for now we ignore noise.
540 # the parent was supposed to poll and wait until it sees
541 # twistd.pid go away before it exits, so twistd.pid should be
543 self.failIf(os.path.exists(TWISTD_PID_FILE))
545 def _remove_hotline(res):
546 os.unlink(HOTLINE_FILE)
548 d.addBoth(_remove_hotline)
551 def test_baddir(self):
552 self.skip_if_cannot_daemonize()
553 basedir = self.workdir("test_baddir")
554 fileutil.make_dirs(basedir)
556 d = utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "start", "--basedir", basedir], env=os.environ)
558 out, err, rc_or_sig = res
559 self.failUnlessEqual(rc_or_sig, 1)
560 self.failUnless("does not look like a node directory" in err, err)
563 def _then_stop_it(res):
564 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "stop", "--basedir", basedir], env=os.environ)
565 d.addCallback(_then_stop_it)
568 out, err, rc_or_sig = res
569 self.failUnlessEqual(rc_or_sig, 2)
570 self.failUnless("does not look like a running node directory" in err)
573 def _then_start_in_bogus_basedir(res):
574 not_a_dir = os.path.join(basedir, "bogus")
575 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "start", "--basedir", not_a_dir], env=os.environ)
576 d.addCallback(_then_start_in_bogus_basedir)
579 out, err, rc_or_sig = res
580 self.failUnlessEqual(rc_or_sig, 1)
581 self.failUnless("does not look like a directory at all" in err, err)
585 def test_keygen(self):
586 self.skip_if_cannot_daemonize()
587 basedir = self.workdir("test_keygen")
588 c1 = os.path.join(basedir, "c1")
589 TWISTD_PID_FILE = os.path.join(c1, "twistd.pid")
590 KEYGEN_FURL_FILE = os.path.join(c1, "key_generator.furl")
592 d = utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "create-key-generator", "--basedir", c1], env=os.environ)
594 out, err, rc_or_sig = res
595 self.failUnlessEqual(rc_or_sig, 0)
599 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "start", c1], env=os.environ)
600 d.addCallback(_start)
603 out, err, rc_or_sig = res
604 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
605 self.failUnlessEqual(rc_or_sig, 0, errstr)
606 self.failUnlessEqual(out, "", errstr)
607 # self.failUnlessEqual(err, "", errstr) # See test_client_no_noise -- for now we ignore noise.
609 # the parent (twistd) has exited. However, twistd writes the pid
610 # from the child, not the parent, so we can't expect twistd.pid
611 # to exist quite yet.
613 # the node is running, but it might not have made it past the
614 # first reactor turn yet, and if we kill it too early, it won't
615 # remove the twistd.pid file. So wait until it does something
616 # that we know it won't do until after the first turn.
619 def _node_has_started():
620 return os.path.exists(KEYGEN_FURL_FILE)
621 d.addCallback(lambda res: self.poll(_node_has_started))
624 self.failUnless(os.path.exists(TWISTD_PID_FILE))
625 # rm this so we can detect when the second incarnation is ready
626 os.unlink(KEYGEN_FURL_FILE)
627 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "restart", c1], env=os.environ)
628 d.addCallback(_started)
631 out, err, rc_or_sig = res
632 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
633 self.failUnlessEqual(rc_or_sig, 0, errstr)
634 self.failUnlessEqual(out, "", errstr)
635 # self.failUnlessEqual(err, "", errstr) # See test_client_no_noise -- for now we ignore noise.
638 # again, the second incarnation of the node might not be ready yet,
639 # so poll until it is
640 d.addCallback(lambda res: self.poll(_node_has_started))
642 # now we can kill it. TODO: On a slow machine, the node might kill
643 # itself before we get a chance too, especially if spawning the
644 # 'tahoe stop' command takes a while.
646 self.failUnless(os.path.exists(TWISTD_PID_FILE))
647 return utils.getProcessOutputAndValue(bintahoe, args=["--quiet", "stop", c1], env=os.environ)
651 out, err, rc_or_sig = res
652 # the parent has exited by now
653 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc_or_sig, out, err)
654 self.failUnlessEqual(rc_or_sig, 0, errstr)
655 self.failUnlessEqual(out, "", errstr)
656 # self.failUnlessEqual(err, "", errstr) # See test_client_no_noise -- for now we ignore noise.
657 # the parent was supposed to poll and wait until it sees
658 # twistd.pid go away before it exits, so twistd.pid should be
660 self.failIf(os.path.exists(TWISTD_PID_FILE))