| 1 | package host |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "net/http" |
| 6 | "net/http/httptest" |
| 7 | "testing" |
| 8 | "time" |
| 9 | ) |
| 10 | |
| 11 | func TestWrappedClaimRootStartsAndServes(t *testing.T) { |
| 12 | ctx, cancel := context.WithCancel(t.Context()) |
| 13 | defer cancel() |
| 14 | var handler http.Handler = ClaimRootWithLaunch{Root: ClaimRootHTTP{}} |
| 15 | lifecycle, ok := handler.(interface{ Start(context.Context) }) |
| 16 | if !ok { |
| 17 | t.Fatal("wrapped handler lost lifecycle") |
| 18 | } |
| 19 | lifecycle.Start(ctx) |
| 20 | r := httptest.NewRecorder() |
| 21 | handler.ServeHTTP(r, httptest.NewRequest(http.MethodGet, "/claim/retire", nil)) |
| 22 | if r.Code != http.StatusServiceUnavailable { |
| 23 | t.Fatal(r.Code) |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | type recoveryPages struct { |
| 28 | servingParkAuthority |
| 29 | calls []string |
| 30 | } |
| 31 | |
| 32 | func (p *recoveryPages) recoverServingParks(_ context.Context, after string, limit int) (servingParkRecoveryPage, error) { |
| 33 | p.calls = append(p.calls, after) |
| 34 | page := servingParkRecoveryPage{} |
| 35 | count := 128 |
| 36 | if after != "" { |
| 37 | count = 72 |
| 38 | } |
| 39 | for i := 0; i < count; i++ { |
| 40 | page.Results = append(page.Results, servingParkRecoveryResult{Host: "kept", ID: "park", Err: errServingParkRetagPending}) |
| 41 | } |
| 42 | if after == "" { |
| 43 | page.More = true |
| 44 | page.Next = "128" |
| 45 | } |
| 46 | return page, nil |
| 47 | } |
| 48 | func TestServingParkRecoveryPagesRetainedRecords(t *testing.T) { |
| 49 | a := &recoveryPages{} |
| 50 | ctx, cancel := context.WithCancel(t.Context()) |
| 51 | defer cancel() |
| 52 | p := &servingParkRuntime{authority: a, ctx: ctx, cancel: cancel, idle: make(chan struct{})} |
| 53 | for i := 0; i < 2; i++ { |
| 54 | if err := p.recoverPending(ctx); err != nil { |
| 55 | t.Fatal("retained parks blocked recovery", err) |
| 56 | } |
| 57 | } |
| 58 | if len(a.calls) != 2 || a.calls[0] != "" || a.calls[1] != "128" { |
| 59 | t.Fatal(a.calls) |
| 60 | } |
| 61 | } |
| 62 | func TestServingParkPressurePrecedesSlowRecovery(t *testing.T) { |
| 63 | cleaned := false |
| 64 | ctx, cancel := context.WithTimeout(t.Context(), time.Second) |
| 65 | defer cancel() |
| 66 | _, err := maintainServingParkPass(ctx, "", func(call context.Context) error { |
| 67 | if call.Err() != nil { |
| 68 | t.Fatal(call.Err()) |
| 69 | } |
| 70 | cleaned = true |
| 71 | return nil |
| 72 | }, func(call context.Context, _ string, _ int) (servingParkRecoveryPage, error) { |
| 73 | if !cleaned { |
| 74 | t.Fatal("recovery starved pressure cleanup") |
| 75 | } |
| 76 | <-call.Done() |
| 77 | return servingParkRecoveryPage{}, call.Err() |
| 78 | }, 10*time.Millisecond) |
| 79 | if !cleaned || err == nil { |
| 80 | t.Fatal(cleaned, err) |
| 81 | } |
| 82 | } |
| 83 | |