diff --git a/storagebatchoperations/api/README.md b/storagebatchoperations/api/README.md new file mode 100644 index 00000000000..fb019dfbcb2 --- /dev/null +++ b/storagebatchoperations/api/README.md @@ -0,0 +1,31 @@ +# Cloud Storage Batch Operations Sample + +These samples demonstrate how to interact with the [Google Cloud Storage Batch Operations API][Storage Batch Operations] from C# and +the .NET client libraries to call the Storage Batch Operations API. + +The samples require [.NET 8][.NET].That means using +[Visual Studio 2022](https://www.visualstudio.com/), or the command line. + +## Setup + +1. Set up a [.NET development environment](https://cloud.google.com/dotnet/docs/setup). + +2. Enable APIs for your project. + [Click here][enable-api] + to visit Cloud Platform Console and enable the Google Cloud Storage Batch Operations API. + +## Contributing changes + +* See [CONTRIBUTING.md](../../CONTRIBUTING.md) + +## Licensing + +* See [LICENSE](../../LICENSE) + +## Testing + +* See [TESTING.md](../../TESTING.md) + +[Storage Batch Operations]: https://cloud.google.com/storage/docs/batch-operations/overview +[enable-api]: https://console.cloud.google.com/flows/enableapi?apiid=storagebatchoperations_api&showconfirmation=true +[.NET]: https://dotnet.microsoft.com/en-us/download diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CancelBatchJobTest.cs b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CancelBatchJobTest.cs new file mode 100644 index 00000000000..b781eeee53b --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CancelBatchJobTest.cs @@ -0,0 +1,141 @@ +// 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.Api.Gax.ResourceNames; +using Google.Cloud.StorageBatchOperations.V1; +using Google.LongRunning; +using System; +using System.IO; +using System.Text; +using System.Threading; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class CancelBatchJobTest +{ + private readonly StorageFixture _fixture; + private readonly BucketList.Types.Bucket _bucket; + private readonly BucketList _bucketList = new(); + private readonly PrefixList _prefixListObject = new(); + + public CancelBatchJobTest(StorageFixture fixture) + { + int i = 20; + _fixture = fixture; + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + // Uploading objects to the bucket. + while (i >= 0) + { + var objectName = _fixture.GenerateGuid(); + var objectContent = _fixture.GenerateGuid(); + byte[] byteObjectContent = Encoding.UTF8.GetBytes(objectContent); + MemoryStream streamObjectContent = new MemoryStream(byteObjectContent); + _fixture.Client.UploadObject(bucketName, objectName, "application/text", streamObjectContent); + i--; + } + + _bucket = new BucketList.Types.Bucket + { + Bucket_ = bucketName, + // The prefix list is used to specify the objects to be deleted. To match all objects, use an empty list. + PrefixList = _prefixListObject + }; + // Adding the bucket to the bucket list. + _bucketList.Buckets.Insert(0, _bucket); + } + + [Fact] + public void TestCancelBatchJob() + { + CancelBatchJobSample cancelBatchJob = new CancelBatchJobSample(); + ListBatchJobsSample listBatchJobs = new ListBatchJobsSample(); + GetBatchJobSample getBatchJob = new GetBatchJobSample(); + + string filter = "state:canceled"; + int pageSize = 10; + string orderBy = "create_time"; + + var jobId = _fixture.GenerateGuid(); + var createdJobName = CreateBatchJob(_fixture.LocationName, _bucketList, jobId); + Assert.NotNull(createdJobName); + + // Poll until the job is in a state that can be cancelled (Running) + // This prevents attempting to cancel a job that hasn't started or has already finished. + bool isCancellable = false; + for (int attempt = 0; attempt < 10; attempt++) + { + Job currentJob = getBatchJob.GetBatchJob(createdJobName); + if (currentJob.State == Job.Types.State.Running) + { + isCancellable = true; + break; + } + if (currentJob.State == Job.Types.State.Succeeded) break; + } + + Assert.True(isCancellable, "Job did not reach a Running state in time to be cancelled."); + cancelBatchJob.CancelBatchJob(createdJobName); + + Job finalJob = null; + for (int attempt = 0; attempt < 1000; attempt++) + { + finalJob = getBatchJob.GetBatchJob(createdJobName); + if (finalJob.State == Job.Types.State.Canceled) break; + } + Assert.Equal(createdJobName, finalJob.Name.ToString()); + Assert.Equal(Job.Types.State.Canceled, finalJob.State); + + var batchJobs = listBatchJobs.ListBatchJobs(_fixture.LocationName, filter, pageSize, orderBy); + Assert.Contains(batchJobs, j => j.Name == createdJobName); + _fixture.DeleteBatchJob(createdJobName); + } + + /// + /// Create a batch job with the specified transformation case and bucket list. + /// + public static string CreateBatchJob(LocationName locationName, + BucketList bucketList, + string jobId = "12345678910") + { + StorageBatchOperationsClient storageBatchClient = StorageBatchOperationsClient.Create(); + + // Creates a batch job with the specified bucket list and delete object settings. + CreateJobRequest request = new CreateJobRequest + { + ParentAsLocationName = locationName, + JobId = jobId, + Job = new Job + { + BucketList = bucketList, + DeleteObject = new DeleteObject { PermanentObjectDeletionEnabled = true } + }, + RequestId = jobId, + }; + + Operation response = storageBatchClient.CreateJob(request); + string jobName = String.Empty; + for (int attempt = 0; attempt < 10; attempt++) + { + Operation retrievedResponse = storageBatchClient.PollOnceCreateJob(response.Name); + jobName = retrievedResponse.Metadata?.Job?.Name; + + if (!string.IsNullOrEmpty(jobName)) + { + break; + } + } + return jobName; + } +} diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithDeleteObjectTest.cs b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithDeleteObjectTest.cs new file mode 100644 index 00000000000..8f4eb162473 --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithDeleteObjectTest.cs @@ -0,0 +1,80 @@ +// 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.Cloud.StorageBatchOperations.V1; +using System; +using System.IO; +using System.Text; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class CreateBatchJobWithDeleteObjectTest +{ + private readonly StorageFixture _fixture; + private readonly BucketList.Types.Bucket _bucket = new(); + private readonly BucketList _bucketList = new(); + private readonly PrefixList _prefixListObject = new(); + + public CreateBatchJobWithDeleteObjectTest(StorageFixture fixture) + { + _fixture = fixture; + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + + var manifestBucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(manifestBucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + + var objectName = _fixture.GenerateGuid(); + var manifestObjectName = _fixture.GenerateGuid(); + var objectContent = _fixture.GenerateGuid(); + var manifestObjectContent = $"bucket,name,generation{Environment.NewLine}{bucketName},{objectName}"; + + byte[] byteObjectContent = Encoding.UTF8.GetBytes(objectContent); + using MemoryStream streamObjectContent = new MemoryStream(byteObjectContent); + // Uploading an object to the bucket + _fixture.Client.UploadObject(bucketName, objectName, "application/text", streamObjectContent); + + byte[] byteManifestObjectContent = Encoding.UTF8.GetBytes(manifestObjectContent); + // Uploading a manifest object to the manifest bucket + using MemoryStream streamManifestObjectContent = new MemoryStream(byteManifestObjectContent); + _fixture.Client.UploadObject(manifestBucketName, $"{manifestObjectName}.csv", "text/csv", streamManifestObjectContent); + _bucket = new BucketList.Types.Bucket + { + Bucket_ = bucketName, + // The prefix list is used to specify the objects to be transformed. To match all objects, use an empty list. + PrefixList = _prefixListObject, + // Manifest location contains csv file having list of objects to be transformed" + Manifest = new Manifest { ManifestLocation = $"gs://{manifestBucketName}/{manifestObjectName}.csv" } + }; + // Adding the bucket to the bucket list. + _bucketList.Buckets.Insert(0, _bucket); + } + + [Fact] + public void TestCreateBatchJobWithDeleteObject() + { + CreateBatchJobWithDeleteObjectSample createJob = new CreateBatchJobWithDeleteObjectSample(); + var jobId = _fixture.GenerateGuid(); + + var createdBatchJob = createJob.CreateBatchJobWithDeleteObject(_fixture.LocationName, _bucketList, jobId); + Assert.Equal(createdBatchJob.BucketList, _bucketList); + Assert.Equal("DeleteObject", createdBatchJob.TransformationCase.ToString()); + Assert.Equal(createdBatchJob.SourceCase.ToString(), _bucketList.GetType().Name); + Assert.NotNull(createdBatchJob.Name); + Assert.NotNull(createdBatchJob.JobName); + Assert.NotNull(createdBatchJob.CreateTime); + Assert.NotNull(createdBatchJob.CompleteTime); + _fixture.DeleteBatchJob(createdBatchJob.Name); + } +} diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithPutMetaDataTest.cs b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithPutMetaDataTest.cs new file mode 100644 index 00000000000..cd2a5edb21b --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithPutMetaDataTest.cs @@ -0,0 +1,80 @@ +// 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.Cloud.StorageBatchOperations.V1; +using System; +using System.IO; +using System.Text; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class CreateBatchJobWithPutMetaDataTest +{ + private readonly StorageFixture _fixture; + private readonly BucketList.Types.Bucket _bucket = new(); + private readonly BucketList _bucketList = new(); + private readonly PrefixList _prefixListObject = new(); + + public CreateBatchJobWithPutMetaDataTest(StorageFixture fixture) + { + _fixture = fixture; + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + + var manifestBucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(manifestBucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + + var objectName = _fixture.GenerateGuid(); + var manifestObjectName = _fixture.GenerateGuid(); + var objectContent = _fixture.GenerateGuid(); + var manifestObjectContent = $"bucket,name,generation{Environment.NewLine}{bucketName},{objectName}"; + + byte[] byteObjectContent = Encoding.UTF8.GetBytes(objectContent); + using MemoryStream streamObjectContent = new MemoryStream(byteObjectContent); + // Uploading an object to the bucket + _fixture.Client.UploadObject(bucketName, objectName, "application/text", streamObjectContent); + + byte[] byteManifestObjectContent = Encoding.UTF8.GetBytes(manifestObjectContent); + // Uploading a manifest object to the manifest bucket + using MemoryStream streamManifestObjectContent = new MemoryStream(byteManifestObjectContent); + _fixture.Client.UploadObject(manifestBucketName, $"{manifestObjectName}.csv", "text/csv", streamManifestObjectContent); + _bucket = new BucketList.Types.Bucket + { + Bucket_ = bucketName, + // The prefix list is used to specify the objects to be transformed. To match all objects, use an empty list. + PrefixList = _prefixListObject, + // Manifest location contains csv file having list of objects to be transformed" + Manifest = new Manifest { ManifestLocation = $"gs://{manifestBucketName}/{manifestObjectName}.csv" } + }; + // Adding the bucket to the bucket list. + _bucketList.Buckets.Insert(0, _bucket); + } + + [Fact] + public void TestCreateBatchJobWithPutMetaData() + { + CreateBatchJobWithPutMetadataSample createJob = new CreateBatchJobWithPutMetadataSample(); + var jobId = _fixture.GenerateGuid(); + + var createdBatchJob = createJob.CreateBatchJobWithPutMetadata(_fixture.LocationName, _bucketList, jobId); + Assert.Equal(createdBatchJob.BucketList, _bucketList); + Assert.Equal("PutMetadata", createdBatchJob.TransformationCase.ToString()); + Assert.Equal(createdBatchJob.SourceCase.ToString(), _bucketList.GetType().Name); + Assert.NotNull(createdBatchJob.Name); + Assert.NotNull(createdBatchJob.JobName); + Assert.NotNull(createdBatchJob.CreateTime); + Assert.NotNull(createdBatchJob.CompleteTime); + _fixture.DeleteBatchJob(createdBatchJob.Name); + } +} diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithPutObjectHoldTest.cs b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithPutObjectHoldTest.cs new file mode 100644 index 00000000000..01925673c2e --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithPutObjectHoldTest.cs @@ -0,0 +1,80 @@ +// 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.Cloud.StorageBatchOperations.V1; +using System; +using System.IO; +using System.Text; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class CreateBatchJobWithPutObjectHoldTest +{ + private readonly StorageFixture _fixture; + private readonly BucketList.Types.Bucket _bucket = new(); + private readonly BucketList _bucketList = new(); + private readonly PrefixList _prefixListObject = new(); + + public CreateBatchJobWithPutObjectHoldTest(StorageFixture fixture) + { + _fixture = fixture; + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + + var manifestBucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(manifestBucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + + var objectName = _fixture.GenerateGuid(); + var manifestObjectName = _fixture.GenerateGuid(); + var objectContent = _fixture.GenerateGuid(); + var manifestObjectContent = $"bucket,name,generation{Environment.NewLine}{bucketName},{objectName}"; + + byte[] byteObjectContent = Encoding.UTF8.GetBytes(objectContent); + using MemoryStream streamObjectContent = new MemoryStream(byteObjectContent); + // Uploading an object to the bucket + _fixture.Client.UploadObject(bucketName, objectName, "application/text", streamObjectContent); + + byte[] byteManifestObjectContent = Encoding.UTF8.GetBytes(manifestObjectContent); + // Uploading a manifest object to the manifest bucket + using MemoryStream streamManifestObjectContent = new MemoryStream(byteManifestObjectContent); + _fixture.Client.UploadObject(manifestBucketName, $"{manifestObjectName}.csv", "text/csv", streamManifestObjectContent); + _bucket = new BucketList.Types.Bucket + { + Bucket_ = bucketName, + // The prefix list is used to specify the objects to be transformed. To match all objects, use an empty list. + PrefixList = _prefixListObject, + // Manifest location contains csv file having list of objects to be transformed" + Manifest = new Manifest { ManifestLocation = $"gs://{manifestBucketName}/{manifestObjectName}.csv" } + }; + // Adding the bucket to the bucket list. + _bucketList.Buckets.Insert(0, _bucket); + } + + [Fact] + public void TestCreateBatchJobWithPutObjectHold() + { + CreateBatchJobWithPutObjectHoldSample createJob = new CreateBatchJobWithPutObjectHoldSample(); + var jobId = _fixture.GenerateGuid(); + + var createdBatchJob = createJob.CreateBatchJobWithPutObjectHold(_fixture.LocationName, _bucketList, jobId); + Assert.Equal(createdBatchJob.BucketList, _bucketList); + Assert.Equal("PutObjectHold", createdBatchJob.TransformationCase.ToString()); + Assert.Equal(createdBatchJob.SourceCase.ToString(), _bucketList.GetType().Name); + Assert.NotNull(createdBatchJob.Name); + Assert.NotNull(createdBatchJob.JobName); + Assert.NotNull(createdBatchJob.CreateTime); + Assert.NotNull(createdBatchJob.CompleteTime); + _fixture.DeleteBatchJob(createdBatchJob.Name); + } +} diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithRewriteObjectTest.cs b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithRewriteObjectTest.cs new file mode 100644 index 00000000000..304dac88d8b --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/CreateBatchJobWithRewriteObjectTest.cs @@ -0,0 +1,83 @@ +// 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.Cloud.StorageBatchOperations.V1; +using System; +using System.IO; +using System.Text; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class CreateBatchJobWithRewriteObjectTest +{ + private readonly StorageFixture _fixture; + private readonly BucketList.Types.Bucket _bucket = new(); + private readonly BucketList _bucketList = new(); + private readonly PrefixList _prefixListObject = new(); + + public CreateBatchJobWithRewriteObjectTest(StorageFixture fixture) + { + _fixture = fixture; + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + + var manifestBucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(manifestBucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + + var objectName = _fixture.GenerateGuid(); + var manifestObjectName = _fixture.GenerateGuid(); + var objectContent = _fixture.GenerateGuid(); + var manifestObjectContent = $"bucket,name,generation{Environment.NewLine}{bucketName},{objectName}"; + + byte[] byteObjectContent = Encoding.UTF8.GetBytes(objectContent); + using MemoryStream streamObjectContent = new MemoryStream(byteObjectContent); + // Uploading an object to the bucket + _fixture.Client.UploadObject(bucketName, objectName, "application/text", streamObjectContent); + + byte[] byteManifestObjectContent = Encoding.UTF8.GetBytes(manifestObjectContent); + // Uploading a manifest object to the manifest bucket + using MemoryStream streamManifestObjectContent = new MemoryStream(byteManifestObjectContent); + _fixture.Client.UploadObject(manifestBucketName, $"{manifestObjectName}.csv", "text/csv", streamManifestObjectContent); + _bucket = new BucketList.Types.Bucket + { + Bucket_ = bucketName, + // The prefix list is used to specify the objects to be transformed. To match all objects, use an empty list. + PrefixList = _prefixListObject, + // Manifest location contains csv file having list of objects to be transformed" + Manifest = new Manifest { ManifestLocation = $"gs://{manifestBucketName}/{manifestObjectName}.csv" } + }; + // Adding the bucket to the bucket list. + _bucketList.Buckets.Insert(0, _bucket); + } + + [Fact] + public void TestCreateBatchJobWithRewriteObject() + { + CreateBatchJobWithRewriteObjectSample createJob = new CreateBatchJobWithRewriteObjectSample(); + var jobId = _fixture.GenerateGuid(); + + string kmsKeyName = $"projects/{_fixture.ProjectId}/locations/{_fixture.LocationId}/keyRings/{_fixture.KmsKeyRing}/cryptoKeys/{_fixture.KmsKeyName}"; + var cryptoKeyName = CryptoKeyName.FromProjectLocationKeyRingCryptoKey(_fixture.ProjectId, _fixture.LocationId, _fixture.KmsKeyRing, _fixture.KmsKeyName); + + var createdBatchJob = createJob.CreateBatchJobWithRewriteObject(_fixture.LocationName, _bucketList, jobId, kmsKeyName, cryptoKeyName); + Assert.Equal(createdBatchJob.BucketList, _bucketList); + Assert.Equal("RewriteObject", createdBatchJob.TransformationCase.ToString()); + Assert.Equal(createdBatchJob.SourceCase.ToString(), _bucketList.GetType().Name); + Assert.NotNull(createdBatchJob.Name); + Assert.NotNull(createdBatchJob.JobName); + Assert.NotNull(createdBatchJob.CreateTime); + Assert.NotNull(createdBatchJob.CompleteTime); + _fixture.DeleteBatchJob(createdBatchJob.Name); + } +} diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/DeleteBatchJobTest.cs b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/DeleteBatchJobTest.cs new file mode 100644 index 00000000000..fbeb3da4d92 --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/DeleteBatchJobTest.cs @@ -0,0 +1,64 @@ +// 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.Cloud.StorageBatchOperations.V1; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class DeleteBatchJobTest +{ + private readonly StorageFixture _fixture; + private readonly BucketList.Types.Bucket _bucket; + private readonly BucketList _bucketList = new(); + private readonly PrefixList _prefixListObject = new(); + + public DeleteBatchJobTest(StorageFixture fixture) + { + _fixture = fixture; + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + _bucket = new BucketList.Types.Bucket + { + Bucket_ = bucketName, + // The prefix list is used to specify the objects to be deleted. To match all objects, use an empty list. + PrefixList = _prefixListObject + }; + // Adding the bucket to the bucket list. + _bucketList.Buckets.Insert(0, _bucket); + } + + [Fact] + public void TestDeleteBatchJob() + { + DeleteBatchJobSample deleteBatchJob = new DeleteBatchJobSample(); + ListBatchJobsSample listBatchJobs = new ListBatchJobsSample(); + GetBatchJobSample getBatchJob = new GetBatchJobSample(); + CreateBatchJobWithDeleteObjectSample createBatchJob = new CreateBatchJobWithDeleteObjectSample(); + + string filter = ""; + int pageSize = 10; + string orderBy = "create_time"; + + var jobId = _fixture.GenerateGuid(); + var createdJob = createBatchJob.CreateBatchJobWithDeleteObject(_fixture.LocationName, _bucketList, jobId); + // Delete the created job. + deleteBatchJob.DeleteBatchJob(createdJob.Name); + var batchJobs = listBatchJobs.ListBatchJobs(_fixture.LocationName, filter, pageSize, orderBy); + // Verify that the job is deleted. + Assert.DoesNotContain(batchJobs, job => job.JobName == createdJob.JobName); + // Attempt to get the deleted job, which should throw an exception. + var exception = Assert.Throws(() => getBatchJob.GetBatchJob(createdJob.Name)); + Assert.Equal(Grpc.Core.StatusCode.NotFound, exception.StatusCode); + } +} diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/GetBatchJobTest.cs b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/GetBatchJobTest.cs new file mode 100644 index 00000000000..fb1d9837e88 --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/GetBatchJobTest.cs @@ -0,0 +1,67 @@ +// 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.Cloud.StorageBatchOperations.V1; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class GetBatchJobTest +{ + private readonly StorageFixture _fixture; + private readonly BucketList.Types.Bucket _bucket; + private readonly BucketList _bucketList = new(); + private readonly PrefixList _prefixListObject = new(); + + public GetBatchJobTest(StorageFixture fixture) + { + _fixture = fixture; + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + _bucket = new BucketList.Types.Bucket + { + Bucket_ = bucketName, + // The prefix list is used to specify the objects to be deleted. To match all objects, use an empty list. + PrefixList = _prefixListObject + }; + // Adding the bucket to the bucket list. + _bucketList.Buckets.Insert(0, _bucket); + } + + [Fact] + public void TestGetBatchJob() + { + GetBatchJobSample getJob = new GetBatchJobSample(); + CreateBatchJobWithDeleteObjectSample createJob = new CreateBatchJobWithDeleteObjectSample(); + + var jobId = _fixture.GenerateGuid(); + // Create a batch job with the specified bucket list and job ID. + var createdJob = createJob.CreateBatchJobWithDeleteObject(_fixture.LocationName, _bucketList, jobId); + // Get the created job using its name. + var retrievedJob = getJob.GetBatchJob(createdJob.Name); + // Assert that the retrieved job is not null. + Assert.NotNull(retrievedJob); + // Assert that the retrieved job's metadata matches with the created job's metadata. + Assert.Equal(createdJob.Name, retrievedJob.Name); + Assert.Equal(createdJob.BucketList, retrievedJob.BucketList); + Assert.Equal(createdJob.TransformationCase.ToString(), retrievedJob.TransformationCase.ToString()); + Assert.Equal(createdJob.SourceCase.ToString(), retrievedJob.SourceCase.ToString()); + Assert.Equal(createdJob.State, retrievedJob.State); + Assert.Equal(createdJob.Description, retrievedJob.Description); + Assert.Equal(createdJob.ScheduleTime, retrievedJob.ScheduleTime); + Assert.Equal(createdJob.CompleteTime, retrievedJob.CompleteTime); + Assert.Equal(createdJob.CreateTime, retrievedJob.CreateTime); + Assert.Equal(createdJob.Counters, retrievedJob.Counters); + _fixture.DeleteBatchJob(createdJob.Name); + } +} diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/ListBatchJobsTest.cs b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/ListBatchJobsTest.cs new file mode 100644 index 00000000000..ae7a7961c06 --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/ListBatchJobsTest.cs @@ -0,0 +1,73 @@ +// 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.Cloud.StorageBatchOperations.V1; +using Xunit; + +[Collection(nameof(StorageFixture))] +public class ListBatchJobsTest +{ + private readonly StorageFixture _fixture; + private readonly BucketList.Types.Bucket _bucket; + private readonly BucketList _bucketList = new(); + private readonly PrefixList _prefixListObject = new(); + + public ListBatchJobsTest(StorageFixture fixture) + { + _fixture = fixture; + var bucketName = _fixture.GenerateBucketName(); + _fixture.CreateBucket(bucketName, multiVersion: false, softDelete: false, registerForDeletion: true); + _bucket = new BucketList.Types.Bucket + { + Bucket_ = bucketName, + // The prefix list is used to specify the objects to be processed. To match all objects, use an empty list. + PrefixList = _prefixListObject + }; + // Adding the bucket to the bucket list. + _bucketList.Buckets.Insert(0, _bucket); + } + + [Fact] + public void TestListBatchJobs() + { + ListBatchJobsSample listBatchJobs = new ListBatchJobsSample(); + CreateBatchJobWithDeleteObjectSample createBatchJob = new CreateBatchJobWithDeleteObjectSample(); + + // Filter to list only succeeded jobs + string filter = "state:succeeded"; + int pageSize = 10; + string orderBy = "create_time"; + + var jobId = _fixture.GenerateGuid(); + var createdJob = createBatchJob.CreateBatchJobWithDeleteObject(_fixture.LocationName, _bucketList, jobId); + // List batch jobs with the specified filter, page size, and order by criteria + var batchJobs = listBatchJobs.ListBatchJobs(_fixture.LocationName, filter, pageSize, orderBy); + // Assert that the created job is in the list of batch jobs. + Assert.Contains(batchJobs, job => job.JobName == createdJob.JobName && job.State == createdJob.State && job.SourceCase == createdJob.SourceCase && job.TransformationCase == createdJob.TransformationCase); + // Assert that all batch jobs have the required metadata. + Assert.All(batchJobs, AssertBatchJob); + _fixture.DeleteBatchJob(createdJob.Name); + } + + // Verify that a batch job has all required metadata. + private void AssertBatchJob(Job b) + { + Assert.NotNull(b.Name); + Assert.NotNull(b.JobName); + Assert.NotNull(b.CreateTime); + Assert.NotNull(b.CompleteTime); + Assert.NotNull(b.SourceCase.ToString()); + Assert.NotNull(b.TransformationCase.ToString()); + } +} diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/StorageBatchOperations.Samples.Tests.csproj b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/StorageBatchOperations.Samples.Tests.csproj new file mode 100644 index 00000000000..5ec9770c75b --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/StorageBatchOperations.Samples.Tests.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + false + + + + + + + + + + + + + + diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/StorageFixture.cs b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/StorageFixture.cs new file mode 100644 index 00000000000..47ed3e0d60c --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples.Tests/StorageFixture.cs @@ -0,0 +1,107 @@ +// 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. + +using Google.Api.Gax.ResourceNames; +using Google.Apis.Storage.v1.Data; +using Google.Cloud.Storage.V1; +using Google.Cloud.StorageBatchOperations.V1; +using System; +using System.Collections.Generic; +using System.Threading; +using Xunit; + +[CollectionDefinition(nameof(StorageFixture))] +public class StorageFixture : IDisposable, ICollectionFixture +{ + public string ProjectId { get; } + public string LocationId { get; } = "global"; + public IList TempBucketNames { get; } = []; + public StorageClient Client { get; } + public StorageBatchOperationsClient OperationsClient { get; } + public LocationName LocationName { get; } + public string KmsKeyRing { get; } = Environment.GetEnvironmentVariable("STORAGE_KMS_KEYRING"); + public string KmsKeyName { get; } = Environment.GetEnvironmentVariable("STORAGE_KMS_KEYNAME"); + + public StorageFixture() + { + ProjectId = Environment.GetEnvironmentVariable("GOOGLE_PROJECT_ID"); + if (string.IsNullOrWhiteSpace(ProjectId)) + { + throw new InvalidOperationException("You need to set the Environment variable 'GOOGLE_PROJECT_ID' with your Google Cloud Project's project id."); + } + LocationName = LocationName.FromProjectLocation(ProjectId, LocationId); + Client = StorageClient.Create(); + OperationsClient = StorageBatchOperationsClient.Create(); + } + + /// + /// Creates a bucket. + /// + /// A bucket. + internal Bucket CreateBucket(string name, bool multiVersion, bool softDelete = false, bool registerForDeletion = true) + { + var bucket = Client.CreateBucket(ProjectId, + new Bucket + { + Name = name, + 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, + }); + SleepAfterBucketCreateUpdateDelete(); + if (registerForDeletion) + { + TempBucketNames.Add(name); + } + return bucket; + } + + /// + /// Generate the name of the bucket. + /// + /// The bucketName. + internal string GenerateBucketName() => Guid.NewGuid().ToString(); + + /// + /// Generates a new globally unique identifier (GUID). + /// + /// A new randomly generated GUID as string. + internal string GenerateGuid() => Guid.NewGuid().ToString(); + + /// + /// Bucket creation/update/deletion is rate-limited. To avoid making the tests flaky, we sleep after each operation. + /// + internal void SleepAfterBucketCreateUpdateDelete() => Thread.Sleep(2000); + + /// + /// Deletes the batch job at the end of the test. + /// + internal void DeleteBatchJob(string jobName) => OperationsClient.DeleteJob(jobName); + + public void Dispose() + { + foreach (var bucketName in TempBucketNames) + { + try + { + Client.DeleteBucket(bucketName, new DeleteBucketOptions { DeleteObjects = true }); + SleepAfterBucketCreateUpdateDelete(); + } + catch (Exception) + { + // Do nothing, we delete on a best effort basis. + } + } + } +} diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples/CancelBatchJob.cs b/storagebatchoperations/api/StorageBatchOperations.Samples/CancelBatchJob.cs new file mode 100644 index 00000000000..66df35bd534 --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples/CancelBatchJob.cs @@ -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 +// +// 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_batch_cancel_job] + +using Google.Cloud.StorageBatchOperations.V1; +using System; + +public class CancelBatchJobSample +{ + /// + /// Cancels a storage batch operation job. + /// + /// The name of the job to cancel. Format: projects/{project_id}/locations/{location_id}/jobs/{job_id}. + public CancelJobResponse CancelBatchJob(string jobName = "projects/{project_id}/locations/{location_id}/jobs/{job_id}") + { + StorageBatchOperationsClient operationsClient = StorageBatchOperationsClient.Create(); + // Create a request to cancel the job. + CancelJobRequest request = new CancelJobRequest + { + Name = jobName, + RequestId = Guid.NewGuid().ToString() + }; + // Cancel the job. + var response = operationsClient.CancelJob(request); + Console.WriteLine($"The Storage Batch Operation Job (Name: {jobName}) is cancelled"); + return response; + } +} +// [END storage_batch_cancel_job] diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithDeleteObject.cs b/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithDeleteObject.cs new file mode 100644 index 00000000000..f180ba0af4f --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithDeleteObject.cs @@ -0,0 +1,59 @@ +// 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_batch_create_job] + +using Google.Api.Gax.ResourceNames; +using Google.Cloud.StorageBatchOperations.V1; +using Google.LongRunning; +using System; + +public class CreateBatchJobWithDeleteObjectSample +{ + /// + /// Creates a storage batch operation job with the option of delete objects. + /// + /// A resource name with pattern projects/{project}/locations/{location}. + /// A bucket list contains list of buckets and their objects to be transformed. + /// It is id for the job and it should not be more than 128 characters and must include only + /// characters available in DNS names, as defined by RFC-1123. + public Job CreateBatchJobWithDeleteObject(LocationName locationName, + BucketList bucketList, + string jobId = "your-job-id") + { + StorageBatchOperationsClient operationsClient = StorageBatchOperationsClient.Create(); + + Job job = new Job + { + DeleteObject = new DeleteObject { PermanentObjectDeletionEnabled = true }, + BucketList = bucketList + }; + + // Create a job request with the specified location, job ID, and job details. + CreateJobRequest request = new CreateJobRequest + { + ParentAsLocationName = locationName, + JobId = jobId, + Job = job, + RequestId = jobId, + }; + + Operation response = operationsClient.CreateJob(request); + Operation completedResponse = response.PollUntilCompleted(); + Job result = completedResponse.Result; + Console.WriteLine($"The Storage Batch Operation Job (Name: {result.Name}) is created with the option of Delete Objects"); + return result; + } +} +// [END storage_batch_create_job] diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithPutMetadata.cs b/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithPutMetadata.cs new file mode 100644 index 00000000000..84cdd6a0fbb --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithPutMetadata.cs @@ -0,0 +1,69 @@ +// 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_batch_create_job] + +using Google.Api.Gax.ResourceNames; +using Google.Cloud.StorageBatchOperations.V1; +using Google.LongRunning; +using System; + +public class CreateBatchJobWithPutMetadataSample +{ + /// + /// Creates a storage batch operation job with the options of object metadata update. + /// + /// A resource name with pattern projects/{project}/locations/{location}. + /// A bucket list contains list of buckets and their objects to be transformed. + /// It is id for the job and it should not be more than 128 characters and must include only + /// characters available in DNS names, as defined by RFC-1123. + public Job CreateBatchJobWithPutMetadata(LocationName locationName, + BucketList bucketList, + string jobId = "your-job-id") + { + StorageBatchOperationsClient operationsClient = StorageBatchOperationsClient.Create(); + + PutMetadata putMetadata = new PutMetadata + { + CacheControl = "no-cache", + ContentDisposition = "inline", + ContentEncoding = "gzip", + ContentLanguage = "en-US", + ContentType = "text/plain", + CustomTime = DateTime.UtcNow.ToString("o") + }; + + Job job = new Job + { + PutMetadata = putMetadata, + BucketList = bucketList + }; + + // Create a job request with the specified location, job ID, and job details. + CreateJobRequest request = new CreateJobRequest + { + ParentAsLocationName = locationName, + JobId = jobId, + Job = job, + RequestId = jobId, + }; + + Operation response = operationsClient.CreateJob(request); + Operation completedResponse = response.PollUntilCompleted(); + Job result = completedResponse.Result; + Console.WriteLine($"The Storage Batch Operation Job (Name: {result.Name}) is created with the Object Metadata Update"); + return result; + } +} +// [END storage_batch_create_job] diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithPutObjectHold.cs b/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithPutObjectHold.cs new file mode 100644 index 00000000000..a9f92e86d12 --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithPutObjectHold.cs @@ -0,0 +1,64 @@ +// 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_batch_create_job] + +using Google.Api.Gax.ResourceNames; +using Google.Cloud.StorageBatchOperations.V1; +using Google.LongRunning; +using System; + +public class CreateBatchJobWithPutObjectHoldSample +{ + /// + /// Creates a storage batch operation job with the options to update object hold. + /// + /// A resource name with pattern projects/{project}/locations/{location}. + /// A bucket list contains list of buckets and their objects to be transformed. + /// It is id for the job and it should not be more than 128 characters and must include only + /// characters available in DNS names, as defined by RFC-1123. + public Job CreateBatchJobWithPutObjectHold(LocationName locationName, + BucketList bucketList, + string jobId = "your-job-id") + { + StorageBatchOperationsClient operationsClient = StorageBatchOperationsClient.Create(); + + PutObjectHold putObjectHold = new PutObjectHold + { + EventBasedHold = PutObjectHold.Types.HoldStatus.Set + }; + + Job job = new Job + { + PutObjectHold = putObjectHold, + BucketList = bucketList + }; + + // Create a job request with the specified location, job ID, and job details. + CreateJobRequest request = new CreateJobRequest + { + ParentAsLocationName = locationName, + JobId = jobId, + Job = job, + RequestId = jobId, + }; + + Operation response = operationsClient.CreateJob(request); + Operation completedResponse = response.PollUntilCompleted(); + Job result = completedResponse.Result; + Console.WriteLine($"The Storage Batch Operation Job (Name: {result.Name}) is created with the Object Hold Update"); + return result; + } +} +// [END storage_batch_create_job] diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithRewriteObject.cs b/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithRewriteObject.cs new file mode 100644 index 00000000000..854fbbcf90f --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples/CreateBatchJobWithRewriteObject.cs @@ -0,0 +1,66 @@ +// 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_batch_create_job] + +using Google.Api.Gax.ResourceNames; +using Google.Cloud.StorageBatchOperations.V1; +using Google.LongRunning; +using System; + +public class CreateBatchJobWithRewriteObjectSample +{ + /// + /// Creates a storage batch operation job with the options for object rewrite. + /// + /// A resource name with pattern projects/{project}/locations/{location}. + /// A bucket list contains list of buckets and their objects to be transformed. + /// It is id for the job and it should not be more than 128 characters and must include only + /// characters available in DNS names, as defined by RFC-1123. + /// Resource name of the Cloud KMS key that will be used to encrypt the object.The Cloud + /// KMS key must be located in same location as the object. + /// -typed view over the resource name property./param> + public Job CreateBatchJobWithRewriteObject(LocationName locationName, + BucketList bucketList, + string jobId = "your-job-id", + string kmsKeyName = "your-kms-key", + CryptoKeyName cryptoKeyName = null) + { + StorageBatchOperationsClient operationsClient = StorageBatchOperationsClient.Create(); + + RewriteObject rewriteObject = new RewriteObject { KmsKey = kmsKeyName, KmsKeyAsCryptoKeyName = cryptoKeyName }; + + Job job = new Job + { + RewriteObject = rewriteObject, + BucketList = bucketList + }; + + // Create a job request with the specified location, job ID, and job details. + CreateJobRequest request = new CreateJobRequest + { + ParentAsLocationName = locationName, + JobId = jobId, + Job = job, + RequestId = jobId, + }; + + Operation response = operationsClient.CreateJob(request); + Operation completedResponse = response.PollUntilCompleted(); + Job result = completedResponse.Result; + Console.WriteLine($"The Storage Batch Operation Job (Name: {result.Name}) is created with the Rewrite Object"); + return result; + } +} +// [END storage_batch_create_job] diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples/DeleteBatchJob.cs b/storagebatchoperations/api/StorageBatchOperations.Samples/DeleteBatchJob.cs new file mode 100644 index 00000000000..7ce7fc2dbbe --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples/DeleteBatchJob.cs @@ -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_batch_delete_job] + +using Google.Cloud.StorageBatchOperations.V1; +using System; + +public class DeleteBatchJobSample +{ + /// + /// Deletes a storage batch operation job. + /// + /// The name of the job to delete. Format: projects/{project_id}/locations/{location_id}/jobs/{job_id}. + public void DeleteBatchJob(string jobName = "projects/{project_id}/locations/{location_id}/jobs/{job_id}") + { + StorageBatchOperationsClient operationsClient = StorageBatchOperationsClient.Create(); + // Create a request to delete the job. + DeleteJobRequest request = new DeleteJobRequest + { + Name = jobName + }; + // Delete the job. + operationsClient.DeleteJob(request); + Console.WriteLine($"The Storage Batch Operation Job (Name : {jobName}) is deleted"); + } +} +// [END storage_batch_delete_job] diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples/GetBatchJob.cs b/storagebatchoperations/api/StorageBatchOperations.Samples/GetBatchJob.cs new file mode 100644 index 00000000000..80f0f4c54fd --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples/GetBatchJob.cs @@ -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_batch_get_job] + +using Google.Cloud.StorageBatchOperations.V1; +using System; + +public class GetBatchJobSample +{ + /// + /// Gets a storage batch operation job. + /// + /// The name of the job to get. Format: projects/{project_id}/locations/{location_id}/jobs/{job_id}. + public Job GetBatchJob(string jobName = "projects/{project_id}/locations/{location_id}/jobs/{job_id}") + { + StorageBatchOperationsClient operationsClient = StorageBatchOperationsClient.Create(); + // Create a request to get the job. + GetJobRequest request = new GetJobRequest + { + Name = jobName + }; + var response = operationsClient.GetJob(request); + Console.WriteLine($"The Name of Storage Batch Operation Job is : {response.Name}"); + return response; + } +} +// [END storage_batch_get_job] diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples/ListBatchJobs.cs b/storagebatchoperations/api/StorageBatchOperations.Samples/ListBatchJobs.cs new file mode 100644 index 00000000000..52835cf6f90 --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples/ListBatchJobs.cs @@ -0,0 +1,62 @@ +// 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_batch_list_jobs] + +using Google.Api.Gax; +using Google.Api.Gax.ResourceNames; +using Google.Cloud.StorageBatchOperations.V1; +using System; +using System.Collections.Generic; + +public class ListBatchJobsSample +{ + /// + /// Lists storage batch operation jobs. + /// + /// A resource name with pattern projects/{project}/locations/{location}. + /// The field to filter the list of storage batch operation jobs. + /// The page size to retrieve page of known size. + /// The field to sort the list of storage batch operation jobs. Supported fields are name and create_time. + public IEnumerable ListBatchJobs(LocationName locationName, + string filter = "state:failed", + int pageSize = 100, + string orderBy = "name") + { + StorageBatchOperationsClient operationsClient = StorageBatchOperationsClient.Create(); + // Create a request to list the batch jobs. + ListJobsRequest request = new ListJobsRequest + { + ParentAsLocationName = locationName, + Filter = filter, + OrderBy = orderBy + }; + + PagedEnumerable response = operationsClient.ListJobs(request); + Console.WriteLine("Storage Batch Operation Jobs are as follows:"); + foreach (var item in response) + { + Console.WriteLine(item); + } + // Retrieve a single page of known size + Page singlePage = response.ReadPage(pageSize); + Console.WriteLine($"A single page of {pageSize} page size of Storage Batch Operation Jobs are as follows:"); + foreach (Job item in singlePage) + { + Console.WriteLine(item); + } + return response; + } +} +// [END storage_batch_list_jobs] diff --git a/storagebatchoperations/api/StorageBatchOperations.Samples/StorageBatchOperations.Samples.csproj b/storagebatchoperations/api/StorageBatchOperations.Samples/StorageBatchOperations.Samples.csproj new file mode 100644 index 00000000000..e46f742aecc --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.Samples/StorageBatchOperations.Samples.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.1 + + + + + + + + diff --git a/storagebatchoperations/api/StorageBatchOperations.sln b/storagebatchoperations/api/StorageBatchOperations.sln new file mode 100644 index 00000000000..c3f098d101a --- /dev/null +++ b/storagebatchoperations/api/StorageBatchOperations.sln @@ -0,0 +1,62 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35303.130 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StorageBatchOperations.Samples", "StorageBatchOperations.Samples\StorageBatchOperations.Samples.csproj", "{11EFF973-23FE-41B6-82D5-E8A0BA79F21C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StorageBatchOperations.Samples.Tests", "StorageBatchOperations.Samples.Tests\StorageBatchOperations.Samples.Tests.csproj", "{2BB74746-319D-465B-AAD5-C4430322501E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Debug|x64.ActiveCfg = Debug|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Debug|x64.Build.0 = Debug|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Debug|x86.ActiveCfg = Debug|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Debug|x86.Build.0 = Debug|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Release|Any CPU.Build.0 = Release|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Release|x64.ActiveCfg = Release|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Release|x64.Build.0 = Release|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Release|x86.ActiveCfg = Release|Any CPU + {11EFF973-23FE-41B6-82D5-E8A0BA79F21C}.Release|x86.Build.0 = Release|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Debug|x64.ActiveCfg = Debug|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Debug|x64.Build.0 = Debug|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Debug|x86.ActiveCfg = Debug|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Debug|x86.Build.0 = Debug|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Release|Any CPU.Build.0 = Release|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Release|x64.ActiveCfg = Release|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Release|x64.Build.0 = Release|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Release|x86.ActiveCfg = Release|Any CPU + {2BB74746-319D-465B-AAD5-C4430322501E}.Release|x86.Build.0 = Release|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Debug|x64.ActiveCfg = Debug|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Debug|x64.Build.0 = Debug|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Debug|x86.ActiveCfg = Debug|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Debug|x86.Build.0 = Debug|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Release|Any CPU.Build.0 = Release|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Release|x64.ActiveCfg = Release|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Release|x64.Build.0 = Release|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Release|x86.ActiveCfg = Release|Any CPU + {5F74B143-822C-4514-B5B9-796EF116E44B}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FD4D03FF-F99F-48B7-92EA-B9A73DF78693} + EndGlobalSection +EndGlobal diff --git a/storagebatchoperations/api/runTests.ps1 b/storagebatchoperations/api/runTests.ps1 new file mode 100644 index 00000000000..93af30db874 --- /dev/null +++ b/storagebatchoperations/api/runTests.ps1 @@ -0,0 +1,16 @@ +# 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. + +dotnet restore --force +dotnet test --no-restore --test-adapter-path:. --logger:junit 2>&1 | %{ "$_" }