| 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 |