Skip to content

Commit 3c44e59

Browse files
authored
fix(storage): use correct header for XML pre-conditions (#6903)
1 parent 3bd0486 commit 3c44e59

File tree

5 files changed

+246
-2
lines changed

5 files changed

+246
-2
lines changed

google/cloud/storage/emulator/utils/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def init_xml(cls, request):
9292
def xml_headers_to_json_args(cls, headers):
9393
field_map = {
9494
"x-goog-if-generation-match": "ifGenerationMatch",
95-
"x-goog-if-meta-generation-match": "ifMetagenerationMatch",
95+
"x-goog-if-metageneration-match": "ifMetagenerationMatch",
9696
"x-goog-acl": "predefinedAcl",
9797
}
9898
args = {}

google/cloud/storage/internal/curl_client.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1222,7 +1222,7 @@ StatusOr<ObjectMetadata> CurlClient::InsertObjectMediaXml(
12221222
// IfGenerationNotMatch cannot be set, checked by the caller.
12231223
if (request.HasOption<IfMetagenerationMatch>()) {
12241224
builder.AddHeader(
1225-
"x-goog-if-meta-generation-match: " +
1225+
"x-goog-if-metageneration-match: " +
12261226
std::to_string(request.GetOption<IfMetagenerationMatch>().value()));
12271227
}
12281228
// IfMetagenerationNotMatch cannot be set, checked by the caller.

google/cloud/storage/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ set(storage_client_integration_tests
3535
object_file_multi_threaded_test.cc
3636
object_hash_integration_test.cc
3737
object_insert_integration_test.cc
38+
object_insert_preconditions_integration_test.cc
3839
object_integration_test.cc
3940
object_list_objects_versions_integration_test.cc
4041
object_media_integration_test.cc
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "google/cloud/storage/client.h"
16+
#include "google/cloud/storage/testing/storage_integration_test.h"
17+
#include "google/cloud/internal/getenv.h"
18+
#include "google/cloud/testing_util/scoped_environment.h"
19+
#include "google/cloud/testing_util/status_matchers.h"
20+
#include "absl/types/optional.h"
21+
#include <gmock/gmock.h>
22+
#include <string>
23+
24+
namespace google {
25+
namespace cloud {
26+
namespace storage {
27+
inline namespace STORAGE_CLIENT_NS {
28+
namespace {
29+
30+
using ::google::cloud::internal::GetEnv;
31+
using ::google::cloud::testing_util::IsOk;
32+
using ::google::cloud::testing_util::StatusIs;
33+
using ::testing::AnyOf;
34+
using ::testing::IsEmpty;
35+
using ::testing::Not;
36+
37+
struct TestParam {
38+
absl::optional<std::string> rest_config;
39+
Fields fields;
40+
};
41+
42+
class ObjectInsertPreconditionsIntegrationTest
43+
: public ::google::cloud::storage::testing::StorageIntegrationTest,
44+
public ::testing::WithParamInterface<TestParam> {
45+
protected:
46+
ObjectInsertPreconditionsIntegrationTest()
47+
: config_("GOOGLE_CLOUD_CPP_STORAGE_REST_CONFIG",
48+
GetParam().rest_config) {}
49+
50+
void SetUp() override {
51+
bucket_name_ =
52+
GetEnv("GOOGLE_CLOUD_CPP_STORAGE_TEST_BUCKET_NAME").value_or("");
53+
54+
ASSERT_THAT(bucket_name_, Not(IsEmpty()));
55+
}
56+
57+
std::string const& bucket_name() const { return bucket_name_; }
58+
59+
private:
60+
std::string bucket_name_;
61+
google::cloud::testing_util::ScopedEnvironment config_;
62+
};
63+
64+
TEST_P(ObjectInsertPreconditionsIntegrationTest, IfGenerationMatchSuccess) {
65+
StatusOr<Client> client = MakeIntegrationTestClient();
66+
ASSERT_STATUS_OK(client);
67+
68+
auto const object_name = MakeRandomObjectName();
69+
auto const expected_text = LoremIpsum();
70+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
71+
IfGenerationMatch(0));
72+
ASSERT_THAT(meta, IsOk());
73+
74+
auto insert = client->InsertObject(bucket_name(), object_name, expected_text,
75+
GetParam().fields,
76+
IfGenerationMatch(meta->generation()));
77+
ASSERT_THAT(insert, IsOk());
78+
79+
(void)client->DeleteObject(bucket_name(), object_name,
80+
Generation(insert->generation()));
81+
(void)client->DeleteObject(bucket_name(), object_name,
82+
Generation(meta->generation()));
83+
}
84+
85+
TEST_P(ObjectInsertPreconditionsIntegrationTest, IfGenerationMatchFailure) {
86+
StatusOr<Client> client = MakeIntegrationTestClient();
87+
ASSERT_STATUS_OK(client);
88+
89+
auto const object_name = MakeRandomObjectName();
90+
auto const expected_text = LoremIpsum();
91+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
92+
IfGenerationMatch(0));
93+
ASSERT_THAT(meta, IsOk());
94+
95+
auto insert = client->InsertObject(bucket_name(), object_name, expected_text,
96+
GetParam().fields,
97+
IfGenerationMatch(meta->generation() + 1));
98+
ASSERT_THAT(insert, StatusIs(StatusCode::kFailedPrecondition));
99+
100+
(void)client->DeleteObject(bucket_name(), object_name,
101+
Generation(meta->generation()));
102+
}
103+
104+
TEST_P(ObjectInsertPreconditionsIntegrationTest, IfGenerationNotMatchSuccess) {
105+
StatusOr<Client> client = MakeIntegrationTestClient();
106+
ASSERT_STATUS_OK(client);
107+
108+
auto const object_name = MakeRandomObjectName();
109+
auto const expected_text = LoremIpsum();
110+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
111+
IfGenerationMatch(0));
112+
ASSERT_THAT(meta, IsOk());
113+
114+
auto insert = client->InsertObject(
115+
bucket_name(), object_name, expected_text, GetParam().fields,
116+
IfGenerationNotMatch(meta->generation() + 1));
117+
ASSERT_THAT(insert, IsOk());
118+
119+
(void)client->DeleteObject(bucket_name(), object_name,
120+
Generation(insert->generation()));
121+
(void)client->DeleteObject(bucket_name(), object_name,
122+
Generation(meta->generation()));
123+
}
124+
125+
TEST_P(ObjectInsertPreconditionsIntegrationTest, IfGenerationNotMatchFailure) {
126+
StatusOr<Client> client = MakeIntegrationTestClient();
127+
ASSERT_STATUS_OK(client);
128+
129+
auto const object_name = MakeRandomObjectName();
130+
auto const expected_text = LoremIpsum();
131+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
132+
IfGenerationMatch(0));
133+
ASSERT_THAT(meta, IsOk());
134+
135+
auto insert = client->InsertObject(bucket_name(), object_name, expected_text,
136+
GetParam().fields,
137+
IfGenerationNotMatch(meta->generation()));
138+
ASSERT_THAT(insert, StatusIs(AnyOf(StatusCode::kFailedPrecondition,
139+
StatusCode::kAborted)));
140+
141+
(void)client->DeleteObject(bucket_name(), object_name,
142+
Generation(meta->generation()));
143+
}
144+
145+
TEST_P(ObjectInsertPreconditionsIntegrationTest, IfMetagenerationMatchSuccess) {
146+
StatusOr<Client> client = MakeIntegrationTestClient();
147+
ASSERT_STATUS_OK(client);
148+
149+
auto const object_name = MakeRandomObjectName();
150+
auto const expected_text = LoremIpsum();
151+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
152+
IfGenerationMatch(0));
153+
ASSERT_THAT(meta, IsOk());
154+
155+
auto insert = client->InsertObject(
156+
bucket_name(), object_name, expected_text, GetParam().fields,
157+
IfMetagenerationMatch(meta->metageneration()));
158+
ASSERT_THAT(insert, IsOk());
159+
160+
(void)client->DeleteObject(bucket_name(), object_name,
161+
Generation(insert->generation()));
162+
(void)client->DeleteObject(bucket_name(), object_name,
163+
Generation(meta->generation()));
164+
}
165+
166+
TEST_P(ObjectInsertPreconditionsIntegrationTest, IfMetagenerationMatchFailure) {
167+
StatusOr<Client> client = MakeIntegrationTestClient();
168+
ASSERT_STATUS_OK(client);
169+
170+
auto const object_name = MakeRandomObjectName();
171+
auto const expected_text = LoremIpsum();
172+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
173+
IfGenerationMatch(0));
174+
ASSERT_THAT(meta, IsOk());
175+
176+
auto insert = client->InsertObject(
177+
bucket_name(), object_name, expected_text, GetParam().fields,
178+
IfMetagenerationMatch(meta->metageneration() + 1));
179+
ASSERT_THAT(insert, StatusIs(StatusCode::kFailedPrecondition));
180+
181+
(void)client->DeleteObject(bucket_name(), object_name,
182+
Generation(meta->generation()));
183+
}
184+
185+
TEST_P(ObjectInsertPreconditionsIntegrationTest,
186+
IfMetagenerationNotMatchSuccess) {
187+
StatusOr<Client> client = MakeIntegrationTestClient();
188+
ASSERT_STATUS_OK(client);
189+
190+
auto const object_name = MakeRandomObjectName();
191+
auto const expected_text = LoremIpsum();
192+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
193+
IfGenerationMatch(0));
194+
ASSERT_THAT(meta, IsOk());
195+
196+
auto insert = client->InsertObject(
197+
bucket_name(), object_name, expected_text, GetParam().fields,
198+
IfMetagenerationNotMatch(meta->metageneration() + 1));
199+
ASSERT_THAT(insert, IsOk());
200+
201+
(void)client->DeleteObject(bucket_name(), object_name,
202+
Generation(insert->generation()));
203+
(void)client->DeleteObject(bucket_name(), object_name,
204+
Generation(meta->generation()));
205+
}
206+
207+
TEST_P(ObjectInsertPreconditionsIntegrationTest,
208+
IfMetagenerationNotMatchFailure) {
209+
StatusOr<Client> client = MakeIntegrationTestClient();
210+
ASSERT_STATUS_OK(client);
211+
212+
auto const object_name = MakeRandomObjectName();
213+
auto const expected_text = LoremIpsum();
214+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
215+
IfGenerationMatch(0));
216+
ASSERT_THAT(meta, IsOk());
217+
218+
auto insert = client->InsertObject(
219+
bucket_name(), object_name, expected_text, GetParam().fields,
220+
IfMetagenerationNotMatch(meta->metageneration()));
221+
ASSERT_THAT(insert, StatusIs(AnyOf(StatusCode::kFailedPrecondition,
222+
StatusCode::kAborted)));
223+
224+
(void)client->DeleteObject(bucket_name(), object_name,
225+
Generation(meta->generation()));
226+
}
227+
228+
INSTANTIATE_TEST_SUITE_P(XmlEnabledAndUsed,
229+
ObjectInsertPreconditionsIntegrationTest,
230+
::testing::Values(TestParam{absl::nullopt,
231+
Fields("")}));
232+
INSTANTIATE_TEST_SUITE_P(XmlEnabledNotUsed,
233+
ObjectInsertPreconditionsIntegrationTest,
234+
::testing::Values(TestParam{absl::nullopt, Fields()}));
235+
INSTANTIATE_TEST_SUITE_P(XmlDisabled, ObjectInsertPreconditionsIntegrationTest,
236+
::testing::Values(TestParam{"disable-xml", Fields()}));
237+
238+
} // namespace
239+
} // namespace STORAGE_CLIENT_NS
240+
} // namespace storage
241+
} // namespace cloud
242+
} // namespace google

google/cloud/storage/tests/storage_client_integration_tests.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ storage_client_integration_tests = [
3636
"object_file_multi_threaded_test.cc",
3737
"object_hash_integration_test.cc",
3838
"object_insert_integration_test.cc",
39+
"object_insert_preconditions_integration_test.cc",
3940
"object_integration_test.cc",
4041
"object_list_objects_versions_integration_test.cc",
4142
"object_media_integration_test.cc",

0 commit comments

Comments
 (0)