|
14 | 14 |
|
15 | 15 | #include "google/cloud/storage/internal/async/writer_connection_impl.h" |
16 | 16 | #include "google/cloud/mocks/mock_async_streaming_read_write_rpc.h" |
| 17 | +#include "google/cloud/storage/async/options.h" |
17 | 18 | #include "google/cloud/storage/internal/async/write_object.h" |
18 | 19 | #include "google/cloud/storage/internal/crc32c.h" |
19 | 20 | #include "google/cloud/storage/internal/grpc/ctype_cord_workaround.h" |
| 21 | +#include "google/cloud/storage/internal/grpc/object_metadata_parser.h" |
20 | 22 | #include "google/cloud/storage/internal/hash_function_impl.h" |
21 | 23 | #include "google/cloud/storage/options.h" |
22 | 24 | #include "google/cloud/storage/testing/canonical_errors.h" |
@@ -744,6 +746,123 @@ TEST(AsyncWriterConnectionTest, FinalizeAppendableNoChecksum) { |
744 | 746 | next.first.set_value(true); |
745 | 747 | } |
746 | 748 |
|
| 749 | +TEST(AsyncWriterConnectionTest, FinalizeAppendableWithExpectedChecksum) { |
| 750 | + AsyncSequencer<bool> sequencer; |
| 751 | + auto mock = std::make_unique<MockStream>(); |
| 752 | + EXPECT_CALL(*mock, Cancel).Times(1); |
| 753 | + EXPECT_CALL(*mock, Write) |
| 754 | + .WillOnce([&](Request const& request, grpc::WriteOptions wopt) { |
| 755 | + EXPECT_TRUE(request.finish_write()); |
| 756 | + EXPECT_TRUE(wopt.is_last_message()); |
| 757 | + EXPECT_EQ(request.common_object_request_params().encryption_algorithm(), |
| 758 | + "test-only-algo"); |
| 759 | + EXPECT_TRUE(request.has_object_checksums()); |
| 760 | + EXPECT_EQ(request.object_checksums().crc32c(), |
| 761 | + 123456); // wait, it might be an int in proto |
| 762 | + return sequencer.PushBack("Write"); |
| 763 | + }); |
| 764 | + EXPECT_CALL(*mock, Read).WillOnce([&]() { |
| 765 | + return sequencer.PushBack("Read").then([](auto f) { |
| 766 | + if (!f.get()) return absl::optional<Response>(); |
| 767 | + return absl::make_optional(MakeTestResponse()); |
| 768 | + }); |
| 769 | + }); |
| 770 | + EXPECT_CALL(*mock, Finish).WillOnce([&] { |
| 771 | + return sequencer.PushBack("Finish").then([](auto f) { |
| 772 | + if (f.get()) return Status{}; |
| 773 | + return PermanentError(); |
| 774 | + }); |
| 775 | + }); |
| 776 | + auto hash = std::make_shared<MockHashFunction>(); |
| 777 | + EXPECT_CALL(*hash, Update(_, An<absl::Cord const&>(), _)).Times(1); |
| 778 | + EXPECT_CALL(*hash, Finish) |
| 779 | + .WillOnce(Return(storage::internal::HashValues{ |
| 780 | + storage_internal::Crc32cFromProto(123456), {}})); |
| 781 | + |
| 782 | + auto request = MakeRequest(); |
| 783 | + request.mutable_write_object_spec()->set_appendable(true); |
| 784 | + |
| 785 | + auto options = internal::MakeImmutableOptions( |
| 786 | + Options{}.set<storage::UseCrc32cValueOption>(123456)); |
| 787 | + |
| 788 | + auto tested = std::make_unique<AsyncWriterConnectionImpl>( |
| 789 | + options, std::move(request), std::move(mock), hash, 1024); |
| 790 | + auto response = tested->Finalize(WritePayload{}); |
| 791 | + |
| 792 | + auto next = sequencer.PopFrontWithName(); |
| 793 | + ASSERT_THAT(next.second, "Write"); |
| 794 | + next.first.set_value(true); |
| 795 | + next = sequencer.PopFrontWithName(); |
| 796 | + ASSERT_THAT(next.second, "Read"); |
| 797 | + next.first.set_value(true); |
| 798 | + auto object = response.get(); |
| 799 | + EXPECT_THAT(object, IsOkAndHolds(IsProtoEqual(MakeTestObject()))) |
| 800 | + << "=" << object->DebugString(); |
| 801 | + |
| 802 | + tested = {}; |
| 803 | + next = sequencer.PopFrontWithName(); |
| 804 | + ASSERT_THAT(next.second, "Finish"); |
| 805 | + next.first.set_value(true); |
| 806 | +} |
| 807 | + |
| 808 | +TEST(AsyncWriterConnectionTest, |
| 809 | + FinalizeAppendableWithExpectedChecksumFromCurrentOptions) { |
| 810 | + AsyncSequencer<bool> sequencer; |
| 811 | + auto mock = std::make_unique<MockStream>(); |
| 812 | + EXPECT_CALL(*mock, Cancel).Times(1); |
| 813 | + EXPECT_CALL(*mock, Write) |
| 814 | + .WillOnce([&](Request const& request, grpc::WriteOptions wopt) { |
| 815 | + EXPECT_TRUE(request.finish_write()); |
| 816 | + EXPECT_TRUE(wopt.is_last_message()); |
| 817 | + EXPECT_EQ(request.common_object_request_params().encryption_algorithm(), |
| 818 | + "test-only-algo"); |
| 819 | + EXPECT_TRUE(request.has_object_checksums()); |
| 820 | + EXPECT_EQ(request.object_checksums().crc32c(), 654321); |
| 821 | + return sequencer.PushBack("Write"); |
| 822 | + }); |
| 823 | + EXPECT_CALL(*mock, Read).WillOnce([&]() { |
| 824 | + return sequencer.PushBack("Read").then([](auto f) { |
| 825 | + if (!f.get()) return absl::optional<Response>(); |
| 826 | + return absl::make_optional(MakeTestResponse()); |
| 827 | + }); |
| 828 | + }); |
| 829 | + EXPECT_CALL(*mock, Finish).WillOnce([&] { |
| 830 | + return sequencer.PushBack("Finish").then([](auto f) { |
| 831 | + if (f.get()) return Status{}; |
| 832 | + return PermanentError(); |
| 833 | + }); |
| 834 | + }); |
| 835 | + auto hash = std::make_shared<MockHashFunction>(); |
| 836 | + EXPECT_CALL(*hash, Update(_, An<absl::Cord const&>(), _)).Times(1); |
| 837 | + // It shouldn't call Finish() because we use kFinalize! |
| 838 | + EXPECT_CALL(*hash, Finish).Times(0); |
| 839 | + |
| 840 | + auto request = MakeRequest(); |
| 841 | + request.mutable_write_object_spec()->set_appendable(true); |
| 842 | + |
| 843 | + auto tested = std::make_unique<AsyncWriterConnectionImpl>( |
| 844 | + TestOptions(), std::move(request), std::move(mock), hash, 1024); |
| 845 | + |
| 846 | + internal::OptionsSpan span( |
| 847 | + Options{}.set<storage::UseCrc32cValueOption>(654321)); |
| 848 | + auto response = tested->Finalize(WritePayload{}); |
| 849 | + |
| 850 | + auto next = sequencer.PopFrontWithName(); |
| 851 | + ASSERT_THAT(next.second, "Write"); |
| 852 | + next.first.set_value(true); |
| 853 | + next = sequencer.PopFrontWithName(); |
| 854 | + ASSERT_THAT(next.second, "Read"); |
| 855 | + next.first.set_value(true); |
| 856 | + auto object = response.get(); |
| 857 | + EXPECT_THAT(object, IsOkAndHolds(IsProtoEqual(MakeTestObject()))) |
| 858 | + << "=" << object->DebugString(); |
| 859 | + |
| 860 | + tested = {}; |
| 861 | + next = sequencer.PopFrontWithName(); |
| 862 | + ASSERT_THAT(next.second, "Finish"); |
| 863 | + next.first.set_value(true); |
| 864 | +} |
| 865 | + |
747 | 866 | TEST(AsyncWriterConnectionTest, ResumeWithHandle) { |
748 | 867 | AsyncSequencer<bool> sequencer; |
749 | 868 | auto mock = std::make_unique<MockStream>(); |
|
0 commit comments