OLD | NEW |
| (Empty) |
1 # -*- test-case-name: buildbot.test.test_bonsaipoller -*- | |
2 | |
3 from twisted.trial import unittest | |
4 from buildbot.changes.bonsaipoller import FileNode, CiNode, BonsaiResult, \ | |
5 BonsaiParser, BonsaiPoller, InvalidResultError, EmptyResult | |
6 from buildbot.changes.changes import ChangeMaster | |
7 | |
8 from copy import deepcopy | |
9 import re | |
10 | |
11 log1 = "Add Bug 338541a" | |
12 who1 = "sar@gmail.com" | |
13 date1 = 1161908700 | |
14 log2 = "bug 357427 add static ctor/dtor methods" | |
15 who2 = "aarrg@ooacm.org" | |
16 date2 = 1161910620 | |
17 log3 = "Testing log #3 lbah blah" | |
18 who3 = "huoents@hueont.net" | |
19 date3 = 1889822728 | |
20 rev1 = "1.8" | |
21 file1 = "mozilla/testing/mochitest/tests/index.html" | |
22 rev2 = "1.1" | |
23 file2 = "mozilla/testing/mochitest/tests/test_bug338541.xhtml" | |
24 rev3 = "1.1812" | |
25 file3 = "mozilla/xpcom/threads/nsAutoLock.cpp" | |
26 rev4 = "1.3" | |
27 file4 = "mozilla/xpcom/threads/nsAutoLock.h" | |
28 rev5 = "2.4" | |
29 file5 = "mozilla/xpcom/threads/test.cpp" | |
30 | |
31 nodes = [] | |
32 files = [] | |
33 files.append(FileNode(rev1,file1)) | |
34 nodes.append(CiNode(log1, who1, date1, files)) | |
35 | |
36 files = [] | |
37 files.append(FileNode(rev2, file2)) | |
38 files.append(FileNode(rev3, file3)) | |
39 nodes.append(CiNode(log2, who2, date2, files)) | |
40 | |
41 nodes.append(CiNode(log3, who3, date3, [])) | |
42 | |
43 goodParsedResult = BonsaiResult(nodes) | |
44 | |
45 goodUnparsedResult = """\ | |
46 <?xml version="1.0"?> | |
47 <queryResults> | |
48 <ci who="%s" date="%d"> | |
49 <log>%s</log> | |
50 <files> | |
51 <f rev="%s">%s</f> | |
52 </files> | |
53 </ci> | |
54 <ci who="%s" date="%d"> | |
55 <log>%s</log> | |
56 <files> | |
57 <f rev="%s">%s</f> | |
58 <f rev="%s">%s</f> | |
59 </files> | |
60 </ci> | |
61 <ci who="%s" date="%d"> | |
62 <log>%s</log> | |
63 <files> | |
64 </files> | |
65 </ci> | |
66 </queryResults> | |
67 """ % (who1, date1, log1, rev1, file1, | |
68 who2, date2, log2, rev2, file2, rev3, file3, | |
69 who3, date3, log3) | |
70 | |
71 badUnparsedResult = deepcopy(goodUnparsedResult) | |
72 badUnparsedResult = badUnparsedResult.replace("</queryResults>", "") | |
73 | |
74 invalidDateResult = deepcopy(goodUnparsedResult) | |
75 invalidDateResult = invalidDateResult.replace(str(date1), "foobar") | |
76 | |
77 missingFilenameResult = deepcopy(goodUnparsedResult) | |
78 missingFilenameResult = missingFilenameResult.replace(file2, "") | |
79 | |
80 duplicateLogResult = deepcopy(goodUnparsedResult) | |
81 duplicateLogResult = re.sub("<log>"+log1+"</log>", | |
82 "<log>blah</log><log>blah</log>", | |
83 duplicateLogResult) | |
84 | |
85 duplicateFilesResult = deepcopy(goodUnparsedResult) | |
86 duplicateFilesResult = re.sub("<files>\s*</files>", | |
87 "<files></files><files></files>", | |
88 duplicateFilesResult) | |
89 | |
90 missingCiResult = deepcopy(goodUnparsedResult) | |
91 r = re.compile("<ci.*</ci>", re.DOTALL | re.MULTILINE) | |
92 missingCiResult = re.sub(r, "", missingCiResult) | |
93 | |
94 badResultMsgs = { 'badUnparsedResult': | |
95 "BonsaiParser did not raise an exception when given a bad query", | |
96 'invalidDateResult': | |
97 "BonsaiParser did not raise an exception when given an invalid date", | |
98 'missingRevisionResult': | |
99 "BonsaiParser did not raise an exception when a revision was missing", | |
100 'missingFilenameResult': | |
101 "BonsaiParser did not raise an exception when a filename was missing", | |
102 'duplicateLogResult': | |
103 "BonsaiParser did not raise an exception when there was two <log> tags", | |
104 'duplicateFilesResult': | |
105 "BonsaiParser did not raise an exception when there was two <files> tags", | |
106 'missingCiResult': | |
107 "BonsaiParser did not raise an exception when there was no <ci> tags" | |
108 } | |
109 | |
110 noCheckinMsgResult = """\ | |
111 <?xml version="1.0"?> | |
112 <queryResults> | |
113 <ci who="johndoe@domain.tld" date="12345678"> | |
114 <log></log> | |
115 <files> | |
116 <f rev="1.1">first/file.ext</f> | |
117 </files> | |
118 </ci> | |
119 <ci who="johndoe@domain.tld" date="12345678"> | |
120 <log></log> | |
121 <files> | |
122 <f rev="1.2">second/file.ext</f> | |
123 </files> | |
124 </ci> | |
125 <ci who="johndoe@domain.tld" date="12345678"> | |
126 <log></log> | |
127 <files> | |
128 <f rev="1.3">third/file.ext</f> | |
129 </files> | |
130 </ci> | |
131 </queryResults> | |
132 """ | |
133 | |
134 noCheckinMsgRef = [dict(filename="first/file.ext", | |
135 revision="1.1"), | |
136 dict(filename="second/file.ext", | |
137 revision="1.2"), | |
138 dict(filename="third/file.ext", | |
139 revision="1.3")] | |
140 | |
141 class FakeChangeMaster(ChangeMaster): | |
142 def __init__(self): | |
143 ChangeMaster.__init__(self) | |
144 | |
145 def addChange(self, change): | |
146 pass | |
147 | |
148 class FakeBonsaiPoller(BonsaiPoller): | |
149 def __init__(self): | |
150 BonsaiPoller.__init__(self, "fake url", "fake module", "fake branch") | |
151 self.parent = FakeChangeMaster() | |
152 | |
153 class TestBonsaiPoller(unittest.TestCase): | |
154 def testFullyFormedResult(self): | |
155 br = BonsaiParser(goodUnparsedResult) | |
156 result = br.getData() | |
157 # make sure the result is a BonsaiResult | |
158 self.failUnless(isinstance(result, BonsaiResult)) | |
159 # test for successful parsing | |
160 self.failUnlessEqual(goodParsedResult, result, | |
161 "BonsaiParser did not return the expected BonsaiResult") | |
162 | |
163 def testBadUnparsedResult(self): | |
164 try: | |
165 BonsaiParser(badUnparsedResult) | |
166 self.fail(badResultMsgs["badUnparsedResult"]) | |
167 except InvalidResultError: | |
168 pass | |
169 | |
170 def testInvalidDateResult(self): | |
171 try: | |
172 BonsaiParser(invalidDateResult) | |
173 self.fail(badResultMsgs["invalidDateResult"]) | |
174 except InvalidResultError: | |
175 pass | |
176 | |
177 def testMissingFilenameResult(self): | |
178 try: | |
179 BonsaiParser(missingFilenameResult) | |
180 self.fail(badResultMsgs["missingFilenameResult"]) | |
181 except InvalidResultError: | |
182 pass | |
183 | |
184 def testDuplicateLogResult(self): | |
185 try: | |
186 BonsaiParser(duplicateLogResult) | |
187 self.fail(badResultMsgs["duplicateLogResult"]) | |
188 except InvalidResultError: | |
189 pass | |
190 | |
191 def testDuplicateFilesResult(self): | |
192 try: | |
193 BonsaiParser(duplicateFilesResult) | |
194 self.fail(badResultMsgs["duplicateFilesResult"]) | |
195 except InvalidResultError: | |
196 pass | |
197 | |
198 def testMissingCiResult(self): | |
199 try: | |
200 BonsaiParser(missingCiResult) | |
201 self.fail(badResultMsgs["missingCiResult"]) | |
202 except EmptyResult: | |
203 pass | |
204 | |
205 def testChangeNotSubmitted(self): | |
206 "Make sure a change is not submitted if the BonsaiParser fails" | |
207 poller = FakeBonsaiPoller() | |
208 lastChangeBefore = poller.lastChange | |
209 poller._process_changes(badUnparsedResult) | |
210 # self.lastChange will not be updated if the change was not submitted | |
211 self.failUnlessEqual(lastChangeBefore, poller.lastChange) | |
212 | |
213 def testParserWorksAfterInvalidResult(self): | |
214 """Make sure the BonsaiPoller still works after catching an | |
215 InvalidResultError""" | |
216 | |
217 poller = FakeBonsaiPoller() | |
218 | |
219 lastChangeBefore = poller.lastChange | |
220 # generate an exception first. pretend that we're doing a poll and | |
221 # increment the timestamp, otherwise the failIfEqual test at the | |
222 # bottom will depend upon there being a noticeable difference between | |
223 # two successive calls to time.time(). | |
224 poller.lastPoll += 1.0 | |
225 poller._process_changes(badUnparsedResult) | |
226 # now give it a valid one... | |
227 poller.lastPoll += 1.0 | |
228 poller._process_changes(goodUnparsedResult) | |
229 # if poller.lastChange has not been updated then the good result | |
230 # was not parsed | |
231 self.failIfEqual(lastChangeBefore, poller.lastChange) | |
232 | |
233 def testMergeEmptyLogMsg(self): | |
234 """Ensure that BonsaiPoller works around the bonsai xml output | |
235 issue when the check-in comment is empty""" | |
236 bp = BonsaiParser(noCheckinMsgResult) | |
237 result = bp.getData() | |
238 self.failUnlessEqual(len(result.nodes), 1) | |
239 self.failUnlessEqual(result.nodes[0].who, "johndoe@domain.tld") | |
240 self.failUnlessEqual(result.nodes[0].date, 12345678) | |
241 self.failUnlessEqual(result.nodes[0].log, "") | |
242 for file, ref in zip(result.nodes[0].files, noCheckinMsgRef): | |
243 self.failUnlessEqual(file.filename, ref['filename']) | |
244 self.failUnlessEqual(file.revision, ref['revision']) | |
OLD | NEW |