Skip to content

Commit 85971c9

Browse files
committed
More Tracing
1 parent 098705a commit 85971c9

19 files changed

Lines changed: 1532 additions & 81 deletions

src/TurboHTTP.StreamTests/Http10/Http10ConnectionStageSpec.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ public async Task Http10ConnectionStage_should_encode_request_and_emit_on_networ
6464
return ClosedShape.Instance;
6565
})).Run(Materializer);
6666

67-
var netSubscription = await networkSub.ExpectSubscriptionAsync();
68-
var resSubscription = await responseSub.ExpectSubscriptionAsync();
69-
var appSubscription = await appProbe.ExpectSubscriptionAsync();
70-
var serverSubscription = await serverProbe.ExpectSubscriptionAsync();
67+
var netSubscription = await networkSub.ExpectSubscriptionAsync(TestContext.Current.CancellationToken);
68+
var resSubscription = await responseSub.ExpectSubscriptionAsync(TestContext.Current.CancellationToken);
69+
var appSubscription = await appProbe.ExpectSubscriptionAsync(TestContext.Current.CancellationToken);
70+
var serverSubscription = await serverProbe.ExpectSubscriptionAsync(TestContext.Current.CancellationToken);
7171

7272
// Pull on network outlet to signal demand
7373
netSubscription.Request(10);
@@ -77,10 +77,10 @@ public async Task Http10ConnectionStage_should_encode_request_and_emit_on_networ
7777
appSubscription.SendNext(MakeRequest("/test"));
7878

7979
// Should get StreamAcquireItem + NetworkBuffer on network outlet
80-
var item1 = await networkSub.ExpectNextAsync();
80+
var item1 = await networkSub.ExpectNextAsync(TestContext.Current.CancellationToken);
8181
Assert.IsType<StreamAcquireItem>(item1);
8282

83-
var item2 = await networkSub.ExpectNextAsync();
83+
var item2 = await networkSub.ExpectNextAsync(TestContext.Current.CancellationToken);
8484
var buffer = Assert.IsType<NetworkBuffer>(item2);
8585
var encoded = Encoding.ASCII.GetString(buffer.Span);
8686
Assert.StartsWith("GET /test HTTP/1.0\r\n", encoded);
@@ -114,10 +114,10 @@ public async Task Http10ConnectionStage_should_decode_response_and_correlate_wit
114114
return ClosedShape.Instance;
115115
})).Run(Materializer);
116116

117-
var netSubscription = await networkSub.ExpectSubscriptionAsync();
118-
var resSubscription = await responseSub.ExpectSubscriptionAsync();
119-
var appSubscription = await appProbe.ExpectSubscriptionAsync();
120-
var serverSubscription = await serverProbe.ExpectSubscriptionAsync();
117+
var netSubscription = await networkSub.ExpectSubscriptionAsync(TestContext.Current.CancellationToken);
118+
var resSubscription = await responseSub.ExpectSubscriptionAsync(TestContext.Current.CancellationToken);
119+
var appSubscription = await appProbe.ExpectSubscriptionAsync(TestContext.Current.CancellationToken);
120+
var serverSubscription = await serverProbe.ExpectSubscriptionAsync(TestContext.Current.CancellationToken);
121121

122122
netSubscription.Request(10);
123123
resSubscription.Request(10);

src/TurboHTTP.StreamTests/Http3/Http30Request2FrameBackpressureSpec.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ public async Task Http30Request2Frame_should_process_multiple_requests_when_enco
9797

9898
// Push second request — frame outlet should still work.
9999
reqSub.SendNext(MakeRequest("/second"));
100-
await frameOut.ExpectNextAsync(TimeSpan.FromSeconds(3));
100+
await frameOut.ExpectNextAsync(TimeSpan.FromSeconds(3), TestContext.Current.CancellationToken);
101101

102102
// Push third request — still flowing.
103103
reqSub.SendNext(MakeRequest("/third"));
104-
await frameOut.ExpectNextAsync(TimeSpan.FromSeconds(3));
104+
await frameOut.ExpectNextAsync(TimeSpan.FromSeconds(3), TestContext.Current.CancellationToken);
105105
}
106106

