Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
40eac28
initial commit for moveObject feature
mahendra-google Mar 21, 2025
0384a8c
storage fixture changes for move object
mahendra-google Mar 21, 2025
0f96e2a
moveobject test added
mahendra-google Mar 21, 2025
0b12a11
Google.Apis.Storage.v1 package upgrade in storage project file
mahendra-google Mar 21, 2025
137731e
move object test case updated
mahendra-google Mar 24, 2025
72a4f84
MoveObject Test changes
mahendra-google Mar 24, 2025
5e83b6c
Move Test updated
mahendra-google Mar 24, 2025
8d854b9
move object test update
mahendra-google Mar 25, 2025
74308d7
storage client implementation changes
mahendra-google Mar 25, 2025
57adb0f
linter changes
mahendra-google Mar 26, 2025
dc443da
move object test changes
mahendra-google Mar 26, 2025
f6fe52f
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1/StorageCl…
mahendra-google Apr 3, 2025
c9bd462
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1/StorageCl…
mahendra-google Apr 3, 2025
7e287f4
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1/StorageCl…
mahendra-google Apr 3, 2025
71baf65
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1/StorageCl…
mahendra-google Apr 3, 2025
eb34f06
fixture changes
mahendra-google Apr 3, 2025
370c40b
Update StorageFixture.cs
mahendra-google Apr 3, 2025
0d6641a
move object fixture and test recommended changes
mahendra-google Apr 4, 2025
c3bade9
Extrametadata removed from move object
mahendra-google Apr 4, 2025
3458a7d
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Integrati…
mahendra-google Apr 9, 2025
2ad2f99
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1/StorageCl…
mahendra-google Apr 9, 2025
ab25509
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Integrati…
mahendra-google Apr 10, 2025
8aa845e
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Integrati…
mahendra-google Apr 10, 2025
b5da672
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Integrati…
mahendra-google Apr 10, 2025
3c013b5
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Integrati…
mahendra-google Apr 10, 2025
f8d312d
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Integrati…
mahendra-google Apr 10, 2025
299c3a4
Update apis/Google.Cloud.Storage.V1/Google.Cloud.Storage.V1.Integrati…
mahendra-google Apr 10, 2025
de2d78a
MoveObjectTest changes
mahendra-google Apr 10, 2025
4663b1a
Update apis.json
mahendra-google Apr 11, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2025 Google Inc. All Rights Reserved.
//
// 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.

using Google.Cloud.ClientTesting;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Xunit;
using static Google.Cloud.Storage.V1.IntegrationTests.TestHelpers;

namespace Google.Cloud.Storage.V1.IntegrationTests;

