|
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
| 3 | +using System.Reflection; |
3 | 4 | using System.Threading.Tasks; |
4 | 5 | using AWS.Lambda.Powertools.Metrics; |
5 | 6 | using Xunit; |
@@ -281,6 +282,61 @@ public async Task AddMetric_ConcurrentModificationDuringIteration_ShouldHandleAr |
281 | 282 | CleanupMetrics(); |
282 | 283 | } |
283 | 284 |
|
| 285 | + [Fact] |
| 286 | + public void GetExistingMetric_ArgumentOutOfRangeException_ShouldReturnNull() |
| 287 | + { |
| 288 | + // Arrange - Use reflection to test the private GetExistingMetric method directly |
| 289 | + var getExistingMetricMethod = typeof(Metrics).GetMethod("GetExistingMetric", |
| 290 | + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); |
| 291 | + |
| 292 | + Assert.NotNull(getExistingMetricMethod); |
| 293 | + |
| 294 | + // Create a custom list that will throw ArgumentOutOfRangeException |
| 295 | + var metricsList = new TestMetricsList(); |
| 296 | + metricsList.Add(new MetricDefinition("TestMetric", MetricUnit.Count, new List<double> { 1.0 }, MetricResolution.Default)); |
| 297 | + |
| 298 | + // Act - Call the private method via reflection, searching for a different key |
| 299 | + // This will cause the method to iterate and hit the indexer that throws ArgumentOutOfRangeException |
| 300 | + var result = getExistingMetricMethod.Invoke(null, new object[] { metricsList, "NonExistentMetric" }); |
| 301 | + |
| 302 | + // Assert - Should return null when ArgumentOutOfRangeException is caught |
| 303 | + Assert.Null(result); |
| 304 | + } |
| 305 | + |
| 306 | + /// <summary> |
| 307 | + /// Custom list that throws ArgumentOutOfRangeException on indexer access |
| 308 | + /// to simulate the race condition scenario |
| 309 | + /// </summary> |
| 310 | + private class TestMetricsList : List<MetricDefinition> |
| 311 | + { |
| 312 | + private bool _shouldThrow = false; |
| 313 | + |
| 314 | + public new int Count |
| 315 | + { |
| 316 | + get |
| 317 | + { |
| 318 | + // Return 1 initially, but set flag to throw on indexer access |
| 319 | + _shouldThrow = true; |
| 320 | + return base.Count; |
| 321 | + } |
| 322 | + } |
| 323 | + |
| 324 | + public new MetricDefinition this[int index] |
| 325 | + { |
| 326 | + get |
| 327 | + { |
| 328 | + if (_shouldThrow) |
| 329 | + { |
| 330 | + // Throw ArgumentOutOfRangeException to simulate the race condition |
| 331 | + // where collection was modified between Count check and indexer access |
| 332 | + throw new ArgumentOutOfRangeException(nameof(index), "Simulated race condition"); |
| 333 | + } |
| 334 | + return base[index]; |
| 335 | + } |
| 336 | + set => base[index] = value; |
| 337 | + } |
| 338 | + } |
| 339 | + |
284 | 340 | /// <summary> |
285 | 341 | /// Cleanup method to ensure no state leaks between tests |
286 | 342 | /// </summary> |
|
0 commit comments