@@ -163,6 +163,107 @@ func TestCASBlobAccessPut(t *testing.T) {
163163 })
164164}
165165
166+ func TestCASBlobAccessGet (t * testing.T ) {
167+ ctrl , ctx := gomock .WithContext (context .Background (), t )
168+
169+ client := mock .NewMockClientConnInterface (ctrl )
170+ uuidGenerator := mock .NewMockUUIDGenerator (ctrl )
171+ blobAccess := grpcclients .NewCASBlobAccess (client , uuidGenerator .Call , 10 )
172+
173+ t .Run ("Success" , func (t * testing.T ) {
174+ blobDigest := digest .MustNewDigest ("hello" , remoteexecution .DigestFunction_MD5 , "8b1a9953c4611296a827abf8c47804d7" , 5 )
175+
176+ clientStream := mock .NewMockClientStream (ctrl )
177+ client .EXPECT ().NewStream (gomock .Any (), gomock .Any (), "/google.bytestream.ByteStream/Read" ).
178+ Return (clientStream , nil )
179+ clientStream .EXPECT ().SendMsg (testutil .EqProto (t , & bytestream.ReadRequest {
180+ ResourceName : "hello/blobs/8b1a9953c4611296a827abf8c47804d7/5" ,
181+ ReadOffset : 0 ,
182+ ReadLimit : 0 ,
183+ })).Return (nil )
184+ clientStream .EXPECT ().RecvMsg (gomock .Any ()).DoAndReturn (func (m interface {}) error {
185+ resp := m .(* bytestream.ReadResponse )
186+ resp .Data = []byte ("Hello" )
187+ return nil
188+ })
189+ clientStream .EXPECT ().RecvMsg (gomock .Any ()).Return (io .EOF ).AnyTimes ()
190+ clientStream .EXPECT ().CloseSend ().Return (nil )
191+
192+ buffer := blobAccess .Get (ctx , blobDigest )
193+ data , err := buffer .ToByteSlice (1000 )
194+ require .NoError (t , err )
195+ require .Equal (t , []byte ("Hello" ), data )
196+ })
197+
198+ t .Run ("SuccessLargeBlob" , func (t * testing.T ) {
199+ // Create large blob data (1000 bytes)
200+ expectedData := make ([]byte , 1000 )
201+ for i := range expectedData {
202+ expectedData [i ] = byte ('A' + (i % 26 )) // Repeating alphabet pattern
203+ }
204+ largeDigest := digest .MustNewDigest ("hello" , remoteexecution .DigestFunction_MD5 , "1411ffd5854fa029dc4d231aa89311eb" , 1000 )
205+
206+ clientStream := mock .NewMockClientStream (ctrl )
207+ client .EXPECT ().NewStream (gomock .Any (), gomock .Any (), "/google.bytestream.ByteStream/Read" ).
208+ Return (clientStream , nil )
209+ clientStream .EXPECT ().SendMsg (testutil .EqProto (t , & bytestream.ReadRequest {
210+ ResourceName : "hello/blobs/1411ffd5854fa029dc4d231aa89311eb/1000" ,
211+ ReadOffset : 0 ,
212+ ReadLimit : 0 ,
213+ })).Return (nil )
214+
215+ // Send data in a single chunk (simpler for testing)
216+ clientStream .EXPECT ().RecvMsg (gomock .Any ()).DoAndReturn (func (m interface {}) error {
217+ resp := m .(* bytestream.ReadResponse )
218+ resp .Data = expectedData
219+ return nil
220+ })
221+ clientStream .EXPECT ().RecvMsg (gomock .Any ()).Return (io .EOF ).AnyTimes ()
222+ clientStream .EXPECT ().CloseSend ().Return (nil )
223+
224+ buffer := blobAccess .Get (ctx , largeDigest )
225+ data , err := buffer .ToByteSlice (1500 )
226+ require .NoError (t , err )
227+ require .Equal (t , expectedData , data )
228+ })
229+
230+ t .Run ("InitialFailure" , func (t * testing.T ) {
231+ blobDigest := digest .MustNewDigest ("hello" , remoteexecution .DigestFunction_MD5 , "8b1a9953c4611296a827abf8c47804d7" , 5 )
232+
233+ // Failure to create the outgoing connection.
234+ client .EXPECT ().NewStream (gomock .Any (), gomock .Any (), "/google.bytestream.ByteStream/Read" ).
235+ Return (nil , status .Error (codes .Internal , "Failed to create outgoing connection" ))
236+
237+ buffer := blobAccess .Get (ctx , blobDigest )
238+ _ , err := buffer .ToByteSlice (1000 )
239+ testutil .RequireEqualStatus (t ,
240+ status .Error (codes .Internal , "Failed to create outgoing connection" ),
241+ err )
242+ })
243+
244+ t .Run ("ReceiveFailure" , func (t * testing.T ) {
245+ blobDigest := digest .MustNewDigest ("hello" , remoteexecution .DigestFunction_MD5 , "8b1a9953c4611296a827abf8c47804d7" , 5 )
246+
247+ // Failure to receive a response.
248+ clientStream := mock .NewMockClientStream (ctrl )
249+ client .EXPECT ().NewStream (gomock .Any (), gomock .Any (), "/google.bytestream.ByteStream/Read" ).
250+ Return (clientStream , nil )
251+ clientStream .EXPECT ().SendMsg (testutil .EqProto (t , & bytestream.ReadRequest {
252+ ResourceName : "hello/blobs/8b1a9953c4611296a827abf8c47804d7/5" ,
253+ ReadOffset : 0 ,
254+ ReadLimit : 0 ,
255+ })).Return (nil )
256+ clientStream .EXPECT ().RecvMsg (gomock .Any ()).Return (status .Error (codes .Internal , "Lost connection to server" )).AnyTimes ()
257+ clientStream .EXPECT ().CloseSend ().Return (nil )
258+
259+ buffer := blobAccess .Get (ctx , blobDigest )
260+ _ , err := buffer .ToByteSlice (1000 )
261+ testutil .RequireEqualStatus (t ,
262+ status .Error (codes .Internal , "Lost connection to server" ),
263+ err )
264+ })
265+ }
266+
166267func TestCASBlobAccessGetCapabilities (t * testing.T ) {
167268 ctrl , ctx := gomock .WithContext (context .Background (), t )
168269
0 commit comments