feat: add bounded process metrics and private monitoring endpoint
This commit is contained in:
93
internal/observability/http_test.go
Normal file
93
internal/observability/http_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package observability
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coder/websocket"
|
||||
)
|
||||
|
||||
func TestWebSocketHandshakeIsNotConnectionLifetime(t *testing.T) {
|
||||
r := NewRegistry()
|
||||
released := make(chan struct{})
|
||||
done := make(chan struct{})
|
||||
h := r.Middleware(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
defer close(done)
|
||||
c, err := websocket.Accept(w, req, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer c.CloseNow()
|
||||
<-released
|
||||
}))
|
||||
server := httptest.NewTLSServer(h)
|
||||
defer server.Close()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
c, _, err := websocket.Dial(ctx, strings.Replace(server.URL, "https://", "wss://", 1)+"/v1/worker/connect", &websocket.DialOptions{HTTPClient: server.Client()})
|
||||
if err != nil {
|
||||
close(released)
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.CloseNow()
|
||||
// Dial returns after the upgrade response, while the server handler stays open.
|
||||
deadline := time.Now().Add(time.Second)
|
||||
for !strings.Contains(r.Render(), `orbit_websocket_connections{route="worker_connect"} 1`) {
|
||||
if time.Now().After(deadline) {
|
||||
close(released)
|
||||
t.Fatal("upgrade not observed")
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
out := r.Render()
|
||||
close(released)
|
||||
<-done
|
||||
if !strings.Contains(out, `orbit_http_requests_total{method="GET",route="worker_connect",status_class="1xx"} 1`) || !strings.Contains(out, "orbit_http_requests_in_flight 0\n") {
|
||||
t.Fatal("upgrade counted as unfinished HTTP")
|
||||
}
|
||||
// done closes inside the handler; wait for middleware's defer to publish closure.
|
||||
deadline = time.Now().Add(time.Second)
|
||||
for !strings.Contains(r.Render(), `orbit_websocket_connections{route="worker_connect"} 0`) {
|
||||
if time.Now().After(deadline) {
|
||||
t.Fatal("connection gauge leaked")
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
if !strings.Contains(r.Render(), `orbit_http_requests_total{method="GET",route="worker_connect",status_class="1xx"} 1`) {
|
||||
t.Fatal("upgrade counted twice")
|
||||
}
|
||||
}
|
||||
func TestInformationalResponseAndStreamingPreserveHTTP(t *testing.T) {
|
||||
r := NewRegistry()
|
||||
server := httptest.NewServer(r.Middleware(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(103)
|
||||
w.WriteHeader(201)
|
||||
_, _ = io.WriteString(w, "first")
|
||||
if err := http.NewResponseController(w).Flush(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, _ = io.WriteString(w, "second")
|
||||
})))
|
||||
defer server.Close()
|
||||
resp, err := server.Client().Get(server.URL + "/v1/tasks")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil || resp.StatusCode != 201 || string(body) != "firstsecond" {
|
||||
t.Fatal("wrapper changed HTTP response", resp.StatusCode, err)
|
||||
}
|
||||
deadline := time.Now().Add(time.Second)
|
||||
for !strings.Contains(r.Render(), `route="tasks",status_class="2xx"} 1`) {
|
||||
if time.Now().After(deadline) {
|
||||
t.Fatal("103 blocked final status metric")
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user