107107
[Fact(Timeout = 10_000)]
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System.Diagnostics;
2+
using TurboHTTP.Diagnostics;
3+
4+
namespace TurboHTTP.Tests.Diagnostics;
5+
6+
[Collection("OTEL")]
7+
public sealed class TurboHttpDiagnosticSourceSpec : IDisposable
8+
{
9+
private readonly List<KeyValuePair<string, object?>> _events = [];
10+
private readonly IDisposable _subscription;
11+
12+
public TurboHttpDiagnosticSourceSpec()
13+
{
14+
var observer = new TestObserver(_events);
15+
_subscription = DiagnosticListener.AllListeners.Subscribe(new TestListenerObserver(observer));
16+
}
17+
18+
public void Dispose()
19+
{
20+
_subscription.Dispose();
21+
}
22+
23+
[Fact]
24+
public void ListenerName_should_be_TurboHTTP()
25+
{
26+
Assert.Equal("TurboHTTP", TurboHttpDiagnosticSource.ListenerName);
27+
}
28+
29+
[Fact]
30+
public void OnRequestStart_should_emit_event()
31+
{
32+
var request = new HttpRequestMessage(HttpMethod.Get, "https://example.com/");
33+
34+
TurboHttpDiagnosticSource.OnRequestStart(request);
35+
36+
var evt = _events.FirstOrDefault(e => e.Key == "TurboHTTP.HttpRequestOut.Start");
37+
Assert.NotNull(evt.Value);
38+
}
39+
40+
[Fact]
41+
public void OnRequestStop_should_emit_event()
42+
{
43+
var request = new HttpRequestMessage(HttpMethod.Get, "https://example.com/");
44+
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
45+
46+
TurboHttpDiagnosticSource.OnRequestStop(request, response, TaskStatus.RanToCompletion);
47+
48+
var evt = _events.FirstOrDefault(e => e.Key == "TurboHTTP.HttpRequestOut.Stop");
49+
Assert.NotNull(evt.Value);
50+
}
51+
52+
[Fact]
53+
public void OnException_should_emit_event()
54+
{
55+
var request = new HttpRequestMessage(HttpMethod.Get, "https://example.com/");
56+
var exception = new HttpRequestException("Connection refused");
57+
58+
TurboHttpDiagnosticSource.OnException(request, exception);
59+
60+
var evt = _events.FirstOrDefault(e => e.Key == "TurboHTTP.Exception");
61+
Assert.NotNull(evt.Value);
62+
}
63+
64+
private sealed class TestListenerObserver(TestObserver inner) : IObserver<DiagnosticListener>
65+
{
66+
public void OnNext(DiagnosticListener value)
67+
{
68+
if (value.Name == TurboHttpDiagnosticSource.ListenerName)
69+
{
70+
value.Subscribe(inner);
71+
}
72+
}
73+
74+
public void OnError(Exception error) { }
75+
public void OnCompleted() { }
76+
}
77+
78+
private sealed class TestObserver(List<KeyValuePair<string, object?>> events)
79+
: IObserver<KeyValuePair<string, object?>>
80+
{
81+
public void OnNext(KeyValuePair<string, object?> value) => events.Add(value);
82+
public void OnError(Exception error) { }
83+
public void OnCompleted() { }
84+
}
85+
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
using System.Diagnostics.Tracing;
2+
using TurboHTTP.Diagnostics;
3+
4+
namespace TurboHTTP.Tests.Diagnostics;
5+
6+
public sealed class TurboHttpEventSourceSpec : IDisposable
7+
{
8+
private readonly TestEventListener _listener;
9+
10+
public TurboHttpEventSourceSpec()
11+
{
12+
_listener = new TestEventListener();
13+
_listener.EnableEvents(TurboHttpEventSource.Instance, EventLevel.Verbose, EventKeywords.All);
14+
}
15+
16+
public void Dispose()
17+
{
18+
_listener.Dispose();
19+
}
20+
21+
[Fact]
22+
public void EventSource_should_have_correct_name()
23+
{
24+
Assert.Equal("TurboHTTP", TurboHttpEventSource.Instance.Name);
25+
}
26+
27+
[Fact]
28+
public void RequestStart_should_emit_event()
29+
{
30+
TurboHttpEventSource.Instance.RequestStart("GET", "https://example.com/");
31+
32+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 1);
33+
Assert.NotNull(evt);
34+
Assert.Equal("GET", evt.Payload?[0]);
35+
}
36+
37+
[Fact]
38+
public void RequestStop_should_emit_event()
39+
{
40+
TurboHttpEventSource.Instance.RequestStop("GET", 200, 42.5);
41+
42+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 2);
43+
Assert.NotNull(evt);
44+
Assert.Equal(200, evt.Payload?[1]);
45+
}
46+
47+
[Fact]
48+
public void RequestFailed_should_emit_event()
49+
{
50+
TurboHttpEventSource.Instance.RequestFailed("GET", "https://example.com/", "HttpRequestException");
51+
52+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 3);
53+
Assert.NotNull(evt);
54+
Assert.Equal("HttpRequestException", evt.Payload?[2]);
55+
}
56+
57+
[Fact]
58+
public void ConnectionStart_should_emit_event()
59+
{
60+
TurboHttpEventSource.Instance.ConnectionStart("example.com", 443);
61+
62+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 10);
63+
Assert.NotNull(evt);
64+
Assert.Equal("example.com", evt.Payload?[0]);
65+
}
66+
67+
[Fact]
68+
public void ConnectionStop_should_emit_event()
69+
{
70+
TurboHttpEventSource.Instance.ConnectionStop("example.com", 443, 1234.5);
71+
72+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 11);
73+
Assert.NotNull(evt);
74+
}
75+
76+
[Fact]
77+
public void DnsLookupStart_should_emit_event()
78+
{
79+
TurboHttpEventSource.Instance.DnsLookupStart("example.com");
80+
81+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 20);
82+
Assert.NotNull(evt);
83+
Assert.Equal("example.com", evt.Payload?[0]);
84+
}
85+
86+
[Fact]
87+
public void DnsLookupStop_should_emit_event()
88+
{
89+
TurboHttpEventSource.Instance.DnsLookupStop("example.com", 5.2);
90+
91+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 21);
92+
Assert.NotNull(evt);
93+
}
94+
95+
[Fact]
96+
public void TlsHandshakeStart_should_emit_event()
97+
{
98+
TurboHttpEventSource.Instance.TlsHandshakeStart("example.com");
99+
100+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 30);
101+
Assert.NotNull(evt);
102+
}
103+
104+
[Fact]
105+
public void TlsHandshakeStop_should_emit_event()
106+
{
107+
TurboHttpEventSource.Instance.TlsHandshakeStop("example.com", 15.3);
108+
109+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 31);
110+
Assert.NotNull(evt);
111+
}
112+
113+
[Fact]
114+
public void Redirect_should_emit_event()
115+
{
116+
TurboHttpEventSource.Instance.Redirect(301, "https://example.com/new");
117+
118+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 40);
119+
Assert.NotNull(evt);
120+
}
121+
122+
[Fact]
123+
public void RetryAttempt_should_emit_event()
124+
{
125+
TurboHttpEventSource.Instance.RetryAttempt(2);
126+
127+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 50);
128+
Assert.NotNull(evt);
129+
Assert.Equal(2, evt.Payload?[0]);
130+
}
131+
132+
[Fact]
133+
public void CacheHit_should_emit_event()
134+
{
135+
TurboHttpEventSource.Instance.CacheHit("https://example.com/cached");
136+
137+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 60);
138+
Assert.NotNull(evt);
139+
}
140+
141+
[Fact]
142+
public void CacheMiss_should_emit_event()
143+
{
144+
TurboHttpEventSource.Instance.CacheMiss("https://example.com/uncached");
145+
146+
var evt = _listener.Events.FirstOrDefault(e => e.EventId == 61);
147+
Assert.NotNull(evt);
148+
}
149+
150+
private sealed class TestEventListener : EventListener
151+
{
152+
public List<EventWrittenEventArgs> Events { get; } = [];
153+
154+
protected override void OnEventWritten(EventWrittenEventArgs eventData)
155+
{
156+
Events.Add(eventData);
157+
}
158+
}
159+
}

0 commit comments

Comments
 (0)