Cross Compile Go / build (push) Canceled after 0s
- embedded React admin UI at /admin/ui (go:embed), login with ADMIN_SECRET via signed HttpOnly session cookie, X-ADMIN-KEY still works for scripts - admin API: overview stats, indexing queue, addon management (priority, reindex, delete/restore/purge, bulk), whitelist CRUD, duplicate hashes, traffic, metrics explorer, services, events/audit log, system info - built-in metrics: request latency per route, visitors, top addons and searches, indexer/scraper counters; minute buckets in the DB with hourly rollups and retention; optional Prometheus /metrics (METRICS_TOKEN) - POST /back/telemetry for indexers/scrapers (metrics, events, heartbeat) and a stdlib-only Go client in telemetry/ - auth hardening: empty secrets no longer allow access, constant-time compare, CORS not applied to /admin and /back, TRUSTED_PROXIES setting - Dockerfile builds the UI and no longer bakes config.yaml into the image; CI builds the UI, runs tests and builds arm64 with CGO
74 lines
1.8 KiB
Go
74 lines
1.8 KiB
Go
package telemetry
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"sync/atomic"
|
|
"testing"
|
|
)
|
|
|
|
func TestFlushAndRetry(t *testing.T) {
|
|
var fail atomic.Bool
|
|
var got []batch
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/back/telemetry" || r.Header.Get("X-SECRET-KEY") != "k" {
|
|
w.WriteHeader(http.StatusForbidden)
|
|
return
|
|
}
|
|
if fail.Load() {
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
return
|
|
}
|
|
body, _ := io.ReadAll(r.Body)
|
|
var b batch
|
|
if err := json.Unmarshal(body, &b); err != nil {
|
|
t.Error(err)
|
|
}
|
|
got = append(got, b)
|
|
w.Write([]byte(`{"accepted":1}`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := New(Config{BaseURL: srv.URL + "/", SecretKey: "k", Service: "indexer", Instance: "i1"})
|
|
c.Counter("jobs_total", "result", "ok").Add(2)
|
|
c.Gauge("queue").Set(7)
|
|
c.Summary("took_seconds").Observe(1)
|
|
c.Summary("took_seconds").Observe(3)
|
|
c.Event(Warn, "hello", nil)
|
|
|
|
fail.Store(true)
|
|
if err := c.Flush(context.Background()); err == nil {
|
|
t.Fatal("expected an error while the server fails")
|
|
}
|
|
c.Counter("jobs_total", "result", "ok").Add(1)
|
|
|
|
fail.Store(false)
|
|
if err := c.Flush(context.Background()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(got) != 2 {
|
|
t.Fatalf("got %d batches, want the retried one plus the new one", len(got))
|
|
}
|
|
first := got[0]
|
|
if first.Service != "indexer" || first.Instance != "i1" || len(first.Events) != 1 {
|
|
t.Fatalf("unexpected first batch %+v", first)
|
|
}
|
|
var sum float64
|
|
for _, b := range got {
|
|
for _, m := range b.Metrics {
|
|
if m.Name == "jobs_total" {
|
|
sum += m.Value
|
|
}
|
|
if m.Name == "took_seconds" && (m.Count != 2 || m.Min != 1 || m.Max != 3) {
|
|
t.Fatalf("bad summary %+v", m)
|
|
}
|
|
}
|
|
}
|
|
if sum != 3 {
|
|
t.Fatalf("counter total = %v, want 3", sum)
|
|
}
|
|
}
|