OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2014 The LUCI Authors. All rights reserved. | 2 # Copyright 2014 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 binascii | 6 import binascii |
| 7 import os |
| 8 import re |
| 9 import sys |
7 import time | 10 import time |
8 import unittest | 11 import unittest |
9 import sys | |
10 | 12 |
11 # Somehow this lets us find isolate_storage | 13 # Somehow this lets us find isolate_storage |
12 import net_utils | 14 import net_utils |
13 | 15 |
14 from depot_tools import auto_stub | 16 from depot_tools import auto_stub |
15 import isolate_storage | 17 import isolate_storage |
16 import test_utils | 18 import test_utils |
17 | 19 |
18 | 20 class ByteStreamStubMock(object): |
19 class FileServiceStubMock(object): | |
20 """Replacement for real gRPC stub | 21 """Replacement for real gRPC stub |
21 | 22 |
22 We can't mock *within* the real stub to replace individual functions, plus | 23 We can't mock *within* the real stub to replace individual functions, plus |
23 we'd have to mock __init__ every time anyway. So this class replaces the | 24 we'd have to mock __init__ every time anyway. So this class replaces the |
24 entire stub. As for the functions, they implement default happy path | 25 entire stub. As for the functions, they implement default happy path |
25 behaviour where possible, and are not implemented otherwise. | 26 behaviour where possible, and are not implemented otherwise. |
26 """ | 27 """ |
27 def __init__(self, _channel): | 28 def __init__(self, _channel): |
28 self._push_requests = [] | 29 self._push_requests = [] |
29 self._contains_requests = [] | 30 self._contains_requests = [] |
30 | 31 |
31 def FetchBlobs(self, request, timeout=None): | 32 def Read(self, request, timeout=None): |
| 33 del request, timeout |
32 raise NotImplementedError() | 34 raise NotImplementedError() |
33 | 35 |
34 def PushBlobs(self, requests): | 36 def Write(self, requests, timeout=None): |
| 37 del timeout |
| 38 nb = 0 |
35 for r in requests: | 39 for r in requests: |
| 40 nb += len(r.data) |
36 self._push_requests.append(r.__deepcopy__()) | 41 self._push_requests.append(r.__deepcopy__()) |
37 response = isolate_storage.isolate_bot_pb2.PushBlobsReply() | 42 resp = isolate_storage.bytestream_pb2.WriteResponse() |
38 response.status.succeeded = True | 43 resp.committed_size = nb |
39 return response | 44 return resp |
40 | |
41 def Contains(self, request, timeout=None): | |
42 del timeout | |
43 response = isolate_storage.isolate_bot_pb2.ContainsReply() | |
44 self._contains_requests.append(request.__deepcopy__()) | |
45 response.status.succeeded = True | |
46 return response | |
47 | 45 |
48 def popContainsRequests(self): | 46 def popContainsRequests(self): |
49 cr = self._contains_requests | 47 cr = self._contains_requests |
50 self._contains_requests = [] | 48 self._contains_requests = [] |
51 return cr | 49 return cr |
52 | 50 |
53 def popPushRequests(self): | 51 def popPushRequests(self): |
54 pr = self._push_requests | 52 pr = self._push_requests |
55 self._push_requests = [] | 53 self._push_requests = [] |
56 return pr | 54 return pr |
57 | 55 |
| 56 def raiseError(code): |
| 57 raise isolate_storage.grpc.RpcError( |
| 58 'cannot turn this into a real code yet: %s' % code) |
58 | 59 |
59 class IsolateStorageTest(auto_stub.TestCase): | 60 class IsolateStorageTest(auto_stub.TestCase): |
60 def get_server(self): | 61 def get_server(self): |
61 return isolate_storage.IsolateServerGrpc('grpc-proxy.luci.com', | 62 os.environ['ISOLATED_GRPC_PROXY'] = 'https://luci.com/client/bob' |
| 63 return isolate_storage.IsolateServerGrpc('https://luci.appspot.com', |
62 'default-gzip') | 64 'default-gzip') |
63 | 65 |
64 def testFetchHappySimple(self): | 66 def testFetchHappySimple(self): |
65 """Fetch: if we get a few chunks with the right offset, everything works""" | 67 """Fetch: if we get a few chunks with the right offset, everything works""" |
66 def FetchBlobs(self, request, timeout=None): | 68 def Read(self, request, timeout=None): |
67 del timeout | 69 del timeout |
68 self.request = request | 70 self.request = request |
69 response = isolate_storage.isolate_bot_pb2.FetchBlobsReply() | 71 response = isolate_storage.bytestream_pb2.ReadResponse() |
70 response.status.succeeded = True | |
71 for i in range(0, 3): | 72 for i in range(0, 3): |
72 response.data.data = str(i) | 73 response.data = str(i) |
73 response.data.offset = i | |
74 yield response | 74 yield response |
75 self.mock(FileServiceStubMock, 'FetchBlobs', FetchBlobs) | 75 self.mock(ByteStreamStubMock, 'Read', Read) |
76 | 76 |
77 s = self.get_server() | 77 s = self.get_server() |
78 replies = s.fetch('abc123') | 78 replies = s.fetch('abc123') |
79 response = replies.next() | 79 response = replies.next() |
80 self.assertEqual(binascii.unhexlify('abc123'), | |
81 s._stub.request.digest[0].digest) | |
82 self.assertEqual('0', response) | 80 self.assertEqual('0', response) |
83 response = replies.next() | 81 response = replies.next() |
84 self.assertEqual('1', response) | 82 self.assertEqual('1', response) |
85 response = replies.next() | 83 response = replies.next() |
86 self.assertEqual('2', response) | 84 self.assertEqual('2', response) |
87 | 85 |
88 def testFetchHappyZeroLengthBlob(self): | 86 def testFetchHappyZeroLengthBlob(self): |
89 """Fetch: if we get a zero-length blob, everything works""" | 87 """Fetch: if we get a zero-length blob, everything works""" |
90 def FetchBlobs(self, request, timeout=None): | 88 def Read(self, request, timeout=None): |
91 del timeout | 89 del timeout |
92 self.request = request | 90 self.request = request |
93 response = isolate_storage.isolate_bot_pb2.FetchBlobsReply() | 91 response = isolate_storage.bytestream_pb2.ReadResponse() |
94 response.status.succeeded = True | 92 response.data = '' |
95 response.data.data = '' | |
96 yield response | 93 yield response |
97 self.mock(FileServiceStubMock, 'FetchBlobs', FetchBlobs) | 94 self.mock(ByteStreamStubMock, 'Read', Read) |
98 | 95 |
99 s = self.get_server() | 96 s = self.get_server() |
100 replies = s.fetch('abc123') | 97 replies = s.fetch('abc123') |
101 response = replies.next() | 98 reply = replies.next() |
102 self.assertEqual(binascii.unhexlify('abc123'), | 99 self.assertEqual(0, len(reply)) |
103 s._stub.request.digest[0].digest) | |
104 self.assertEqual(0, len(response)) | |
105 | 100 |
106 def testFetchThrowsOnWrongOffset(self): | 101 def testFetchThrowsOnFailure(self): |
107 """Fetch: if we get a chunk with the wrong offset, we throw an exception""" | 102 """Fetch: if something goes wrong in Isolate, we throw an exception""" |
108 def FetchBlobs(self, request, timeout=None): | 103 def Read(self, request, timeout=None): |
109 del timeout | 104 del timeout |
110 self.request = request | 105 self.request = request |
111 response = isolate_storage.isolate_bot_pb2.FetchBlobsReply() | 106 raiseError(isolate_storage.grpc.StatusCode.INTERNAL) |
112 response.status.succeeded = True | 107 self.mock(ByteStreamStubMock, 'Read', Read) |
113 response.data.data = str(42) | |
114 response.data.offset = 1 | |
115 yield response | |
116 self.mock(FileServiceStubMock, 'FetchBlobs', FetchBlobs) | |
117 | 108 |
118 s = self.get_server() | 109 s = self.get_server() |
119 replies = s.fetch('abc123') | 110 replies = s.fetch('abc123') |
120 with self.assertRaises(IOError): | |
121 _response = replies.next() | |
122 | |
123 def testFetchThrowsOnFailure(self): | |
124 """Fetch: if something goes wrong in Isolate, we throw an exception""" | |
125 def FetchBlobs(self, request, timeout=None): | |
126 del timeout | |
127 self.request = request | |
128 response = isolate_storage.isolate_bot_pb2.FetchBlobsReply() | |
129 response.status.succeeded = False | |
130 yield response | |
131 self.mock(FileServiceStubMock, 'FetchBlobs', FetchBlobs) | |
132 | |
133 s = self.get_server() | |
134 replies = s.fetch('abc123') | |
135 with self.assertRaises(IOError): | 111 with self.assertRaises(IOError): |
136 _response = replies.next() | 112 _response = replies.next() |
137 | 113 |
138 def testFetchThrowsCorrectExceptionOnGrpcFailure(self): | 114 def testFetchThrowsCorrectExceptionOnGrpcFailure(self): |
139 """Fetch: if something goes wrong in gRPC, we throw an IOError""" | 115 """Fetch: if something goes wrong in gRPC, we throw an IOError""" |
140 def FetchBlobs(_self, _request, timeout=None): | 116 def Read(_self, _request, timeout=None): |
141 del timeout | 117 del timeout |
142 raise isolate_storage.grpc.RpcError('proxy died during initial fetch :(') | 118 raise isolate_storage.grpc.RpcError('proxy died during initial fetch :(') |
143 self.mock(FileServiceStubMock, 'FetchBlobs', FetchBlobs) | 119 self.mock(ByteStreamStubMock, 'Read', Read) |
144 | 120 |
145 s = self.get_server() | 121 s = self.get_server() |
146 replies = s.fetch('abc123') | 122 replies = s.fetch('abc123') |
147 with self.assertRaises(IOError): | 123 with self.assertRaises(IOError): |
148 _response = replies.next() | 124 _response = replies.next() |
149 | 125 |
150 def testFetchThrowsCorrectExceptionOnStreamingGrpcFailure(self): | 126 def testFetchThrowsCorrectExceptionOnStreamingGrpcFailure(self): |
151 """Fetch: if something goes wrong in gRPC, we throw an IOError""" | 127 """Fetch: if something goes wrong in gRPC, we throw an IOError""" |
152 def FetchBlobs(self, request, timeout=None): | 128 def Read(self, request, timeout=None): |
153 del timeout | 129 del timeout |
154 self.request = request | 130 self.request = request |
155 response = isolate_storage.isolate_bot_pb2.FetchBlobsReply() | 131 response = isolate_storage.bytestream_pb2.ReadResponse() |
156 response.status.succeeded = True | |
157 for i in range(0, 3): | 132 for i in range(0, 3): |
158 if i is 2: | 133 if i is 2: |
159 raise isolate_storage.grpc.RpcError( | 134 raise isolate_storage.grpc.RpcError( |
160 'proxy died during fetch stream :(') | 135 'proxy died during fetch stream :(') |
161 response.data.data = str(i) | 136 response.data = str(i) |
162 response.data.offset = i | |
163 yield response | 137 yield response |
164 self.mock(FileServiceStubMock, 'FetchBlobs', FetchBlobs) | 138 self.mock(ByteStreamStubMock, 'Read', Read) |
165 | 139 |
166 s = self.get_server() | 140 s = self.get_server() |
167 with self.assertRaises(IOError): | 141 with self.assertRaises(IOError): |
168 for _response in s.fetch('abc123'): | 142 for _response in s.fetch('abc123'): |
169 pass | 143 pass |
170 | 144 |
171 def testPushHappySingleSmall(self): | 145 def testPushHappySingleSmall(self): |
172 """Push: send one chunk of small data""" | 146 """Push: send one chunk of small data""" |
173 s = self.get_server() | 147 s = self.get_server() |
174 i = isolate_storage.Item(digest='abc123', size=4) | 148 i = isolate_storage.Item(digest='abc123', size=4) |
175 s.push(i, isolate_storage._IsolateServerGrpcPushState(), '1234') | 149 s.push(i, isolate_storage._IsolateServerGrpcPushState(), '1234') |
176 requests = s._stub.popPushRequests() | 150 requests = s._stub.popPushRequests() |
177 self.assertEqual(1, len(requests)) | 151 self.assertEqual(1, len(requests)) |
178 self.assertEqual(binascii.unhexlify('abc123'), | 152 m = re.search('client/bob/uploads/.*/blobs/abc123/4', |
179 requests[0].data.digest.digest) | 153 requests[0].resource_name) |
180 self.assertEqual(4, requests[0].data.digest.size_bytes) | 154 self.assertTrue(m) |
181 self.assertEqual('1234', requests[0].data.data) | 155 self.assertEqual('1234', requests[0].data) |
| 156 self.assertEqual(0, requests[0].write_offset) |
| 157 self.assertTrue(requests[0].finish_write) |
182 | 158 |
183 def testPushHappySingleBig(self): | 159 def testPushHappySingleBig(self): |
184 """Push: send one chunk of big data by splitting it into two""" | 160 """Push: send one chunk of big data by splitting it into two""" |
185 self.mock(isolate_storage, 'NET_IO_FILE_CHUNK', 3) | 161 self.mock(isolate_storage, 'NET_IO_FILE_CHUNK', 3) |
186 s = self.get_server() | 162 s = self.get_server() |
187 i = isolate_storage.Item(digest='abc123', size=4) | 163 i = isolate_storage.Item(digest='abc123', size=4) |
188 s.push(i, isolate_storage._IsolateServerGrpcPushState(), '1234') | 164 s.push(i, isolate_storage._IsolateServerGrpcPushState(), '1234') |
189 requests = s._stub.popPushRequests() | 165 requests = s._stub.popPushRequests() |
190 self.assertEqual(2, len(requests)) | 166 self.assertEqual(2, len(requests)) |
191 self.assertEqual(binascii.unhexlify('abc123'), | 167 m = re.search('client/bob/uploads/.*/blobs/abc123/4', |
192 requests[0].data.digest.digest) | 168 requests[0].resource_name) |
193 self.assertEqual(4, requests[0].data.digest.size_bytes) | 169 self.assertTrue(m) |
194 self.assertEqual('123', requests[0].data.data) | 170 self.assertEqual('123', requests[0].data) |
195 self.assertFalse(requests[1].data.HasField('digest')) | 171 self.assertEqual(0, requests[0].write_offset) |
196 self.assertEqual('4', requests[1].data.data) | 172 self.assertFalse(requests[0].finish_write) |
| 173 self.assertEqual('4', requests[1].data) |
| 174 self.assertEqual(3, requests[1].write_offset) |
| 175 self.assertTrue(requests[1].finish_write) |
197 | 176 |
198 def testPushHappyMultiSmall(self): | 177 def testPushHappyMultiSmall(self): |
199 """Push: sends multiple small chunks""" | 178 """Push: sends multiple small chunks""" |
200 s = self.get_server() | 179 s = self.get_server() |
201 i = isolate_storage.Item(digest='abc123', size=4) | 180 i = isolate_storage.Item(digest='abc123', size=4) |
202 s.push(i, isolate_storage._IsolateServerGrpcPushState(), ['12', '34']) | 181 s.push(i, isolate_storage._IsolateServerGrpcPushState(), ['12', '34']) |
203 requests = s._stub.popPushRequests() | 182 requests = s._stub.popPushRequests() |
204 self.assertEqual(2, len(requests)) | 183 self.assertEqual(2, len(requests)) |
205 self.assertEqual(binascii.unhexlify('abc123'), | 184 m = re.search('client/bob/uploads/.*/blobs/abc123/4', |
206 requests[0].data.digest.digest) | 185 requests[0].resource_name) |
207 self.assertEqual(4, requests[0].data.digest.size_bytes) | 186 self.assertTrue(m) |
208 self.assertEqual('12', requests[0].data.data) | 187 self.assertEqual('12', requests[0].data) |
209 self.assertFalse(requests[1].data.HasField('digest')) | 188 self.assertEqual(0, requests[0].write_offset) |
210 self.assertEqual('34', requests[1].data.data) | 189 self.assertFalse(requests[0].finish_write) |
| 190 self.assertEqual('34', requests[1].data) |
| 191 self.assertEqual(2, requests[1].write_offset) |
| 192 self.assertTrue(requests[1].finish_write) |
211 | 193 |
212 def testPushHappyMultiBig(self): | 194 def testPushHappyMultiBig(self): |
213 """Push: sends multiple chunks, each of which have to be split""" | 195 """Push: sends multiple chunks, each of which have to be split""" |
214 self.mock(isolate_storage, 'NET_IO_FILE_CHUNK', 2) | 196 self.mock(isolate_storage, 'NET_IO_FILE_CHUNK', 2) |
215 s = self.get_server() | 197 s = self.get_server() |
216 i = isolate_storage.Item(digest='abc123', size=6) | 198 i = isolate_storage.Item(digest='abc123', size=6) |
217 s.push(i, isolate_storage._IsolateServerGrpcPushState(), ['123', '456']) | 199 s.push(i, isolate_storage._IsolateServerGrpcPushState(), ['123', '456']) |
218 requests = s._stub.popPushRequests() | 200 requests = s._stub.popPushRequests() |
219 self.assertEqual(4, len(requests)) | 201 self.assertEqual(4, len(requests)) |
220 self.assertEqual(binascii.unhexlify('abc123'), | 202 m = re.search('client/bob/uploads/.*/blobs/abc123/6', |
221 requests[0].data.digest.digest) | 203 requests[0].resource_name) |
222 self.assertEqual(6, requests[0].data.digest.size_bytes) | 204 self.assertTrue(m) |
223 self.assertEqual('12', requests[0].data.data) | 205 self.assertEqual(0, requests[0].write_offset) |
224 self.assertFalse(requests[1].data.HasField('digest')) | 206 self.assertEqual('12', requests[0].data) |
225 self.assertEqual('3', requests[1].data.data) | 207 self.assertFalse(requests[0].finish_write) |
226 self.assertEqual('45', requests[2].data.data) | 208 self.assertEqual(2, requests[1].write_offset) |
227 self.assertEqual('6', requests[3].data.data) | 209 self.assertEqual('3', requests[1].data) |
| 210 self.assertFalse(requests[1].finish_write) |
| 211 self.assertEqual(3, requests[2].write_offset) |
| 212 self.assertEqual('45', requests[2].data) |
| 213 self.assertFalse(requests[2].finish_write) |
| 214 self.assertEqual(5, requests[3].write_offset) |
| 215 self.assertEqual('6', requests[3].data) |
| 216 self.assertTrue(requests[3].finish_write) |
228 | 217 |
229 def testPushHappyZeroLengthBlob(self): | 218 def testPushHappyZeroLengthBlob(self): |
230 """Push: send a zero-length blob""" | 219 """Push: send a zero-length blob""" |
231 s = self.get_server() | 220 s = self.get_server() |
232 i = isolate_storage.Item(digest='abc123', size=0) | 221 i = isolate_storage.Item(digest='abc123', size=0) |
233 s.push(i, isolate_storage._IsolateServerGrpcPushState(), '') | 222 s.push(i, isolate_storage._IsolateServerGrpcPushState(), '') |
234 requests = s._stub.popPushRequests() | 223 requests = s._stub.popPushRequests() |
235 self.assertEqual(1, len(requests)) | 224 self.assertEqual(1, len(requests)) |
236 self.assertEqual(binascii.unhexlify('abc123'), | 225 m = re.search('client/bob/uploads/.*/blobs/abc123/0', |
237 requests[0].data.digest.digest) | 226 requests[0].resource_name) |
238 self.assertEqual(0, requests[0].data.digest.size_bytes) | 227 self.assertTrue(m) |
239 self.assertEqual('', requests[0].data.data) | 228 self.assertEqual(0, requests[0].write_offset) |
| 229 self.assertEqual('', requests[0].data) |
| 230 self.assertTrue(requests[0].finish_write) |
240 | 231 |
241 def testPushThrowsOnFailure(self): | 232 def testPushThrowsOnFailure(self): |
242 """Push: if something goes wrong in Isolate, we throw an exception""" | 233 """Push: if something goes wrong in Isolate, we throw an exception""" |
243 def PushBlobs(self, request, timeout=None): | 234 def Write(self, request, timeout=None): |
244 del request, timeout, self | 235 del request, timeout, self |
245 response = isolate_storage.isolate_bot_pb2.PushBlobsReply() | 236 raiseError(isolate_storage.grpc.StatusCode.INTERNAL_ERROR) |
246 response.status.succeeded = False | 237 self.mock(ByteStreamStubMock, 'Write', Write) |
247 return response | |
248 self.mock(FileServiceStubMock, 'PushBlobs', PushBlobs) | |
249 | 238 |
250 s = self.get_server() | 239 s = self.get_server() |
251 i = isolate_storage.Item(digest='abc123', size=0) | 240 i = isolate_storage.Item(digest='abc123', size=0) |
252 with self.assertRaises(IOError): | 241 with self.assertRaises(IOError): |
253 s.push(i, isolate_storage._IsolateServerGrpcPushState(), '1234') | 242 s.push(i, isolate_storage._IsolateServerGrpcPushState(), '1234') |
254 | 243 |
255 def testPushThrowsCorrectExceptionOnGrpcFailure(self): | 244 def testPushThrowsCorrectExceptionOnGrpcFailure(self): |
256 """Push: if something goes wrong in Isolate, we throw an exception""" | 245 """Push: if something goes wrong in Isolate, we throw an exception""" |
257 def PushBlobs(_self, _request, timeout=None): | 246 def Write(_self, _request, timeout=None): |
258 del timeout | 247 del timeout |
259 raise isolate_storage.grpc.RpcError('proxy died during push :(') | 248 raise isolate_storage.grpc.RpcError('proxy died during push :(') |
260 self.mock(FileServiceStubMock, 'PushBlobs', PushBlobs) | 249 self.mock(ByteStreamStubMock, 'Write', Write) |
261 | 250 |
262 s = self.get_server() | 251 s = self.get_server() |
263 i = isolate_storage.Item(digest='abc123', size=0) | 252 i = isolate_storage.Item(digest='abc123', size=0) |
264 with self.assertRaises(IOError): | 253 with self.assertRaises(IOError): |
265 s.push(i, isolate_storage._IsolateServerGrpcPushState(), '1234') | 254 s.push(i, isolate_storage._IsolateServerGrpcPushState(), '1234') |
266 | 255 |
267 def testContainsHappySimple(self): | |
268 """Contains: basic sanity check""" | |
269 items = [] | |
270 for i in range(0, 3): | |
271 digest = ''.join(['a', str(i)]) | |
272 i = isolate_storage.Item(digest=digest, size=1) | |
273 items.append(i) | |
274 s = self.get_server() | |
275 response = s.contains(items) | |
276 self.assertEqual(0, len(response)) | |
277 requests = s._stub.popContainsRequests() | |
278 self.assertEqual(3, len(requests[0].digest)) | |
279 self.assertEqual('\xa0', requests[0].digest[0].digest) | |
280 self.assertEqual('\xa1', requests[0].digest[1].digest) | |
281 self.assertEqual('\xa2', requests[0].digest[2].digest) | |
282 | |
283 def testContainsMissingSimple(self): | |
284 """Contains: the digests are missing""" | |
285 def Contains(self, request, timeout=None): | |
286 del timeout, self | |
287 response = isolate_storage.isolate_bot_pb2.ContainsReply() | |
288 response.status.succeeded = False | |
289 response.status.error = ( | |
290 isolate_storage.isolate_bot_pb2.BlobStatus.MISSING_DIGEST) | |
291 for d in request.digest: | |
292 msg = response.status.missing_digest.add() | |
293 msg.CopyFrom(d) | |
294 return response | |
295 self.mock(FileServiceStubMock, 'Contains', Contains) | |
296 | |
297 items = [] | |
298 for i in range(0, 3): | |
299 digest = ''.join(['a', str(i)]) | |
300 i = isolate_storage.Item(digest=digest, size=1) | |
301 items.append(i) | |
302 s = self.get_server() | |
303 response = s.contains(items) | |
304 self.assertEqual(3, len(response)) | |
305 self.assertTrue(items[0] in response) | |
306 self.assertTrue(items[1] in response) | |
307 self.assertTrue(items[2] in response) | |
308 | |
309 def testContainsThrowsCorrectExceptionOnGrpcFailure(self): | |
310 """Contains: the digests are missing""" | |
311 def Contains(_self, _request, timeout=None): | |
312 del timeout | |
313 raise isolate_storage.grpc.RpcError('proxy died during contains :(') | |
314 self.mock(FileServiceStubMock, 'Contains', Contains) | |
315 | |
316 items = [] | |
317 for i in range(0, 3): | |
318 digest = ''.join(['a', str(i)]) | |
319 i = isolate_storage.Item(digest=digest, size=1) | |
320 items.append(i) | |
321 s = self.get_server() | |
322 with self.assertRaises(IOError): | |
323 _response = s.contains(items) | |
324 | |
325 | 256 |
326 if __name__ == '__main__': | 257 if __name__ == '__main__': |
327 if not isolate_storage.grpc: | 258 if not isolate_storage.grpc: |
328 # Don't print to stderr or return error code as this will | 259 # Don't print to stderr or return error code as this will |
329 # show up as a warning and fail in presubmit. | 260 # show up as a warning and fail in presubmit. |
330 print('gRPC could not be loaded; skipping tests') | 261 print('gRPC could not be loaded; skipping tests') |
331 sys.exit(0) | 262 sys.exit(0) |
332 isolate_storage.isolate_bot_pb2.FileServiceStub = FileServiceStubMock | 263 isolate_storage.bytestream_pb2.ByteStreamStub = ByteStreamStubMock |
333 test_utils.main() | 264 test_utils.main() |
OLD | NEW |