/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/EqualPartitionsBalancingStrategyTests.cs

https://github.com/Azure/azure-cosmos-dotnet-v3 · C# · 216 lines · 191 code · 22 blank · 3 comment · 10 complexity · 9a752ed9f03ed7bb3f58066239dbc610 MD5 · raw file

  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace Microsoft.Azure.Cosmos.ChangeFeed.Tests
  5. {
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using Microsoft.Azure.Cosmos.ChangeFeed.FeedManagement;
  10. using Microsoft.Azure.Cosmos.ChangeFeed.LeaseManagement;
  11. using Microsoft.VisualStudio.TestTools.UnitTesting;
  12. using Moq;
  13. [TestClass]
  14. [TestCategory("ChangeFeed")]
  15. public class EqualPartitionsBalancingStrategyTests
  16. {
  17. private const string ownerSelf = "self";
  18. private const string owner1 = "owner 1";
  19. private const string owner2 = "owner 2";
  20. private const string ownerNone = null;
  21. [TestMethod]
  22. public void CalculateLeasesToTake_NoLeases_ReturnsEmpty()
  23. {
  24. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  25. IEnumerable<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(Enumerable.Empty<DocumentServiceLease>());
  26. Assert.IsTrue(leasesToTake.Count() == 0);
  27. }
  28. [TestMethod]
  29. public void CalculateLeasesToTake_OwnLeasesOnly_ReturnsEmpty()
  30. {
  31. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  32. IEnumerable<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(new[] { this.CreateLease(ownerSelf, "1"), this.CreateLease(ownerSelf, "2") });
  33. Assert.IsTrue(leasesToTake.Count() == 0);
  34. }
  35. [TestMethod]
  36. public void CalculateLeasesToTake_NotOwnedLeasesOnly_ReturnsAll()
  37. {
  38. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  39. HashSet<DocumentServiceLease> allLeases = new HashSet<DocumentServiceLease> { this.CreateLease(ownerNone, "1"), this.CreateLease(ownerNone, "2") };
  40. IEnumerable<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases);
  41. CollectionAssert.AreEqual(allLeases.ToList(), new HashSet<DocumentServiceLease>(leasesToTake).ToList());
  42. }
  43. [TestMethod]
  44. public void CalculateLeasesToTake_ExpiredLeasesOnly_ReturnsAll()
  45. {
  46. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  47. HashSet<DocumentServiceLease> allLeases = new HashSet<DocumentServiceLease> { this.CreateExpiredLease(ownerSelf, "1"), this.CreateExpiredLease(owner1, "2") };
  48. IEnumerable<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases);
  49. CollectionAssert.AreEqual(allLeases.ToList(), new HashSet<DocumentServiceLease>(leasesToTake).ToList());
  50. }
  51. [TestMethod]
  52. public void CalculateLeasesToTake_OtherSingleOwnerTwoLeasesOnly_ReturnsOne()
  53. {
  54. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  55. HashSet<DocumentServiceLease> allLeases = new HashSet<DocumentServiceLease> { this.CreateLease(owner1, "1"), this.CreateLease(owner1, "2") };
  56. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  57. Assert.IsTrue(leasesToTake.Count == 1);
  58. CollectionAssert.IsSubsetOf(new HashSet<DocumentServiceLease>(leasesToTake).ToList(), allLeases.ToList());
  59. }
  60. [TestMethod]
  61. public void CalculateLeasesToTake_ExpiredAndOtherOwner_ReturnsExpiredOnly()
  62. {
  63. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  64. DocumentServiceLease expiredLease = this.CreateExpiredLease(owner1, "4");
  65. HashSet<DocumentServiceLease> allLeases = new HashSet<DocumentServiceLease>
  66. {
  67. this.CreateLease(owner1, "1"),
  68. this.CreateLease(owner1, "2"),
  69. this.CreateLease(owner1, "3"),
  70. expiredLease
  71. };
  72. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  73. Assert.IsTrue(leasesToTake.Count == 1);
  74. CollectionAssert.Contains(leasesToTake, expiredLease);
  75. }
  76. [TestMethod]
  77. public void CalculateLeasesToTake_ExpiredAndOtherSingleOwner_ReturnsHalfOfExpiredRoundedUp()
  78. {
  79. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  80. List<DocumentServiceLease> allLeases1 = new List<DocumentServiceLease>();
  81. allLeases1.Add(this.CreateLease(owner1, "0"));
  82. allLeases1.AddRange(Enumerable.Range(1, 10).Select(index => this.CreateExpiredLease(owner1, index.ToString())));
  83. List<DocumentServiceLease> allLeases = allLeases1;
  84. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  85. Assert.AreEqual(6, leasesToTake.Count);
  86. }
  87. [TestMethod]
  88. public void CalculateLeasesToTake_MinPartitionsSet_ReturnsMinCountOfPartitions()
  89. {
  90. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy(minPartitionCount: 7);
  91. List<DocumentServiceLease> allLeases1 = new List<DocumentServiceLease>();
  92. allLeases1.Add(this.CreateLease(owner1, "0"));
  93. allLeases1.AddRange(Enumerable.Range(1, 10).Select(index => this.CreateExpiredLease(owner1, index.ToString())));
  94. List<DocumentServiceLease> allLeases = allLeases1;
  95. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  96. Assert.AreEqual(7, leasesToTake.Count);
  97. }
  98. [TestMethod]
  99. public void CalculateLeasesToTake_MaxPartitionsSet_ReturnsMaxCountOfPartitions()
  100. {
  101. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy(maxPartitionCount: 3);
  102. List<DocumentServiceLease> allLeases1 = new List<DocumentServiceLease>();
  103. allLeases1.Add(this.CreateLease(owner1, "0"));
  104. allLeases1.AddRange(Enumerable.Range(1, 10).Select(index => this.CreateExpiredLease(owner1, index.ToString())));
  105. List<DocumentServiceLease> allLeases = allLeases1;
  106. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  107. Assert.AreEqual(3, leasesToTake.Count);
  108. }
  109. [TestMethod]
  110. public void CalculateLeasesToTake_TwoOwners_ReturnsStolenFromLargerOwner()
  111. {
  112. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  113. List<DocumentServiceLease> allLeases = new List<DocumentServiceLease>();
  114. allLeases.AddRange(Enumerable.Range(1, 5).Select(index => this.CreateLease(owner1, "A" + index.ToString())));
  115. allLeases.AddRange(Enumerable.Range(1, 10).Select(index => this.CreateLease(owner2, "B" + index.ToString())));
  116. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  117. Assert.IsTrue(leasesToTake.Count == 1);
  118. Assert.IsTrue(leasesToTake.First().CurrentLeaseToken.StartsWith("B"));
  119. }
  120. [TestMethod]
  121. public void CalculateLeasesToTake_HavingMoreThanOtherOwner_ReturnsEmpty()
  122. {
  123. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  124. List<DocumentServiceLease> allLeases = new List<DocumentServiceLease>();
  125. allLeases.AddRange(Enumerable.Range(1, 5).Select(index => this.CreateLease(owner1, "A" + index.ToString())));
  126. allLeases.AddRange(Enumerable.Range(1, 6).Select(index => this.CreateLease(ownerSelf, "B" + index.ToString())));
  127. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  128. Assert.IsTrue(leasesToTake.Count == 0);
  129. }
  130. [TestMethod]
  131. public void CalculateLeasesToTake_HavingEqualThanOtherOwner_ReturnsEmpty()
  132. {
  133. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  134. List<DocumentServiceLease> allLeases = new List<DocumentServiceLease>();
  135. allLeases.AddRange(Enumerable.Range(1, 5).Select(index => this.CreateLease(owner1, "A" + index.ToString())));
  136. allLeases.AddRange(Enumerable.Range(1, 5).Select(index => this.CreateLease(ownerSelf, "B" + index.ToString())));
  137. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  138. Assert.IsTrue(leasesToTake.Count == 0);
  139. }
  140. [TestMethod]
  141. public void CalculateLeasesToTake_AllOtherOwnersEqualTargetCount_ReturnsEmpty()
  142. {
  143. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  144. List<DocumentServiceLease> allLeases = new List<DocumentServiceLease>();
  145. allLeases.AddRange(Enumerable.Range(1, 4).Select(index => this.CreateLease(owner1, "A" + index.ToString())));
  146. allLeases.AddRange(Enumerable.Range(1, 3).Select(index => this.CreateLease(ownerSelf, "B" + index.ToString())));
  147. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  148. Assert.IsTrue(leasesToTake.Count == 0);
  149. }
  150. [TestMethod]
  151. public void CalculateLeasesToTake_OtherOwnerGreaterThanTargetCount_ReturnsLease()
  152. {
  153. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  154. List<DocumentServiceLease> allLeases = new List<DocumentServiceLease>();
  155. allLeases.AddRange(Enumerable.Range(1, 4).Select(index => this.CreateLease(owner1, "A" + index.ToString())));
  156. allLeases.AddRange(Enumerable.Range(1, 2).Select(index => this.CreateLease(ownerSelf, "B" + index.ToString())));
  157. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  158. Assert.IsTrue(leasesToTake.Count == 1);
  159. Assert.IsTrue(leasesToTake.First().CurrentLeaseToken.StartsWith("A"));
  160. }
  161. [TestMethod]
  162. public void CalculateLeasesToTake_NeedTwoAndOtherOwnersEqualThanTargetCount_ReturnsLease()
  163. {
  164. EqualPartitionsBalancingStrategy strategy = this.CreateStrategy();
  165. List<DocumentServiceLease> allLeases = new List<DocumentServiceLease>();
  166. allLeases.AddRange(Enumerable.Range(1, 10).Select(index => this.CreateLease(owner1, "A" + index.ToString())));
  167. allLeases.AddRange(Enumerable.Range(1, 10).Select(index => this.CreateLease(owner2, "B" + index.ToString())));
  168. allLeases.AddRange(Enumerable.Range(1, 8).Select(index => this.CreateLease(ownerSelf, "C" + index.ToString())));
  169. List<DocumentServiceLease> leasesToTake = strategy.SelectLeasesToTake(allLeases).ToList();
  170. Assert.IsTrue(leasesToTake.Count == 1);
  171. }
  172. private EqualPartitionsBalancingStrategy CreateStrategy(int minPartitionCount = 0, int maxPartitionCount = 0)
  173. {
  174. TimeSpan leaseExpirationInterval = TimeSpan.FromMinutes(10);
  175. return new EqualPartitionsBalancingStrategy(ownerSelf, minPartitionCount, maxPartitionCount, leaseExpirationInterval);
  176. }
  177. private DocumentServiceLease CreateLease(string owner, string partitionId)
  178. {
  179. return CreateLease(owner, partitionId, DateTime.UtcNow);
  180. }
  181. private DocumentServiceLease CreateExpiredLease(string owner, string partitionId)
  182. {
  183. return CreateLease(owner, partitionId, DateTime.UtcNow.AddYears(-1));
  184. }
  185. private static DocumentServiceLease CreateLease(string owner, string partitionId, DateTime timestamp)
  186. {
  187. DocumentServiceLease lease = Mock.Of<DocumentServiceLease>();
  188. Mock.Get(lease).Setup(l => l.Owner).Returns(owner);
  189. Mock.Get(lease).Setup(l => l.CurrentLeaseToken).Returns(partitionId);
  190. Mock.Get(lease).Setup(l => l.Timestamp).Returns(timestamp);
  191. return lease;
  192. }
  193. }
  194. }