|
16 | 16 | #include "google/cloud/storage/hashing_options.h" |
17 | 17 | #include "google/cloud/storage/internal/grpc/ctype_cord_workaround.h" |
18 | 18 | #include "google/cloud/storage/internal/grpc/object_metadata_parser.h" |
| 19 | +#include "google/cloud/storage/internal/hash_function_impl.h" |
19 | 20 | #include "google/cloud/storage/testing/mock_storage_stub.h" |
20 | 21 | #include "google/cloud/testing_util/status_matchers.h" |
21 | 22 | #include <google/protobuf/text_format.h> |
@@ -350,6 +351,72 @@ TEST(GrpcObjectReadSource, StallTimeout) { |
350 | 351 | EXPECT_THAT(response, StatusIs(StatusCode::kDeadlineExceeded)); |
351 | 352 | } |
352 | 353 |
|
| 354 | +TEST(GrpcObjectReadSource, ChecksumMismatch) { |
| 355 | + auto mock = std::make_unique<MockObjectMediaStream>(); |
| 356 | + std::string const contents = "0123456789"; |
| 357 | + |
| 358 | + ::testing::InSequence sequence; |
| 359 | + EXPECT_CALL(*mock, Read) |
| 360 | + .WillOnce([&contents](storage_proto::ReadObjectResponse* r) { |
| 361 | + SetContent(*r, contents); |
| 362 | + r->mutable_checksummed_data()->set_crc32c(123); // Wrong CRC |
| 363 | + return absl::nullopt; |
| 364 | + }); |
| 365 | + |
| 366 | + auto hash_function = |
| 367 | + std::make_shared<storage::internal::Crc32cMessageHashFunction>( |
| 368 | + storage::internal::CreateNullHashFunction()); |
| 369 | + |
| 370 | + GrpcObjectReadSource tested(MakeSimpleTimerSource(), std::move(mock), |
| 371 | + std::move(hash_function)); |
| 372 | + std::vector<char> buffer(1024); |
| 373 | + auto response = tested.Read(buffer.data(), buffer.size()); |
| 374 | + EXPECT_THAT(response, StatusIs(StatusCode::kInvalidArgument, |
| 375 | + HasSubstr("mismatched crc32c checksum"))); |
| 376 | + EXPECT_THAT(tested.Close(), |
| 377 | + StatusIs(StatusCode::kInvalidArgument, |
| 378 | + HasSubstr("mismatched crc32c checksum"))); |
| 379 | +} |
| 380 | + |
| 381 | +TEST(GrpcObjectReadSource, ChecksumWithNonZeroOffset) { |
| 382 | + auto mock = std::make_unique<MockObjectMediaStream>(); |
| 383 | + std::string const contents1 = "0123456789"; |
| 384 | + std::string const contents2 = "abcdefghij"; |
| 385 | + auto const expected_crc32c_1 = storage::ComputeCrc32cChecksum(contents1); |
| 386 | + auto const expected_crc32c_2 = storage::ComputeCrc32cChecksum(contents2); |
| 387 | + |
| 388 | + ::testing::InSequence sequence; |
| 389 | + EXPECT_CALL(*mock, Read) |
| 390 | + .WillOnce([&contents1, |
| 391 | + expected_crc32c_1](storage_proto::ReadObjectResponse* r) { |
| 392 | + SetContent(*r, contents1); |
| 393 | + r->mutable_content_range()->set_start(100); |
| 394 | + r->mutable_checksummed_data()->set_crc32c( |
| 395 | + storage_internal::Crc32cToProto(expected_crc32c_1).value()); |
| 396 | + return absl::nullopt; |
| 397 | + }) |
| 398 | + .WillOnce([&contents2, |
| 399 | + expected_crc32c_2](storage_proto::ReadObjectResponse* r) { |
| 400 | + SetContent(*r, contents2); |
| 401 | + r->mutable_checksummed_data()->set_crc32c( |
| 402 | + storage_internal::Crc32cToProto(expected_crc32c_2).value()); |
| 403 | + return absl::nullopt; |
| 404 | + }) |
| 405 | + .WillOnce(Return(Status{})); |
| 406 | + EXPECT_CALL(*mock, GetRequestMetadata).WillOnce(Return(RpcMetadata{})); |
| 407 | + |
| 408 | + auto hash_function = |
| 409 | + std::make_shared<storage::internal::Crc32cMessageHashFunction>( |
| 410 | + storage::internal::CreateNullHashFunction()); |
| 411 | + |
| 412 | + GrpcObjectReadSource tested(MakeSimpleTimerSource(), std::move(mock), |
| 413 | + std::move(hash_function)); |
| 414 | + std::vector<char> buffer(1024); |
| 415 | + auto response = tested.Read(buffer.data(), buffer.size()); |
| 416 | + ASSERT_STATUS_OK(response); |
| 417 | + EXPECT_EQ(contents1.size() + contents2.size(), response->bytes_received); |
| 418 | +} |
| 419 | + |
353 | 420 | } // namespace |
354 | 421 | GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END |
355 | 422 | } // namespace storage_internal |
|
0 commit comments