OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2016 The LUCI Authors. All rights reserved. | 2 # Copyright 2016 The LUCI Authors. All rights reserved. |
3 # Use of this source code is governed under the Apache License, Version 2.0 | 3 # Use of this source code is governed under the Apache License, Version 2.0 |
4 # that can be found in the LICENSE file. | 4 # that can be found in the LICENSE file. |
5 | 5 |
6 import logging | 6 import logging |
7 import sys | 7 import sys |
8 import threading | 8 import threading |
9 import time | 9 import time |
10 import unittest | 10 import unittest |
(...skipping 18 matching lines...) Expand all Loading... | |
29 def TaskUpdate(self, request, **_kwargs): | 29 def TaskUpdate(self, request, **_kwargs): |
30 return self._testobj._handle_call('TaskUpdate', request) | 30 return self._testobj._handle_call('TaskUpdate', request) |
31 | 31 |
32 def Handshake(self, request, **_kwargs): | 32 def Handshake(self, request, **_kwargs): |
33 return self._testobj._handle_call('Handshake', request) | 33 return self._testobj._handle_call('Handshake', request) |
34 | 34 |
35 def Poll(self, request, **_kwargs): | 35 def Poll(self, request, **_kwargs): |
36 return self._testobj._handle_call('Poll', request) | 36 return self._testobj._handle_call('Poll', request) |
37 | 37 |
38 | 38 |
39 class FakeGrpcError(remote_client_grpc.grpc.RpcError): | |
40 """Duplicates a basic UNAVAILABLE error""" | |
41 def __init__(self, code): | |
42 self._code = code | |
43 super(FakeGrpcError, self).__init__('something terrible happened') | |
44 | |
45 def code(self): | |
46 return self._code | |
47 | |
M-A Ruel
2016/12/21 16:31:44
add empty line here
aludwin
2016/12/21 16:50:35
Done.
| |
39 class TestRemoteClientGrpc(auto_stub.TestCase): | 48 class TestRemoteClientGrpc(auto_stub.TestCase): |
40 def setUp(self): | 49 def setUp(self): |
41 super(TestRemoteClientGrpc, self).setUp() | 50 super(TestRemoteClientGrpc, self).setUp() |
51 self._num_sleeps = 0 | |
52 def fake_sleep(_time): | |
53 self._num_sleeps += 1 | |
54 self.mock(time, 'sleep', fake_sleep) | |
42 self._client = remote_client_grpc.RemoteClientGrpc('1.2.3.4:90') | 55 self._client = remote_client_grpc.RemoteClientGrpc('1.2.3.4:90') |
43 self._client._stub = FakeBotServiceStub(self) | 56 self._client._stub = FakeBotServiceStub(self) |
44 self._expected = [] | 57 self._expected = [] |
58 self._error_codes = [] | |
45 | 59 |
46 def _handle_call(self, method, request): | 60 def _handle_call(self, method, request): |
47 """This is called by FakeBotServiceStub to implement fake calls""" | 61 """This is called by FakeBotServiceStub to implement fake calls""" |
62 if len(self._error_codes) > 0: | |
63 code, self._error_codes = self._error_codes[0], self._error_codes[1:] | |
64 raise FakeGrpcError(code) | |
65 | |
66 if self._error_codes: | |
67 text = self._error_codes | |
68 self._error_codes = '' | |
69 raise FakeGrpcError(text) | |
70 | |
48 # Pop off the first item on the list | 71 # Pop off the first item on the list |
49 self.assertTrue(len(self._expected) > 0) | 72 self.assertTrue(len(self._expected) > 0) |
50 expected, self._expected = self._expected[0], self._expected[1:] | 73 expected, self._expected = self._expected[0], self._expected[1:] |
51 # Each element of the "expected" array should be a 3-tuple: | 74 # Each element of the "expected" array should be a 3-tuple: |
52 # * The name of the method (eg 'TaskUpdate') | 75 # * The name of the method (eg 'TaskUpdate') |
53 # * The proto request | 76 # * The proto request |
54 # * The proto response | 77 # * The proto response |
55 self.assertEqual(method, expected[0]) | 78 self.assertEqual(method, expected[0]) |
56 self.assertEqual(request, expected[1]) | 79 self.assertEqual(request, expected[1]) |
57 return expected[2] | 80 return expected[2] |
58 | 81 |
59 def get_bot_attributes_dict(self): | 82 def get_bot_attributes_dict(self): |
60 """Gets the attributes of a basic bot""" | 83 """Gets the attributes of a basic bot; must match next function""" |
61 return { | 84 return { |
62 'version': '123', | 85 'version': '123', |
63 'dimensions': { | 86 'dimensions': { |
64 'mammal': ['ferrett', 'wombat'], | 87 'mammal': ['ferrett', 'wombat'], |
65 'pool': ['dead'], | 88 'pool': ['dead'], |
66 }, | 89 }, |
67 'state': { | 90 'state': { |
68 'audio': ['Rachmaninov', 'Stravinsky'], | 91 'audio': ['Rachmaninov', 'Stravinsky'], |
69 'cost_usd_hour': 3.141, | 92 'cost_usd_hour': 3.141, |
70 'cpu': 'Intel 8080', | 93 'cpu': 'Intel 8080', |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 'server_version': u'101', | 141 'server_version': u'101', |
119 'bot_version': u'102', | 142 'bot_version': u'102', |
120 'bot_group_cfg_version': u'', | 143 'bot_group_cfg_version': u'', |
121 'bot_group_cfg': { | 144 'bot_group_cfg': { |
122 'dimensions': { | 145 'dimensions': { |
123 u'mammal': [u'kangaroo', u'emu'], | 146 u'mammal': [u'kangaroo', u'emu'], |
124 }, | 147 }, |
125 }, | 148 }, |
126 }) | 149 }) |
127 | 150 |
151 def test_handshake_grpc_unavailable(self): | |
152 """Ensures that the handshake function sleeps after a gRPC error""" | |
153 msg_req = remote_client_grpc.swarming_bot_pb2.HandshakeRequest() | |
154 msg_req.attributes.CopyFrom(self.get_bot_attributes_proto()) | |
155 | |
156 # Create proto response | |
157 msg_rsp = remote_client_grpc.swarming_bot_pb2.HandshakeResponse() | |
158 msg_rsp.server_version = '101' | |
159 msg_rsp.bot_version = '102' | |
160 d1 = msg_rsp.bot_group_cfg.dimensions.add() | |
161 d1.name = 'mammal' | |
162 d1.values.extend(['kangaroo', 'emu']) | |
163 | |
164 # Execute call and verify response | |
165 expected_call = ('Handshake', msg_req, msg_rsp) | |
166 self._expected.append(expected_call) | |
167 self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE) | |
168 self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE) | |
169 response = self._client.do_handshake(self.get_bot_attributes_dict()) | |
170 self.assertEqual(self._num_sleeps, 2) | |
171 self.assertEqual(response, { | |
172 'server_version': u'101', | |
173 'bot_version': u'102', | |
174 'bot_group_cfg_version': u'', | |
175 'bot_group_cfg': { | |
176 'dimensions': { | |
177 u'mammal': [u'kangaroo', u'emu'], | |
178 }, | |
179 }, | |
180 }) | |
181 | |
182 def test_handshake_grpc_other_error(self): | |
183 """Ensures that the handshake function only catches UNAVAILABLE""" | |
184 self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE) | |
185 self._error_codes.append(remote_client_grpc.grpc.StatusCode.INTERNAL) | |
186 got_exception = None | |
187 try: | |
188 self._client.do_handshake(self.get_bot_attributes_dict()) | |
189 except remote_client_grpc.grpc.RpcError as g: | |
190 got_exception = g | |
191 self.assertEqual(got_exception.code(), | |
192 remote_client_grpc.grpc.StatusCode.INTERNAL) | |
193 self.assertEqual(self._num_sleeps, 1) | |
194 | |
195 def test_handshake_grpc_too_many_errors(self): | |
196 """Ensures that the handshake function only catches UNAVAILABLE""" | |
197 self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE) | |
198 self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE) | |
199 self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE) | |
200 self.mock(remote_client_grpc, 'MAX_GRPC_ATTEMPTS', 2) | |
201 got_exception = None | |
202 try: | |
M-A Ruel
2016/12/21 16:31:44
FYI, you can do instead:
with self.asserRaises(re
aludwin
2016/12/21 16:50:35
Done.
| |
203 self._client.do_handshake(self.get_bot_attributes_dict()) | |
204 except remote_client_grpc.grpc.RpcError as g: | |
205 got_exception = g | |
206 self.assertEqual(self._num_sleeps, 2) | |
207 self.assertEqual(got_exception.code(), | |
208 remote_client_grpc.grpc.StatusCode.UNAVAILABLE) | |
209 | |
128 def test_poll_manifest(self): | 210 def test_poll_manifest(self): |
129 """Verifies that we can generate a reasonable manifest from a proto""" | 211 """Verifies that we can generate a reasonable manifest from a proto""" |
130 msg_req = remote_client_grpc.swarming_bot_pb2.PollRequest() | 212 msg_req = remote_client_grpc.swarming_bot_pb2.PollRequest() |
131 msg_req.attributes.CopyFrom(self.get_bot_attributes_proto()) | 213 msg_req.attributes.CopyFrom(self.get_bot_attributes_proto()) |
132 | 214 |
133 # Create dict response | 215 # Create dict response |
134 dict_rsp = { | 216 dict_rsp = { |
135 'bot_id': u'baby_bot', | 217 'bot_id': u'baby_bot', |
136 'command': None, | 218 'command': None, |
137 'dimensions': { | 219 'dimensions': { |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
245 self._expected.append(expected_call) | 327 self._expected.append(expected_call) |
246 response = self._client.post_task_update('abc123', 'baby_bot', params, | 328 response = self._client.post_task_update('abc123', 'baby_bot', params, |
247 ['abc', 7], -5) | 329 ['abc', 7], -5) |
248 self.assertTrue(response) | 330 self.assertTrue(response) |
249 | 331 |
250 if __name__ == '__main__': | 332 if __name__ == '__main__': |
251 logging.basicConfig( | 333 logging.basicConfig( |
252 level=logging.DEBUG if '-v' in sys.argv else logging.CRITICAL) | 334 level=logging.DEBUG if '-v' in sys.argv else logging.CRITICAL) |
253 unittest.TestCase.maxDiff = None | 335 unittest.TestCase.maxDiff = None |
254 unittest.main() | 336 unittest.main() |
OLD | NEW |