@@ -36,6 +36,23 @@ namespace {
3636bool IsSet (std::chrono::system_clock::time_point tp) {
3737 return tp != std::chrono::system_clock::time_point{};
3838}
39+
40+ void AssertHasCustomContext (google::cloud::storage::ObjectMetadata const & meta,
41+ std::string const & key,
42+ std::string const & expected_value) {
43+ EXPECT_TRUE (meta.has_contexts ())
44+ << " Missing contexts entirely in metadata: " << meta;
45+ EXPECT_TRUE (meta.contexts ().has_key (key))
46+ << " Missing expected context key '" << key << " ' in metadata: " << meta;
47+ if (meta.contexts ().has_key (key)) {
48+ EXPECT_EQ (expected_value, meta.contexts ().custom ().at (key).value )
49+ << " Mismatch in context value for key '" << key << " '\n "
50+ << " Expecting value '" << expected_value << " '\n "
51+ << " Actual metadata: " << meta;
52+ EXPECT_TRUE (IsSet (meta.contexts ().custom ().at (key).create_time ));
53+ EXPECT_TRUE (IsSet (meta.contexts ().custom ().at (key).update_time ));
54+ }
55+ }
3956} // namespace
4057
4158namespace google {
@@ -68,35 +85,34 @@ struct ObjectBasicCRUDIntegrationTest
6885 return MakeIntegrationTestClient (std::move (options));
6986 }
7087
71- // void SetUp() override {
72- // // 1. Run the base class SetUp first. This initializes 'bucket_name_'
73- // // from the environment variable.
74- // ::google::cloud::storage::testing::ObjectIntegrationTest::SetUp();
75-
76- // // 2. Create a client to interact with the emulator/backend.
77- // auto client = MakeIntegrationTestClient();
78-
79- // // 3. Check if the bucket exists.
80- // auto metadata = client.GetBucketMetadata(bucket_name_);
81-
82- // // 4. If it's missing (kNotFound), create it.
83- // if (metadata.status().code() == StatusCode::kNotFound) {
84- // // Use a default project ID if the env var isn't set (common in local
85- // // emulators).
86- // auto project_id =
87- // google::cloud::internal::GetEnv("GOOGLE_CLOUD_PROJECT")
88- // .value_or("test-project");
89-
90- // auto created = client.CreateBucketForProject(bucket_name_, project_id,
91- // BucketMetadata());
92- // ASSERT_STATUS_OK(created)
93- // << "Failed to auto-create missing bucket: " << bucket_name_;
94- // } else {
95- // // If it exists (or failed for another reason), assert it is OK.
96- // ASSERT_STATUS_OK(metadata)
97- // << "Failed to verify bucket existence: " << bucket_name_;
98- // }
99- // }
88+ void SetUp () override {
89+ // 1. Run the base class SetUp first. This initializes 'bucket_name_'
90+ // from the environment variable.
91+ ::google::cloud::storage::testing::ObjectIntegrationTest::SetUp ();
92+
93+ // 2. Create a client to interact with the emulator/backend.
94+ auto client = MakeIntegrationTestClient ();
95+
96+ // 3. Check if the bucket exists.
97+ auto metadata = client.GetBucketMetadata (bucket_name_);
98+
99+ // 4. If it's missing (kNotFound), create it.
100+ if (metadata.status ().code () == StatusCode::kNotFound ) {
101+ // Use a default project ID if the env var isn't set (common in local
102+ // emulators).
103+ auto project_id = google::cloud::internal::GetEnv (" GOOGLE_CLOUD_PROJECT" )
104+ .value_or (" test-project" );
105+
106+ auto created = client.CreateBucketForProject (bucket_name_, project_id,
107+ BucketMetadata ());
108+ ASSERT_STATUS_OK (created)
109+ << " Failed to auto-create missing bucket: " << bucket_name_;
110+ } else {
111+ // If it exists (or failed for another reason), assert it is OK.
112+ ASSERT_STATUS_OK (metadata)
113+ << " Failed to verify bucket existence: " << bucket_name_;
114+ }
115+ }
100116};
101117
102118// / @test Verify the Object CRUD (Create, Get, Update, Delete, List) operations.
@@ -195,55 +211,7 @@ TEST_F(ObjectBasicCRUDIntegrationTest, BasicCRUD) {
195211}
196212
197213// / @test Verify the Object CRUD operations with object contexts.
198- TEST_F (ObjectBasicCRUDIntegrationTest, BasicInsertAndGetWithObjectContexts) {
199- auto client = MakeIntegrationTestClient ();
200-
201- auto list_object_names = [&client, this ] {
202- std::vector<std::string> names;
203- for (auto o : client.ListObjects (bucket_name_)) {
204- EXPECT_STATUS_OK (o);
205- if (!o) break ;
206- names.push_back (o->name ());
207- }
208- return names;
209- };
210-
211- auto object_name = MakeRandomObjectName ();
212- ASSERT_THAT (list_object_names (), Not (Contains (object_name)))
213- << " Test aborted. The object <" << object_name << " > already exists."
214- << " This is unexpected as the test generates a random object name." ;
215-
216- // Create the object, but only if it does not exist already, inserting
217- // a custom context {"department": "engineering"}.
218- StatusOr<ObjectMetadata> insert_meta = client.InsertObject (
219- bucket_name_, object_name, LoremIpsum (), IfGenerationMatch (0 ),
220- Projection (" full" ),
221- WithObjectMetadata (ObjectMetadata ().set_contexts (
222- ObjectContexts ().upsert (" department" , {" engineering" , {}, {}}))));
223- ASSERT_STATUS_OK (insert_meta);
224- EXPECT_THAT (list_object_names (), Contains (object_name).Times (1 ));
225-
226- // Verify the response ObjectMetadata has the custom contexts we set.
227- StatusOr<ObjectMetadata> get_meta = client.GetObjectMetadata (
228- bucket_name_, object_name, Generation (insert_meta->generation ()),
229- Projection (" full" ));
230- ASSERT_STATUS_OK (get_meta);
231- EXPECT_TRUE (get_meta->has_contexts ()) << *get_meta;
232- EXPECT_TRUE (get_meta->contexts ().has_key (" department" )) << *get_meta;
233- EXPECT_EQ (" engineering" , get_meta->contexts ().custom ().at (" department" ).value )
234- << *get_meta;
235- EXPECT_TRUE (IsSet (get_meta->contexts ().custom ().at (" department" ).update_time ))
236- << *get_meta;
237- EXPECT_TRUE (IsSet (get_meta->contexts ().custom ().at (" department" ).create_time ))
238- << *get_meta;
239-
240- auto status = client.DeleteObject (bucket_name_, object_name);
241- ASSERT_STATUS_OK (status);
242- EXPECT_THAT (list_object_names (), Not (Contains (object_name)));
243- }
244-
245- // / @test Verify the Object CRUD operations with object contexts.
246- TEST_F (ObjectBasicCRUDIntegrationTest, BasicUpdateWithObjectContexts) {
214+ TEST_F (ObjectBasicCRUDIntegrationTest, BasicCRUDWithObjectContexts) {
247215 auto client = MakeIntegrationTestClient ();
248216
249217 auto list_object_names = [&client, this ] {
@@ -261,25 +229,21 @@ TEST_F(ObjectBasicCRUDIntegrationTest, BasicUpdateWithObjectContexts) {
261229 << " Test aborted. The object <" << object_name << " > already exists."
262230 << " This is unexpected as the test generates a random object name." ;
263231
264- // Create the object, but only if it does not exist already, inserting
265- // a custom context {"department": "engineering"}.
232+ // 1. Insert Object with custom contexts.
266233 StatusOr<ObjectMetadata> insert_meta = client.InsertObject (
267234 bucket_name_, object_name, LoremIpsum (), IfGenerationMatch (0 ),
268235 Projection (" full" ),
269236 WithObjectMetadata (ObjectMetadata ().set_contexts (
270237 ObjectContexts ().upsert (" department" , {" engineering" , {}, {}}))));
271238 ASSERT_STATUS_OK (insert_meta);
272239 EXPECT_THAT (list_object_names (), Contains (object_name).Times (1 ));
273-
274- // Verify the response ObjectMetadata has the custom contexts we set.
275240 StatusOr<ObjectMetadata> get_meta = client.GetObjectMetadata (
276241 bucket_name_, object_name, Generation (insert_meta->generation ()),
277242 Projection (" full" ));
278243 ASSERT_STATUS_OK (get_meta);
279- EXPECT_TRUE (get_meta->has_contexts ()) << *get_meta;
280- EXPECT_TRUE (get_meta->contexts ().has_key (" department" )) << *get_meta;
244+ AssertHasCustomContext (*get_meta, " department" , " engineering" );
281245
282- // Update object with two keys.
246+ // 2. Update object with two keys.
283247 ObjectMetadata update = *get_meta;
284248 update.set_contexts (
285249 ObjectContexts ()
@@ -289,125 +253,38 @@ TEST_F(ObjectBasicCRUDIntegrationTest, BasicUpdateWithObjectContexts) {
289253 bucket_name_, object_name, update, Generation (get_meta->generation ()),
290254 Projection (" full" ));
291255 ASSERT_STATUS_OK (updated_meta);
256+ AssertHasCustomContext (*updated_meta, " department" ,
257+ " engineering and research" );
258+ AssertHasCustomContext (*updated_meta, " region" , " Asia Pacific" );
292259
293- // Verify the response ObjectMetadata has the updated custom contexts.
294- EXPECT_TRUE (updated_meta->has_contexts ()) << *updated_meta;
295- EXPECT_TRUE (updated_meta->contexts ().has_key (" department" )) << *updated_meta;
296- // EXPECT_EQ("engineering and research",
297- // updated_meta->contexts().custom().at("department").value)
298- // << *updated_meta;
299- EXPECT_TRUE (updated_meta->contexts ().has_key (" region" )) << *updated_meta;
300- // EXPECT_EQ("Asia Pacific",
301- // updated_meta->contexts().custom().at("region").value)
302- // << *updated_meta;
303-
304- // This is the test for Object CRUD, we cannot rely on `ScheduleForDelete()`.
305- auto status = client.DeleteObject (bucket_name_, object_name);
306- ASSERT_STATUS_OK (status);
307- EXPECT_THAT (list_object_names (), Not (Contains (object_name)));
308- }
309-
310- // / @test Verify the Object CRUD operations with object contexts.
311- TEST_F (ObjectBasicCRUDIntegrationTest, BasicPatchWithObjectContexts) {
312- auto client = MakeIntegrationTestClient ();
313-
314- auto list_object_names = [&client, this ] {
315- std::vector<std::string> names;
316- for (auto o : client.ListObjects (bucket_name_)) {
317- EXPECT_STATUS_OK (o);
318- if (!o) break ;
319- names.push_back (o->name ());
320- }
321- return names;
322- };
323-
324- auto object_name = MakeRandomObjectName ();
325- ASSERT_THAT (list_object_names (), Not (Contains (object_name)))
326- << " Test aborted. The object <" << object_name << " > already exists."
327- << " This is unexpected as the test generates a random object name." ;
328-
329- // Create the object, but only if it does not exist already, inserting
330- // a custom context {"department": "engineering"}.
331- StatusOr<ObjectMetadata> insert_meta = client.InsertObject (
332- bucket_name_, object_name, LoremIpsum (), IfGenerationMatch (0 ),
333- Projection (" full" ),
334- WithObjectMetadata (ObjectMetadata ().set_contexts (
335- ObjectContexts ().upsert (" department" , {" engineering" , {}, {}}))));
336- ASSERT_STATUS_OK (insert_meta);
337- EXPECT_THAT (list_object_names (), Contains (object_name).Times (1 ));
338-
339- // Verify the response ObjectMetadata has the custom contexts we set.
340- StatusOr<ObjectMetadata> get_meta = client.GetObjectMetadata (
341- bucket_name_, object_name, Generation (insert_meta->generation ()),
342- Projection (" full" ));
343- ASSERT_STATUS_OK (get_meta);
344- EXPECT_TRUE (get_meta->has_contexts ()) << *get_meta;
345- EXPECT_TRUE (get_meta->contexts ().has_key (" department" )) << *get_meta;
346-
260+ // 3. Patch the object contexts by updating one key's value.
347261 StatusOr<ObjectMetadata> patched_meta =
348262 client.PatchObject (bucket_name_, object_name,
349263 ObjectMetadataPatchBuilder ().SetContext (
350264 " region" , {" Asia Pacific - Singapore" }),
351265 Projection (" full" ));
352266 ASSERT_STATUS_OK (patched_meta);
267+ AssertHasCustomContext (*patched_meta, " department" ,
268+ " engineering and research" );
269+ AssertHasCustomContext (*patched_meta, " region" , " Asia Pacific - Singapore" );
353270
354- EXPECT_TRUE (patched_meta->has_contexts ()) << *patched_meta;
355- EXPECT_TRUE (patched_meta->contexts ().has_key (" department" )) << *patched_meta;
356- EXPECT_TRUE (patched_meta->contexts ().has_key (" region" )) << *patched_meta;
357-
358- // This is the test for Object CRUD, we cannot rely on `ScheduleForDelete()`.
359- auto status = client.DeleteObject (bucket_name_, object_name);
360- ASSERT_STATUS_OK (status);
361- EXPECT_THAT (list_object_names (), Not (Contains (object_name)));
362- }
363-
364- // / @test Verify the Object CRUD operations with object contexts.
365- TEST_F (ObjectBasicCRUDIntegrationTest, BasicResetWithObjectContexts) {
366- auto client = MakeIntegrationTestClient ();
367-
368- auto list_object_names = [&client, this ] {
369- std::vector<std::string> names;
370- for (auto o : client.ListObjects (bucket_name_)) {
371- EXPECT_STATUS_OK (o);
372- if (!o) break ;
373- names.push_back (o->name ());
374- }
375- return names;
376- };
377-
378- auto object_name = MakeRandomObjectName ();
379- ASSERT_THAT (list_object_names (), Not (Contains (object_name)))
380- << " Test aborted. The object <" << object_name << " > already exists."
381- << " This is unexpected as the test generates a random object name." ;
382-
383- // Create the object, but only if it does not exist already, inserting
384- // a custom context {"department": "engineering"}.
385- StatusOr<ObjectMetadata> insert_meta = client.InsertObject (
386- bucket_name_, object_name, LoremIpsum (), IfGenerationMatch (0 ),
387- Projection (" full" ),
388- WithObjectMetadata (ObjectMetadata ().set_contexts (
389- ObjectContexts ().upsert (" department" , {" engineering" , {}, {}}))));
390- ASSERT_STATUS_OK (insert_meta);
391- EXPECT_THAT (list_object_names (), Contains (object_name).Times (1 ));
392-
393- // Verify the response ObjectMetadata has the custom contexts we set.
394- StatusOr<ObjectMetadata> get_meta = client.GetObjectMetadata (
395- bucket_name_, object_name, Generation (insert_meta->generation ()),
396- Projection (" full" ));
397- ASSERT_STATUS_OK (get_meta);
398- EXPECT_TRUE (get_meta->has_contexts ()) << *get_meta;
399- EXPECT_TRUE (get_meta->contexts ().has_key (" department" )) << *get_meta;
271+ // 4. Patch object contexts by deleting one existing key.
272+ StatusOr<ObjectMetadata> reset_key_meta = client.PatchObject (
273+ bucket_name_, object_name,
274+ ObjectMetadataPatchBuilder ().ResetContext (" region" ), Projection (" full" ));
275+ ASSERT_STATUS_OK (reset_key_meta);
276+ AssertHasCustomContext (*reset_key_meta, " department" ,
277+ " engineering and research" );
278+ EXPECT_FALSE (reset_key_meta->contexts ().has_key (" region" ));
400279
401- // Patch object with reset of all contexts.
280+ // 5. Patch object with reset of all contexts.
402281 StatusOr<ObjectMetadata> reset_meta = client.PatchObject (
403282 bucket_name_, object_name, ObjectMetadataPatchBuilder ().ResetContexts (),
404283 Projection (" full" ));
405284 ASSERT_STATUS_OK (reset_meta);
406-
407- // Verify the response ObjectMetadata that no custom contexts exists.
408285 EXPECT_FALSE (reset_meta->has_contexts ()) << *reset_meta;
409286
410- // This is the test for Object CRUD, we cannot rely on `ScheduleForDelete()` .
287+ // 6. Delete the object away to clean up .
411288 auto status = client.DeleteObject (bucket_name_, object_name);
412289 ASSERT_STATUS_OK (status);
413290 EXPECT_THAT (list_object_names (), Not (Contains (object_name)));
0 commit comments