Skip to content

Commit 3bd0486

Browse files
authored
test(storage): verify writes with pre-conditions work (#6904)
1 parent ed8c316 commit 3bd0486

File tree

3 files changed

+236
-0
lines changed

3 files changed

+236
-0
lines changed

google/cloud/storage/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ set(storage_client_integration_tests
4646
object_resumable_parallel_upload_integration_test.cc
4747
object_resumable_write_integration_test.cc
4848
object_rewrite_integration_test.cc
49+
object_write_preconditions_integration_test.cc
4950
object_write_streambuf_integration_test.cc
5051
service_account_integration_test.cc
5152
signed_url_conformance_test.cc
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
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+
class ObjectWritePreconditionsIntegrationTest
38+
: public ::google::cloud::storage::testing::StorageIntegrationTest {
39+
protected:
40+
ObjectWritePreconditionsIntegrationTest() = default;
41+
42+
void SetUp() override {
43+
bucket_name_ =
44+
GetEnv("GOOGLE_CLOUD_CPP_STORAGE_TEST_BUCKET_NAME").value_or("");
45+
46+
ASSERT_THAT(bucket_name_, Not(IsEmpty()));
47+
}
48+
49+
std::string const& bucket_name() const { return bucket_name_; }
50+
51+
private:
52+
std::string bucket_name_;
53+
};
54+
55+
TEST_F(ObjectWritePreconditionsIntegrationTest, IfGenerationMatchSuccess) {
56+
StatusOr<Client> client = MakeIntegrationTestClient();
57+
ASSERT_STATUS_OK(client);
58+
59+
auto const object_name = MakeRandomObjectName();
60+
auto const expected_text = LoremIpsum();
61+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
62+
IfGenerationMatch(0));
63+
ASSERT_THAT(meta, IsOk());
64+
65+
auto os = client->WriteObject(bucket_name(), object_name,
66+
IfGenerationMatch(meta->generation()));
67+
os << expected_text;
68+
os.Close();
69+
ASSERT_THAT(os.metadata(), IsOk());
70+
71+
(void)client->DeleteObject(bucket_name(), object_name,
72+
Generation(os.metadata()->generation()));
73+
(void)client->DeleteObject(bucket_name(), object_name,
74+
Generation(meta->generation()));
75+
}
76+
77+
TEST_F(ObjectWritePreconditionsIntegrationTest, IfGenerationMatchFailure) {
78+
StatusOr<Client> client = MakeIntegrationTestClient();
79+
ASSERT_STATUS_OK(client);
80+
81+
auto const object_name = MakeRandomObjectName();
82+
auto const expected_text = LoremIpsum();
83+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
84+
IfGenerationMatch(0));
85+
ASSERT_THAT(meta, IsOk());
86+
87+
auto os = client->WriteObject(bucket_name(), object_name,
88+
IfGenerationMatch(meta->generation() + 1));
89+
os << expected_text;
90+
os.Close();
91+
ASSERT_THAT(os.metadata(), StatusIs(StatusCode::kFailedPrecondition));
92+
93+
(void)client->DeleteObject(bucket_name(), object_name,
94+
Generation(meta->generation()));
95+
}
96+
97+
TEST_F(ObjectWritePreconditionsIntegrationTest, IfGenerationNotMatchSuccess) {
98+
StatusOr<Client> client = MakeIntegrationTestClient();
99+
ASSERT_STATUS_OK(client);
100+
101+
auto const object_name = MakeRandomObjectName();
102+
auto const expected_text = LoremIpsum();
103+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
104+
IfGenerationMatch(0));
105+
ASSERT_THAT(meta, IsOk());
106+
107+
auto os = client->WriteObject(bucket_name(), object_name,
108+
IfGenerationNotMatch(meta->generation() + 1));
109+
os << expected_text;
110+
os.Close();
111+
ASSERT_THAT(os.metadata(), IsOk());
112+
113+
(void)client->DeleteObject(bucket_name(), object_name,
114+
Generation(os.metadata()->generation()));
115+
(void)client->DeleteObject(bucket_name(), object_name,
116+
Generation(meta->generation()));
117+
}
118+
119+
TEST_F(ObjectWritePreconditionsIntegrationTest, IfGenerationNotMatchFailure) {
120+
StatusOr<Client> client = MakeIntegrationTestClient();
121+
ASSERT_STATUS_OK(client);
122+
123+
auto const object_name = MakeRandomObjectName();
124+
auto const expected_text = LoremIpsum();
125+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
126+
IfGenerationMatch(0));
127+
ASSERT_THAT(meta, IsOk());
128+
129+
auto os = client->WriteObject(bucket_name(), object_name,
130+
IfGenerationNotMatch(meta->generation()));
131+
os << expected_text;
132+
os.Close();
133+
ASSERT_THAT(os.metadata(), StatusIs(AnyOf(StatusCode::kFailedPrecondition,
134+
StatusCode::kAborted)));
135+
136+
(void)client->DeleteObject(bucket_name(), object_name,
137+
Generation(meta->generation()));
138+
}
139+
140+
TEST_F(ObjectWritePreconditionsIntegrationTest, IfMetagenerationMatchSuccess) {
141+
StatusOr<Client> client = MakeIntegrationTestClient();
142+
ASSERT_STATUS_OK(client);
143+
144+
auto const object_name = MakeRandomObjectName();
145+
auto const expected_text = LoremIpsum();
146+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
147+
IfGenerationMatch(0));
148+
ASSERT_THAT(meta, IsOk());
149+
150+
auto os = client->WriteObject(bucket_name(), object_name,
151+
IfMetagenerationMatch(meta->metageneration()));
152+
os << expected_text;
153+
os.Close();
154+
ASSERT_THAT(os.metadata(), IsOk());
155+
156+
(void)client->DeleteObject(bucket_name(), object_name,
157+
Generation(os.metadata()->generation()));
158+
(void)client->DeleteObject(bucket_name(), object_name,
159+
Generation(meta->generation()));
160+
}
161+
162+
TEST_F(ObjectWritePreconditionsIntegrationTest, IfMetagenerationMatchFailure) {
163+
StatusOr<Client> client = MakeIntegrationTestClient();
164+
ASSERT_STATUS_OK(client);
165+
166+
auto const object_name = MakeRandomObjectName();
167+
auto const expected_text = LoremIpsum();
168+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
169+
IfGenerationMatch(0));
170+
ASSERT_THAT(meta, IsOk());
171+
172+
auto os =
173+
client->WriteObject(bucket_name(), object_name,
174+
IfMetagenerationMatch(meta->metageneration() + 1));
175+
os << expected_text;
176+
os.Close();
177+
ASSERT_THAT(os.metadata(), StatusIs(StatusCode::kFailedPrecondition));
178+
179+
(void)client->DeleteObject(bucket_name(), object_name,
180+
Generation(meta->generation()));
181+
}
182+
183+
TEST_F(ObjectWritePreconditionsIntegrationTest,
184+
IfMetagenerationNotMatchSuccess) {
185+
StatusOr<Client> client = MakeIntegrationTestClient();
186+
ASSERT_STATUS_OK(client);
187+
188+
auto const object_name = MakeRandomObjectName();
189+
auto const expected_text = LoremIpsum();
190+
auto meta = client->InsertObject(bucket_name(), object_name, expected_text,
191+
IfGenerationMatch(0));
192+
ASSERT_THAT(meta, IsOk());
193+
194+
auto os =
195+
client->WriteObject(bucket_name(), object_name,
196+
IfMetagenerationNotMatch(meta->metageneration() + 1));
197+
os << expected_text;
198+
os.Close();
199+
ASSERT_THAT(os.metadata(), IsOk());
200+
201+
(void)client->DeleteObject(bucket_name(), object_name,
202+
Generation(os.metadata()->generation()));
203+
(void)client->DeleteObject(bucket_name(), object_name,
204+
Generation(meta->generation()));
205+
}
206+
207+
TEST_F(ObjectWritePreconditionsIntegrationTest,
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 os =
219+
client->WriteObject(bucket_name(), object_name,
220+
IfMetagenerationNotMatch(meta->metageneration()));
221+
os << expected_text;
222+
os.Close();
223+
ASSERT_THAT(os.metadata(), StatusIs(AnyOf(StatusCode::kFailedPrecondition,
224+
StatusCode::kAborted)));
225+
226+
(void)client->DeleteObject(bucket_name(), object_name,
227+
Generation(meta->generation()));
228+
}
229+
230+
} // namespace
231+
} // namespace STORAGE_CLIENT_NS
232+
} // namespace storage
233+
} // namespace cloud
234+
} // 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
@@ -47,6 +47,7 @@ storage_client_integration_tests = [
4747
"object_resumable_parallel_upload_integration_test.cc",
4848
"object_resumable_write_integration_test.cc",
4949
"object_rewrite_integration_test.cc",
50+
"object_write_preconditions_integration_test.cc",
5051
"object_write_streambuf_integration_test.cc",
5152
"service_account_integration_test.cc",
5253
"signed_url_conformance_test.cc",

0 commit comments

Comments
 (0)