Skip to content
quarry Artifact [320a8ea734]
Login

Artifact [320a8ea734]

Artifact 320a8ea73429b2137a87258b3448241a4cc89af0f6e9fbf356198076f104a1c6:


package obs

import (
	"errors"
	"sync/atomic"
	"testing"
	"time"
)

// A traffic page is computed once a minute per range and filters: fresh
// answers come from the memo, stale ones come back at once while one
// refresh runs behind them, a past window is never memoised, and a
// failed refresh keeps serving the last answer.
func TestTrafficIsMemoisedAndRefreshedBehind(t *testing.T) {
	var m trafficMemo
	var calls atomic.Int32
	compute := func(q TrafficQuery) (*Traffic, error) {
		calls.Add(1)
		return &Traffic{Range: q.Range}, nil
	}
	q := TrafficQuery{Range: TrafficRange{Name: "7d"}, Filters: map[string]string{"repo": "quarry"}}
	now := time.Now()
	if _, err := m.get(q, now, compute); err != nil || calls.Load() != 1 {
		t.Fatalf("FAIL: first read %v, %d computes", err, calls.Load())
	}
	m.get(q, now.Add(20*time.Second), compute)
	if calls.Load() != 1 {
		t.Errorf("FAIL: a fresh read computed again (%d)", calls.Load())
	}
	if got, _ := m.get(q, now.Add(2*time.Minute), compute); got == nil {
		t.Error("FAIL: a stale read did not answer at once")
	}
	for i := 0; i < 50 && calls.Load() < 2; i++ {
		time.Sleep(10 * time.Millisecond)
	}
	if calls.Load() != 2 {
		t.Errorf("FAIL: a stale read started %d refreshes, want one", calls.Load()-1)
	}
	other := TrafficQuery{Range: TrafficRange{Name: "7d"}}
	m.get(other, now, compute)
	if calls.Load() != 3 {
		t.Error("FAIL: a different filter set shared an answer")
	}
	past := TrafficQuery{Range: TrafficRange{Name: "7d"}, Now: now.Add(-time.Hour)}
	m.get(past, now, compute)
	m.get(past, now, compute)
	if calls.Load() != 5 {
		t.Error("FAIL: a question about the past was memoised")
	}
	failing := func(TrafficQuery) (*Traffic, error) { return nil, errors.New("down") }
	var f trafficMemo
	f.get(q, now, compute)
	if got, err := f.get(q, now.Add(2*time.Minute), failing); got == nil || err != nil {
		t.Error("FAIL: a failing refresh did not keep serving the last answer")
	}
	t.Log("ok")
}