Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Unified Diff: appengine/swarming/swarming_bot/bot_code/remote_client_grpc_test.py

Issue 2592683002: Retry non-streaming gRPC calls (Closed)
Patch Set: Disable incorrect pylint warning Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « appengine/swarming/swarming_bot/bot_code/remote_client_grpc.py ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: appengine/swarming/swarming_bot/bot_code/remote_client_grpc_test.py
diff --git a/appengine/swarming/swarming_bot/bot_code/remote_client_grpc_test.py b/appengine/swarming/swarming_bot/bot_code/remote_client_grpc_test.py
index 30085ee0c2b7c725594fd0142fdd1b65522e6eeb..7110c5bb6438a38a6ff6eb6733ecbb1b14213125 100755
--- a/appengine/swarming/swarming_bot/bot_code/remote_client_grpc_test.py
+++ b/appengine/swarming/swarming_bot/bot_code/remote_client_grpc_test.py
@@ -36,15 +36,44 @@ class FakeBotServiceStub(object):
return self._testobj._handle_call('Poll', request)
+# If gRPC isn't successfully imported, this will be seen as a nonstandard
+# exception because it won't appear to be derived from Exception. This
+# only affects PyLint because the test will never be run if gRPC import
+# fails.
+# pylint: disable=W0710
+class FakeGrpcError(remote_client_grpc.grpc.RpcError):
+ """Duplicates a basic UNAVAILABLE error"""
+ def __init__(self, code):
+ self._code = code
+ super(FakeGrpcError, self).__init__('something terrible happened')
+
+ def code(self):
+ return self._code
+
+
class TestRemoteClientGrpc(auto_stub.TestCase):
def setUp(self):
super(TestRemoteClientGrpc, self).setUp()
+ self._num_sleeps = 0
+ def fake_sleep(_time):
+ self._num_sleeps += 1
+ self.mock(time, 'sleep', fake_sleep)
self._client = remote_client_grpc.RemoteClientGrpc('1.2.3.4:90')
self._client._stub = FakeBotServiceStub(self)
self._expected = []
+ self._error_codes = []
def _handle_call(self, method, request):
"""This is called by FakeBotServiceStub to implement fake calls"""
+ if len(self._error_codes) > 0:
+ code, self._error_codes = self._error_codes[0], self._error_codes[1:]
+ raise FakeGrpcError(code)
+
+ if self._error_codes:
+ text = self._error_codes
+ self._error_codes = ''
+ raise FakeGrpcError(text)
+
# Pop off the first item on the list
self.assertTrue(len(self._expected) > 0)
expected, self._expected = self._expected[0], self._expected[1:]
@@ -57,7 +86,7 @@ class TestRemoteClientGrpc(auto_stub.TestCase):
return expected[2]
def get_bot_attributes_dict(self):
- """Gets the attributes of a basic bot"""
+ """Gets the attributes of a basic bot; must match next function"""
return {
'version': '123',
'dimensions': {
@@ -125,6 +154,62 @@ class TestRemoteClientGrpc(auto_stub.TestCase):
},
})
+ def test_handshake_grpc_unavailable(self):
+ """Ensures that the handshake function sleeps after a gRPC error"""
+ msg_req = remote_client_grpc.swarming_bot_pb2.HandshakeRequest()
+ msg_req.attributes.CopyFrom(self.get_bot_attributes_proto())
+
+ # Create proto response
+ msg_rsp = remote_client_grpc.swarming_bot_pb2.HandshakeResponse()
+ msg_rsp.server_version = '101'
+ msg_rsp.bot_version = '102'
+ d1 = msg_rsp.bot_group_cfg.dimensions.add()
+ d1.name = 'mammal'
+ d1.values.extend(['kangaroo', 'emu'])
+
+ # Execute call and verify response
+ expected_call = ('Handshake', msg_req, msg_rsp)
+ self._expected.append(expected_call)
+ self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE)
+ self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE)
+ response = self._client.do_handshake(self.get_bot_attributes_dict())
+ self.assertEqual(self._num_sleeps, 2)
+ self.assertEqual(response, {
+ 'server_version': u'101',
+ 'bot_version': u'102',
+ 'bot_group_cfg_version': u'',
+ 'bot_group_cfg': {
+ 'dimensions': {
+ u'mammal': [u'kangaroo', u'emu'],
+ },
+ },
+ })
+
+ def test_handshake_grpc_other_error(self):
+ """Ensures that the handshake function only catches UNAVAILABLE"""
+ self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE)
+ self._error_codes.append(remote_client_grpc.grpc.StatusCode.INTERNAL)
+ got_exception = None
+ try:
+ self._client.do_handshake(self.get_bot_attributes_dict())
+ except remote_client_grpc.grpc.RpcError as g:
+ got_exception = g
+ self.assertEqual(got_exception.code(),
+ remote_client_grpc.grpc.StatusCode.INTERNAL)
+ self.assertEqual(self._num_sleeps, 1)
+
+ def test_handshake_grpc_too_many_errors(self):
+ """Ensures that the handshake function only catches UNAVAILABLE"""
+ self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE)
+ self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE)
+ self._error_codes.append(remote_client_grpc.grpc.StatusCode.UNAVAILABLE)
+ self.mock(remote_client_grpc, 'MAX_GRPC_ATTEMPTS', 2)
+ with self.assertRaises(remote_client_grpc.grpc.RpcError) as g:
+ self._client.do_handshake(self.get_bot_attributes_dict())
+ self.assertEqual(self._num_sleeps, 2)
+ self.assertEqual(g.exception.code(),
+ remote_client_grpc.grpc.StatusCode.UNAVAILABLE)
+
def test_poll_manifest(self):
"""Verifies that we can generate a reasonable manifest from a proto"""
msg_req = remote_client_grpc.swarming_bot_pb2.PollRequest()
« no previous file with comments | « appengine/swarming/swarming_bot/bot_code/remote_client_grpc.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698