Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions storage/api/Storage.Samples.Tests/ListSoftDeletedObjectsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License").
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Google.Apis.Storage.v1.Data;
using System.Linq;
using Xunit;

[Collection(nameof(StorageFixture))]
public class ListSoftDeletedObjectsTest
{
private readonly StorageFixture _fixture;

public ListSoftDeletedObjectsTest(StorageFixture fixture)
{
_fixture = fixture;
}

[Fact]
public void ListSoftDeletedObjects()
{
ListSoftDeletedObjectsSample listSoftDeletedObjects = new ListSoftDeletedObjectsSample();
UploadObjectFromMemorySample uploadObjectFromMemory = new UploadObjectFromMemorySample();
var bucketName = _fixture.GenerateBucketName();
_fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true);
var objectNameOne = _fixture.GenerateName();
var objectOneContent = _fixture.GenerateContent();
var objectNameTwo = _fixture.GenerateName();
var objectTwoContent = _fixture.GenerateContent();
uploadObjectFromMemory.UploadObjectFromMemory(bucketName, objectNameOne, objectOneContent);
uploadObjectFromMemory.UploadObjectFromMemory(bucketName, objectNameTwo, objectTwoContent);
var preSoftDeleteObjects = _fixture.Client.ListObjects(bucketName);
int preSoftDeleteObjectsCount = preSoftDeleteObjects.Count();
_fixture.Client.DeleteObject(bucketName, objectNameOne);
_fixture.Client.DeleteObject(bucketName, objectNameTwo);
var softDeletedObjects = listSoftDeletedObjects.ListSoftDeletedObjects(bucketName);
int softDeletedObjectsCount = softDeletedObjects.Count();
Assert.Equal(preSoftDeleteObjectsCount, softDeletedObjectsCount);
Assert.All(softDeletedObjects, AssertSoftDeletedObject);
Assert.Multiple(
() => Assert.Contains(softDeletedObjects, softDeletedObject => softDeletedObject.Name == objectNameOne),
() => Assert.Contains(softDeletedObjects, softDeletedObject => softDeletedObject.Name == objectNameTwo)
);
}

// Validates that the given object is soft-deleted.
private void AssertSoftDeletedObject(Object o)
{
Assert.NotNull(o.Generation);
Assert.NotNull(o.HardDeleteTimeDateTimeOffset);
Assert.NotNull(o.SoftDeleteTimeDateTimeOffset);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License").
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Google.Apis.Storage.v1.Data;
using System.Collections.Generic;
using System.Linq;
using Xunit;

[Collection(nameof(StorageFixture))]
public class ListSoftDeletedVersionsOfObjectTest
{
private readonly StorageFixture _fixture;
private IList<long> _softDeleteObjectGenerations { get; } = new List<long>();

public ListSoftDeletedVersionsOfObjectTest(StorageFixture fixture)
{
_fixture = fixture;
}

[Fact]
public void ListSoftDeletedVersionsOfObject()
{
int i = 3;
int preSoftDeleteObjectVersionsCount = i;
ListSoftDeletedVersionsOfObjectSample listSoftDeletedVersionOfObject = new ListSoftDeletedVersionsOfObjectSample();
UploadObjectFromMemorySample uploadObjectFromMemory = new UploadObjectFromMemorySample();
RestoreSoftDeletedObjectSample restoreSoftDeletedObjectSample = new RestoreSoftDeletedObjectSample();
GetMetadataSample getMetadataSample = new GetMetadataSample();
var bucketName = _fixture.GenerateBucketName();
_fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true);
var objectName = _fixture.GenerateName();
var objectContent = _fixture.GenerateContent();
uploadObjectFromMemory.UploadObjectFromMemory(bucketName, objectName, objectContent);
while (i >= 1)
{
var objectMetaData = getMetadataSample.GetMetadata(bucketName, objectName);
_softDeleteObjectGenerations.Add(objectMetaData.Generation.Value);
_fixture.Client.DeleteObject(bucketName, objectName);
var restoredObject = restoreSoftDeletedObjectSample.RestoreSoftDeletedObject(bucketName, objectName, objectMetaData.Generation.Value);
i--;
}
var softDeletedObjectVersions = listSoftDeletedVersionOfObject.ListSoftDeletedVersionsOfObject(bucketName, objectName);
int softDeletedObjectVersionsCount = softDeletedObjectVersions.Count();
Assert.Equal(preSoftDeleteObjectVersionsCount, softDeletedObjectVersionsCount);
Assert.All(softDeletedObjectVersions, AssertSoftDeletedVersionsOfObject);
Assert.Multiple(
() => Assert.Contains(softDeletedObjectVersions, softDeletedObject => softDeletedObject.Name == objectName && softDeletedObject.Generation == _softDeleteObjectGenerations[_softDeleteObjectGenerations.Count - 1]),
() => Assert.Contains(softDeletedObjectVersions, softDeletedObject => softDeletedObject.Name == objectName && softDeletedObject.Generation == _softDeleteObjectGenerations[_softDeleteObjectGenerations.Count - 2]),
() => Assert.Contains(softDeletedObjectVersions, softDeletedObject => softDeletedObject.Name == objectName && softDeletedObject.Generation == _softDeleteObjectGenerations[_softDeleteObjectGenerations.Count - 3])
);
_fixture.Client.DeleteObject(bucketName, objectName);
}

private void AssertSoftDeletedVersionsOfObject(Object o)
{
Assert.NotNull(o.Generation);
Assert.NotNull(o.HardDeleteTimeDateTimeOffset);
Assert.NotNull(o.SoftDeleteTimeDateTimeOffset);
}
}
46 changes: 46 additions & 0 deletions storage/api/Storage.Samples.Tests/RestoreSoftDeletedObjectTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License").
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Xunit;

