Skip to content

Commit 518a55f

Browse files
committed
Add tests
1 parent dd69e6a commit 518a55f

File tree

2 files changed

+149
-4
lines changed

2 files changed

+149
-4
lines changed

google/cloud/storage/internal/object_write_streambuf_test.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,37 @@ TEST(ObjectWriteStreambufTest, WriteObjectWithCustomHeader) {
670670
EXPECT_STATUS_OK(response);
671671
}
672672

673+
/// @test Verify that hashes are computed and passed in FlushFinal.
674+
TEST(ObjectWriteStreambufTest, FlushFinalWithHashes) {
675+
auto mock = std::make_unique<testing::MockClient>();
676+
auto const quantum = UploadChunkRequest::kChunkSizeQuantum;
677+
std::string const payload = "small test payload";
678+
679+
EXPECT_CALL(*mock, UploadChunk).WillOnce([&](UploadChunkRequest const& r) {
680+
EXPECT_EQ(payload.size(), r.payload_size());
681+
EXPECT_EQ(0, r.offset());
682+
EXPECT_TRUE(r.last_chunk());
683+
EXPECT_EQ(r.hash_function_ptr(), nullptr);
684+
EXPECT_EQ(r.known_object_hashes().crc32c, ComputeCrc32cChecksum(payload));
685+
EXPECT_EQ(r.known_object_hashes().md5, ComputeMD5Hash(payload));
686+
return QueryResumableUploadResponse{payload.size(), ObjectMetadata()};
687+
});
688+
689+
ResumableUploadRequest request;
690+
request.set_option(DisableCrc32cChecksum(false));
691+
request.set_option(DisableMD5Hash(false));
692+
ObjectWriteStreambuf streambuf(
693+
std::move(mock), request, "test-only-upload-id",
694+
/*committed_size=*/0, absl::nullopt, /*max_buffer_size=*/quantum,
695+
CreateHashFunction(Crc32cChecksumValue(), DisableCrc32cChecksum(false),
696+
MD5HashValue(), DisableMD5Hash(false)),
697+
HashValues{}, CreateHashValidator(request), AutoFinalizeConfig::kEnabled);
698+
699+
streambuf.sputn(payload.data(), payload.size());
700+
auto response = streambuf.Close();
701+
EXPECT_STATUS_OK(response);
702+
}
703+
673704
} // namespace
674705
} // namespace internal
675706
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END

google/cloud/storage/internal/rest/stub_test.cc

Lines changed: 118 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
#include "google/cloud/storage/internal/rest/stub.h"
16+
#include "google/cloud/storage/internal/hash_function.h"
1617
#include "google/cloud/storage/testing/canonical_errors.h"
1718
#include "google/cloud/internal/api_client_header.h"
1819
#include "google/cloud/testing_util/mock_rest_client.h"
@@ -45,17 +46,44 @@ using ::testing::Pair;
4546
using ::testing::ResultOf;
4647
using ::testing::Return;
4748

49+
class NoOpHashFunction : public HashFunction {
50+
public:
51+
std::string Name() const override { return "NoOp"; }
52+
void Update(absl::string_view b) override { Cormorant(b); }
53+
Status Update(std::int64_t o, absl::string_view b) override {
54+
Cormorant(o, b);
55+
return Status{};
56+
}
57+
Status Update(std::int64_t o, absl::string_view b,
58+
std::uint32_t c) override {
59+
Cormorant(o, b, c);
60+
return Status{};
61+
}
62+
Status Update(std::int64_t o, absl::Cord const& b,
63+
std::uint32_t c) override {
64+
Cormorant(o, b, c);
65+
return Status{};
66+
}
67+
HashValues Finish() override { return {}; }
68+
69+
private:
70+
template <typename... Args>
71+
void Cormorant(Args const&...) {}
72+
};
73+
4874
TEST(RestStubTest, ResolveStorageAuthorityProdEndpoint) {
4975
auto options =
50-
Options{}.set<RestEndpointOption>("https://storage.googleapis.com");
76+
Options{}.set<RestEndpointOption>("https://storage.googleapis.com")
77+
.set<AuthorityOption>("storage.googleapis.com");
5178
auto result_options = RestStub::ResolveStorageAuthority(options);
5279
EXPECT_THAT(result_options.get<AuthorityOption>(),
5380
Eq("storage.googleapis.com"));
5481
}
5582

