private async Task Server_MetricsAreEmitted(MessageType messageType) { // There are several invariants around metrics that involve cross-request and cross-connection state. // Bring up a service, connect to it several times, and make several requests each time. const string expectedServiceName = "unittest.comm.DummyTest"; string expectedMethodName; Action<DummyTestProxy<EpoxyConnection>> doRpc; switch (messageType) { case MessageType.REQUEST: expectedMethodName = "ReqRspMethod"; doRpc = async proxy => await proxy.ReqRspMethodAsync(new Dummy()); break; case MessageType.EVENT: expectedMethodName = "EventMethod"; doRpc = proxy => proxy.EventMethodAsync(new Dummy()); break; default: throw new ArgumentException(nameof(messageType)); } var metricsSink = new TestMetricsSink(); var serverTransport = new EpoxyTransportBuilder().SetMetricsSink(metricsSink).Construct(); var listener = serverTransport.MakeListener("127.0.0.1"); listener.AddService(new DummyTestService()); await listener.StartAsync(); var serverEndpoint = listener.ListenEndpoint.ToString(); var connectionsSeen = 0; var requestsSeen = 0; var connectionIdsSeen = new HashSet<string>(); var requestIdsSeen = new HashSet<string>(); for (var i = 0; i < 3; i++) { var clientTransport = new EpoxyTransportBuilder().Construct(); var clientConn = await clientTransport.ConnectToAsync("epoxy://127.0.0.1"); var clientEndpoint = clientConn.LocalEndPoint.ToString(); var proxy = new DummyTestProxy<EpoxyConnection>(clientConn); string currentConnectionId = null; for (var j = 0; j < 3; j++) { doRpc(proxy); WaitForMetrics(); Assert.AreEqual(requestsSeen + 1, metricsSink.RequestMetricsReceived, "Did not get a RequestMetrics."); Assert.NotNull(metricsSink.LastRequestMetrics); var requestMetrics = metricsSink.LastRequestMetrics; // The new RequestMetrics should have non-empty unique IDs. The request ID should be unique // and the connection ID should match that of any requests previously made on this connection. AssertValidId(requestMetrics.request_id); AssertValidId(requestMetrics.connection_id); CollectionAssert.DoesNotContain(requestIdsSeen, requestMetrics.request_id, "Got two RequestMetrics with the same request ID."); requestIdsSeen.Add(requestMetrics.request_id); if (currentConnectionId == null) { currentConnectionId = requestMetrics.connection_id; } else { Assert.AreEqual(currentConnectionId, requestMetrics.connection_id, "Got two different connection IDs in RequestMetrics for the same connection."); } Assert.AreEqual(serverEndpoint, requestMetrics.local_endpoint); Assert.AreEqual(clientEndpoint, requestMetrics.remote_endpoint); Assert.AreEqual(expectedServiceName, requestMetrics.service_name); Assert.AreEqual(expectedMethodName, requestMetrics.method_name); Assert.Null(requestMetrics.error); Assert.Greater(requestMetrics.total_time_millis, 0.0); Assert.Greater(requestMetrics.service_method_time_millis, 0.0); Assert.Greater(requestMetrics.total_time_millis, requestMetrics.service_method_time_millis); requestsSeen++; } // We're still connected, so there shouldn't be any new connection metrics. Assert.AreEqual(connectionsSeen, metricsSink.ConnectionMetricsReceived); await clientConn.StopAsync(); WaitForMetrics(); Assert.AreEqual(connectionsSeen + 1, metricsSink.ConnectionMetricsReceived); Assert.NotNull(metricsSink.LastConnectionMetrics); var connectionMetrics = metricsSink.LastConnectionMetrics; AssertValidId(connectionMetrics.connection_id); // The connection ID in the new ConnectionMetrics must match the one seen by the requests. Assert.AreEqual(currentConnectionId, connectionMetrics.connection_id, "Got a different connection IDs in ConnectionMetrics and this connection's RequestMetrics."); CollectionAssert.DoesNotContain(connectionIdsSeen, connectionMetrics.connection_id, "Got two different ConnectionMetrics with the same connection ID."); connectionIdsSeen.Add(connectionMetrics.connection_id); Assert.AreEqual(serverEndpoint, connectionMetrics.local_endpoint); Assert.AreEqual(clientEndpoint, connectionMetrics.remote_endpoint); Assert.Greater(connectionMetrics.duration_millis, 0.0); connectionsSeen++; } await listener.StopAsync(); }