(t *testing.T)
| 16 | ) |
| 17 | |
| 18 | func TestExecute_PerModelIsolation(t *testing.T) { |
| 19 | t.Parallel() |
| 20 | |
| 21 | sonnetCalls := atomic.Int32{} |
| 22 | haikuCalls := atomic.Int32{} |
| 23 | |
| 24 | cbs := circuitbreaker.NewProviderCircuitBreakers("test", &config.CircuitBreaker{ |
| 25 | FailureThreshold: 1, |
| 26 | Interval: time.Minute, |
| 27 | Timeout: time.Minute, |
| 28 | MaxRequests: 1, |
| 29 | }, func(endpoint, model string, from, to gobreaker.State) {}, nil) |
| 30 | |
| 31 | endpoint := "/v1/messages" |
| 32 | sonnetModel := "claude-sonnet-4-20250514" |
| 33 | haikuModel := "claude-3-5-haiku-20241022" |
| 34 | |
| 35 | // Trip circuit on sonnet model (returns 503) |
| 36 | w := httptest.NewRecorder() |
| 37 | err := cbs.Execute(endpoint, sonnetModel, w, func(rw http.ResponseWriter) error { |
| 38 | sonnetCalls.Add(1) |
| 39 | rw.WriteHeader(http.StatusServiceUnavailable) |
| 40 | return nil |
| 41 | }) |
| 42 | assert.NoError(t, err) |
| 43 | assert.Equal(t, int32(1), sonnetCalls.Load()) |
| 44 | |
| 45 | // Second sonnet request should be blocked by circuit breaker |
| 46 | w = httptest.NewRecorder() |
| 47 | err = cbs.Execute(endpoint, sonnetModel, w, func(rw http.ResponseWriter) error { |
| 48 | sonnetCalls.Add(1) |
| 49 | rw.WriteHeader(http.StatusOK) |
| 50 | return nil |
| 51 | }) |
| 52 | assert.True(t, errors.Is(err, circuitbreaker.ErrCircuitOpen)) |
| 53 | assert.Equal(t, int32(1), sonnetCalls.Load()) // No new call |
| 54 | assert.Equal(t, http.StatusServiceUnavailable, w.Code) |
| 55 | |
| 56 | // Haiku model on same endpoint should still work (independent circuit) |
| 57 | w = httptest.NewRecorder() |
| 58 | err = cbs.Execute(endpoint, haikuModel, w, func(rw http.ResponseWriter) error { |
| 59 | haikuCalls.Add(1) |
| 60 | rw.WriteHeader(http.StatusOK) |
| 61 | return nil |
| 62 | }) |
| 63 | assert.NoError(t, err) |
| 64 | assert.Equal(t, int32(1), haikuCalls.Load()) |
| 65 | } |
| 66 | |
| 67 | func TestExecute_PerEndpointIsolation(t *testing.T) { |
| 68 | t.Parallel() |
nothing calls this directly
no test coverage detected