[Collection(nameof(StorageFixture))]
public class MoveObjectTest
{
private readonly StorageFixture _fixture;
private readonly string _bucket;
private readonly string _originName;
private readonly string _destinationName;
private readonly string _contentType;
private readonly MemoryStream _data;

public MoveObjectTest(StorageFixture fixture)
{
_fixture = fixture;
_bucket = _fixture.HnsBucket;
_originName = IdGenerator.FromGuid();
_destinationName = IdGenerator.FromGuid();
_contentType = "application/octet-stream";
_data = GenerateData(100);
}

[Fact]
public async Task MoveObjectAsync()
{
await _fixture.Client.UploadObjectAsync(_bucket, _originName, _contentType, _data);

await _fixture.Client.MoveObjectAsync(_bucket, _originName, _destinationName);

var objects = _fixture.Client.ListObjects(_bucket);
Assert.DoesNotContain(objects, obj => obj.Name == _originName);
Assert.Contains(objects, obj => obj.Name == _destinationName);

using var stream = new MemoryStream();
await _fixture.Client.DownloadObjectAsync(_bucket, _destinationName, stream);
Assert.Equal(_data.ToArray(), stream.ToArray());
}

[Fact]
public async Task MoveObjectAsync_GenerationMismatch_Fails()
{
await _fixture.Client.UploadObjectAsync(_bucket, _originName, _contentType, _data);

var exception = await Assert.ThrowsAsync<GoogleApiException>(() => _fixture.Client.MoveObjectAsync(
_bucket, _originName, _destinationName,
new MoveObjectOptions { IfSourceGenerationMatch = 1 }));
Assert.Equal(HttpStatusCode.PreconditionFailed, exception.HttpStatusCode);
}

[Fact]
public async Task MoveObjectAsync_MetaGenerationMismatch_Fails()
{
await _fixture.Client.UploadObjectAsync(_bucket, _originName, _contentType, _data);

var exception = await Assert.ThrowsAsync<GoogleApiException>(() => _fixture.Client.MoveObjectAsync(
_bucket, _originName, _destinationName,
new MoveObjectOptions { IfSourceMetagenerationMatch = 0 }));
Assert.Equal(HttpStatusCode.PreconditionFailed, exception.HttpStatusCode);
}

[Fact]
public async Task MoveObjectAsync_PreconditionsMatch()
{
var origin = await _fixture.Client.UploadObjectAsync(_bucket, _originName, _contentType, _data);

await _fixture.Client.MoveObjectAsync(
_bucket, _originName, _destinationName,
new MoveObjectOptions
{
IfSourceMetagenerationMatch = origin.Metageneration,
IfSourceGenerationMatch = origin.Generation
});
var objects = _fixture.Client.ListObjects(_bucket);

Assert.Contains(objects, obj => obj.Name == _destinationName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public sealed class StorageFixture : CloudProjectFixtureBase, ICollectionFixture
/// </summary>
public string SoftDeleteBucket => BucketPrefix + "-soft-delete";

/// <summary>
/// Name of a bucket with hierarchical namespace enabled
/// </summary>
public string HnsBucket => BucketPrefix + "-hns";

/// <summary>
/// A small amount of content. Do not mutate the array.
/// </summary>
Expand Down Expand Up @@ -167,6 +172,7 @@ public StorageFixture()
CreateBucket(LabelsTestBucket, multiVersion: false);
CreateBucket(InitiallyEmptyBucket, multiVersion: false);
CreateBucket(SoftDeleteBucket, multiVersion: false, softDelete: true);
CreateBucket(HnsBucket, multiVersion: false, hnsEnabled: true);

RequesterPaysClient = CreateRequesterPaysClient();
if (RequesterPaysClient != null)
Expand Down Expand Up @@ -249,7 +255,7 @@ void CreateObject()

}

internal Bucket CreateBucket(string name, bool multiVersion, bool softDelete = false, bool registerForDeletion = true)
internal Bucket CreateBucket(string name, bool multiVersion, bool softDelete = false, bool registerForDeletion = true, bool hnsEnabled = false)
{
var bucket = Client.CreateBucket(ProjectId,
new Bucket
Expand All @@ -258,6 +264,11 @@ internal Bucket CreateBucket(string name, bool multiVersion, bool softDelete = f
Versioning = new Bucket.VersioningData { Enabled = multiVersion },
// The minimum allowed for soft delete is 7 days.
SoftDeletePolicy = softDelete ? new Bucket.SoftDeletePolicyData { RetentionDurationSeconds = (int) TimeSpan.FromDays(7).TotalSeconds } : null,
IamConfiguration = hnsEnabled ? new Bucket.IamConfigurationData
{
UniformBucketLevelAccess = new Bucket.IamConfigurationData.UniformBucketLevelAccessData { Enabled = true }
} : null,
HierarchicalNamespace = hnsEnabled ? new Bucket.HierarchicalNamespaceData { Enabled = true } : null,
});
SleepAfterBucketCreateDelete();
if (registerForDeletion)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2025 Google Inc. All Rights Reserved.
//
// 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.

using System;
using Xunit;
using static Google.Apis.Storage.v1.ObjectsResource;

namespace Google.Cloud.Storage.V1.Tests;

public class MoveObjectOptionsTest
{
[Fact]
public void ModifyRequest_DefaultOptions()
{
var request = new MoveRequest(null, "sourceBucket", "sourceObject", "destObject");
var options = new MoveObjectOptions();
options.ModifyRequest(request);
Assert.Null(request.IfGenerationMatch);
Assert.Null(request.IfGenerationNotMatch);
Assert.Null(request.IfMetagenerationMatch);
Assert.Null(request.IfMetagenerationNotMatch);
Assert.Null(request.IfSourceGenerationMatch);
Assert.Null(request.IfSourceGenerationNotMatch);
Assert.Null(request.IfSourceMetagenerationMatch);
Assert.Null(request.IfSourceMetagenerationNotMatch);
Assert.Null(request.UserProject);
}

[Fact]
public void ModifyRequest_AllOptions_PositiveMatch()
{
var request = new MoveRequest(null, "sourceBucket", "sourceObject", "destObject");
var options = new MoveObjectOptions
{
IfGenerationMatch = 1L,
IfMetagenerationMatch = 2L,
IfSourceGenerationMatch = 3L,
IfSourceMetagenerationMatch = 4L,
UserProject = "proj"
};
options.ModifyRequest(request);
Assert.Equal(1L, request.IfGenerationMatch);
Assert.Null(request.IfGenerationNotMatch);
Assert.Equal(2L, request.IfMetagenerationMatch);
Assert.Null(request.IfMetagenerationNotMatch);
Assert.Equal(3L, request.IfSourceGenerationMatch);
Assert.Null(request.IfSourceGenerationNotMatch);
Assert.Equal(4L, request.IfSourceMetagenerationMatch);
Assert.Null(request.IfSourceMetagenerationNotMatch);
Assert.Equal("proj", request.UserProject);
}

[Fact]
public void ModifyRequest_AllOptions_NegativeMatch()
{
var request = new MoveRequest(null, "sourceBucket", "sourceObject", "destObject");
var options = new MoveObjectOptions
{
IfGenerationNotMatch = 1L,
IfMetagenerationNotMatch = 2L,
IfSourceGenerationNotMatch = 3L,
IfSourceMetagenerationNotMatch = 4L,
};
options.ModifyRequest(request);
Assert.Null(request.IfGenerationMatch);
Assert.Equal(1L, request.IfGenerationNotMatch);
Assert.Null(request.IfMetagenerationMatch);
Assert.Equal(2L, request.IfMetagenerationNotMatch);
Assert.Null(request.IfSourceGenerationMatch);
Assert.Equal(3L, request.IfSourceGenerationNotMatch);
Assert.Null(request.IfSourceMetagenerationMatch);
Assert.Equal(4L, request.IfSourceMetagenerationNotMatch);
}

[Fact]
public void ModifyRequest_MatchNotMatchConflicts()
{
var request = new MoveRequest(null, "sourceBucket", "sourceObject", "destObject");
Assert.Throws<ArgumentException>(() =>
{
var options = new MoveObjectOptions { IfGenerationMatch = 1L, IfGenerationNotMatch = 2L };
options.ModifyRequest(request);
});
Assert.Throws<ArgumentException>(() =>
{
var options = new MoveObjectOptions { IfMetagenerationMatch = 1L, IfMetagenerationNotMatch = 2L };
options.ModifyRequest(request);
});
Assert.Throws<ArgumentException>(() =>
{
var options = new MoveObjectOptions { IfSourceGenerationMatch = 1L, IfSourceGenerationNotMatch = 2L };
options.ModifyRequest(request);
});
Assert.Throws<ArgumentException>(() =>
{
var options = new MoveObjectOptions { IfSourceMetagenerationMatch = 1L, IfSourceMetagenerationNotMatch = 2L };
options.ModifyRequest(request);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="All" />
<PackageReference Include="Google.Api.Gax.Rest" />
<PackageReference Include="Google.Apis.Storage.v1" VersionOverride="[1.68.0.3604, 2.0.0.0)" />
<PackageReference Include="Google.Apis.Storage.v1" VersionOverride="[1.69.0.3707, 2.0.0.0)" />
</ItemGroup>
<ItemGroup>
<Compile Update="StorageClient.*.cs">
Expand Down
Loading