From ba3c128633f7fb9f4686af3893820a60d3050ffe Mon Sep 17 00:00:00 2001 From: mahendra-google Date: Wed, 9 Oct 2024 01:50:09 -0700 Subject: [PATCH 1/6] feat(Storage Transfer) : Addition of Sample and Test Case for storagetransfer_transfer_to_nearline. --- .../TransferToNearlineTest.cs | 67 ++++++++++++++++++ .../TransferToNearlineSample.cs | 68 +++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 storagetransfer/api/StorageTransfer.Samples.Tests/TransferToNearlineTest.cs create mode 100644 storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs diff --git a/storagetransfer/api/StorageTransfer.Samples.Tests/TransferToNearlineTest.cs b/storagetransfer/api/StorageTransfer.Samples.Tests/TransferToNearlineTest.cs new file mode 100644 index 00000000000..bf688b6eb7f --- /dev/null +++ b/storagetransfer/api/StorageTransfer.Samples.Tests/TransferToNearlineTest.cs @@ -0,0 +1,67 @@ +// Copyright 2024 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.Storage.V1; +using Google.Cloud.StorageTransfer.V1; +using System; +using Xunit; + +namespace StorageTransfer.Samples.Tests; + +[Collection(nameof(StorageFixture))] +public class TransferToNearlineTest : IDisposable +{ + private readonly StorageFixture _fixture; + private string _transferJobName; + public TransferToNearlineTest(StorageFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public void TestTransferToNearline() + { + TransferToNearlineSample transferToNearlineSample = new TransferToNearlineSample(); + var storage = StorageClient.Create(); + var bucket = storage.GetBucket(_fixture.BucketNameSink); + string storageClass = StorageClasses.Nearline; + bucket.StorageClass = storageClass; + bucket = storage.UpdateBucket(bucket); + var transferJob = transferToNearlineSample.TransferToNearline(_fixture.ProjectId, _fixture.BucketNameSource, _fixture.BucketNameSink); + Assert.Contains("transferJobs/", transferJob.Name); + _transferJobName = transferJob.Name; + } + + public void Dispose() + { + try + { + _fixture.Sts.UpdateTransferJob(new UpdateTransferJobRequest() + { + ProjectId = _fixture.ProjectId, + JobName = _transferJobName, + TransferJob = new TransferJob() + { + Name = _transferJobName, + Status = TransferJob.Types.Status.Deleted + } + }); + } + catch (Exception) + { + // Do nothing, we delete on a best effort basis. + } + } +} diff --git a/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs b/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs new file mode 100644 index 00000000000..c62ec5eb74d --- /dev/null +++ b/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs @@ -0,0 +1,68 @@ +// Copyright 2024 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 storagetransfer_transfer_to_nearline] + +using Google.Cloud.StorageTransfer.V1; +using Google.Protobuf.WellKnownTypes; +using System; + + +namespace StorageTransfer.Samples +{ + + public class TransferToNearlineSample + { + /*Creates a one-off transfer job that transfers objects from a standard GCS bucket that are more + than 30 days old to a Nearline GCS bucket.*/ + public TransferJob TransferToNearline( + // Your Google Cloud Project ID + string projectId = "my-project-id", + // The GCS bucket to transfer objects from + string sourceBucket = "my-source-bucket", + // The GCS Nearline bucket to transfer old objects to + string sinkBucket = "my-sink-bucket") + { + // A description of this job + string jobDescription = $"Transfers old objects from standard bucket ({sourceBucket}) that haven't been modified in the last 30 days to a Nearline bucket ({sinkBucket})"; + + TransferJob transferJob = new TransferJob + { + ProjectId = projectId, + Description = jobDescription, + TransferSpec = new TransferSpec + { + GcsDataSink = new GcsData { BucketName = sinkBucket }, + GcsDataSource = new GcsData { BucketName = sourceBucket }, + ObjectConditions = new ObjectConditions { MinTimeElapsedSinceLastModification = Duration.FromTimeSpan(TimeSpan.FromSeconds(2592000)) }, + TransferOptions = new TransferOptions { DeleteObjectsFromSourceAfterTransfer = true }, + }, + Status = TransferJob.Types.Status.Enabled, + Schedule = new Schedule { ScheduleStartDate = Google.Type.Date.FromDateTime(System.DateTime.UtcNow.Date.AddMonths(1)) } + }; + // Create a Transfer Service client + StorageTransferServiceClient client = StorageTransferServiceClient.Create(); + // Create a Transfer job + TransferJob response = client.CreateTransferJob(new CreateTransferJobRequest { TransferJob = transferJob }); + client.RunTransferJob(new RunTransferJobRequest + { + JobName = response.Name, + ProjectId = projectId + }); + + Console.WriteLine($"Created transfer job from standard bucket {sourceBucket} to Nearline bucket {sinkBucket} with name {response.Name}"); + return response; + } + } +} +// [END storagetransfer_transfer_to_nearline] From 36706a44a3919436d4c8515d19afc9436f167998 Mon Sep 17 00:00:00 2001 From: mahendra-google Date: Wed, 9 Oct 2024 02:17:01 -0700 Subject: [PATCH 2/6] feat(Storage Transfer) : Addition of Schedule End Date in Sample for storagetransfer_transfer_to_nearline. --- .../api/StorageTransfer.Samples/TransferToNearlineSample.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs b/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs index c62ec5eb74d..7b50d3e015e 100644 --- a/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs +++ b/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs @@ -48,7 +48,7 @@ public TransferJob TransferToNearline( TransferOptions = new TransferOptions { DeleteObjectsFromSourceAfterTransfer = true }, }, Status = TransferJob.Types.Status.Enabled, - Schedule = new Schedule { ScheduleStartDate = Google.Type.Date.FromDateTime(System.DateTime.UtcNow.Date.AddMonths(1)) } + Schedule = new Schedule { ScheduleStartDate = Google.Type.Date.FromDateTime(System.DateTime.UtcNow.Date.AddMonths(1)), ScheduleEndDate = Google.Type.Date.FromDateTime(System.DateTime.UtcNow.Date.AddMonths(1)) } }; // Create a Transfer Service client StorageTransferServiceClient client = StorageTransferServiceClient.Create(); @@ -60,7 +60,7 @@ public TransferJob TransferToNearline( ProjectId = projectId }); - Console.WriteLine($"Created transfer job from standard bucket {sourceBucket} to Nearline bucket {sinkBucket} with name {response.Name}"); + Console.WriteLine($"Created one-off transfer job from standard bucket {sourceBucket} to Nearline bucket {sinkBucket} with name {response.Name}"); return response; } } From afcba298ce660c521a296791ed6f1c28098f10a6 Mon Sep 17 00:00:00 2001 From: mahendra-google Date: Wed, 9 Oct 2024 02:17:01 -0700 Subject: [PATCH 3/6] samples(storage transfer) : Addition of schedule end date in sample for storagetransfer_transfer_to_nearline. --- .../api/StorageTransfer.Samples/TransferToNearlineSample.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs b/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs index c62ec5eb74d..7b50d3e015e 100644 --- a/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs +++ b/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs @@ -48,7 +48,7 @@ public TransferJob TransferToNearline( TransferOptions = new TransferOptions { DeleteObjectsFromSourceAfterTransfer = true }, }, Status = TransferJob.Types.Status.Enabled, - Schedule = new Schedule { ScheduleStartDate = Google.Type.Date.FromDateTime(System.DateTime.UtcNow.Date.AddMonths(1)) } + Schedule = new Schedule { ScheduleStartDate = Google.Type.Date.FromDateTime(System.DateTime.UtcNow.Date.AddMonths(1)), ScheduleEndDate = Google.Type.Date.FromDateTime(System.DateTime.UtcNow.Date.AddMonths(1)) } }; // Create a Transfer Service client StorageTransferServiceClient client = StorageTransferServiceClient.Create(); @@ -60,7 +60,7 @@ public TransferJob TransferToNearline( ProjectId = projectId }); - Console.WriteLine($"Created transfer job from standard bucket {sourceBucket} to Nearline bucket {sinkBucket} with name {response.Name}"); + Console.WriteLine($"Created one-off transfer job from standard bucket {sourceBucket} to Nearline bucket {sinkBucket} with name {response.Name}"); return response; } } From 3efcf764d5d7521dd8f60c335be6346bc889637d Mon Sep 17 00:00:00 2001 From: mahendra-google Date: Thu, 10 Oct 2024 02:55:33 -0700 Subject: [PATCH 4/6] chore(deps): add dependency xunit.abstractions version 2.0.3 to see output message in sample output and related small changes. --- .../QuickstartTest.cs | 11 +++++++---- .../QuickstartSample.cs | 18 +++++++++++------- .../StorageTransfer.Samples.csproj | 1 + 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/storagetransfer/api/StorageTransfer.Samples.Tests/QuickstartTest.cs b/storagetransfer/api/StorageTransfer.Samples.Tests/QuickstartTest.cs index 30cac132e63..5b96b7519c6 100644 --- a/storagetransfer/api/StorageTransfer.Samples.Tests/QuickstartTest.cs +++ b/storagetransfer/api/StorageTransfer.Samples.Tests/QuickstartTest.cs @@ -1,5 +1,5 @@ -/** - * Copyright 2021 Google Inc. +/** + * Copyright 2024 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ using System; using Google.Cloud.StorageTransfer.V1; using Xunit; +using Xunit.Abstractions; namespace StorageTransfer.Samples.Tests { @@ -25,16 +26,18 @@ public class QuickstartTest : IDisposable { private readonly StorageFixture _fixture; private string _transferJobName; + private readonly ITestOutputHelper _outputHelper; - public QuickstartTest(StorageFixture fixture) + public QuickstartTest(StorageFixture fixture , ITestOutputHelper outputHelper) { _fixture = fixture; + _outputHelper = outputHelper; } [Fact] public void TestQuickstart() { - QuickstartSample quickstartSample = new QuickstartSample(); + QuickstartSample quickstartSample = new QuickstartSample(_outputHelper); var transferJob = quickstartSample.Quickstart(_fixture.ProjectId, _fixture.BucketNameSource, _fixture.BucketNameSink); Assert.Contains("transferJobs/", transferJob.Name); _transferJobName = transferJob.Name; diff --git a/storagetransfer/api/StorageTransfer.Samples/QuickstartSample.cs b/storagetransfer/api/StorageTransfer.Samples/QuickstartSample.cs index cc84bfe0620..68e60844d0d 100644 --- a/storagetransfer/api/StorageTransfer.Samples/QuickstartSample.cs +++ b/storagetransfer/api/StorageTransfer.Samples/QuickstartSample.cs @@ -1,5 +1,5 @@ -/** - * Copyright 2021 Google Inc. +/** + * Copyright 2024 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,19 @@ * limitations under the License. */ - // [START storagetransfer_quickstart] -using System; using Google.Cloud.StorageTransfer.V1; +using Xunit.Abstractions; namespace StorageTransfer.Samples { public class QuickstartSample { + private readonly ITestOutputHelper _output; + public QuickstartSample(ITestOutputHelper output) + { + _output = output; + } public TransferJob Quickstart( // Your Google Cloud Project ID string projectId = "my-project-id", @@ -36,8 +40,8 @@ public TransferJob Quickstart( ProjectId = projectId, TransferSpec = new TransferSpec { - GcsDataSink = new GcsData { BucketName = sourceBucket }, - GcsDataSource = new GcsData { BucketName = sinkBucket } + GcsDataSink = new GcsData { BucketName = sinkBucket }, + GcsDataSource = new GcsData { BucketName = sourceBucket } }, Status = TransferJob.Types.Status.Enabled }; @@ -50,7 +54,7 @@ public TransferJob Quickstart( ProjectId = projectId }); - Console.WriteLine($"Created and ran transfer job from {sourceBucket} to {sinkBucket} with name {response.Name}"); + _output.WriteLine($"Created and ran transfer job from {sourceBucket} to {sinkBucket} with name {response.Name}"); return response; } diff --git a/storagetransfer/api/StorageTransfer.Samples/StorageTransfer.Samples.csproj b/storagetransfer/api/StorageTransfer.Samples/StorageTransfer.Samples.csproj index cb35bdd48fa..2b68373281f 100644 --- a/storagetransfer/api/StorageTransfer.Samples/StorageTransfer.Samples.csproj +++ b/storagetransfer/api/StorageTransfer.Samples/StorageTransfer.Samples.csproj @@ -6,5 +6,6 @@ + From 35e18a36bb880ab70a9205a7e732df3059c98cc3 Mon Sep 17 00:00:00 2001 From: mahendra-google Date: Thu, 10 Oct 2024 04:37:44 -0700 Subject: [PATCH 5/6] code changes in transfer to nearline related to capture message in standard output of test log summary. --- .../TransferToNearlineTest.cs | 7 +++++-- .../StorageTransfer.Samples/TransferToNearlineSample.cs | 8 +++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/storagetransfer/api/StorageTransfer.Samples.Tests/TransferToNearlineTest.cs b/storagetransfer/api/StorageTransfer.Samples.Tests/TransferToNearlineTest.cs index bf688b6eb7f..c3d1856f192 100644 --- a/storagetransfer/api/StorageTransfer.Samples.Tests/TransferToNearlineTest.cs +++ b/storagetransfer/api/StorageTransfer.Samples.Tests/TransferToNearlineTest.cs @@ -17,6 +17,7 @@ using Google.Cloud.StorageTransfer.V1; using System; using Xunit; +using Xunit.Abstractions; namespace StorageTransfer.Samples.Tests; @@ -25,15 +26,17 @@ public class TransferToNearlineTest : IDisposable { private readonly StorageFixture _fixture; private string _transferJobName; - public TransferToNearlineTest(StorageFixture fixture) + private readonly ITestOutputHelper _outputHelper; + public TransferToNearlineTest(StorageFixture fixture, ITestOutputHelper outputHelper) { _fixture = fixture; + _outputHelper = outputHelper; } [Fact] public void TestTransferToNearline() { - TransferToNearlineSample transferToNearlineSample = new TransferToNearlineSample(); + TransferToNearlineSample transferToNearlineSample = new TransferToNearlineSample(_outputHelper); var storage = StorageClient.Create(); var bucket = storage.GetBucket(_fixture.BucketNameSink); string storageClass = StorageClasses.Nearline; diff --git a/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs b/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs index 7b50d3e015e..2d7238eea76 100644 --- a/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs +++ b/storagetransfer/api/StorageTransfer.Samples/TransferToNearlineSample.cs @@ -16,6 +16,7 @@ using Google.Cloud.StorageTransfer.V1; using Google.Protobuf.WellKnownTypes; using System; +using Xunit.Abstractions; namespace StorageTransfer.Samples @@ -25,6 +26,11 @@ public class TransferToNearlineSample { /*Creates a one-off transfer job that transfers objects from a standard GCS bucket that are more than 30 days old to a Nearline GCS bucket.*/ + private readonly ITestOutputHelper _output; + public TransferToNearlineSample(ITestOutputHelper output) + { + _output = output; + } public TransferJob TransferToNearline( // Your Google Cloud Project ID string projectId = "my-project-id", @@ -60,7 +66,7 @@ public TransferJob TransferToNearline( ProjectId = projectId }); - Console.WriteLine($"Created one-off transfer job from standard bucket {sourceBucket} to Nearline bucket {sinkBucket} with name {response.Name}"); + _output.WriteLine($"Created one-off transfer job from standard bucket {sourceBucket} to Nearline bucket {sinkBucket} with the name {response.Name}"); return response; } } From 0acb7fdb5d1a113ec95fbb0d20fc50126e6a953a Mon Sep 17 00:00:00 2001 From: mahendra-google Date: Thu, 10 Oct 2024 07:14:02 -0700 Subject: [PATCH 6/6] feat(storage transfer) : addition of sample and test case to check latest transfer operation. --- .../CheckLatestTransferOperationTest.cs | 40 +++++++++++ .../StorageFixture.cs | 7 +- .../CheckLatestTransferOperationSample.cs | 70 +++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 storagetransfer/api/StorageTransfer.Samples.Tests/CheckLatestTransferOperationTest.cs create mode 100644 storagetransfer/api/StorageTransfer.Samples/CheckLatestTransferOperationSample.cs diff --git a/storagetransfer/api/StorageTransfer.Samples.Tests/CheckLatestTransferOperationTest.cs b/storagetransfer/api/StorageTransfer.Samples.Tests/CheckLatestTransferOperationTest.cs new file mode 100644 index 00000000000..4790fc473b4 --- /dev/null +++ b/storagetransfer/api/StorageTransfer.Samples.Tests/CheckLatestTransferOperationTest.cs @@ -0,0 +1,40 @@ +// Copyright 2024 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; +using Xunit.Abstractions; + +namespace StorageTransfer.Samples.Tests; + +[Collection(nameof(StorageFixture))] +public class CheckLatestTransferOperationTest +{ + + private readonly StorageFixture _fixture; + private string _jobName; + private readonly ITestOutputHelper _outputHelper; + public CheckLatestTransferOperationTest(StorageFixture fixture, ITestOutputHelper outputHelper) + { + _outputHelper = outputHelper; + _fixture = fixture; + } + + [Fact] + public void CheckLatestTransferOperation() + { + CheckLatestTransferOperationSample checkLatestTransferOperationSample = new CheckLatestTransferOperationSample(_outputHelper); + var transferJob = checkLatestTransferOperationSample.CheckLatestTransferOperation(_fixture.ProjectId,_fixture.JobName); + Assert.Contains("transferJobs/", transferJob.Name); + _jobName = transferJob.Name; + } +} diff --git a/storagetransfer/api/StorageTransfer.Samples.Tests/StorageFixture.cs b/storagetransfer/api/StorageTransfer.Samples.Tests/StorageFixture.cs index 2938516a605..08e7c9ce72f 100644 --- a/storagetransfer/api/StorageTransfer.Samples.Tests/StorageFixture.cs +++ b/storagetransfer/api/StorageTransfer.Samples.Tests/StorageFixture.cs @@ -1,4 +1,4 @@ -/** +/** * Copyright 2021 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,11 +28,16 @@ public class StorageFixture : IDisposable, ICollectionFixture public string ProjectId { get; } public string BucketNameSource { get; } = Guid.NewGuid().ToString(); public string BucketNameSink { get; } = Guid.NewGuid().ToString(); + public string JobName { get; } public StorageClient Storage { get; } = StorageClient.Create(); public StorageTransferServiceClient Sts { get; } = StorageTransferServiceClient.Create(); public StorageFixture() { + // Instantiate random number generator + Random random = new Random(); + JobName = "transferJobs/" + random.NextInt64(1000000000000000, 9223372036854775807) + " "; + ProjectId = Environment.GetEnvironmentVariable("GOOGLE_PROJECT_ID"); if (string.IsNullOrWhiteSpace(ProjectId)) { diff --git a/storagetransfer/api/StorageTransfer.Samples/CheckLatestTransferOperationSample.cs b/storagetransfer/api/StorageTransfer.Samples/CheckLatestTransferOperationSample.cs new file mode 100644 index 00000000000..c8f447e3b91 --- /dev/null +++ b/storagetransfer/api/StorageTransfer.Samples/CheckLatestTransferOperationSample.cs @@ -0,0 +1,70 @@ +// Copyright 2024 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 storagetransfer_get_latest_transfer_operation] + +using Google.Cloud.StorageTransfer.V1; +using System; +using Xunit.Abstractions; + +namespace StorageTransfer.Samples +{ + public class CheckLatestTransferOperationSample + { + private readonly ITestOutputHelper _output; + public CheckLatestTransferOperationSample(ITestOutputHelper output) + { + _output = output; + + } + //Checks the latest transfer operation for a given transfer job. + public TransferJob CheckLatestTransferOperation( + // Your Google Cloud Project ID + string projectId = "my-project-id", + // The name of the job to check + string jobName = "transferJobs/1234567890") + { + if(string.IsNullOrEmpty(jobName)) + { + throw new Exception("JobName can not be null or empty"); + } + // Create a Transfer Service client + StorageTransferServiceClient storageTransfer = StorageTransferServiceClient.Create(); + + GetTransferJobRequest getTransferJobRequest = new GetTransferJobRequest { ProjectId = projectId, JobName = jobName }; + try + { + // Get Transfer job + TransferJob transferJob = storageTransfer.GetTransferJob(getTransferJobRequest); + // Get Latest operation name from tranfer job + string latestOperationName = transferJob.LatestOperationName; + + + if (!string.IsNullOrEmpty(latestOperationName)) + { + _output.WriteLine("The latest operation for transfer job " +jobName+ " is: " +latestOperationName+ ""); + } + else + { + _output.WriteLine("Transfer job "+ jobName +" hasn't run yet, try again once after job started running."); + } + return transferJob; + } + catch (Exception) + { + throw new Exception("Failed to get transfer job "+ jobName + ""); + } + } + } +} +// [END storagetransfer_get_latest_transfer_operation]