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