Skip to content

Commit aab03ae

Browse files
committed
fix(storage): allow providing expected CRC32C to Finalize()
1 parent 982d3bf commit aab03ae

1 file changed

Lines changed: 119 additions & 0 deletions

File tree

google/cloud/storage/internal/async/writer_connection_impl_test.cc

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414

1515
#include "google/cloud/storage/internal/async/writer_connection_impl.h"
1616
#include "google/cloud/mocks/mock_async_streaming_read_write_rpc.h"
17+
#include "google/cloud/storage/async/options.h"
1718
#include "google/cloud/storage/internal/async/write_object.h"
1819
#include "google/cloud/storage/internal/crc32c.h"
1920
#include "google/cloud/storage/internal/grpc/ctype_cord_workaround.h"
21+
#include "google/cloud/storage/internal/grpc/object_metadata_parser.h"
2022
#include "google/cloud/storage/internal/hash_function_impl.h"
2123
#include "google/cloud/storage/options.h"
2224
#include "google/cloud/storage/testing/canonical_errors.h"
@@ -744,6 +746,123 @@ TEST(AsyncWriterConnectionTest, FinalizeAppendableNoChecksum) {
744746
next.first.set_value(true);
745747
}
746748

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+
747866
TEST(AsyncWriterConnectionTest, ResumeWithHandle) {
748867
AsyncSequencer<bool> sequencer;
749868
auto mock = std::make_unique<MockStream>();

0 commit comments

Comments
 (0)