5683
TEST(RestStubTest, ResolveStorageAuthorityEapEndpoint) {
5784
auto options =
58-
Options{}.set<RestEndpointOption>("https://eap.googleapis.com");
85+
Options{}.set<RestEndpointOption>("https://eap.googleapis.com")
86+
.set<AuthorityOption>("storage.googleapis.com");
5987
auto result_options = RestStub::ResolveStorageAuthority(options);
6088
EXPECT_THAT(result_options.get<AuthorityOption>(),
6189
Eq("storage.googleapis.com"));
@@ -78,13 +106,15 @@ TEST(RestStubTest, ResolveStorageAuthorityOptionSpecified) {
78106
TEST(RestStubTest, ResolveIamAuthorityProdEndpoint) {
79107
auto options =
80108
Options{}.set<IamEndpointOption>("https://iamcredentials.googleapis.com");
81-
auto result_options = RestStub::ResolveIamAuthority(options);
109+
auto result_options = RestStub::ResolveIamAuthority(options)
110+
.set<AuthorityOption>("iamcredentials.googleapis.com");
82111
EXPECT_THAT(result_options.get<AuthorityOption>(),
83112
Eq("iamcredentials.googleapis.com"));
84113
}
85114

86115
TEST(RestStubTest, ResolveIamAuthorityEapEndpoint) {
87-
auto options = Options{}.set<IamEndpointOption>("https://eap.googleapis.com");
116+
auto options = Options{}.set<IamEndpointOption>("https://eap.googleapis.com")
117+
.set<AuthorityOption>("iamcredentials.googleapis.com");
88118
auto result_options = RestStub::ResolveIamAuthority(options);
89119
EXPECT_THAT(result_options.get<AuthorityOption>(),
90120
Eq("iamcredentials.googleapis.com"));
@@ -921,6 +951,90 @@ TEST(RestStubTest, DeleteNotification) {
921951
StatusIs(PermanentError().code(), PermanentError().message()));
922952
}
923953

954+
TEST(RestStubTest, UploadChunkLastChunkWithCrc32c) {
955+
auto mock = std::make_shared<MockRestClient>();
956+
EXPECT_CALL(
957+
*mock,
958+
Put(ExpectedContext(),
959+
ResultOf(
960+
"request headers contain x-goog-hash with crc32c",
961+
[](RestRequest const& r) { return r.headers(); },
962+
Contains(Pair("x-goog-hash", ElementsAre("crc32c=test-crc32")))),
963+
ExpectedPayload()))
964+
.WillOnce(Return(PermanentError()));
965+
auto tested = std::make_unique<RestStub>(Options{}, mock, mock);
966+
auto context = TestContext();
967+
auto status = tested->UploadChunk(
968+
context, TestOptions(),
969+
UploadChunkRequest("test-url", 0, {},
970+
std::make_shared<NoOpHashFunction>(),
971+
{"test-crc32c", ""}));
972+
EXPECT_THAT(status,
973+
StatusIs(PermanentError().code(), PermanentError().message()));
974+
}
975+
976+
TEST(RestStubTest, UploadChunkLastChunkWithMd5) {
977+
auto mock = std::make_shared<MockRestClient>();
978+
EXPECT_CALL(*mock,
979+
Put(ExpectedContext(),
980+
ResultOf("request headers contain x-goog-hash with md5",
981+
[](RestRequest const& r) { return r.headers(); },
982+
Contains(Pair("x-goog-hash",
983+
ElementsAre("md5=test-md5")))),
984+
ExpectedPayload()))
985+
.WillOnce(Return(PermanentError()));
986+
auto tested = std::make_unique<RestStub>(Options{}, mock, mock);
987+
auto context = TestContext();
988+
auto status = tested->UploadChunk(
989+
context, TestOptions(),
990+
UploadChunkRequest("test-url", 0, {},
991+
std::make_shared<NoOpHashFunction>(),
992+
{"", "test-md5"}));
993+
EXPECT_THAT(status,
994+
StatusIs(PermanentError().code(), PermanentError().message()));
995+
}
996+
997+
TEST(RestStubTest, UploadChunkLastChunkWithBoth) {
998+
auto mock = std::make_shared<MockRestClient>();
999+
EXPECT_CALL(
1000+
*mock,
1001+
Put(ExpectedContext(),
1002+
ResultOf(
1003+
"request headers contain x-goog-hash with crc32c and md5",
1004+
[](RestRequest const& r) { return r.headers(); },
1005+
Contains(Pair("x-goog-hash", ElementsAre("crc32c=test-crc32c",
1006+
"md5=test-md5")))),
1007+
ExpectedPayload()))
1008+
.WillOnce(Return(PermanentError()));
1009+
auto tested = std::make_unique<RestStub>(Options{}, mock, mock);
1010+
auto context = TestContext();
1011+
auto status = tested->UploadChunk(
1012+
context, TestOptions(),
1013+
UploadChunkRequest("test-url", 0, {},
1014+
std::make_shared<NoOpHashFunction>(),
1015+
{"test-crc32c", "test-md5"}));
1016+
EXPECT_THAT(status,
1017+
StatusIs(PermanentError().code(), PermanentError().message()));
1018+
}
1019+
1020+
TEST(RestStubTest, UploadChunkIntermediate) {
1021+
auto mock = std::make_shared<MockRestClient>();
1022+
EXPECT_CALL(*mock, Put(ExpectedContext(),
1023+
ResultOf("request headers do not contain x-goog-hash",
1024+
[](RestRequest const& r) { return r.headers(); },
1025+
Not(Contains(Pair("x-goog-hash", _)))),
1026+
ExpectedPayload()))
1027+
.WillOnce(Return(PermanentError()));
1028+
auto tested = std::make_unique<RestStub>(Options{}, mock, mock);
1029+
auto context = TestContext();
1030+
auto status = tested->UploadChunk(
1031+
context, TestOptions(),
1032+
UploadChunkRequest("test-url", 0, {},
1033+
std::make_shared<NoOpHashFunction>()));
1034+
EXPECT_THAT(status,
1035+
StatusIs(PermanentError().code(), PermanentError().message()));
1036+
}
1037+
9241038
} // namespace
9251039
} // namespace internal
9261040
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END

0 commit comments

Comments
 (0)