|
2 | 2 | package controller |
3 | 3 |
|
4 | 4 | import ( |
| 5 | + "net/http" |
5 | 6 | "reflect" |
6 | 7 | "testing" |
7 | 8 | "time" |
@@ -209,3 +210,85 @@ func TestSaveAsyncUsageInfoDoesNotStoreInitialUsage(t *testing.T) { |
209 | 210 | require.Zero(t, captured.Usage.TotalTokens) |
210 | 211 | require.Equal(t, "priority", captured.UsageContext.ServiceTier) |
211 | 212 | } |
| 213 | + |
| 214 | +func TestBuildRequestDetailForLogSkipsRequestBodyForUpstreamOnlyStatuses(t *testing.T) { |
| 215 | + t.Parallel() |
| 216 | + |
| 217 | + bodyDetail := &relaycontroller.BodyDetail{ |
| 218 | + RequestBody: `{"prompt":"secret"}`, |
| 219 | + ResponseBody: `{"error":"upstream"}`, |
| 220 | + } |
| 221 | + |
| 222 | + for _, statusCode := range []int{ |
| 223 | + http.StatusUnauthorized, |
| 224 | + http.StatusPaymentRequired, |
| 225 | + http.StatusForbidden, |
| 226 | + http.StatusNotFound, |
| 227 | + http.StatusMethodNotAllowed, |
| 228 | + http.StatusTooManyRequests, |
| 229 | + } { |
| 230 | + t.Run(http.StatusText(statusCode), func(t *testing.T) { |
| 231 | + t.Parallel() |
| 232 | + |
| 233 | + detail := buildRequestDetailForLog(bodyDetail, model.ModelConfig{}, statusCode, false) |
| 234 | + |
| 235 | + require.NotNil(t, detail) |
| 236 | + assert.Empty(t, detail.RequestBody) |
| 237 | + assert.Equal(t, `{"error":"upstream"}`, detail.ResponseBody) |
| 238 | + }) |
| 239 | + } |
| 240 | +} |
| 241 | + |
| 242 | +func TestBuildRequestDetailForLogKeepsRequestBodyWhenForced(t *testing.T) { |
| 243 | + t.Parallel() |
| 244 | + |
| 245 | + detail := buildRequestDetailForLog( |
| 246 | + &relaycontroller.BodyDetail{ |
| 247 | + RequestBody: `{"prompt":"secret"}`, |
| 248 | + ResponseBody: `{"error":"limited"}`, |
| 249 | + }, |
| 250 | + model.ModelConfig{}, |
| 251 | + http.StatusTooManyRequests, |
| 252 | + true, |
| 253 | + ) |
| 254 | + |
| 255 | + require.NotNil(t, detail) |
| 256 | + assert.Equal(t, `{"prompt":"secret"}`, detail.RequestBody) |
| 257 | + assert.Equal(t, `{"error":"limited"}`, detail.ResponseBody) |
| 258 | +} |
| 259 | + |
| 260 | +func TestBuildRequestDetailForLogKeepsRequestBodyForClientPayloadErrors(t *testing.T) { |
| 261 | + t.Parallel() |
| 262 | + |
| 263 | + detail := buildRequestDetailForLog( |
| 264 | + &relaycontroller.BodyDetail{ |
| 265 | + RequestBody: `{"prompt":"secret"}`, |
| 266 | + ResponseBody: `{"error":"bad request"}`, |
| 267 | + }, |
| 268 | + model.ModelConfig{}, |
| 269 | + http.StatusBadRequest, |
| 270 | + false, |
| 271 | + ) |
| 272 | + |
| 273 | + require.NotNil(t, detail) |
| 274 | + assert.Equal(t, `{"prompt":"secret"}`, detail.RequestBody) |
| 275 | + assert.Equal(t, `{"error":"bad request"}`, detail.ResponseBody) |
| 276 | +} |
| 277 | + |
| 278 | +func TestBuildRequestDetailForLogDropsInvalidUTF8Bodies(t *testing.T) { |
| 279 | + t.Parallel() |
| 280 | + |
| 281 | + detail := buildRequestDetailForLog( |
| 282 | + &relaycontroller.BodyDetail{ |
| 283 | + RequestBody: string([]byte{0xff, 0xfe}), |
| 284 | + ResponseBody: string([]byte{'o', 'k', 0xff}), |
| 285 | + }, |
| 286 | + model.ModelConfig{}, |
| 287 | + http.StatusBadRequest, |
| 288 | + false, |
| 289 | + ) |
| 290 | + |
| 291 | + require.NotNil(t, detail) |
| 292 | + assert.Empty(t, detail.RequestBody) |
| 293 | + assert.Empty(t, detail.ResponseBody) |
| 294 | +} |
0 commit comments