~james/core

core/spindle/webhook/webhook_fairness_test.go -rw-r--r-- 1.5 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 15 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package webhook

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"
)

func TestHungTargetDoesNotStarveOtherTargets(t *testing.T) {
	database := newTestDB(t)

	const healthy = 5
	arrived := make(chan string, healthy)
	fast := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		arrived <- r.URL.Path
	}))
	t.Cleanup(fast.Close)

	stop := make(chan struct{})
	hung := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		select {
		case <-stop:
		case <-r.Context().Done():
		}
	}))
	t.Cleanup(hung.Close)

	s := New(database, true)
	// cleanups run in reverse, and the service has to drain before hung.Close cuts it off
	t.Cleanup(func() {
		ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
		defer cancel()
		s.Close(ctx)
	})
	t.Cleanup(func() { close(stop) })

	// more than the queue holds, all to a host that never answers
	for i := range 300 {
		s.dispatch(hookJob(context.Background(), fmt.Sprintf("%s/hung%d", hung.URL, i)))
	}
	// webhook queues are per hostname, and localhost gets a different one from 127.0.0.1
	otherHost := strings.Replace(fast.URL, "127.0.0.1", "localhost", 1)
	for i := range healthy {
		s.dispatch(hookJob(context.Background(), fmt.Sprintf("%s/ok%d", otherHost, i)))
	}

	timeout := time.After(5 * time.Second)
	for got := range healthy {
		select {
		case <-arrived:
		case <-timeout:
			t.Fatalf("%d of %d healthy deliveries arrived within 5s while another target hung", got, healthy)
		}
	}
}