2 from twisted.trial import unittest
4 from cStringIO import StringIO
5 from twisted.python import usage, runtime
6 from twisted.internet import defer
8 from allmydata.scripts import runner, debug
9 from allmydata.util import fileutil, testutil
11 class CreateNode(unittest.TestCase):
12 def workdir(self, name):
13 basedir = os.path.join("test_runner", "CreateNode", name)
14 fileutil.make_dirs(basedir)
17 def test_client(self):
18 basedir = self.workdir("test_client")
19 c1 = os.path.join(basedir, "c1")
20 argv = ["--quiet", "create-client", "--basedir", c1]
21 out,err = StringIO(), StringIO()
22 rc = runner.runner(argv, stdout=out, stderr=err)
23 self.failUnlessEqual(err.getvalue(), "")
24 self.failUnlessEqual(out.getvalue(), "")
25 self.failUnlessEqual(rc, 0)
26 self.failUnless(os.path.exists(c1))
27 self.failUnless(os.path.exists(os.path.join(c1, "client.tac")))
29 # creating the client a second time should throw an exception
30 out,err = StringIO(), StringIO()
31 rc = runner.runner(argv, stdout=out, stderr=err)
32 self.failIfEqual(rc, 0)
33 self.failUnlessEqual(out.getvalue(), "")
34 self.failUnless("The base directory already exists" in err.getvalue())
36 c2 = os.path.join(basedir, "c2")
37 argv = ["--quiet", "create-client", c2]
39 self.failUnless(os.path.exists(c2))
40 self.failUnless(os.path.exists(os.path.join(c2, "client.tac")))
42 self.failUnlessRaises(usage.UsageError,
44 ["create-client", "basedir", "extraarg"],
47 self.failUnlessRaises(usage.UsageError,
52 def test_introducer(self):
53 basedir = self.workdir("test_introducer")
54 c1 = os.path.join(basedir, "c1")
55 argv = ["--quiet", "create-introducer", "--basedir", c1]
56 out,err = StringIO(), StringIO()
57 rc = runner.runner(argv, stdout=out, stderr=err)
58 self.failUnlessEqual(err.getvalue(), "")
59 self.failUnlessEqual(out.getvalue(), "")
60 self.failUnlessEqual(rc, 0)
61 self.failUnless(os.path.exists(c1))
62 self.failUnless(os.path.exists(os.path.join(c1, "introducer.tac")))
64 # creating the introducer a second time should throw an exception
65 out,err = StringIO(), StringIO()
66 rc = runner.runner(argv, stdout=out, stderr=err)
67 self.failIfEqual(rc, 0)
68 self.failUnlessEqual(out.getvalue(), "")
69 self.failUnless("The base directory already exists" in err.getvalue())
71 c2 = os.path.join(basedir, "c2")
72 argv = ["--quiet", "create-introducer", c2]
74 self.failUnless(os.path.exists(c2))
75 self.failUnless(os.path.exists(os.path.join(c2, "introducer.tac")))
77 self.failUnlessRaises(usage.UsageError,
79 ["create-introducer", "basedir", "extraarg"],
82 self.failUnlessRaises(usage.UsageError,
84 ["create-introducer"],
87 def test_subcommands(self):
88 self.failUnlessRaises(usage.UsageError,
93 class Diagnostics(unittest.TestCase):
94 def test_dump_root_dirnode_failure(self):
96 config = {'basedirs': ["missing_basedir"]}
97 rc = debug.dump_root_dirnode(config, s)
99 self.failUnless("unable to read root dirnode file from" in output)
100 self.failIfEqual(rc, 0)
102 class RunNode(unittest.TestCase, testutil.PollMixin):
103 def workdir(self, name):
104 basedir = os.path.join("test_runner", "RunNode", name)
105 fileutil.make_dirs(basedir)
108 def test_client(self):
109 if runtime.platformType == "win32":
110 # twistd on windows doesn't daemonize. cygwin works normally.
111 raise unittest.SkipTest("twistd does not fork under windows")
112 basedir = self.workdir("test_client")
113 c1 = os.path.join(basedir, "c1")
114 argv = ["--quiet", "create-client", "--basedir", c1]
115 out,err = StringIO(), StringIO()
116 rc = runner.runner(argv, stdout=out, stderr=err)
117 self.failUnlessEqual(rc, 0)
118 # by writing this file, we get ten seconds before the client will
119 # exit. This insures that even if the test fails (and the 'stop'
120 # command doesn't work), the client should still terminate.
121 HOTLINE_FILE = os.path.join(c1, "suicide_prevention_hotline")
122 open(HOTLINE_FILE, "w").write("")
123 open(os.path.join(c1, "introducer.furl"), "w").write("pb://xrndsskn2zuuian5ltnxrte7lnuqdrkz@127.0.0.1:55617/introducer\n")
124 # now it's safe to start the node
126 TWISTD_PID_FILE = os.path.join(c1, "twistd.pid")
128 d = defer.succeed(None)
130 argv = ["--quiet", "start", c1]
131 out,err = StringIO(), StringIO()
132 rc = runner.runner(argv, stdout=out, stderr=err)
133 open(HOTLINE_FILE, "w").write("")
134 outs = out.getvalue() ; errs = err.getvalue()
135 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc, outs, errs)
136 self.failUnlessEqual(rc, 0, errstr)
137 self.failUnlessEqual(outs, "", errstr)
138 self.failUnlessEqual(errs, "", errstr)
140 # the parent (twistd) has exited. However, twistd writes the pid
141 # from the child, not the parent, so we can't expect twistd.pid
142 # to exist quite yet.
144 # the node is running, but it might not have made it past the
145 # first reactor turn yet, and if we kill it too early, it won't
146 # remove the twistd.pid file. So wait until it does something
147 # that we know it won't do until after the first turn.
149 d.addCallback(_start)
151 PORTNUMFILE = os.path.join(c1, "client.port")
152 def _node_has_started():
153 return os.path.exists(PORTNUMFILE)
154 d.addCallback(lambda res: self.poll(_node_has_started))
157 open(HOTLINE_FILE, "w").write("")
158 self.failUnless(os.path.exists(TWISTD_PID_FILE))
159 # rm this so we can detect when the second incarnation is ready
160 os.unlink(PORTNUMFILE)
161 argv = ["--quiet", "restart", c1]
162 out,err = StringIO(), StringIO()
163 rc = runner.runner(argv, stdout=out, stderr=err)
164 open(HOTLINE_FILE, "w").write("")
165 outs = out.getvalue() ; errs = err.getvalue()
166 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc, outs, errs)
167 self.failUnlessEqual(rc, 0, errstr)
168 self.failUnlessEqual(outs, "", errstr)
169 self.failUnlessEqual(errs, "", errstr)
170 d.addCallback(_started)
172 # again, the second incarnation of the node might not be ready yet,
173 # so poll until it is
174 d.addCallback(lambda res: self.poll(_node_has_started))
176 # now we can kill it. TODO: On a slow machine, the node might kill
177 # itself before we get a chance too, especially if spawning the
178 # 'allmydata-tahoe stop' command takes a while.
180 open(HOTLINE_FILE, "w").write("")
181 self.failUnless(os.path.exists(TWISTD_PID_FILE))
182 argv = ["--quiet", "stop", c1]
183 out,err = StringIO(), StringIO()
184 rc = runner.runner(argv, stdout=out, stderr=err)
185 open(HOTLINE_FILE, "w").write("")
186 # the parent has exited by now
187 outs = out.getvalue() ; errs = err.getvalue()
188 errstr = "rc=%d, OUT: '%s', ERR: '%s'" % (rc, outs, errs)
189 self.failUnlessEqual(rc, 0, errstr)
190 self.failUnlessEqual(outs, "", errstr)
191 self.failUnlessEqual(errs, "", errstr)
192 # the parent was supposed to poll and wait until it sees
193 # twistd.pid go away before it exits, so twistd.pid should be
195 self.failIf(os.path.exists(TWISTD_PID_FILE))
197 def _remove_hotline(res):
198 os.unlink(HOTLINE_FILE)
200 d.addBoth(_remove_hotline)
203 def test_baddir(self):
204 basedir = self.workdir("test_baddir")
205 fileutil.make_dirs(basedir)
206 argv = ["--quiet", "start", "--basedir", basedir]
207 out,err = StringIO(), StringIO()
208 rc = runner.runner(argv, stdout=out, stderr=err)
209 self.failUnlessEqual(rc, 1)
210 self.failUnless("does not look like a node directory" in err.getvalue())
212 argv = ["--quiet", "stop", "--basedir", basedir]
213 out,err = StringIO(), StringIO()
214 rc = runner.runner(argv, stdout=out, stderr=err)
215 self.failUnlessEqual(rc, 2)
216 self.failUnless("does not look like a running node directory"
219 not_a_dir = os.path.join(basedir, "bogus")
220 argv = ["--quiet", "start", "--basedir", not_a_dir]
221 out,err = StringIO(), StringIO()
222 rc = runner.runner(argv, stdout=out, stderr=err)
223 self.failUnlessEqual(rc, 1)
224 self.failUnless("does not look like a node directory" in err.getvalue())
225 self.failUnless("doesn't look like a directory at all"