Skip to content

samples(Storage): Add samples and tests for ObjectContext#21

Open
mahendra-google wants to merge 2 commits intomainfrom
object-context-samples
Open

samples(Storage): Add samples and tests for ObjectContext#21
mahendra-google wants to merge 2 commits intomainfrom
object-context-samples

Conversation

@mahendra-google
Copy link
Copy Markdown
Owner

@mahendra-google mahendra-google commented Mar 25, 2026

This PR adds three new samples and tests for Object Contexts.

storage_get_object_contexts : Retrieves the ContextsData for a specific object.

storage_list_object_contexts : Demonstrates how to iterate through and display the context metadata associated with an object.

storage_set_object_contexts: llustrates how to update or apply new context data to an existing object. Note :- We need a new version of Google.Cloud.Storage.V1 Nuget Package which contains Filter option of ListObjectOptions so that sample and test for List Objects with Context Data will not fail on Kokoro server. As of now I have updated Google.Cloud.Storage.V1 to 4.15.0 in the project file which is yet to be released.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the Google Cloud Storage client library samples by introducing the capability to manage object contexts. It provides a new sample and associated test for setting custom context data on storage objects, enabling users to attach key-payload pairs for identification and metadata purposes.

Highlights

  • New Sample Added: Added a new sample, SetObjectContexts, demonstrating how to update or apply new context data to an existing Google Cloud Storage object.
  • New Test Added: Introduced a corresponding test, SetObjectContextsTest, to validate the functionality of setting object contexts.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new sample and corresponding test for setting object contexts in Google Cloud Storage. The review identifies an issue where the test currently verifies only the return value of the sample method, rather than confirming the actual update of the object's contexts in Cloud Storage by retrieving the object. Additionally, it suggests an improvement for the sample method to return the Object instance provided by the UpdateObject call, ensuring the most accurate state from the service.

Comment thread storage/api/Storage.Samples.Tests/SetObjectContextsTest.cs Outdated
Comment thread storage/api/Storage.Samples/SetObjectContexts.cs Outdated
@mahendra-google
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new sample and an associated test for setting object contexts in Google Cloud Storage. The SetObjectContexts.cs file provides a SetObjectContextsSample class with a method to update an object's contexts using StorageClient.UpdateObject, while SetObjectContextsTest.cs adds an xUnit test to verify this functionality, including handling Unicode characters in context keys and values. Feedback includes improving the sample's robustness by providing a default non-null Object.ContextsData if contextsData is null, making the SetObjectContexts method and potentially its class static due to their stateless nature, and generalizing the console output message for accuracy.

public Google.Apis.Storage.v1.Data.Object.ContextsData SetObjectContexts(
string bucketName = "your-unique-bucket-name",
string objectName = "your-object-name",
Google.Apis.Storage.v1.Data.Object.ContextsData contextsData = null)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The default value null for the contextsData parameter is problematic for a sample demonstrating how to "set" contexts. If the sample is run without arguments, obj.Contexts will be null, which typically means the Contexts field will not be updated in a PATCH request. This contradicts the sample's description of "update or apply new context data".

