| @@ -8,7 +8,9 @@ import ( · 7 unmodified lines |
| 8 | 8 | "net/http" |
| 9 | 9 | "net/http/httptest" |
| 10 | 10 | "strings" |
| 11 | + "sync" |
| 11 | 12 | "testing" |
| 13 | + "time" |
| 12 | 14 | |
| 13 | 15 | "github.com/gin-gonic/gin" |
| 14 | 16 | "github.com/klauspost/compress/zstd" |
| @@ -206,6 +208,97 @@ func TestApplyClaudeHeaders_DoesNotDowngradeConfiguredBaselineOnFirstClaudeClien · 191 unmodified lines |
| 206 | 208 | assertClaudeFingerprint(t, newerClaudeReq.Header, "claude-cli/2.1.71 (external, cli)", "0.81.0", "v24.6.0", "Linux", "x64") |
| 207 | 209 | } |
| 208 | 210 | |
| 211 | +func TestResolveClaudeDeviceProfile_RechecksCacheBeforeStoringCandidate(t *testing.T) { |
| 212 | + resetClaudeDeviceProfileCache() |
| 213 | + stabilize := true |
| 214 | + |
| 215 | + cfg := &config.Config{ |
| 216 | + ClaudeHeaderDefaults: config.ClaudeHeaderDefaults{ |
| 217 | + UserAgent: "claude-cli/2.1.60 (external, cli)", |
| 218 | + PackageVersion: "0.70.0", |
| 219 | + RuntimeVersion: "v22.0.0", |
| 220 | + OS: "MacOS", |
| 221 | + Arch: "arm64", |
| 222 | + StabilizeDeviceProfile: &stabilize, |
| 223 | + }, |
| 224 | + } |
| 225 | + auth := &cliproxyauth.Auth{ |
| 226 | + ID: "auth-racy-upgrade", |
| 227 | + Attributes: map[string]string{ |
| 228 | + "api_key": "key-racy-upgrade", |
| 229 | + }, |
| 230 | + } |
| 231 | + |
| 232 | + lowPaused := make(chan struct{}) |
| 233 | + releaseLow := make(chan struct{}) |
| 234 | + var pauseOnce sync.Once |
| 235 | + var releaseOnce sync.Once |
| 236 | + |
| 237 | + claudeDeviceProfileBeforeCandidateStore = func(candidate claudeDeviceProfile) { |
| 238 | + if candidate.UserAgent != "claude-cli/2.1.62 (external, cli)" { |
| 239 | + return |
| 240 | + } |
| 241 | + pauseOnce.Do(func() { close(lowPaused) }) |
| 242 | + <-releaseLow |
| 243 | + } |
| 244 | + t.Cleanup(func() { |
| 245 | + claudeDeviceProfileBeforeCandidateStore = nil |
| 246 | + releaseOnce.Do(func() { close(releaseLow) }) |
| 247 | + }) |
| 248 | + |
| 249 | + lowResultCh := make(chan claudeDeviceProfile, 1) |
| 250 | + go func() { |
| 251 | + lowResultCh <- resolveClaudeDeviceProfile(auth, "key-racy-upgrade", http.Header{ |
| 252 | + "User-Agent": []string{"claude-cli/2.1.62 (external, cli)"}, |
| 253 | + "X-Stainless-Package-Version": []string{"0.74.0"}, |
| 254 | + "X-Stainless-Runtime-Version": []string{"v24.3.0"}, |
| 255 | + "X-Stainless-Os": []string{"Linux"}, |
| 256 | + "X-Stainless-Arch": []string{"x64"}, |
| 257 | + }, cfg) |
| 258 | + }() |
| 259 | + |
| 260 | + select { |
| 261 | + case <-lowPaused: |
| 262 | + case <-time.After(2 * time.Second): |
| 263 | + t.Fatal("timed out waiting for lower candidate to pause before storing") |
| 264 | + } |
| 265 | + |
| 266 | + highResult := resolveClaudeDeviceProfile(auth, "key-racy-upgrade", http.Header{ |
| 267 | + "User-Agent": []string{"claude-cli/2.1.63 (external, cli)"}, |
| 268 | + "X-Stainless-Package-Version": []string{"0.75.0"}, |
| 269 | + "X-Stainless-Runtime-Version": []string{"v24.4.0"}, |
| 270 | + "X-Stainless-Os": []string{"MacOS"}, |
| 271 | + "X-Stainless-Arch": []string{"arm64"}, |
| 272 | + }, cfg) |
| 273 | + releaseOnce.Do(func() { close(releaseLow) }) |
| 274 | + |
| 275 | + select { |
| 276 | + case lowResult := <-lowResultCh: |
| 277 | + if lowResult.UserAgent != "claude-cli/2.1.63 (external, cli)" { |
| 278 | + t.Fatalf("lowResult.UserAgent = %q, want %q", lowResult.UserAgent, "claude-cli/2.1.63 (external, cli)") |
| 279 | + } |
| 280 | + if lowResult.PackageVersion != "0.75.0" { |
| 281 | + t.Fatalf("lowResult.PackageVersion = %q, want %q", lowResult.PackageVersion, "0.75.0") |
| 282 | + } |
| 283 | + case <-time.After(2 * time.Second): |
| 284 | + t.Fatal("timed out waiting for lower candidate result") |
| 285 | + } |
| 286 | + |
| 287 | + if highResult.UserAgent != "claude-cli/2.1.63 (external, cli)" { |
| 288 | + t.Fatalf("highResult.UserAgent = %q, want %q", highResult.UserAgent, "claude-cli/2.1.63 (external, cli)") |
| 289 | + } |
| 290 | + |
| 291 | + cached := resolveClaudeDeviceProfile(auth, "key-racy-upgrade", http.Header{ |
| 292 | + "User-Agent": []string{"curl/8.7.1"}, |
| 293 | + }, cfg) |
| 294 | + if cached.UserAgent != "claude-cli/2.1.63 (external, cli)" { |
| 295 | + t.Fatalf("cached.UserAgent = %q, want %q", cached.UserAgent, "claude-cli/2.1.63 (external, cli)") |
| 296 | + } |
| 297 | + if cached.PackageVersion != "0.75.0" { |
| 298 | + t.Fatalf("cached.PackageVersion = %q, want %q", cached.PackageVersion, "0.75.0") |
| 299 | + } |
| 300 | +} |
| 301 | + |
| 209 | 302 | func TestApplyClaudeHeaders_DisableDeviceProfileStabilization(t *testing.T) { |
| 210 | 303 | resetClaudeDeviceProfileCache() |
| 211 | 304 | |