Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / chromite / cbuildbot / tree_status_unittest.py
1 #!/usr/bin/python
2 # Copyright 2014 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Test suite for tree_status.py"""
7
8 from __future__ import print_function
9
10 import os
11 import sys
12 import urllib
13
14 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(
15     os.path.abspath(__file__)))))
16
17 from chromite.cbuildbot import constants
18 from chromite.cbuildbot import tree_status
19 from chromite.lib import cros_test_lib
20 from chromite.lib import timeout_util
21
22 import mock
23
24
25 # pylint: disable=W0212,R0904
26
27 class TestTreeStatus(cros_test_lib.MoxTestCase):
28   """Tests TreeStatus method in cros_build_lib."""
29
30   status_url = 'https://chromiumos-status.appspot.com/current?format=json'
31
32   def setUp(self):
33     pass
34
35   def _TreeStatusFile(self, message, general_state):
36     """Returns a file-like object with the status message writtin in it."""
37     my_response = self.mox.CreateMockAnything()
38     my_response.json = '{"message": "%s", "general_state": "%s"}' % (
39         message, general_state)
40     return my_response
41
42   def _SetupMockTreeStatusResponses(self, status_url,
43                                     final_tree_status='Tree is open.',
44                                     final_general_state=constants.TREE_OPEN,
45                                     rejected_tree_status='Tree is closed.',
46                                     rejected_general_state=
47                                     constants.TREE_CLOSED,
48                                     rejected_status_count=0,
49                                     retries_500=0,
50                                     output_final_status=True):
51     """Mocks out urllib.urlopen commands to simulate a given tree status.
52
53     Args:
54       status_url: The status url that status will be fetched from.
55       final_tree_status: The final value of tree status that will be returned
56         by urlopen.
57       final_general_state: The final value of 'general_state' that will be
58         returned by urlopen.
59       rejected_tree_status: An intermediate value of tree status that will be
60         returned by urlopen and retried upon.
61       rejected_general_state: An intermediate value of 'general_state' that
62         will be returned by urlopen and retried upon.
63       rejected_status_count: The number of times urlopen will return the
64         rejected state.
65       retries_500: The number of times urlopen will fail with a 500 code.
66       output_final_status: If True, the status given by final_tree_status and
67         final_general_state will be the last status returned by urlopen. If
68         False, final_tree_status will never be returned, and instead an
69         unlimited number of times rejected_response will be returned.
70     """
71
72     final_response = self._TreeStatusFile(final_tree_status,
73                                           final_general_state)
74     rejected_response = self._TreeStatusFile(rejected_tree_status,
75                                             rejected_general_state)
76     error_500_response = self.mox.CreateMockAnything()
77     self.mox.StubOutWithMock(urllib, 'urlopen')
78
79     for _ in range(retries_500):
80       urllib.urlopen(status_url).AndReturn(error_500_response)
81       error_500_response.getcode().AndReturn(500)
82
83     if output_final_status:
84       for _ in range(rejected_status_count):
85         urllib.urlopen(status_url).AndReturn(rejected_response)
86         rejected_response.getcode().AndReturn(200)
87         rejected_response.read().AndReturn(rejected_response.json)
88
89       urllib.urlopen(status_url).AndReturn(final_response)
90       final_response.getcode().AndReturn(200)
91       final_response.read().AndReturn(final_response.json)
92     else:
93       urllib.urlopen(status_url).MultipleTimes().AndReturn(rejected_response)
94       rejected_response.getcode().MultipleTimes().AndReturn(200)
95       rejected_response.read().MultipleTimes().AndReturn(
96           rejected_response.json)
97
98     self.mox.ReplayAll()
99
100   def testTreeIsOpen(self):
101     """Tests that we return True is the tree is open."""
102     self._SetupMockTreeStatusResponses(self.status_url,
103                                        rejected_status_count=5,
104                                        retries_500=5)
105     self.assertTrue(tree_status.IsTreeOpen(status_url=self.status_url,
106                                            period=0))
107
108   def testTreeIsClosed(self):
109     """Tests that we return false is the tree is closed."""
110     self._SetupMockTreeStatusResponses(self.status_url,
111                                        output_final_status=False)
112     self.assertFalse(tree_status.IsTreeOpen(status_url=self.status_url,
113                                             period=0.1))
114
115   def testTreeIsThrottled(self):
116     """Tests that we return True if the tree is throttled."""
117     self._SetupMockTreeStatusResponses(self.status_url,
118         'Tree is throttled (flaky bug on flaky builder)',
119         constants.TREE_THROTTLED)
120     self.assertTrue(tree_status.IsTreeOpen(status_url=self.status_url,
121                     throttled_ok=True))
122
123   def testTreeIsThrottledNotOk(self):
124     """Tests that we respect throttled_ok"""
125     self._SetupMockTreeStatusResponses(self.status_url,
126       rejected_tree_status='Tree is throttled (flaky bug on flaky builder)',
127       rejected_general_state=constants.TREE_THROTTLED,
128       output_final_status=False)
129     self.assertFalse(tree_status.IsTreeOpen(status_url=self.status_url,
130                                             period=0.1))
131
132   def testWaitForStatusOpen(self):
133     """Tests that we can wait for a tree open response."""
134     self._SetupMockTreeStatusResponses(self.status_url)
135     self.assertEqual(tree_status.WaitForTreeStatus(status_url=self.status_url),
136                      constants.TREE_OPEN)
137
138
139   def testWaitForStatusThrottled(self):
140     """Tests that we can wait for a tree open response."""
141     self._SetupMockTreeStatusResponses(self.status_url,
142         final_general_state=constants.TREE_THROTTLED)
143     self.assertEqual(tree_status.WaitForTreeStatus(status_url=self.status_url,
144                                                    throttled_ok=True),
145                      constants.TREE_THROTTLED)
146
147   def testWaitForStatusFailure(self):
148     """Tests that we can wait for a tree open response."""
149     self._SetupMockTreeStatusResponses(self.status_url,
150                                        output_final_status=False)
151     self.assertRaises(timeout_util.TimeoutError,
152                       tree_status.WaitForTreeStatus,
153                       status_url=self.status_url,
154                       period=0.1)
155
156   def testGetStatusDictParsesMessage(self):
157     """Tests that _GetStatusDict parses message correctly."""
158     self._SetupMockTreeStatusResponses(
159         self.status_url,
160         final_tree_status="Tree is throttled (foo canary: taco investigating)",
161         final_general_state=constants.TREE_OPEN)
162     data = tree_status._GetStatusDict(self.status_url)
163     self.assertEqual(data[tree_status.TREE_STATUS_MESSAGE],
164                      'foo canary: taco investigating')
165
166   def testGetStatusDictEmptyMessage(self):
167     """Tests that _GetStatusDict stores an empty string for unknown format."""
168     self._SetupMockTreeStatusResponses(
169         self.status_url,
170         final_tree_status='Tree is throttled. foo canary -> crbug.com/bar',
171         final_general_state=constants.TREE_OPEN)
172     data = tree_status._GetStatusDict(self.status_url)
173     self.assertEqual(data[tree_status.TREE_STATUS_MESSAGE], '')
174
175   def testGetStatusDictRawMessage(self):
176     """Tests that _GetStatusDict stores raw message if requested."""
177     self._SetupMockTreeStatusResponses(self.status_url,
178                                        final_tree_status='Tree is open (taco).',
179                                        final_general_state=constants.TREE_OPEN)
180     data = tree_status._GetStatusDict(self.status_url, raw_message=True)
181     self.assertEqual(data[tree_status.TREE_STATUS_MESSAGE],
182                      'Tree is open (taco).')
183
184   def testUpdateTreeStatusWithEpilogue(self):
185     """Tests that epilogue is appended to the message."""
186     with mock.patch.object(tree_status,'_UpdateTreeStatus') as m:
187       tree_status.UpdateTreeStatus(
188           constants.TREE_CLOSED, 'failure', announcer='foo',
189           epilogue='bar')
190       m.assert_called_once_with(mock.ANY, 'Tree is closed (foo: failure | bar)')
191
192   def testUpdateTreeStatusWithoutEpilogue(self):
193     """Tests that the tree status message is created as expected."""
194     with mock.patch.object(tree_status,'_UpdateTreeStatus') as m:
195       tree_status.UpdateTreeStatus(
196           constants.TREE_CLOSED, 'failure', announcer='foo')
197       m.assert_called_once_with(mock.ANY, 'Tree is closed (foo: failure)')
198
199   def testUpdateTreeStatusUnknownStatus(self):
200     """Tests that the exception is raised on unknown tree status."""
201     with mock.patch.object(tree_status,'_UpdateTreeStatus'):
202       self.assertRaises(tree_status.InvalidTreeStatus,
203                         tree_status.UpdateTreeStatus, 'foostatus', 'failure')
204
205   def testThrottlesTreeOnWithBuildNumberAndType(self):
206     """Tests that tree is throttled with the build number in the message."""
207     self._SetupMockTreeStatusResponses(self.status_url,
208                                        final_tree_status='Tree is open (taco)',
209                                        final_general_state=constants.TREE_OPEN)
210     with mock.patch.object(tree_status, '_UpdateTreeStatus') as m:
211       tree_status.ThrottleOrCloseTheTree('foo', 'failure', buildnumber=1234,
212                                          internal=True)
213       m.assert_called_once_with(mock.ANY,
214                                 'Tree is throttled (foo-i-1234: failure)')
215
216   def testThrottlesTreeOnWithBuildNumberAndPublicType(self):
217     """Tests that tree is throttled with the build number in the message."""
218     self._SetupMockTreeStatusResponses(self.status_url,
219                                        final_tree_status='Tree is open (taco)',
220                                        final_general_state=constants.TREE_OPEN)
221     with mock.patch.object(tree_status, '_UpdateTreeStatus') as m:
222       tree_status.ThrottleOrCloseTheTree('foo', 'failure', buildnumber=1234,
223                                          internal=False)
224       m.assert_called_once_with(mock.ANY,
225                                 'Tree is throttled (foo-p-1234: failure)')
226
227   def testThrottlesTreeOnOpen(self):
228     """Tests that ThrottleOrCloseTheTree throttles the tree if tree is open."""
229     self._SetupMockTreeStatusResponses(self.status_url,
230                                        final_tree_status='Tree is open (taco)',
231                                        final_general_state=constants.TREE_OPEN)
232     with mock.patch.object(tree_status,'_UpdateTreeStatus') as m:
233       tree_status.ThrottleOrCloseTheTree('foo', 'failure')
234       m.assert_called_once_with(mock.ANY, 'Tree is throttled (foo: failure)')
235
236   def testThrottlesTreeOnThrottled(self):
237     """Tests ThrottleOrCloseTheTree throttles the tree if tree is throttled."""
238     self._SetupMockTreeStatusResponses(
239         self.status_url,
240         final_tree_status='Tree is throttled (taco)',
241         final_general_state=constants.TREE_THROTTLED)
242     with mock.patch.object(tree_status,'_UpdateTreeStatus') as m:
243       tree_status.ThrottleOrCloseTheTree('foo', 'failure')
244       # Also make sure that previous status message is included.
245       m.assert_called_once_with(mock.ANY,
246                                 'Tree is throttled (foo: failure | taco)')
247
248   def testClosesTheTreeOnClosed(self):
249     """Tests ThrottleOrCloseTheTree closes the tree if tree is closed."""
250     self._SetupMockTreeStatusResponses(
251         self.status_url,
252         final_tree_status='Tree is closed (taco)',
253         final_general_state=constants.TREE_CLOSED)
254     with mock.patch.object(tree_status,'_UpdateTreeStatus') as m:
255       tree_status.ThrottleOrCloseTheTree('foo', 'failure')
256       m.assert_called_once_with(mock.ANY,
257                                 'Tree is closed (foo: failure | taco)')
258
259   def testClosesTheTreeOnMaintenance(self):
260     """Tests ThrottleOrCloseTheTree closes the tree if tree is closed."""
261     self._SetupMockTreeStatusResponses(
262         self.status_url,
263         final_tree_status='Tree is under maintenance (taco)',
264         final_general_state=constants.TREE_MAINTENANCE)
265     with mock.patch.object(tree_status,'_UpdateTreeStatus') as m:
266       tree_status.ThrottleOrCloseTheTree('foo', 'failure')
267       m.assert_called_once_with(
268           mock.ANY,
269           'Tree is under maintenance (foo: failure | taco)')
270
271   def testDiscardUpdateFromTheSameAnnouncer(self):
272     """Tests we don't include messages from the same announcer."""
273     self._SetupMockTreeStatusResponses(
274         self.status_url,
275         final_tree_status='Tree is throttled (foo: failure | bar: taco)',
276         final_general_state=constants.TREE_THROTTLED)
277     with mock.patch.object(tree_status,'_UpdateTreeStatus') as m:
278       tree_status.ThrottleOrCloseTheTree('foo', 'failure')
279       # Also make sure that previous status message is included.
280       m.assert_called_once_with(mock.ANY,
281                                 'Tree is throttled (foo: failure | bar: taco)')
282
283
284 class TestGettingSheriffEmails(cros_test_lib.MockTestCase):
285   """Tests functions related to retrieving the sheriff's email address."""
286
287   def testParsingSheriffEmails(self):
288     """Tests parsing the raw data to get sheriff emails."""
289     # Test parsing when there is only one sheriff.
290     raw_line = "document.write('taco')"
291     self.PatchObject(tree_status, '_OpenSheriffURL', return_value=raw_line)
292     self.assertEqual(tree_status.GetSheriffEmailAddresses('build'),
293                      ['taco@google.com'])
294
295     # Test parsing when there are multiple sheriffs.
296     raw_line = "document.write('taco, burrito')"
297     self.PatchObject(tree_status, '_OpenSheriffURL', return_value=raw_line)
298     self.assertEqual(tree_status.GetSheriffEmailAddresses('build'),
299                      ['taco@google.com', 'burrito@google.com'])
300
301     # Test parsing when sheriff is None.
302     raw_line = "document.write('None (channel is sheriff)')"
303     self.PatchObject(tree_status, '_OpenSheriffURL', return_value=raw_line)
304     self.assertEqual(tree_status.GetSheriffEmailAddresses('lab'), [])
305
306
307 if __name__ == '__main__':
308   cros_test_lib.main()