[Collection(nameof(StorageFixture))]
public class RestoreSoftDeletedObjectTest
{
private readonly StorageFixture _fixture;

public RestoreSoftDeletedObjectTest(StorageFixture fixture)
{
_fixture = fixture;
}

[Fact]
public void RestoreSoftDeletedObject()
{
RestoreSoftDeletedObjectSample restoreSoftDeletedObjectSample = new RestoreSoftDeletedObjectSample();
UploadObjectFromMemorySample uploadObjectFromMemory = new UploadObjectFromMemorySample();
GetMetadataSample getMetadataSample = new GetMetadataSample();
var bucketName = _fixture.GenerateBucketName();
_fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true);
var objectName = _fixture.GenerateName();
var objectContent = _fixture.GenerateContent();
uploadObjectFromMemory.UploadObjectFromMemory(bucketName, objectName, objectContent);
var objectMetaData = getMetadataSample.GetMetadata(bucketName, objectName);
_fixture.Client.DeleteObject(bucketName, objectName);
var restoredObject = restoreSoftDeletedObjectSample.RestoreSoftDeletedObject(bucketName, objectName, objectMetaData.Generation.Value);
Assert.Equal(objectName, restoredObject.Name);
Assert.Equal(objectMetaData.Size, restoredObject.Size);
Assert.Equal(objectMetaData.Md5Hash, restoredObject.Md5Hash);
_fixture.Client.DeleteObject(bucketName, objectName);
}
}
12 changes: 12 additions & 0 deletions storage/api/Storage.Samples.Tests/StorageFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,18 @@ internal Bucket CreateBucket(string name, bool multiVersion, bool softDelete = f

internal string GenerateBucketName() => Guid.NewGuid().ToString();

/// <summary>
/// Generate the name of the object.
/// </summary>
/// <returns>The objectName.</returns>
internal string GenerateName() => Guid.NewGuid().ToString();

/// <summary>
/// Generate the content of the object.
/// </summary>
/// <returns>The objectContent.</returns>
internal string GenerateContent() => Guid.NewGuid().ToString();

/// <summary>
/// Bucket creation/update/deletion is rate-limited. To avoid making the tests flaky, we sleep after each operation.
/// </summary>
Expand Down
39 changes: 39 additions & 0 deletions storage/api/Storage.Samples/ListSoftDeletedObjects.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START storage_list_soft_deleted_objects]

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

public class ListSoftDeletedObjectsSample
{
/// <summary>
/// List all soft-deleted objects in the bucket.
/// </summary>
/// <param name="bucketName">The name of the bucket.</param>
public IEnumerable<Google.Apis.Storage.v1.Data.Object> ListSoftDeletedObjects(string bucketName = "your-unique-bucket-name")
{
var storage = StorageClient.Create();
var objects = storage.ListObjects(bucketName, prefix: null, new ListObjectsOptions { SoftDeletedOnly = true });
Console.WriteLine($"The Names of the Soft Deleted Objects in the Bucket (Bucket Name: {bucketName}) are as follows:");
foreach (var obj in objects)
{
Console.WriteLine($"Object Name: {obj.Name}");
}
return objects;
}
}
// [END storage_list_soft_deleted_objects]
41 changes: 41 additions & 0 deletions storage/api/Storage.Samples/ListSoftDeletedVersionsOfObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START storage_list_soft_deleted_object_versions]

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

public class ListSoftDeletedVersionsOfObjectSample
{
/// <summary>
/// List all soft-deleted versions of the object in the bucket.
/// </summary>
/// <param name="bucketName">The name of the bucket.</param>
/// <param name="objectName">The name of the object.</param>
public IEnumerable<Google.Apis.Storage.v1.Data.Object> ListSoftDeletedVersionsOfObject(string bucketName = "your-unique-bucket-name",
string objectName = "your-object-name")
{
var storage = StorageClient.Create();
var objects = storage.ListObjects(bucketName, prefix: null, new ListObjectsOptions { SoftDeletedOnly = true, MatchGlob = objectName });
Console.WriteLine($"The Name and Versions of the Soft Deleted Object in the Bucket (Bucket Name: {bucketName}) are as follows:");
foreach (var obj in objects)
{
Console.WriteLine($"Object Name: {obj.Name} and Version: {obj.Generation}");
}
return objects;
}
}
// [END storage_list_soft_deleted_object_versions]
39 changes: 39 additions & 0 deletions storage/api/Storage.Samples/RestoreSoftDeletedObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License").
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START storage_restore_object]

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

public class RestoreSoftDeletedObjectSample
{
/// <summary>
/// Restores a soft-deleted object.
/// </summary>
/// <param name="bucketName">The name of the bucket.</param>
/// <param name="objectName">The name of the soft-deleted object.</param>
/// <param name="generation">The generation of the soft-deleted object.</param>
public Google.Apis.Storage.v1.Data.Object RestoreSoftDeletedObject(
string bucketName = "your-unique-bucket-name",
string objectName = "your-object-name",
long generation = 1579287380533984)
{
var client = StorageClient.Create();
var restoredObject = client.RestoreObject(bucketName, objectName, generation);
Console.WriteLine($"The Name of the Restored Object which was previously Soft-deleted is : {restoredObject.Name}");
return restoredObject;
}
}
// [END storage_restore_object]