120 lines
2.9 KiB
Go
120 lines
2.9 KiB
Go
package analytics
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNoopClient(t *testing.T) {
|
|
c := NoopClient{}
|
|
c.Capture(Event{Name: "foo"})
|
|
c.Close()
|
|
}
|
|
|
|
func TestPostHogClient_Batching(t *testing.T) {
|
|
var (
|
|
mu sync.Mutex
|
|
received [][]captureItem
|
|
)
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/batch/" {
|
|
t.Errorf("unexpected path %s", r.URL.Path)
|
|
}
|
|
body, _ := io.ReadAll(r.Body)
|
|
var payload capturePayload
|
|
if err := json.Unmarshal(body, &payload); err != nil {
|
|
t.Errorf("decode payload: %v", err)
|
|
}
|
|
if payload.APIKey != "test-key" {
|
|
t.Errorf("api_key = %q, want test-key", payload.APIKey)
|
|
}
|
|
mu.Lock()
|
|
received = append(received, payload.Batch)
|
|
mu.Unlock()
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewPostHogClient(PostHogConfig{
|
|
APIKey: "test-key",
|
|
Host: srv.URL,
|
|
BatchSize: 2,
|
|
FlushEvery: time.Hour, // irrelevant, we hit the size trigger
|
|
})
|
|
|
|
c.Capture(Event{Name: "signup", DistinctID: "u1", WorkspaceID: "w1"})
|
|
c.Capture(Event{Name: "workspace_created", DistinctID: "u1", WorkspaceID: "w1"})
|
|
c.Close() // drains
|
|
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
total := 0
|
|
for _, b := range received {
|
|
total += len(b)
|
|
}
|
|
if total != 2 {
|
|
t.Fatalf("received %d events, want 2 (batches=%d)", total, len(received))
|
|
}
|
|
// Both events should carry workspace_id in properties.
|
|
for _, batch := range received {
|
|
for _, item := range batch {
|
|
if item.Properties["workspace_id"] != "w1" {
|
|
t.Errorf("missing workspace_id on event %s", item.Event)
|
|
}
|
|
if item.DistinctID != "u1" {
|
|
t.Errorf("distinct_id = %q, want u1", item.DistinctID)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPostHogClient_DropsWhenFull(t *testing.T) {
|
|
// Handler blocks so batches never flush — queue will fill up.
|
|
block := make(chan struct{})
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
<-block
|
|
}))
|
|
defer srv.Close()
|
|
defer close(block)
|
|
|
|
c := NewPostHogClient(PostHogConfig{
|
|
APIKey: "test-key",
|
|
Host: srv.URL,
|
|
QueueSize: 2,
|
|
BatchSize: 1,
|
|
FlushEvery: time.Hour,
|
|
})
|
|
defer c.Close()
|
|
|
|
// First event may be consumed by the worker (which is now blocked in send).
|
|
// Next events will sit in the queue (cap=2) until it's full and then drop.
|
|
for i := 0; i < 20; i++ {
|
|
c.Capture(Event{Name: "spam", DistinctID: "u"})
|
|
}
|
|
// Give the worker a chance to pick up at least one.
|
|
time.Sleep(50 * time.Millisecond)
|
|
if c.dropped.Load() == 0 {
|
|
t.Fatalf("expected some drops when queue saturated")
|
|
}
|
|
}
|
|
|
|
func TestEmailDomain(t *testing.T) {
|
|
cases := map[string]string{
|
|
"a@example.com": "example.com",
|
|
"user@Company.co.uk": "company.co.uk",
|
|
"": "",
|
|
"no-at": "",
|
|
"trailing@": "",
|
|
}
|
|
for in, want := range cases {
|
|
if got := emailDomain(in); got != want {
|
|
t.Errorf("emailDomain(%q) = %q, want %q", in, got, want)
|
|
}
|
|
}
|
|
}
|