github.com/google/osv-scalibr@v0.4.1/veles/secrets/anthropicapikey/model_validator_test.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package anthropicapikey_test 16 17 import ( 18 "net/http" 19 "net/http/httptest" 20 "testing" 21 22 "github.com/google/osv-scalibr/veles" 23 "github.com/google/osv-scalibr/veles/secrets/anthropicapikey" 24 ) 25 26 const ( 27 modelValidatorTestKey = "sk-ant-api03-test123456789012345678901234567890123456789012345678" 28 ) 29 30 // mockAnthropicModelServer creates a mock Anthropic API server for testing model keys 31 func mockAnthropicModelServer(t *testing.T, expectedKey string, statusCode int, responseBody string) *httptest.Server { 32 t.Helper() 33 34 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 35 modelsEndpoint := anthropicapikey.AnthropicModelsEndpoint 36 // Check if it's a GET request to the models endpoint 37 if r.Method != http.MethodGet || r.URL.Path != modelsEndpoint { 38 t.Errorf("unexpected request: %s %s, expected: GET %s", r.Method, r.URL.Path, modelsEndpoint) 39 http.Error(w, "not found", http.StatusNotFound) 40 return 41 } 42 43 // Check headers 44 if r.Header.Get("X-Api-Key") != expectedKey { 45 t.Errorf("expected X-Api-Key: %s, got: %s", expectedKey, r.Header.Get("X-Api-Key")) 46 } 47 if r.Header.Get("Anthropic-Version") != "2023-06-01" { 48 t.Errorf("expected Anthropic-Version: 2023-06-01, got: %s", r.Header.Get("Anthropic-Version")) 49 } 50 51 // Set response 52 w.Header().Set("Content-Type", "application/json") 53 w.WriteHeader(statusCode) 54 if responseBody != "" { 55 if _, err := w.Write([]byte(responseBody)); err != nil { 56 t.Errorf("unable to write response: %v", err) 57 } 58 } 59 })) 60 61 return server 62 } 63 64 func TestModelValidator(t *testing.T) { 65 cases := []struct { 66 name string 67 statusCode int 68 responseBody string 69 want veles.ValidationStatus 70 expectError bool 71 }{ 72 { 73 name: "valid_key", 74 statusCode: http.StatusOK, 75 responseBody: `{ 76 "data": [ 77 { 78 "id": "claude-3-opus-20240229", 79 "object": "model", 80 "created": 1709251200, 81 "owned_by": "anthropic" 82 } 83 ] 84 }`, 85 want: veles.ValidationValid, 86 }, 87 { 88 name: "invalid_key_unauthorized", 89 statusCode: http.StatusUnauthorized, 90 responseBody: `{ 91 "error": { 92 "type": "authentication_error", 93 "message": "Invalid API key" 94 } 95 }`, 96 want: veles.ValidationInvalid, 97 }, 98 { 99 name: "forbidden_but_likely_valid", 100 statusCode: http.StatusForbidden, 101 responseBody: `{ 102 "error": { 103 "type": "permission_error", 104 "message": "Your account does not have permission to perform this action" 105 } 106 }`, 107 want: veles.ValidationFailed, 108 expectError: true, 109 }, 110 { 111 name: "rate_limited_but_likely_valid", 112 statusCode: http.StatusTooManyRequests, 113 responseBody: `{ 114 "error": { 115 "type": "rate_limit_error", 116 "message": "Rate limit exceeded" 117 } 118 }`, 119 want: veles.ValidationValid, 120 }, 121 { 122 name: "server_error", 123 statusCode: http.StatusInternalServerError, 124 responseBody: `{ 125 "error": { 126 "type": "server_error", 127 "message": "Internal server error" 128 } 129 }`, 130 want: veles.ValidationFailed, 131 expectError: true, 132 }, 133 } 134 135 for _, tc := range cases { 136 t.Run(tc.name, func(t *testing.T) { 137 // Create mock server 138 server := mockAnthropicModelServer(t, modelValidatorTestKey, tc.statusCode, tc.responseBody) 139 defer server.Close() 140 141 // Create validator with mock client and server URL 142 validator := anthropicapikey.NewModelValidator() 143 validator.HTTPC = server.Client() 144 validator.Endpoint = server.URL + anthropicapikey.AnthropicModelsEndpoint 145 146 // Create test key 147 key := anthropicapikey.ModelAPIKey{Key: modelValidatorTestKey} 148 149 // Test validation 150 got, err := validator.Validate(t.Context(), key) 151 152 // Check error expectation 153 if tc.expectError { 154 if err == nil { 155 t.Errorf("Validate() expected error, got nil") 156 } 157 } else { 158 if err != nil { 159 t.Errorf("Validate() unexpected error: %v", err) 160 } 161 } 162 163 // Check validation status 164 if got != tc.want { 165 t.Errorf("Validate() = %v, want %v", got, tc.want) 166 } 167 }) 168 } 169 }