github.com/google/osv-scalibr@v0.4.1/veles/secrets/openai/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 openai_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/openai" 24 ) 25 26 const ( 27 projectValidatorTestKey = "sk-proj-12345678901234567890T3BlbkFJ" + 28 "12345678901234567890123456" 29 ) 30 31 // mockOpenAIServer creates a mock OpenAI API server for testing project keys 32 func mockOpenAIServer(t *testing.T, expectedKey string, statusCode int) *httptest.Server { 33 t.Helper() 34 35 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, 36 r *http.Request) { 37 modelsEndpoint := openai.ModelsEndpoint 38 // Check if it's a GET request to the models endpoint 39 if r.Method != http.MethodGet || r.URL.Path != modelsEndpoint { 40 t.Errorf("unexpected request: %s %s, expected: GET %s", 41 r.Method, r.URL.Path, modelsEndpoint) 42 http.Error(w, "not found", http.StatusNotFound) 43 return 44 } 45 46 // Check Authorization header (Bearer token format) 47 expectedAuth := "Bearer " + expectedKey 48 if r.Header.Get("Authorization") != expectedAuth { 49 t.Errorf("expected Authorization: %s, got: %s", 50 expectedAuth, r.Header.Get("Authorization")) 51 } 52 53 // Set response 54 w.Header().Set("Content-Type", "application/json") 55 w.WriteHeader(statusCode) 56 })) 57 58 return server 59 } 60 61 func TestProjectValidator(t *testing.T) { 62 cases := []struct { 63 name string 64 statusCode int 65 want veles.ValidationStatus 66 expectError bool 67 }{ 68 { 69 name: "valid_key", 70 statusCode: http.StatusOK, 71 want: veles.ValidationValid, 72 }, 73 { 74 name: "invalid_key_unauthorized", 75 statusCode: http.StatusUnauthorized, 76 want: veles.ValidationInvalid, 77 }, 78 { 79 name: "forbidden_but_likely_valid", 80 statusCode: http.StatusForbidden, 81 want: veles.ValidationFailed, 82 expectError: true, 83 }, 84 { 85 name: "rate_limited_but_likely_valid", 86 statusCode: http.StatusTooManyRequests, 87 want: veles.ValidationValid, 88 }, 89 { 90 name: "server_error", 91 statusCode: http.StatusInternalServerError, 92 want: veles.ValidationFailed, 93 expectError: true, 94 }, 95 } 96 97 for _, tc := range cases { 98 t.Run(tc.name, func(t *testing.T) { 99 // Create mock server 100 server := mockOpenAIServer(t, projectValidatorTestKey, 101 tc.statusCode) 102 defer server.Close() 103 104 // Create validator with mock client and server URL 105 validator := openai.NewProjectValidator() 106 validator.HTTPC = server.Client() 107 validator.Endpoint = server.URL + openai.ModelsEndpoint 108 109 // Create test key 110 key := openai.APIKey{Key: projectValidatorTestKey} 111 112 // Test validation 113 got, err := validator.Validate(t.Context(), key) 114 115 // Check error expectation 116 if tc.expectError { 117 if err == nil { 118 t.Errorf("Validate() expected error, got nil") 119 } 120 } else { 121 if err != nil { 122 t.Errorf("Validate() unexpected error: %v", err) 123 } 124 } 125 126 // Check validation status 127 if got != tc.want { 128 t.Errorf("Validate() = %v, want %v", got, tc.want) 129 } 130 }) 131 } 132 }