From eacc11515b34f7b14449365f7b8317a0b362ae65 Mon Sep 17 00:00:00 2001 From: Malhar Khimsaria <96malhar@gmail.com> Date: Tue, 6 Aug 2024 10:44:15 -0700 Subject: [PATCH] Add the ability to mock BatchWrite and MultiTableBatchWrite operations --- sdk/src/Core/AWSSDK.Core.NetFramework.csproj | 2 +- sdk/src/Core/AWSSDK.Core.NetStandard.csproj | 2 +- .../DynamoDBv2/Custom/DataModel/BatchWrite.cs | 270 ++++++++---------- .../DynamoDBv2/Custom/DataModel/Context.cs | 85 +----- .../Custom/DataModel/IDynamoDBContext.cs | 14 +- .../DataModel/_async/BatchWrite.Async.cs | 47 ++- .../Custom/DataModel/_async/Context.Async.cs | 12 +- .../_async/IDynamoDBContext.Async.cs | 2 +- .../Custom/DataModel/_bcl/BatchWrite.Sync.cs | 47 ++- .../Custom/DataModel/_bcl/Context.Sync.cs | 9 +- .../DataModel/_bcl/IDynamoDBContext.Sync.cs | 3 +- .../Custom/MockabilityTests/BatchGetTests.cs | 2 +- .../MockabilityTests/BatchWriteTests.cs | 121 ++++++++ 13 files changed, 315 insertions(+), 301 deletions(-) create mode 100644 sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/BatchWriteTests.cs diff --git a/sdk/src/Core/AWSSDK.Core.NetFramework.csproj b/sdk/src/Core/AWSSDK.Core.NetFramework.csproj index 3d740253846d..aa96aa545da5 100644 --- a/sdk/src/Core/AWSSDK.Core.NetFramework.csproj +++ b/sdk/src/Core/AWSSDK.Core.NetFramework.csproj @@ -69,6 +69,6 @@ - + diff --git a/sdk/src/Core/AWSSDK.Core.NetStandard.csproj b/sdk/src/Core/AWSSDK.Core.NetStandard.csproj index 2af0a0429fbb..5bbd2016d82d 100644 --- a/sdk/src/Core/AWSSDK.Core.NetStandard.csproj +++ b/sdk/src/Core/AWSSDK.Core.NetStandard.csproj @@ -81,6 +81,6 @@ - + \ No newline at end of file diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/BatchWrite.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/BatchWrite.cs index 99958b020eb2..8c45afba89ea 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/BatchWrite.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/BatchWrite.cs @@ -14,10 +14,7 @@ */ using System; -using System.Collections; using System.Collections.Generic; -using System.Reflection; -using Amazon.DynamoDBv2.Model; using Amazon.DynamoDBv2.DocumentModel; using System.Globalization; #if AWS_ASYNC_API @@ -28,56 +25,19 @@ namespace Amazon.DynamoDBv2.DataModel { /// - /// Represents a non-generic object for writing/deleting a batch of items + /// Represents a non-generic interface for writing/deleting a batch of items /// in a single DynamoDB table /// - public abstract partial class BatchWrite + public partial interface IBatchWrite { - #region Internal/protected properties - - internal DynamoDBContext Context { get; set; } - internal DynamoDBFlatConfig Config { get; set; } - internal DocumentBatchWrite DocumentBatch { get; set; } - - #endregion - - - #region Constructor - - internal BatchWrite(DynamoDBContext context, DynamoDBFlatConfig config) - { - Context = context; - Config = config; - } - - #endregion - - - #region Protected methods - - /// - /// Executes a server call to batch-write/delete the items requested. - /// - internal protected abstract void ExecuteHelper(); - -#if AWS_ASYNC_API - /// - /// Executes an asynchronous server call to batch-write/delete the items requested. - /// - internal protected abstract Task ExecuteHelperAsync(CancellationToken cancellationToken); -#endif - - #endregion } /// - /// Represents a strongly-typed object for writing/deleting a batch of items + /// Represents a generic interface for writing/deleting a batch of items /// in a single DynamoDB table /// - public class BatchWrite : BatchWrite + public interface IBatchWrite : IBatchWrite { - #region Public combine methods - /// /// Creates a MultiTableBatchWrite object that is a combination /// of the current BatchWrite and the specified BatchWrites @@ -87,84 +47,38 @@ public class BatchWrite : BatchWrite /// MultiTableBatchWrite consisting of the multiple BatchWrite objects: /// the current batch and the passed-in batches. /// - public MultiTableBatchWrite Combine(params BatchWrite[] otherBatches) - { - return new MultiTableBatchWrite(this, otherBatches); - } - - #endregion - - - #region Public Put methods + IMultiTableBatchWrite Combine(params IBatchWrite[] otherBatches); /// /// Add a number of items to be put in the current batch operation /// /// Items to put - public void AddPutItems(IEnumerable values) - { - if (values == null) return; - - foreach (T item in values) - { - AddPutItem(item); - } - } + void AddPutItems(IEnumerable values); /// /// Add a single item to be put in the current batch operation /// /// - public void AddPutItem(T item) - { - if (item == null) return; - - ItemStorage storage = Context.ObjectToItemStorageHelper(item, StorageConfig, Config, keysOnly: false, ignoreNullValues: true); - if (storage == null) return; - DocumentBatch.AddDocumentToPut(storage.Document); - } - - #endregion - - - #region Public Delete methods + void AddPutItem(T item); /// /// Add a number of items to be deleted in the current batch operation /// /// Items to be deleted - public void AddDeleteItems(IEnumerable values) - { - if (values == null) return; - - foreach (T item in values) - { - AddDeleteItem(item); - } - } + void AddDeleteItems(IEnumerable values); /// /// Add a single item to be deleted in the current batch operation. /// /// Item to be deleted - public void AddDeleteItem(T item) - { - if (item == null) return; - - ItemStorage storage = Context.ObjectToItemStorageHelper(item, StorageConfig, Config, keysOnly: true, ignoreNullValues: true); - if (storage == null) return; - DocumentBatch.AddItemToDelete(storage.Document); - } + void AddDeleteItem(T item); /// /// Add a single item to be deleted in the current batch operation. /// Item is identified by its hash primary key. /// /// Hash key of the item to delete - public void AddDeleteKey(object hashKey) - { - AddDeleteKey(hashKey, null); - } + void AddDeleteKey(object hashKey); /// /// Add a single item to be deleted in the current batch operation. @@ -172,15 +86,27 @@ public void AddDeleteKey(object hashKey) /// /// Hash key of the item to delete /// Range key of the item to delete - public void AddDeleteKey(object hashKey, object rangeKey) - { - DocumentBatch.AddKeyToDelete(Context.MakeKey(hashKey, rangeKey, StorageConfig, Config)); - } - - #endregion + void AddDeleteKey(object hashKey, object rangeKey); + } + /// + /// Represents a non-generic object for writing/deleting a batch of items + /// in a single DynamoDB table + /// + public abstract partial class BatchWrite : IBatchWrite + { + internal DocumentBatchWrite DocumentBatch { get; set; } + } - #region Constructor + /// + /// Represents a strongly-typed object for writing/deleting a batch of items + /// in a single DynamoDB table + /// + public partial class BatchWrite : BatchWrite, IBatchWrite + { + private readonly DynamoDBContext _context; + private readonly DynamoDBFlatConfig _config; + private readonly ItemStorageConfig _storageConfig; internal BatchWrite(DynamoDBContext context, DynamoDBFlatConfig config) : this(context, typeof(T), config) @@ -188,118 +114,164 @@ internal BatchWrite(DynamoDBContext context, DynamoDBFlatConfig config) } internal BatchWrite(DynamoDBContext context, Type valuesType, DynamoDBFlatConfig config) - : base(context, config) { - StorageConfig = context.StorageConfigCache.GetConfig(valuesType, config); + _context = context; + _config = config; + _storageConfig = context.StorageConfigCache.GetConfig(valuesType, config); - if (StorageConfig.HasVersion) + if (_storageConfig.HasVersion) { - if (!Config.SkipVersionCheck.GetValueOrDefault(false)) + if (!_config.SkipVersionCheck.GetValueOrDefault(false)) throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Object {0} has a versioning field, which is not supported for this operation. To ignore versioning, use the DynamoDBContextConfig.SkipVersionCheck property.", valuesType.Name)); } - Table table = Context.GetTargetTable(StorageConfig, Config); + Table table = _context.GetTargetTable(_storageConfig, _config); DocumentBatch = table.CreateBatchWrite(); } - #endregion + /// + public IMultiTableBatchWrite Combine(params IBatchWrite[] otherBatches) + { + return new MultiTableBatchWrite(this, otherBatches); + } + /// + public void AddPutItems(IEnumerable values) + { + if (values == null) return; - #region Internal/protected/private members + foreach (T item in values) + { + AddPutItem(item); + } + } - internal ItemStorageConfig StorageConfig { get; set; } + /// + public void AddPutItem(T item) + { + if (item == null) return; - /// - /// Execute the batch write. - /// - internal protected override void ExecuteHelper() + ItemStorage storage = _context.ObjectToItemStorageHelper(item, _storageConfig, _config, keysOnly: false, ignoreNullValues: true); + if (storage == null) return; + DocumentBatch.AddDocumentToPut(storage.Document); + } + + /// + public void AddDeleteItems(IEnumerable values) + { + if (values == null) return; + + foreach (T item in values) + { + AddDeleteItem(item); + } + } + + /// + public void AddDeleteItem(T item) + { + if (item == null) return; + + ItemStorage storage = _context.ObjectToItemStorageHelper(item, _storageConfig, _config, keysOnly: true, ignoreNullValues: true); + if (storage == null) return; + DocumentBatch.AddItemToDelete(storage.Document); + } + + /// + public void AddDeleteKey(object hashKey) + { + AddDeleteKey(hashKey, null); + } + + /// + public void AddDeleteKey(object hashKey, object rangeKey) + { + DocumentBatch.AddKeyToDelete(_context.MakeKey(hashKey, rangeKey, _storageConfig, _config)); + } + + private void ExecuteHelper() { DocumentBatch.ExecuteHelper(); } #if AWS_ASYNC_API - /// - /// Execute the batch write asynchronously. - /// - internal protected override Task ExecuteHelperAsync(CancellationToken cancellationToken) + private Task ExecuteHelperAsync(CancellationToken cancellationToken) { return DocumentBatch.ExecuteHelperAsync(cancellationToken); } #endif + } - #endregion + /// + /// Interface for writing/deleting a batch of items in multiple DynamoDB tables, + /// using multiple strongly-typed BatchWrite objects + /// + public partial interface IMultiTableBatchWrite + { + /// + /// Add a BatchWrite object to the multi-table batch request + /// + /// BatchWrite to add + void AddBatch(IBatchWrite batch); } /// /// Class for writing/deleting a batch of items in multiple DynamoDB tables, /// using multiple strongly-typed BatchWrite objects /// - public partial class MultiTableBatchWrite + public partial class MultiTableBatchWrite : IMultiTableBatchWrite { - #region Private members - - private List allBatches = new List(); - - #endregion - - - #region Constructor + private List allBatches = new(); /// /// Constructs a MultiTableBatchWrite object from a number of /// BatchWrite objects /// /// Collection of BatchWrite objects - public MultiTableBatchWrite(params BatchWrite[] batches) + public MultiTableBatchWrite(params IBatchWrite[] batches) { - allBatches = new List(batches); + allBatches = new List(batches); } - internal MultiTableBatchWrite(BatchWrite first, params BatchWrite[] rest) + internal MultiTableBatchWrite(IBatchWrite first, params IBatchWrite[] rest) { - allBatches = new List(); + allBatches = new List(); allBatches.Add(first); allBatches.AddRange(rest); } - #endregion - - - #region Public methods - - /// - /// Add a BatchWrite object to the multi-table batch request - /// - /// BatchGet to add - public void AddBatch(BatchWrite batch) + /// + public void AddBatch(IBatchWrite batch) { allBatches.Add(batch); } - internal void ExecuteHelper() + private void ExecuteHelper() { MultiTableDocumentBatchWrite superBatch = new MultiTableDocumentBatchWrite(); + var errorMsg = $"All batches must be of type {nameof(BatchWrite)}"; foreach (var batch in allBatches) { - superBatch.AddBatch(batch.DocumentBatch); + var abstractBatch = batch as BatchWrite ?? throw new InvalidOperationException(errorMsg); + superBatch.AddBatch(abstractBatch.DocumentBatch); } superBatch.ExecuteHelper(); } #if AWS_ASYNC_API - internal Task ExecuteHelperAsync(CancellationToken cancellationToken) + private Task ExecuteHelperAsync(CancellationToken cancellationToken) { MultiTableDocumentBatchWrite superBatch = new MultiTableDocumentBatchWrite(); + var errorMsg = $"All batches must be of type {nameof(BatchWrite)}"; foreach (var batch in allBatches) { - superBatch.AddBatch(batch.DocumentBatch); + var abstractBatch = batch as BatchWrite ?? throw new InvalidOperationException(errorMsg); + superBatch.AddBatch(abstractBatch.DocumentBatch); } return superBatch.ExecuteHelperAsync(cancellationToken); } #endif - - #endregion } } diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs index b16b61b105d3..3012c9089c93 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/Context.cs @@ -239,105 +239,48 @@ public IMultiTableBatchGet CreateMultiTableBatchGet(params IBatchGet[] batches) #region BatchWrite - /// - /// Creates a strongly-typed BatchWrite object, allowing - /// a batch-write operation against DynamoDB. - /// - /// Type of objects to write - /// Empty strongly-typed BatchWrite object - public BatchWrite CreateBatchWrite() + /// + public IBatchWrite CreateBatchWrite() { return CreateBatchWrite((BatchWriteConfig)null); } - /// - /// Creates a strongly-typed BatchWrite object, allowing - /// a batch-write operation against DynamoDB. - /// - /// Type of objects to write - /// Config object which can be used to override that table used. - /// Empty strongly-typed BatchWrite object + /// [Obsolete("Use the CreateBatchWrite overload that takes BatchWriteConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to BatchWrite.")] - public BatchWrite CreateBatchWrite(DynamoDBOperationConfig operationConfig) + public IBatchWrite CreateBatchWrite(DynamoDBOperationConfig operationConfig) { DynamoDBFlatConfig config = new DynamoDBFlatConfig(operationConfig, this.Config); return new BatchWrite(this, config); } - /// - /// Creates a strongly-typed BatchWrite object, allowing - /// a batch-write operation against DynamoDB. - /// - /// This is intended for use only when the valuesType is not known at compile-time, for example, - /// when hooking into EF's ChangeTracker to record audit logs from EF into DynamoDB. - /// - /// In scenarios when the valuesType is known at compile-time, the - /// method is generally preferred. - /// - /// Type of objects to write - /// Empty strongly-typed BatchWrite object - public BatchWrite CreateBatchWrite(Type valuesType) + /// + public IBatchWrite CreateBatchWrite(Type valuesType) { return CreateBatchWrite(valuesType, (BatchWriteConfig)null); } - /// - /// Creates a strongly-typed BatchWrite object, allowing - /// a batch-write operation against DynamoDB. - /// - /// This is intended for use only when the valuesType is not known at compile-time, for example, - /// when hooking into EF's ChangeTracker to record audit logs from EF into DynamoDB. - /// - /// In scenarios when the valuesType is known at compile-time, the - /// method is generally preferred. - /// - /// Type of objects to write - /// Config object which can be used to override that table used. - /// Empty strongly-typed BatchWrite object + /// [Obsolete("Use the CreateBatchWrite overload that takes BatchWriteConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to BatchWrite.")] - public BatchWrite CreateBatchWrite(Type valuesType, DynamoDBOperationConfig operationConfig) + public IBatchWrite CreateBatchWrite(Type valuesType, DynamoDBOperationConfig operationConfig) { DynamoDBFlatConfig config = new DynamoDBFlatConfig(operationConfig, this.Config); return new BatchWrite(this, valuesType, config); } - /// - /// Creates a strongly-typed BatchWrite object, allowing - /// a batch-write operation against DynamoDB. - /// - /// Type of objects to write - /// Config object that can be used to override properties on the table's context for this request. - /// Empty strongly-typed BatchWrite object - public BatchWrite CreateBatchWrite(BatchWriteConfig batchWriteConfig) + /// + public IBatchWrite CreateBatchWrite(BatchWriteConfig batchWriteConfig) { return new BatchWrite(this, new DynamoDBFlatConfig(batchWriteConfig?.ToDynamoDBOperationConfig(), Config)); } - /// - /// Creates a strongly-typed BatchWrite object, allowing - /// a batch-write operation against DynamoDB. - /// - /// This is intended for use only when the valuesType is not known at compile-time, for example, - /// when hooking into EF's ChangeTracker to record audit logs from EF into DynamoDB. - /// - /// In scenarios when the valuesType is known at compile-time, the - /// method is generally preferred. - /// - /// The type of data which will be persisted in this batch. - /// Config object that can be used to override properties on the table's context for this request. - /// Empty strongly-typed BatchWrite object - public BatchWrite CreateBatchWrite(Type valuesType, BatchWriteConfig batchWriteConfig) + /// + public IBatchWrite CreateBatchWrite(Type valuesType, BatchWriteConfig batchWriteConfig) { return new BatchWrite(this, valuesType, new DynamoDBFlatConfig(batchWriteConfig.ToDynamoDBOperationConfig(), Config)); } - /// - /// Creates a MultiTableBatchWrite object, composed of multiple - /// individual BatchWrite objects. - /// - /// Individual BatchWrite objects - /// Composite MultiTableBatchWrite object - public MultiTableBatchWrite CreateMultiTableBatchWrite(params BatchWrite[] batches) + /// + public IMultiTableBatchWrite CreateMultiTableBatchWrite(params IBatchWrite[] batches) { return new MultiTableBatchWrite(batches); } diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/IDynamoDBContext.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/IDynamoDBContext.cs index cc8120571cd7..d7a18828685c 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/IDynamoDBContext.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/IDynamoDBContext.cs @@ -192,7 +192,7 @@ public partial interface IDynamoDBContext : IDisposable /// /// Type of objects to write /// Empty strongly-typed BatchWrite object - BatchWrite CreateBatchWrite(); + IBatchWrite CreateBatchWrite(); /// /// Creates a strongly-typed BatchWrite object, allowing @@ -203,7 +203,7 @@ public partial interface IDynamoDBContext : IDisposable /// Empty strongly-typed BatchWrite object [Obsolete("Use the CreateBatchWrite overload that takes BatchWriteConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to BatchWrite.")] - BatchWrite CreateBatchWrite(DynamoDBOperationConfig operationConfig = null); + IBatchWrite CreateBatchWrite(DynamoDBOperationConfig operationConfig = null); /// /// Creates a strongly-typed BatchWrite object, allowing @@ -217,7 +217,7 @@ public partial interface IDynamoDBContext : IDisposable /// /// The type of data which will be persisted in this batch. /// Empty strongly-typed BatchWrite object - BatchWrite CreateBatchWrite(Type valuesType); + IBatchWrite CreateBatchWrite(Type valuesType); /// /// Creates a strongly-typed BatchWrite object, allowing @@ -233,7 +233,7 @@ public partial interface IDynamoDBContext : IDisposable /// Config object which can be used to override that table used. /// Empty strongly-typed BatchWrite object [Obsolete("Use the CreateBatchWrite overload that takes BatchWriteConfig instead, since DynamoDBOperationConfig contains properties that are not applicable to BatchWrite.")] - BatchWrite CreateBatchWrite(Type valuesType, DynamoDBOperationConfig operationConfig = null); + IBatchWrite CreateBatchWrite(Type valuesType, DynamoDBOperationConfig operationConfig = null); /// /// Creates a strongly-typed BatchWrite object, allowing @@ -242,7 +242,7 @@ public partial interface IDynamoDBContext : IDisposable /// Type of objects to write /// Config object that can be used to override properties on the table's context for this request. /// Empty strongly-typed BatchWrite object - BatchWrite CreateBatchWrite(BatchWriteConfig batchWriteConfig); + IBatchWrite CreateBatchWrite(BatchWriteConfig batchWriteConfig); /// /// Creates a strongly-typed BatchWrite object, allowing @@ -257,7 +257,7 @@ public partial interface IDynamoDBContext : IDisposable /// The type of data which will be persisted in this batch. /// Config object that can be used to override properties on the table's context for this request. /// Empty strongly-typed BatchWrite object - BatchWrite CreateBatchWrite(Type valuesType, BatchWriteConfig batchWriteConfig); + IBatchWrite CreateBatchWrite(Type valuesType, BatchWriteConfig batchWriteConfig); /// /// Creates a MultiTableBatchWrite object, composed of multiple @@ -265,7 +265,7 @@ public partial interface IDynamoDBContext : IDisposable /// /// Individual BatchWrite objects /// Composite MultiTableBatchWrite object - MultiTableBatchWrite CreateMultiTableBatchWrite(params BatchWrite[] batches); + IMultiTableBatchWrite CreateMultiTableBatchWrite(params IBatchWrite[] batches); #endregion diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/BatchWrite.Async.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/BatchWrite.Async.cs index 4f4cdc0d4789..ec77b8766dd5 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/BatchWrite.Async.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/BatchWrite.Async.cs @@ -14,26 +14,13 @@ */ #pragma warning disable 1574 -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using Amazon.DynamoDBv2.Model; -using Amazon.DynamoDBv2.DocumentModel; using System.Threading.Tasks; -using Amazon.Runtime.Internal; using System.Threading; namespace Amazon.DynamoDBv2.DataModel { - /// - /// Represents a non-generic object for writing/deleting a batch of items - /// in a single DynamoDB table - /// - public abstract partial class BatchWrite + public partial interface IBatchWrite { - #region Public methods - /// /// Executes a server call to batch-write/delete the items requested. /// @@ -43,22 +30,26 @@ public abstract partial class BatchWrite /// Token which can be used to cancel the task. /// /// A Task that can be used to poll or wait for results, or both. - public Task ExecuteAsync(CancellationToken cancellationToken = default(CancellationToken)) + Task ExecuteAsync(CancellationToken cancellationToken = default(CancellationToken)); + } + + public abstract partial class BatchWrite : IBatchWrite + { + /// + public abstract Task ExecuteAsync(CancellationToken cancellationToken); + } + + public partial class BatchWrite : BatchWrite, IBatchWrite + { + /// + public override Task ExecuteAsync(CancellationToken cancellationToken) { return ExecuteHelperAsync(cancellationToken); } - - #endregion } - /// - /// Class for writing/deleting a batch of items in multiple DynamoDB tables, - /// using multiple strongly-typed BatchWrite objects - /// - public partial class MultiTableBatchWrite + public partial interface IMultiTableBatchWrite { - #region Public methods - /// /// Executes a multi-table batch request against all configured batches. /// @@ -68,11 +59,15 @@ public partial class MultiTableBatchWrite /// Token which can be used to cancel the task. /// /// A Task that can be used to poll or wait for results, or both. + Task ExecuteAsync(CancellationToken cancellationToken = default(CancellationToken)); + } + + public partial class MultiTableBatchWrite : IMultiTableBatchWrite + { + /// public Task ExecuteAsync(CancellationToken cancellationToken = default(CancellationToken)) { return ExecuteHelperAsync(cancellationToken); } - - #endregion } } diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs index 8ca209c1a640..a408abb50e5a 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/Context.Async.cs @@ -211,16 +211,8 @@ public Task ExecuteBatchGetAsync(params IBatchGet[] batches) #region BatchWrite async - /// - /// Issues a batch-write request with multiple batches. - /// - /// - /// Configured BatchWrite objects - /// - /// - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - public Task ExecuteBatchWriteAsync(BatchWrite[] batches, CancellationToken cancellationToken = default(CancellationToken)) + /// + public Task ExecuteBatchWriteAsync(IBatchWrite[] batches, CancellationToken cancellationToken = default(CancellationToken)) { MultiTableBatchWrite superBatch = new MultiTableBatchWrite(batches); return superBatch.ExecuteAsync(cancellationToken); diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs index 5b49fdbd525f..35faea1bba77 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_async/IDynamoDBContext.Async.cs @@ -422,7 +422,7 @@ partial interface IDynamoDBContext /// /// Token which can be used to cancel the task. /// A Task that can be used to poll or wait for results, or both. - Task ExecuteBatchWriteAsync(BatchWrite[] batches, CancellationToken cancellationToken = default(CancellationToken)); + Task ExecuteBatchWriteAsync(IBatchWrite[] batches, CancellationToken cancellationToken = default(CancellationToken)); #endregion diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/BatchWrite.Sync.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/BatchWrite.Sync.cs index e1da85c60993..68da3b2737fd 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/BatchWrite.Sync.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/BatchWrite.Sync.cs @@ -13,56 +13,51 @@ * permissions and limitations under the License. */ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using Amazon.DynamoDBv2.Model; -using Amazon.DynamoDBv2.DocumentModel; - namespace Amazon.DynamoDBv2.DataModel { - /// - /// Represents a non-generic object for writing/deleting a batch of items - /// in a single DynamoDB table - /// - public abstract partial class BatchWrite + public partial interface IBatchWrite { - #region Public methods - /// /// Executes a server call to batch-write/delete the items requested. /// /// If more than 25 put/delete operations are specified, calls of up to 25 /// put/delete items will be made until all items are processed. /// - public void Execute() + void Execute(); + } + + public abstract partial class BatchWrite : IBatchWrite + { + /// + public abstract void Execute(); + } + + public partial class BatchWrite : BatchWrite, IBatchWrite + { + /// + public override void Execute() { ExecuteHelper(); } - - #endregion } - /// - /// Class for writing/deleting a batch of items in multiple DynamoDB tables, - /// using multiple strongly-typed BatchWrite objects - /// - public partial class MultiTableBatchWrite + public partial interface IMultiTableBatchWrite { - #region Public methods - /// /// Executes a multi-table batch request against all configured batches. /// /// If more than 25 put/delete operations are specified, calls of up to 25 /// put/delete items will be made until all items are processed. /// + void Execute(); + } + + public partial class MultiTableBatchWrite : IMultiTableBatchWrite + { + /// public void Execute() { ExecuteHelper(); } - - #endregion } } diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/Context.Sync.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/Context.Sync.cs index a53c03bbb1fa..ea57d246b026 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/Context.Sync.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/Context.Sync.cs @@ -195,13 +195,8 @@ public void ExecuteTransactGet(params TransactGet[] transactionParts) #region Batch Write - /// - /// Issues a batch-write request with multiple batches. - /// - /// - /// Configured BatchWrite objects - /// - public void ExecuteBatchWrite(params BatchWrite[] batches) + /// + public void ExecuteBatchWrite(params IBatchWrite[] batches) { MultiTableBatchWrite superBatch = new MultiTableBatchWrite(batches); superBatch.Execute(); diff --git a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/IDynamoDBContext.Sync.cs b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/IDynamoDBContext.Sync.cs index 3ddc517527b8..eb6e2c58cb9b 100644 --- a/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/IDynamoDBContext.Sync.cs +++ b/sdk/src/Services/DynamoDBv2/Custom/DataModel/_bcl/IDynamoDBContext.Sync.cs @@ -13,6 +13,7 @@ * permissions and limitations under the License. */ +using System; using System.Collections.Generic; using Amazon.DynamoDBv2.DocumentModel; @@ -351,7 +352,7 @@ partial interface IDynamoDBContext /// /// Configured BatchWrite objects /// - void ExecuteBatchWrite(params BatchWrite[] batches); + void ExecuteBatchWrite(params IBatchWrite[] batches); #endregion diff --git a/sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/BatchGetTests.cs b/sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/BatchGetTests.cs index 7d7ce4df13f1..a739c29a53fc 100644 --- a/sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/BatchGetTests.cs +++ b/sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/BatchGetTests.cs @@ -13,7 +13,7 @@ public void TestMockability_BatchGet() { var mockContext = new Mock(); mockContext - .Setup(x => x.CreateBatchGet
(It.IsAny())) + .Setup(x => x.CreateBatchGet
()) .Returns(CreateBatchGetMock(new List
() { { new Address() { State = "CA", Zip = "12345" }} diff --git a/sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/BatchWriteTests.cs b/sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/BatchWriteTests.cs new file mode 100644 index 000000000000..86cd83e428be --- /dev/null +++ b/sdk/test/Services/DynamoDBv2/UnitTests/Custom/MockabilityTests/BatchWriteTests.cs @@ -0,0 +1,121 @@ +using Amazon.DynamoDBv2.DataModel; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using System.Collections.Generic; + +namespace AWSSDK.UnitTests.DynamoDBv2.NetFramework.Custom.MockabilityTests +{ + [TestClass] + public class BatchWriteTests + { + [TestMethod] + public void TestMockability_BatchWrite() + { + var itemsToPut = new List(); + var inMemoryTable = new List(); + + var mockContext = new Mock(); + mockContext + .Setup(x => x.CreateBatchWrite()) + .Returns(CreateBatchWriteMock(itemsToPut, inMemoryTable)); + + var ddbContext = mockContext.Object; + var batchWrite = ddbContext.CreateBatchWrite(); + + Assert.AreEqual(0, inMemoryTable.Count); + Assert.AreEqual(0, itemsToPut.Count); + + batchWrite.AddPutItem("item1"); + batchWrite.AddPutItem("item2"); + Assert.AreEqual(2, itemsToPut.Count); + Assert.AreEqual(0, inMemoryTable.Count); + + batchWrite.Execute(); + Assert.AreEqual(0, itemsToPut.Count); + Assert.AreEqual(2, inMemoryTable.Count); + Assert.IsTrue(inMemoryTable.Contains("item1")); + Assert.IsTrue(inMemoryTable.Contains("item2")); + } + + [TestMethod] + public void TestMockability_MultiTableBatchWrite() + { + var itemsToPut_table1 = new List(); + var inMemory_table1 = new List(); + var batchWrite_table1 = CreateBatchWriteMock(itemsToPut_table1, inMemory_table1); + batchWrite_table1.AddPutItem("item1"); + + var itemsToPut_table2 = new List(); + var inMemory_table2 = new List(); + var batchWrite_table2 = CreateBatchWriteMock(itemsToPut_table2, inMemory_table2); + batchWrite_table2.AddPutItem("item2"); + + var mockContext = new Mock(); + mockContext + .Setup(x => x.CreateMultiTableBatchWrite()) + .Returns(CreateMultiTableBatchWriteMock()); + + var ddbContext = mockContext.Object; + var multiBatchWrite = ddbContext.CreateMultiTableBatchWrite(); + multiBatchWrite.AddBatch(batchWrite_table1); + multiBatchWrite.AddBatch(batchWrite_table2); + + Assert.AreEqual(0, inMemory_table1.Count); + Assert.AreEqual(0, inMemory_table2.Count); + + multiBatchWrite.Execute(); + Assert.AreEqual(1, inMemory_table1.Count); + Assert.AreEqual(1, inMemory_table2.Count); + Assert.IsTrue(inMemory_table1.Contains("item1")); + Assert.IsTrue(inMemory_table2.Contains("item2")); + } + + public IBatchWrite CreateBatchWriteMock(List itemsToPut, List inMemoryTable) + { + var batchWrite = new Mock>(); + + batchWrite + .Setup(x => x.AddPutItem(It.IsAny())) + .Callback((T item) => itemsToPut.Add(item)); + + batchWrite. + Setup(x => x.Execute()) + .Callback(() => + { + foreach (var item in itemsToPut) + { + inMemoryTable.Add(item); + } + + itemsToPut.Clear(); + }); + + return batchWrite.Object; + } + + public IMultiTableBatchWrite CreateMultiTableBatchWriteMock() + { + var multiBatchWrite = new Mock(); + var batches = new List(); + + multiBatchWrite + .Setup(x => x.AddBatch(It.IsAny())) + .Callback((IBatchWrite batch) => + { + batches.Add(batch); + }); + + multiBatchWrite + .Setup(x => x.Execute()) + .Callback(() => + { + foreach (var batch in batches) + { + batch.Execute(); + } + }); + + return multiBatchWrite.Object; + } + } +}