To ensure the sample always demonstrates setting contexts, even when run standalone, contextsData should either be explicitly provided or a default non-null Object.ContextsData should be created if contextsData is null.

        Google.Apis.Storage.v1.Data.Object.ContextsData contextsData = null)
    {
        // Provide a default example context if none is provided for standalone execution
        contextsData ??= new Google.Apis.Storage.v1.Data.Object.ContextsData
        {
            Custom = new Dictionary<string, ObjectCustomContextPayload>
            {
                { "exampleKey", new ObjectCustomContextPayload { Value = "exampleValue" } }
            }
        };

[Fact]
public void SetObjectContexts()
{
SetObjectContextsSample contextsSample = new SetObjectContextsSample();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The SetObjectContexts method in SetObjectContextsSample does not rely on any instance state. It creates a StorageClient internally and performs an operation. Consider making the SetObjectContexts method static in SetObjectContexts.cs to reflect its stateless nature and avoid unnecessary object instantiation in tests and other sample calls.

        SetObjectContextsSample.SetObjectContexts(bucketName, objectName, contextsData);

using Google.Cloud.Storage.V1;
using System;

public class SetObjectContextsSample
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The SetObjectContexts method within this class does not utilize any instance members. To improve clarity and avoid unnecessary object instantiation, consider making both the class SetObjectContextsSample and the SetObjectContexts method static.

public static class SetObjectContextsSample

};
var updatedObject = storage.UpdateObject(obj);
Console.WriteLine($"Updated custom contexts data for the object {objectName}");
return updatedObject.Contexts;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The console message currently specifies "custom contexts data". However, the contextsData parameter description mentions "User-defined or system-defined object contexts". To be more accurate and general, the message should reflect the possibility of both types of contexts.

        Console.WriteLine($"Updated contexts data for the object {objectName}");

@mahendra-google
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new C# samples and XUnit tests for managing object context data in Google Cloud Storage, specifically for getting and setting custom contexts. Feedback includes addressing a potential NullReferenceException in GetObjectContexts.cs if contextsData.Custom is null, and removing ineffective Contexts property assignments during initial object uploads in both GetObjectContextsTest.cs and SetObjectContextsTest.cs to improve code clarity.

Comment thread storage/api/Storage.Samples/GetObjectContexts.cs Outdated
Comment thread storage/api/Storage.Samples.Tests/GetObjectContextsTest.cs Outdated
Comment thread storage/api/Storage.Samples.Tests/SetObjectContextsTest.cs Outdated
@mahendra-google
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new functionality for managing object contexts in Google Cloud Storage. It adds two new sample methods: GetObjectContexts to retrieve custom context data associated with an object, and SetObjectContexts to update an object with new custom context data. Corresponding XUnit tests, GetObjectContextsTest and SetObjectContextsTest, have also been added to validate this functionality. I have no feedback to provide.

@mahendra-google
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new C# samples and corresponding tests for managing object contexts in Google Cloud Storage. The GetObjectContexts and SetObjectContexts samples demonstrate how to retrieve and set custom context data for objects. Review feedback suggests improving resource management by explicitly disposing MemoryStream instances in tests using using statements, and by reusing StorageClient instances across multiple operations in the samples to reduce overhead.

Comment thread storage/api/Storage.Samples.Tests/GetObjectContextsTest.cs Outdated
Comment thread storage/api/Storage.Samples.Tests/SetObjectContextsTest.cs Outdated
string bucketName = "your-unique-bucket-name",
string objectName = "your-object-name")
{
var storage = StorageClient.Create();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Creating a new StorageClient instance with StorageClient.Create() for each operation can introduce unnecessary overhead. For better efficiency and resource management in a production application, it's generally recommended to reuse a single StorageClient instance across multiple calls, perhaps by making it a static field or injecting it.

string objectName = "your-object-name",
Google.Apis.Storage.v1.Data.Object.ContextsData contextsData = null)
{
var storage = StorageClient.Create();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Creating a new StorageClient instance with StorageClient.Create() for each operation can introduce unnecessary overhead. For better efficiency and resource management in a production application, it's generally recommended to reuse a single StorageClient instance across multiple calls, perhaps by making it a static field or injecting it.

@mahendra-google
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new samples and unit tests for managing object contexts in Google Cloud Storage, including setting, retrieving, and filtering objects by context. It also updates the Google.Cloud.Storage.V1 package to version 4.15.0. The review feedback identifies potential NullReferenceException risks in the sample code when accessing context properties and suggests refactoring duplicated setup logic across the new test files to improve maintainability.

Comment thread storage/api/Storage.Samples/GetObjectContexts.cs
Comment thread storage/api/Storage.Samples/ListObjectsWithContextFilter.cs
Comment on lines +37 to +60
string contextKey = "A\u00F1\u03A9\U0001F680";
string contextValue = "Ab\u00F1\u03A9\U0001F680";

var custom = new Dictionary<string, ObjectCustomContextPayload>
{
{ contextKey, new ObjectCustomContextPayload { Value = contextValue } }
};

var bucketName = _fixture.GenerateBucketName();
var objectName = _fixture.GenerateName();
var contextsData = new Object.ContextsData { Custom = custom };
_fixture.CreateBucket(bucketName, multiVersion: false, softDelete: true, registerForDeletion: true);

var destination = new Object
{
Bucket = bucketName,
Name = objectName
};
var content = _fixture.GenerateName();
byte[] byteArray = Encoding.UTF8.GetBytes(content);
using (MemoryStream source = new MemoryStream(byteArray))
{
_fixture.Client.UploadObject(destination, source);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's a significant amount of duplicated code for setting up the test environment (creating bucket, object, and context data) across GetObjectContextsTest.cs, ListObjectsWithContextFilterTest.cs, and SetObjectContextsTest.cs. To improve maintainability and reduce boilerplate, consider extracting this setup logic into a shared helper method. This could be a private method within each test class or a method in a shared test utility class.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gemini-code-assist I feel that each test should have a different test bucket, test object and test context data. Separate helper methods are already created in StorageFixture for creating test buckets and test objects. In addition to that helper methods are created in such a way that all created resources are getting disposed of at the end of each individual tests.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your point regarding the need for unique test resources to ensure test isolation. However, the current approach results in significant code duplication across these three test files. You can maintain test isolation while reducing boilerplate by creating a shared helper method in StorageFixture that handles the common setup (creating the bucket, object, and context data) and returns the necessary identifiers. This would keep the individual test methods clean and focused on their specific assertions.

@mahendra-google
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds sample code and tests for setting, getting, and filtering Google Cloud Storage objects using metadata contexts, and updates the Google.Cloud.Storage.V1 dependency to version 4.15.0. The review feedback suggests refactoring duplicated test setup logic into a helper method and correcting a typo in the documentation for the context filter parameter.

Comment on lines +50 to +60
var destination = new Object
{
Bucket = bucketName,
Name = objectName
};
var content = _fixture.GenerateName();
byte[] byteArray = Encoding.UTF8.GetBytes(content);
using (MemoryStream source = new MemoryStream(byteArray))
{
_fixture.Client.UploadObject(destination, source);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block of code for creating and uploading a test object is duplicated in ListObjectsWithContextFilterTest.cs and SetObjectContextsTest.cs. To improve maintainability and reduce code duplication, consider extracting this logic into a helper method within the StorageFixture class.

For example, you could add a method like this to StorageFixture:

public Google.Apis.Storage.v1.Data.Object UploadTestObject(string bucketName, string objectName)
{
    var destination = new Google.Apis.Storage.v1.Data.Object
    {
        Bucket = bucketName,
        Name = objectName
    };
    var content = GenerateName();
    byte[] byteArray = Encoding.UTF8.GetBytes(content);
    using (MemoryStream source = new MemoryStream(byteArray))
    {
        return Client.UploadObject(destination, source);
    }
}

Then, you could replace these lines in the test with a single call:
_fixture.UploadTestObject(bucketName, objectName);

Comment thread storage/api/Storage.Samples/ListObjectsWithContextFilter.cs Outdated
@mahendra-google
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds sample code and tests for Google Cloud Storage object contexts and updates the Google.Cloud.Storage.V1 package. Feedback includes fixing potential NullReferenceExceptions when accessing context data, optimizing object listing performance, and removing unused using directives in test files.

Comment on lines +35 to +46
if (contextsData == null)
{
Console.WriteLine($"No Context Data found for the Object {objectName}");
return contextsData;
}

Console.WriteLine($"Context Data for the Object {objectName} is as follows:");
foreach (var (key, contextPayload) in contextsData.Custom)
{
Console.WriteLine($"Context Key: {key}, Context Value: {contextPayload.Value}");
}
return contextsData;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation checks if contextsData is null, but does not handle the case where contextsData.Custom is null or empty. This could lead to a NullReferenceException if contextsData exists but Custom does not, or confusing output if Custom is empty. It's safer to check if contextsData.Custom is null or has no elements before attempting to iterate.

        if (contextsData?.Custom is null || contextsData.Custom.Count == 0)
        {
            Console.WriteLine($"No Context Data found for the Object {objectName}");
            return contextsData;
        }

        Console.WriteLine($"Context Data for the Object {objectName} is as follows:");
        foreach (var (key, contextPayload) in contextsData.Custom)
        {
            Console.WriteLine($"Context Key: {key}, Context Value: {contextPayload.Value}");
        }
        return contextsData;

Comment on lines +39 to +44
Console.WriteLine($"Context Data for the Object {obj.Name} is as follows:");

foreach (var (key, contextPayload) in obj.Contexts.Custom)
{
Console.WriteLine($"Context Key: {key}, Context Value: {contextPayload.Value}");
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The code accesses obj.Contexts.Custom without checking if obj.Contexts or obj.Contexts.Custom might be null. If an object in the list does not have context data, this will cause a NullReferenceException. You should add a check to ensure obj.Contexts.Custom is not null and not empty before iterating over it.

            if (obj.Contexts?.Custom != null && obj.Contexts.Custom.Count > 0)
            {
                Console.WriteLine($"Context Data for the Object {obj.Name} is as follows:");
                foreach (var (key, contextPayload) in obj.Contexts.Custom)
                {
                    Console.WriteLine($"Context Key: {key}, Context Value: {contextPayload.Value}");
                }
            }

Comment on lines +17 to +18
using System.IO;
using System.Text;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The using directives for System.IO and System.Text are not used in this file. They can be removed to improve code cleanliness.

Comment on lines +17 to +18
using System.IO;
using System.Text;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The using directives for System.IO and System.Text are not used in this file. They can be removed to improve code cleanliness.

Comment on lines +17 to +18
using System.IO;
using System.Text;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The using directives for System.IO and System.Text are not used in this file. They can be removed to improve code cleanliness.

string filter = "contexts.\"KEY\"=\"VALUE\"")
{
var storage = StorageClient.Create();
var objects = storage.ListObjects(bucketName, prefix: null, new ListObjectsOptions { Filter = filter }).ToList();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Calling ToList() on the result of ListObjects materializes the entire collection in memory. This can be inefficient if the bucket contains a large number of objects. It's better to iterate over the PagedEnumerable<Object> returned by ListObjects directly, which fetches objects in pages as needed.

        var objects = storage.ListObjects(bucketName, prefix: null, new ListObjectsOptions { Filter = filter });

@mahendra-google
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new sample code and unit tests for managing object contexts in Google Cloud Storage, specifically for setting, retrieving, and filtering objects. It also updates the Google.Cloud.Storage.V1 package version to 4.15.0. The review feedback suggests optimizing the API calls in the samples by explicitly specifying the required fields in the request options to improve performance and ensure the presence of the contexts property in the response.

string objectName = "your-object-name")
{
var storage = StorageClient.Create();
var obj = storage.GetObject(bucketName, objectName);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For efficiency, it's better to request only the fields you need. Since this sample only uses the Contexts property of the object, you can specify that using GetObjectOptions. This avoids fetching the entire object metadata.

        var obj = storage.GetObject(bucketName, objectName, new GetObjectOptions { Fields = "contexts" });

Comment thread storage/api/Storage.Samples/ListObjectsWithContextFilter.cs Outdated
Name = objectName,
Contexts = contextsData
};
var updatedObject = storage.UpdateObject(obj);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For better performance, you can specify that only the Contexts field should be returned in the response object. This reduces the amount of data transferred from the service.

        var updatedObject = storage.UpdateObject(obj, new UpdateObjectOptions { Fields = "contexts" });

@mahendra-google
Copy link
Copy Markdown
Owner Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new samples for managing and filtering object contexts in Google Cloud Storage, including updates to the project dependencies. The review identified potential NullReferenceExceptions when accessing context data in both the retrieval and listing samples, and provided specific code suggestions to safely handle null or empty context collections.

Comment thread storage/api/Storage.Samples/GetObjectContexts.cs Outdated
Comment thread storage/api/Storage.Samples/ListObjectsWithContextFilter.cs Outdated
@mahendra-google mahendra-google force-pushed the object-context-samples branch from 6386527 to 4e50755 Compare March 30, 2026 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant