OLD | NEW |
| (Empty) |
1 | |
2 # this file tests the 'buildbot' command, with its various sub-commands | |
3 | |
4 from twisted.trial import unittest | |
5 from twisted.python import usage | |
6 import os, shutil, shlex | |
7 import sets | |
8 | |
9 from buildbot.scripts import runner, tryclient | |
10 | |
11 class Options(unittest.TestCase): | |
12 optionsFile = "SDFsfsFSdfsfsFSD" | |
13 | |
14 def make(self, d, key): | |
15 # we use a wacky filename here in case the test code discovers the | |
16 # user's real ~/.buildbot/ directory | |
17 if not os.path.isdir(os.sep.join(d + [".buildbot"])): | |
18 os.makedirs(os.sep.join(d + [".buildbot"])) | |
19 f = open(os.sep.join(d + [".buildbot", self.optionsFile]), "w") | |
20 f.write("key = '%s'\n" % key) | |
21 f.close() | |
22 | |
23 def check(self, d, key): | |
24 basedir = os.sep.join(d) | |
25 options = runner.loadOptionsFile(self.optionsFile, here=basedir, | |
26 home=self.home) | |
27 if key is None: | |
28 self.failIf(options.has_key('key')) | |
29 else: | |
30 self.failUnlessEqual(options['key'], key) | |
31 | |
32 def testFindOptions(self): | |
33 self.make(["home", "dir1", "dir2", "dir3"], "one") | |
34 self.make(["home", "dir1", "dir2"], "two") | |
35 self.make(["home"], "home") | |
36 self.home = os.path.abspath("home") | |
37 | |
38 self.check(["home", "dir1", "dir2", "dir3"], "one") | |
39 self.check(["home", "dir1", "dir2"], "two") | |
40 self.check(["home", "dir1"], "home") | |
41 | |
42 self.home = os.path.abspath("nothome") | |
43 if not os.path.isdir(os.sep.join(["nothome", "dir1"])): | |
44 os.makedirs(os.sep.join(["nothome", "dir1"])) | |
45 self.check(["nothome", "dir1"], None) | |
46 | |
47 def doForce(self, args, expected): | |
48 o = runner.ForceOptions() | |
49 o.parseOptions(args) | |
50 self.failUnlessEqual(o.keys(), expected.keys()) | |
51 for k in o.keys(): | |
52 self.failUnlessEqual(o[k], expected[k], | |
53 "[%s] got %s instead of %s" % (k, o[k], | |
54 expected[k])) | |
55 | |
56 def testForceOptions(self): | |
57 if not hasattr(shlex, "split"): | |
58 raise unittest.SkipTest("need python>=2.3 for shlex.split") | |
59 | |
60 exp = {"builder": "b1", "reason": "reason", | |
61 "branch": None, "revision": None} | |
62 self.doForce(shlex.split("b1 reason"), exp) | |
63 self.doForce(shlex.split("b1 'reason'"), exp) | |
64 self.failUnlessRaises(usage.UsageError, self.doForce, | |
65 shlex.split("--builder b1 'reason'"), exp) | |
66 self.doForce(shlex.split("--builder b1 --reason reason"), exp) | |
67 self.doForce(shlex.split("--builder b1 --reason 'reason'"), exp) | |
68 self.doForce(shlex.split("--builder b1 --reason \"reason\""), exp) | |
69 | |
70 exp['reason'] = "longer reason" | |
71 self.doForce(shlex.split("b1 'longer reason'"), exp) | |
72 self.doForce(shlex.split("b1 longer reason"), exp) | |
73 self.doForce(shlex.split("--reason 'longer reason' b1"), exp) | |
74 | |
75 | |
76 class Create(unittest.TestCase): | |
77 def failUnlessIn(self, substring, string, msg=None): | |
78 # trial provides a version of this that requires python-2.3 to test | |
79 # strings. | |
80 self.failUnless(string.find(substring) != -1, msg) | |
81 def failUnlessExists(self, filename): | |
82 self.failUnless(os.path.exists(filename), "%s should exist" % filename) | |
83 def failIfExists(self, filename): | |
84 self.failIf(os.path.exists(filename), "%s should not exist" % filename) | |
85 | |
86 def setUp(self): | |
87 self.cwd = os.getcwd() | |
88 | |
89 def tearDown(self): | |
90 os.chdir(self.cwd) | |
91 | |
92 def testMaster(self): | |
93 basedir = "test_runner.master" | |
94 options = runner.MasterOptions() | |
95 options.parseOptions(["-q", basedir]) | |
96 cwd = os.getcwd() | |
97 runner.createMaster(options) | |
98 os.chdir(cwd) | |
99 | |
100 tac = os.path.join(basedir, "buildbot.tac") | |
101 self.failUnless(os.path.exists(tac)) | |
102 tacfile = open(tac,"rt").read() | |
103 self.failUnlessIn("basedir", tacfile) | |
104 self.failUnlessIn("configfile = r'master.cfg'", tacfile) | |
105 self.failUnlessIn("BuildMaster(basedir, configfile)", tacfile) | |
106 | |
107 cfg = os.path.join(basedir, "master.cfg") | |
108 self.failIfExists(cfg) | |
109 samplecfg = os.path.join(basedir, "master.cfg.sample") | |
110 self.failUnlessExists(samplecfg) | |
111 cfgfile = open(samplecfg,"rt").read() | |
112 self.failUnlessIn("This is a sample buildmaster config file", cfgfile) | |
113 | |
114 makefile = os.path.join(basedir, "Makefile.sample") | |
115 self.failUnlessExists(makefile) | |
116 | |
117 # now verify that running it a second time (with the same options) | |
118 # does the right thing: nothing changes | |
119 runner.createMaster(options) | |
120 os.chdir(cwd) | |
121 | |
122 self.failIfExists(os.path.join(basedir, "buildbot.tac.new")) | |
123 self.failUnlessExists(os.path.join(basedir, "master.cfg.sample")) | |
124 | |
125 oldtac = open(os.path.join(basedir, "buildbot.tac"), "rt").read() | |
126 | |
127 # mutate Makefile.sample, since it should be rewritten | |
128 f = open(os.path.join(basedir, "Makefile.sample"), "rt") | |
129 oldmake = f.read() | |
130 f = open(os.path.join(basedir, "Makefile.sample"), "wt") | |
131 f.write(oldmake) | |
132 f.write("# additional line added\n") | |
133 f.close() | |
134 | |
135 # also mutate master.cfg.sample | |
136 f = open(os.path.join(basedir, "master.cfg.sample"), "rt") | |
137 oldsamplecfg = f.read() | |
138 f = open(os.path.join(basedir, "master.cfg.sample"), "wt") | |
139 f.write(oldsamplecfg) | |
140 f.write("# additional line added\n") | |
141 f.close() | |
142 | |
143 # now run it again (with different options) | |
144 options = runner.MasterOptions() | |
145 options.parseOptions(["-q", "--config", "other.cfg", basedir]) | |
146 runner.createMaster(options) | |
147 os.chdir(cwd) | |
148 | |
149 tac = open(os.path.join(basedir, "buildbot.tac"), "rt").read() | |
150 self.failUnlessEqual(tac, oldtac, "shouldn't change existing .tac") | |
151 self.failUnlessExists(os.path.join(basedir, "buildbot.tac.new")) | |
152 | |
153 make = open(os.path.join(basedir, "Makefile.sample"), "rt").read() | |
154 self.failUnlessEqual(make, oldmake, "*should* rewrite Makefile.sample") | |
155 | |
156 samplecfg = open(os.path.join(basedir, "master.cfg.sample"), | |
157 "rt").read() | |
158 self.failUnlessEqual(samplecfg, oldsamplecfg, | |
159 "*should* rewrite master.cfg.sample") | |
160 | |
161 def testUpgradeMaster(self): | |
162 # first, create a master, run it briefly, then upgrade it. Nothing | |
163 # should change. | |
164 basedir = "test_runner.master2" | |
165 options = runner.MasterOptions() | |
166 options.parseOptions(["-q", basedir]) | |
167 cwd = os.getcwd() | |
168 runner.createMaster(options) | |
169 os.chdir(cwd) | |
170 | |
171 f = open(os.path.join(basedir, "master.cfg"), "w") | |
172 f.write(open(os.path.join(basedir, "master.cfg.sample"), "r").read()) | |
173 f.close() | |
174 | |
175 # the upgrade process (specifically the verify-master.cfg step) will | |
176 # create any builder status directories that weren't already created. | |
177 # Create those ahead of time. | |
178 os.mkdir(os.path.join(basedir, "full")) | |
179 | |
180 files1 = self.record_files(basedir) | |
181 | |
182 # upgrade it | |
183 options = runner.UpgradeMasterOptions() | |
184 options.parseOptions(["--quiet", basedir]) | |
185 cwd = os.getcwd() | |
186 runner.upgradeMaster(options) | |
187 os.chdir(cwd) | |
188 | |
189 files2 = self.record_files(basedir) | |
190 self.failUnlessSameFiles(files1, files2) | |
191 | |
192 # now make it look like the one that 0.7.5 creates: no public_html | |
193 for fn in os.listdir(os.path.join(basedir, "public_html")): | |
194 os.unlink(os.path.join(basedir, "public_html", fn)) | |
195 os.rmdir(os.path.join(basedir, "public_html")) | |
196 | |
197 # and make sure that upgrading it re-populates public_html | |
198 options = runner.UpgradeMasterOptions() | |
199 options.parseOptions(["-q", basedir]) | |
200 cwd = os.getcwd() | |
201 runner.upgradeMaster(options) | |
202 os.chdir(cwd) | |
203 | |
204 files3 = self.record_files(basedir) | |
205 self.failUnlessSameFiles(files1, files3) | |
206 | |
207 # now induce an error in master.cfg and make sure that upgrade | |
208 # notices it. | |
209 f = open(os.path.join(basedir, "master.cfg"), "a") | |
210 f.write("raise RuntimeError('catch me please')\n") | |
211 f.close() | |
212 | |
213 options = runner.UpgradeMasterOptions() | |
214 options.parseOptions(["-q", basedir]) | |
215 cwd = os.getcwd() | |
216 rc = runner.upgradeMaster(options) | |
217 os.chdir(cwd) | |
218 self.failUnless(rc != 0, rc) | |
219 # TODO: change the way runner.py works to let us pass in a stderr | |
220 # filehandle, and use a StringIO to capture its output, and make sure | |
221 # the right error messages appear therein. | |
222 | |
223 | |
224 def failUnlessSameFiles(self, files1, files2): | |
225 f1 = sets.Set(files1.keys()) | |
226 f2 = sets.Set(files2.keys()) | |
227 msg = "" | |
228 if f2 - f1: | |
229 msg += "Missing from files1: %s\n" % (list(f2-f1),) | |
230 if f1 - f2: | |
231 msg += "Missing from files2: %s\n" % (list(f1-f2),) | |
232 if msg: | |
233 self.fail(msg) | |
234 | |
235 def record_files(self, basedir): | |
236 allfiles = {} | |
237 for root, dirs, files in os.walk(basedir): | |
238 for f in files: | |
239 fn = os.path.join(root, f) | |
240 allfiles[fn] = ("FILE", open(fn,"rb").read()) | |
241 for d in dirs: | |
242 allfiles[os.path.join(root, d)] = ("DIR",) | |
243 return allfiles | |
244 | |
245 | |
246 def testSlave(self): | |
247 basedir = "test_runner.slave" | |
248 options = runner.SlaveOptions() | |
249 options.parseOptions(["-q", basedir, "buildmaster:1234", | |
250 "botname", "passwd"]) | |
251 cwd = os.getcwd() | |
252 runner.createSlave(options) | |
253 os.chdir(cwd) | |
254 | |
255 tac = os.path.join(basedir, "buildbot.tac") | |
256 self.failUnless(os.path.exists(tac)) | |
257 tacfile = open(tac,"rt").read() | |
258 self.failUnlessIn("basedir", tacfile) | |
259 self.failUnlessIn("buildmaster_host = 'buildmaster'", tacfile) | |
260 self.failUnlessIn("port = 1234", tacfile) | |
261 self.failUnlessIn("slavename = 'botname'", tacfile) | |
262 self.failUnlessIn("passwd = 'passwd'", tacfile) | |
263 self.failUnlessIn("keepalive = 600", tacfile) | |
264 self.failUnlessIn("BuildSlave(buildmaster_host, port, slavename", | |
265 tacfile) | |
266 | |
267 makefile = os.path.join(basedir, "Makefile.sample") | |
268 self.failUnlessExists(makefile) | |
269 | |
270 self.failUnlessExists(os.path.join(basedir, "info", "admin")) | |
271 self.failUnlessExists(os.path.join(basedir, "info", "host")) | |
272 # edit one to make sure the later install doesn't change it | |
273 f = open(os.path.join(basedir, "info", "admin"), "wt") | |
274 f.write("updated@buildbot.example.org\n") | |
275 f.close() | |
276 | |
277 # now verify that running it a second time (with the same options) | |
278 # does the right thing: nothing changes | |
279 runner.createSlave(options) | |
280 os.chdir(cwd) | |
281 | |
282 self.failIfExists(os.path.join(basedir, "buildbot.tac.new")) | |
283 admin = open(os.path.join(basedir, "info", "admin"), "rt").read() | |
284 self.failUnlessEqual(admin, "updated@buildbot.example.org\n") | |
285 | |
286 | |
287 # mutate Makefile.sample, since it should be rewritten | |
288 oldmake = open(os.path.join(basedir, "Makefile.sample"), "rt").read() | |
289 f = open(os.path.join(basedir, "Makefile.sample"), "wt") | |
290 f.write(oldmake) | |
291 f.write("# additional line added\n") | |
292 f.close() | |
293 oldtac = open(os.path.join(basedir, "buildbot.tac"), "rt").read() | |
294 | |
295 # now run it again (with different options) | |
296 options = runner.SlaveOptions() | |
297 options.parseOptions(["-q", "--keepalive", "30", | |
298 basedir, "buildmaster:9999", | |
299 "newbotname", "passwd"]) | |
300 runner.createSlave(options) | |
301 os.chdir(cwd) | |
302 | |
303 tac = open(os.path.join(basedir, "buildbot.tac"), "rt").read() | |
304 self.failUnlessEqual(tac, oldtac, "shouldn't change existing .tac") | |
305 self.failUnlessExists(os.path.join(basedir, "buildbot.tac.new")) | |
306 tacfile = open(os.path.join(basedir, "buildbot.tac.new"),"rt").read() | |
307 self.failUnlessIn("basedir", tacfile) | |
308 self.failUnlessIn("buildmaster_host = 'buildmaster'", tacfile) | |
309 self.failUnlessIn("port = 9999", tacfile) | |
310 self.failUnlessIn("slavename = 'newbotname'", tacfile) | |
311 self.failUnlessIn("passwd = 'passwd'", tacfile) | |
312 self.failUnlessIn("keepalive = 30", tacfile) | |
313 self.failUnlessIn("BuildSlave(buildmaster_host, port, slavename", | |
314 tacfile) | |
315 | |
316 make = open(os.path.join(basedir, "Makefile.sample"), "rt").read() | |
317 self.failUnlessEqual(make, oldmake, "*should* rewrite Makefile.sample") | |
318 | |
319 class Try(unittest.TestCase): | |
320 # test some aspects of the 'buildbot try' command | |
321 def makeOptions(self, contents): | |
322 if os.path.exists(".buildbot"): | |
323 shutil.rmtree(".buildbot") | |
324 os.mkdir(".buildbot") | |
325 open(os.path.join(".buildbot", "options"), "w").write(contents) | |
326 | |
327 def testGetopt1(self): | |
328 opts = "try_connect = 'ssh'\n" + "try_builders = ['a']\n" | |
329 self.makeOptions(opts) | |
330 config = runner.TryOptions() | |
331 config.parseOptions([]) | |
332 t = tryclient.Try(config) | |
333 self.failUnlessEqual(t.connect, "ssh") | |
334 self.failUnlessEqual(t.builderNames, ['a']) | |
335 | |
336 def testGetopt2(self): | |
337 opts = "" | |
338 self.makeOptions(opts) | |
339 config = runner.TryOptions() | |
340 config.parseOptions(['--connect=ssh', '--builder', 'a']) | |
341 t = tryclient.Try(config) | |
342 self.failUnlessEqual(t.connect, "ssh") | |
343 self.failUnlessEqual(t.builderNames, ['a']) | |
344 | |
345 def testGetopt3(self): | |
346 opts = "" | |
347 self.makeOptions(opts) | |
348 config = runner.TryOptions() | |
349 config.parseOptions(['--connect=ssh', | |
350 '--builder', 'a', '--builder=b']) | |
351 t = tryclient.Try(config) | |
352 self.failUnlessEqual(t.connect, "ssh") | |
353 self.failUnlessEqual(t.builderNames, ['a', 'b']) | |
354 | |
355 def testGetopt4(self): | |
356 opts = "try_connect = 'ssh'\n" + "try_builders = ['a']\n" | |
357 self.makeOptions(opts) | |
358 config = runner.TryOptions() | |
359 config.parseOptions(['--builder=b']) | |
360 t = tryclient.Try(config) | |
361 self.failUnlessEqual(t.connect, "ssh") | |
362 self.failUnlessEqual(t.builderNames, ['b']) | |
363 | |
364 def testGetTopdir(self): | |
365 os.mkdir("gettopdir") | |
366 os.mkdir(os.path.join("gettopdir", "foo")) | |
367 os.mkdir(os.path.join("gettopdir", "foo", "bar")) | |
368 open(os.path.join("gettopdir", "1"),"w").write("1") | |
369 open(os.path.join("gettopdir", "foo", "2"),"w").write("2") | |
370 open(os.path.join("gettopdir", "foo", "bar", "3"),"w").write("3") | |
371 | |
372 target = os.path.abspath("gettopdir") | |
373 t = tryclient.getTopdir("1", "gettopdir") | |
374 self.failUnlessEqual(os.path.abspath(t), target) | |
375 t = tryclient.getTopdir("1", os.path.join("gettopdir", "foo")) | |
376 self.failUnlessEqual(os.path.abspath(t), target) | |
377 t = tryclient.getTopdir("1", os.path.join("gettopdir", "foo", "bar")) | |
378 self.failUnlessEqual(os.path.abspath(t), target) | |
379 | |
380 target = os.path.abspath(os.path.join("gettopdir", "foo")) | |
381 t = tryclient.getTopdir("2", os.path.join("gettopdir", "foo")) | |
382 self.failUnlessEqual(os.path.abspath(t), target) | |
383 t = tryclient.getTopdir("2", os.path.join("gettopdir", "foo", "bar")) | |
384 self.failUnlessEqual(os.path.abspath(t), target) | |
385 | |
386 target = os.path.abspath(os.path.join("gettopdir", "foo", "bar")) | |
387 t = tryclient.getTopdir("3", os.path.join("gettopdir", "foo", "bar")) | |
388 self.failUnlessEqual(os.path.abspath(t), target) | |
389 | |
390 nonexistent = "nonexistent\n29fis3kq\tBAR" | |
391 # hopefully there won't be a real file with that name between here | |
392 # and the filesystem root. | |
393 self.failUnlessRaises(ValueError, tryclient.getTopdir, nonexistent) | |
394 | |
OLD | NEW |