|
15 | 15 | #include "google/cloud/storage/internal/async/connection_impl.h" |
16 | 16 | #include "google/cloud/storage/async/idempotency_policy.h" |
17 | 17 | #include "google/cloud/storage/async/retry_policy.h" |
| 18 | +#include "google/cloud/storage/async/writer_connection.h" |
18 | 19 | #include "google/cloud/storage/internal/async/default_options.h" |
19 | 20 | #include "google/cloud/storage/internal/async/write_payload_impl.h" |
20 | 21 | #include "google/cloud/storage/options.h" |
@@ -105,9 +106,14 @@ TEST_F(AsyncConnectionImplTest, ComposeObject) { |
105 | 106 | return StatusOr<google::storage::v2::Object>(TransientError()); |
106 | 107 | }); |
107 | 108 | }) |
108 | | - .WillOnce([&](CompletionQueue&, auto, |
| 109 | + .WillOnce([&](CompletionQueue&, |
| 110 | + std::shared_ptr<grpc::ClientContext> const& context, |
109 | 111 | google::cloud::internal::ImmutableOptions const& options, |
110 | 112 | google::storage::v2::ComposeObjectRequest const& request) { |
| 113 | + EXPECT_THAT( |
| 114 | + GetMetadata(*context), |
| 115 | + testing::Contains(testing::Pair("x-goog-gcs-idempotency-token", |
| 116 | + testing::Not(testing::IsEmpty())))); |
111 | 117 | // Verify at least one option is initialized with the correct value. |
112 | 118 | EXPECT_EQ(options->get<AuthorityOption>(), kAuthority); |
113 | 119 | auto expected = google::storage::v2::ComposeObjectRequest{}; |
@@ -205,9 +211,14 @@ TEST_F(AsyncConnectionImplTest, DeleteObject) { |
205 | 211 | return TransientError(); |
206 | 212 | }); |
207 | 213 | }) |
208 | | - .WillOnce([&](CompletionQueue&, auto, |
| 214 | + .WillOnce([&](CompletionQueue&, |
| 215 | + std::shared_ptr<grpc::ClientContext> const& context, |
209 | 216 | google::cloud::internal::ImmutableOptions const& options, |
210 | 217 | google::storage::v2::DeleteObjectRequest const& request) { |
| 218 | + EXPECT_THAT( |
| 219 | + GetMetadata(*context), |
| 220 | + testing::Contains(testing::Pair("x-goog-gcs-idempotency-token", |
| 221 | + testing::Not(testing::IsEmpty())))); |
211 | 222 | // Verify at least one option is initialized with the correct values. |
212 | 223 | EXPECT_EQ(options->get<AuthorityOption>(), kAuthority); |
213 | 224 | google::storage::v2::DeleteObjectRequest expected; |
@@ -344,6 +355,63 @@ TEST_F(AsyncConnectionImplTest, RewriteObject) { |
344 | 355 | EXPECT_THAT(r1.get(), IsOkAndHolds(match_progress(1000, 3000))); |
345 | 356 | } |
346 | 357 |
|
| 358 | +TEST_F(AsyncConnectionImplTest, AppendableObjectUploadToken) { |
| 359 | + auto constexpr kRequestText = R"pb( |
| 360 | + write_object_spec { |
| 361 | + resource { |
| 362 | + bucket: "projects/_/buckets/test-bucket" |
| 363 | + name: "test-object" |
| 364 | + content_type: "text/plain" |
| 365 | + } |
| 366 | + } |
| 367 | + )pb"; |
| 368 | + AsyncSequencer<bool> sequencer; |
| 369 | + auto mock = std::make_shared<storage::testing::MockStorageStub>(); |
| 370 | + |
| 371 | + EXPECT_CALL(*mock, AsyncBidiWriteObject) |
| 372 | + .WillOnce([&](CompletionQueue const&, |
| 373 | + std::shared_ptr<grpc::ClientContext> const& context, |
| 374 | + internal::ImmutableOptions const&) { |
| 375 | + EXPECT_THAT( |
| 376 | + GetMetadata(*context), |
| 377 | + testing::Contains(testing::Pair("x-goog-gcs-idempotency-token", |
| 378 | + testing::Not(testing::IsEmpty())))); |
| 379 | + |
| 380 | + auto stream = std::make_unique<::google::cloud::storage::testing:: |
| 381 | + MockAsyncBidiWriteObjectStream>(); |
| 382 | + EXPECT_CALL(*stream, Start).WillOnce([&] { |
| 383 | + return sequencer.PushBack("Start"); |
| 384 | + }); |
| 385 | + EXPECT_CALL(*stream, Finish).WillOnce([&] { |
| 386 | + return sequencer.PushBack("Finish").then( |
| 387 | + [](auto) { return Status(StatusCode::kCancelled, "cancelled"); }); |
| 388 | + }); |
| 389 | + using AsyncBidiWriteObjectStream = |
| 390 | + ::google::cloud::AsyncStreamingReadWriteRpc< |
| 391 | + google::storage::v2::BidiWriteObjectRequest, |
| 392 | + google::storage::v2::BidiWriteObjectResponse>; |
| 393 | + return std::unique_ptr<AsyncBidiWriteObjectStream>(std::move(stream)); |
| 394 | + }); |
| 395 | + |
| 396 | + internal::AutomaticallyCreatedBackgroundThreads pool(1); |
| 397 | + auto connection = MakeTestConnection(pool.cq(), mock); |
| 398 | + |
| 399 | + auto request = google::storage::v2::BidiWriteObjectRequest{}; |
| 400 | + ASSERT_TRUE(TextFormat::ParseFromString(kRequestText, &request)); |
| 401 | + auto pending = connection->StartAppendableObjectUpload( |
| 402 | + {std::move(request), connection->options()}); |
| 403 | + |
| 404 | + auto next = sequencer.PopFrontWithName(); |
| 405 | + EXPECT_EQ(next.second, "Start"); |
| 406 | + next.first.set_value(false); // Fail to start |
| 407 | + |
| 408 | + next = sequencer.PopFrontWithName(); |
| 409 | + EXPECT_EQ(next.second, "Finish"); |
| 410 | + next.first.set_value(true); |
| 411 | + |
| 412 | + EXPECT_THAT(pending.get(), StatusIs(StatusCode::kCancelled)); |
| 413 | +} |
| 414 | + |
347 | 415 | } // namespace |
348 | 416 | GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END |
349 | 417 | } // namespace storage_internal |
|
0 commit comments