@@ -184,34 +184,55 @@ public void OnMeasurementRecorded_WhenMeterNameDoesNotMatch_ShouldStillNotThrow(
184184 // Assert
185185 act . Should ( ) . NotThrow ( ) ;
186186 }
187+
187188 [ Fact ]
188189 public async Task OnMeasurementRecorded_WithCloudWatchClient_ShouldPutMetricData ( )
189190 {
190191 // Arrange
192+ var guid = Guid . NewGuid ( ) . ToString ( "N" ) ;
193+ var uniqueMetricName = $ "test_cloudwatch_success_{ guid } ";
194+
191195 var mockCloudWatch = new Mock < IAmazonCloudWatch > ( ) ;
192196 mockCloudWatch . Setup ( c => c . PutMetricDataAsync ( It . IsAny < PutMetricDataRequest > ( ) , It . IsAny < CancellationToken > ( ) ) )
193197 . ReturnsAsync ( new PutMetricDataResponse { HttpStatusCode = System . Net . HttpStatusCode . OK } ) ;
194198
195199 EmfExporter . Init ( _mockLogger . Object , "test-namespace" , mockCloudWatch . Object ) ;
196200
197201 using var meter = new Meter ( MetricNames . MeterName ) ;
198- var counter = meter . CreateCounter < long > ( "test_cloudwatch_counter" ) ;
199-
200- var tags = new TagList { { "test_key" , "test_value" } } ;
202+ var counter = meter . CreateCounter < long > ( uniqueMetricName ) ;
201203
202204 // Act
203- counter . Add ( 1 , tags ) ;
204- await Task . Delay ( 200 ) ;
205+ counter . Add ( 1 , new KeyValuePair < string , object ? > ( "test_key" , "test_value" ) ) ;
205206
206- // Assert
207- mockCloudWatch . Verify ( c => c . PutMetricDataAsync (
208- It . Is < PutMetricDataRequest > ( r =>
209- r . Namespace == "test-namespace" &&
210- r . MetricData . Count == 1 &&
211- ! string . IsNullOrEmpty ( r . MetricData [ 0 ] . MetricName ) &&
212- r . MetricData [ 0 ] . Value == 1.0 &&
213- r . MetricData [ 0 ] . Dimensions . Any ( d => d . Name == "test_key" && d . Value == "test_value" )
214- ) , It . IsAny < CancellationToken > ( ) ) , Times . Once ) ;
207+ // Assert - Polling loop for CI runner safety
208+ bool metricSent = false ;
209+ for ( int i = 0 ; i < 50 ; i ++ )
210+ {
211+ await Task . Delay ( 100 ) ;
212+
213+ var invocations = mockCloudWatch . Invocations ;
214+ foreach ( var inv in invocations )
215+ {
216+ if ( inv . Method . Name != "PutMetricDataAsync" ) continue ;
217+
218+ var request = ( PutMetricDataRequest ) inv . Arguments [ 0 ] ;
219+
220+ // Verify the metric matches our unique Guid to avoid Humanizer casing bugs
221+ if ( request . Namespace == "test-namespace" &&
222+ request . MetricData . Count == 1 &&
223+ request . MetricData [ 0 ] . MetricName . Contains ( guid , StringComparison . OrdinalIgnoreCase ) &&
224+ request . MetricData [ 0 ] . Value == 1.0 &&
225+ request . MetricData [ 0 ] . Dimensions . Any ( d => d . Name == "test_key" && d . Value == "test_value" ) )
226+ {
227+ metricSent = true ;
228+ break ;
229+ }
230+ }
231+
232+ if ( metricSent ) break ;
233+ }
234+
235+ metricSent . Should ( ) . BeTrue ( "the metric should be successfully pushed to LocalStack CloudWatch" ) ;
215236 }
216237
217238
0 commit comments