MCPcopy Index your code
hub / github.com/coder/coder / TestAIBridgeProviderHotReload

Function TestAIBridgeProviderHotReload

enterprise/coderd/aibridge_reload_test.go:115–293  ·  view source on GitHub ↗

TestAIBridgeProviderHotReload exercises the end-to-end CRUD -> reload -> routing path: every provider mutation made through codersdk must, within a short window, change the routing observed at api/v2/aibridge/{name}/v1/models. The OpenAI passthrough route v1/models reverse-proxies to BaseURL, so the

(t *testing.T)

Source from the content-addressed store, hash-verified

113// /v1/models reverse-proxies to BaseURL, so the upstream that responds
114// identifies which provider the daemon's mux dispatched to.
115func TestAIBridgeProviderHotReload(t *testing.T) {
116 t.Parallel()
117
118 // Two distinct upstreams so an Update that swings the BaseURL is
119 // observable: which upstream answers tells us which BaseURL the
120 // freshly-built provider is pointed at.
121 upstreamA := newMockUpstream(t, "a")
122 upstreamB := newMockUpstream(t, "b")
123
124 dv := coderdtest.DeploymentValues(t)
125 dv.AI.BridgeConfig.Enabled = serpent.Bool(true)
126
127 client, _, api, _ := coderdenttest.NewWithAPI(t, &coderdenttest.Options{
128 Options: &coderdtest.Options{DeploymentValues: dv},
129 LicenseOptions: &coderdenttest.LicenseOptions{
130 Features: license.Features{codersdk.FeatureAIBridge: 1},
131 },
132 })
133
134 metrics := startTestAIBridgeDaemon(t, api.AGPL)
135
136 // requireProviderStatus polls until the provider_info series for
137 // (name, status) settles to value 1. Reloads happen via pubsub, so
138 // the assertion has to be eventual.
139 requireProviderStatus := func(t *testing.T, name, status string) {
140 t.Helper()
141 require.Eventuallyf(t, func() bool {
142 return promtest.ToFloat64(metrics.ProviderInfo.WithLabelValues(name, "openai", status)) == 1
143 }, testutil.WaitShort, testutil.IntervalFast,
144 "expected provider_info{provider_name=%q, status=%q} == 1", name, status)
145 }
146
147 // requireProviderAbsent polls until no series exists for the
148 // provider name in any status. After a delete the Reset on the
149 // next reload must clear all previous status labels for the name.
150 requireProviderAbsent := func(t *testing.T, name string) {
151 t.Helper()
152 require.Eventuallyf(t, func() bool {
153 for _, status := range []string{"enabled", "disabled", "error"} {
154 if promtest.ToFloat64(metrics.ProviderInfo.WithLabelValues(name, "openai", status)) != 0 {
155 return false
156 }
157 }
158 return true
159 }, testutil.WaitShort, testutil.IntervalFast,
160 "expected provider_info series for %q to be cleared after delete", name)
161 }
162
163 ctx := testutil.Context(t, testutil.WaitLong)
164
165 // sendRequest issues GET /api/v2/aibridge/{name}/v1/models and
166 // returns the status and the upstream marker decoded from the
167 // JSON body (empty if the body was not the marker JSON).
168 sendRequest := func(providerName string) (int, string) {
169 url := client.URL.String() + "/api/v2/aibridge/" + providerName + "/v1/models"
170 req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
171 require.NoError(t, err)
172 req.Header.Set("Authorization", "Bearer "+client.SessionToken())

Callers

nothing calls this directly

Calls 15

DeploymentValuesFunction · 0.92
NewWithAPIFunction · 0.92
ContextFunction · 0.92
startTestAIBridgeDaemonFunction · 0.85
WithLabelValuesMethod · 0.80
CreateAIProviderMethod · 0.80
DeleteAIProviderMethod · 0.80
newMockUpstreamFunction · 0.70
HelperMethod · 0.65
SetMethod · 0.65
DoMethod · 0.65
CloseMethod · 0.65

Tested by

no test coverage detected