]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/test/test_runner.py
test_runner: try harder to work on slow buildslaves and cygwin
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / test_runner.py
1
2 from twisted.trial import unittest
3
4 from cStringIO import StringIO
5 from twisted.python import usage, runtime
6 from twisted.internet import defer
7 import os.path
8 from allmydata.scripts import runner, debug
9 from allmydata.util import fileutil, testutil
10
11 class CreateNode(unittest.TestCase):
12     def workdir(self, name):
13         basedir = os.path.join("test_runner", "CreateNode", name)
14         fileutil.make_dirs(basedir)
15         return basedir
16
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")))
28
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())
35
36         c2 = os.path.join(basedir, "c2")
37         argv = ["--quiet", "create-client", c2]
38         runner.runner(argv)
39         self.failUnless(os.path.exists(c2))
40         self.failUnless(os.path.exists(os.path.join(c2, "client.tac")))
41
42         self.failUnlessRaises(usage.UsageError,
43                               runner.runner,
44                               ["create-client", "basedir", "extraarg"],
45                               run_by_human=False)
46
47         self.failUnlessRaises(usage.UsageError,
48                               runner.runner,
49                               ["create-client"],
50                               run_by_human=False)
51
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")))
63
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())
70
71         c2 = os.path.join(basedir, "c2")
72         argv = ["--quiet", "create-introducer", c2]
73         runner.runner(argv)
74         self.failUnless(os.path.exists(c2))
75         self.failUnless(os.path.exists(os.path.join(c2, "introducer.tac")))
76
77         self.failUnlessRaises(usage.UsageError,
78                               runner.runner,
79                               ["create-introducer", "basedir", "extraarg"],
80                               run_by_human=False)
81
82         self.failUnlessRaises(usage.UsageError,
83                               runner.runner,
84                               ["create-introducer"],
85                               run_by_human=False)
86
87     def test_subcommands(self):
88         self.failUnlessRaises(usage.UsageError,
89                               runner.runner,
90                               [],
91                               run_by_human=False)
92
93 class Diagnostics(unittest.TestCase):
94     def test_dump_root_dirnode_failure(self):
95         s = StringIO()
96         config = {'basedirs': ["missing_basedir"]}
97         rc = debug.dump_root_dirnode(config, s)
98         output = s.getvalue()
99         self.failUnless("unable to read root dirnode file from" in output)
100         self.failIfEqual(rc, 0)
101
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)
106         return basedir
107
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
125
126         TWISTD_PID_FILE = os.path.join(c1, "twistd.pid")
127
128         d = defer.succeed(None)
129         def _start(res):
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)
139
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.
143
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.
148
149         d.addCallback(_start)
150
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))
155
156         def _started(res):
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)
171
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))
175
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.
179         def _stop(res):
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
194             # gone by now.
195             self.failIf(os.path.exists(TWISTD_PID_FILE))
196         d.addCallback(_stop)
197         def _remove_hotline(res):
198             os.unlink(HOTLINE_FILE)
199             return res
200         d.addBoth(_remove_hotline)
201         return d
202
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())
211
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"
217                         in err.getvalue())
218
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"
226                         in err.getvalue())
227
228