mirror of https://github.com/sysown/proxysql
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
9.9 KiB
303 lines
9.9 KiB
/**
|
|
* @file ai_error_handling_edge_cases-t.cpp
|
|
* @brief TAP unit tests for AI error handling edge cases
|
|
*
|
|
* Test Categories:
|
|
* 1. API key validation edge cases (special characters, boundary lengths)
|
|
* 2. URL validation edge cases (IPv6, unusual ports, malformed patterns)
|
|
* 3. Timeout scenarios simulation
|
|
* 4. Connection failure handling
|
|
* 5. Rate limiting error responses
|
|
* 6. Invalid LLM response formats
|
|
*
|
|
* @date 2026-01-16
|
|
*/
|
|
|
|
#include "tap.h"
|
|
#include <string.h>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
|
|
// ============================================================================
|
|
// Standalone validation functions (matching AI_Features_Manager.cpp logic)
|
|
// ============================================================================
|
|
|
|
static bool validate_url_format(const char* url) {
|
|
if (!url || strlen(url) == 0) {
|
|
return true; // Empty URL is valid (will use defaults)
|
|
}
|
|
|
|
// Check for protocol prefix (http://, https://)
|
|
const char* http_prefix = "http://";
|
|
const char* https_prefix = "https://";
|
|
|
|
bool has_protocol = (strncmp(url, http_prefix, strlen(http_prefix)) == 0 ||
|
|
strncmp(url, https_prefix, strlen(https_prefix)) == 0);
|
|
|
|
if (!has_protocol) {
|
|
return false;
|
|
}
|
|
|
|
// Check for host part (at least something after ://)
|
|
const char* host_start = strstr(url, "://");
|
|
if (!host_start || strlen(host_start + 3) == 0) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool validate_api_key_format(const char* key, const char* provider_name) {
|
|
if (!key || strlen(key) == 0) {
|
|
return true; // Empty key is valid for local endpoints
|
|
}
|
|
|
|
size_t len = strlen(key);
|
|
|
|
// Check for whitespace
|
|
for (size_t i = 0; i < len; i++) {
|
|
if (key[i] == ' ' || key[i] == '\t' || key[i] == '\n' || key[i] == '\r') {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check minimum length (most API keys are at least 20 chars)
|
|
if (len < 10) {
|
|
return false;
|
|
}
|
|
|
|
// Check for incomplete OpenAI key format
|
|
if (strncmp(key, "sk-", 3) == 0 && len < 20) {
|
|
return false;
|
|
}
|
|
|
|
// Check for incomplete Anthropic key format
|
|
if (strncmp(key, "sk-ant-", 7) == 0 && len < 25) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool validate_numeric_range(const char* value, int min_val, int max_val, const char* var_name) {
|
|
if (!value || strlen(value) == 0) {
|
|
return false;
|
|
}
|
|
|
|
int int_val = atoi(value);
|
|
|
|
if (int_val < min_val || int_val > max_val) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool validate_provider_format(const char* provider) {
|
|
if (!provider || strlen(provider) == 0) {
|
|
return false;
|
|
}
|
|
|
|
const char* valid_formats[] = {"openai", "anthropic", NULL};
|
|
for (int i = 0; valid_formats[i]; i++) {
|
|
if (strcmp(provider, valid_formats[i]) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test: API Key Validation Edge Cases
|
|
// ============================================================================
|
|
|
|
void test_api_key_edge_cases() {
|
|
diag("=== API Key Validation Edge Cases ===");
|
|
|
|
// Test very short keys
|
|
ok(!validate_api_key_format("a", "openai"),
|
|
"Very short key (1 char) rejected");
|
|
ok(!validate_api_key_format("sk", "openai"),
|
|
"Very short OpenAI-like key (2 chars) rejected");
|
|
ok(!validate_api_key_format("sk-ant", "anthropic"),
|
|
"Very short Anthropic-like key (6 chars) rejected");
|
|
|
|
// Test keys with special characters
|
|
ok(validate_api_key_format("sk-abc123!@#$%^&*()", "openai"),
|
|
"API key with special characters accepted");
|
|
ok(validate_api_key_format("sk-ant-xyz789_+-=[]{}|;':\",./<>?", "anthropic"),
|
|
"Anthropic key with special characters accepted");
|
|
|
|
// Test keys with exactly minimum valid lengths
|
|
ok(validate_api_key_format("sk-abcdefghij", "openai"),
|
|
"OpenAI key with exactly 10 chars accepted");
|
|
ok(validate_api_key_format("sk-ant-abcdefghijklmnop", "anthropic"),
|
|
"Anthropic key with exactly 25 chars accepted");
|
|
|
|
// Test keys with whitespace at boundaries (should be rejected)
|
|
ok(!validate_api_key_format(" sk-abcdefghij", "openai"),
|
|
"API key with leading space rejected");
|
|
ok(!validate_api_key_format("sk-abcdefghij ", "openai"),
|
|
"API key with trailing space rejected");
|
|
ok(!validate_api_key_format("sk-abc def-ghij", "openai"),
|
|
"API key with internal space rejected");
|
|
ok(!validate_api_key_format("sk-abcdefghij\t", "openai"),
|
|
"API key with tab rejected");
|
|
ok(!validate_api_key_format("sk-abcdefghij\n", "openai"),
|
|
"API key with newline rejected");
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test: URL Validation Edge Cases
|
|
// ============================================================================
|
|
|
|
void test_url_edge_cases() {
|
|
diag("=== URL Validation Edge Cases ===");
|
|
|
|
// Test IPv6 URLs
|
|
ok(validate_url_format("http://[2001:db8::1]:8080/v1/chat/completions"),
|
|
"IPv6 URL with port accepted");
|
|
ok(validate_url_format("https://[::1]/v1/chat/completions"),
|
|
"IPv6 localhost URL accepted");
|
|
|
|
// Test unusual ports
|
|
ok(validate_url_format("http://localhost:1/v1/chat/completions"),
|
|
"URL with port 1 accepted");
|
|
ok(validate_url_format("http://localhost:65535/v1/chat/completions"),
|
|
"URL with port 65535 accepted");
|
|
|
|
// Test URLs with paths and query parameters
|
|
ok(validate_url_format("https://api.openai.com/v1/chat/completions?timeout=30"),
|
|
"URL with query parameters accepted");
|
|
ok(validate_url_format("http://localhost:11434/v1/chat/completions/model/llama3"),
|
|
"URL with additional path segments accepted");
|
|
|
|
// Test malformed URLs that should be rejected
|
|
ok(!validate_url_format("http://"),
|
|
"URL with only protocol rejected");
|
|
ok(!validate_url_format("http://:8080"),
|
|
"URL with port but no host rejected");
|
|
ok(!validate_url_format("localhost:8080/v1/chat/completions"),
|
|
"URL without protocol rejected");
|
|
ok(!validate_url_format("ftp://localhost/v1/chat/completions"),
|
|
"FTP URL rejected (only HTTP/HTTPS supported)");
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test: Numeric Range Edge Cases
|
|
// ============================================================================
|
|
|
|
void test_numeric_range_edge_cases() {
|
|
diag("=== Numeric Range Edge Cases ===");
|
|
|
|
// Test boundary values
|
|
ok(validate_numeric_range("0", 0, 100, "test_var"),
|
|
"Minimum boundary value accepted");
|
|
ok(validate_numeric_range("100", 0, 100, "test_var"),
|
|
"Maximum boundary value accepted");
|
|
ok(!validate_numeric_range("-1", 0, 100, "test_var"),
|
|
"Value below minimum rejected");
|
|
ok(!validate_numeric_range("101", 0, 100, "test_var"),
|
|
"Value above maximum rejected");
|
|
|
|
// Test string values that are valid numbers
|
|
ok(validate_numeric_range("50", 0, 100, "test_var"),
|
|
"Valid number string accepted");
|
|
ok(!validate_numeric_range("abc", 0, 100, "test_var"),
|
|
"Non-numeric string rejected");
|
|
ok(!validate_numeric_range("50abc", 0, 100, "test_var"),
|
|
"String starting with number rejected");
|
|
ok(!validate_numeric_range("", 0, 100, "test_var"),
|
|
"Empty string rejected");
|
|
|
|
// Test negative numbers
|
|
ok(validate_numeric_range("-50", -100, 0, "test_var"),
|
|
"Negative number within range accepted");
|
|
ok(!validate_numeric_range("-150", -100, 0, "test_var"),
|
|
"Negative number below range rejected");
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test: Provider Format Edge Cases
|
|
// ============================================================================
|
|
|
|
void test_provider_format_edge_cases() {
|
|
diag("=== Provider Format Edge Cases ===");
|
|
|
|
// Test case sensitivity
|
|
ok(!validate_provider_format("OpenAI"),
|
|
"Uppercase 'OpenAI' rejected (case sensitive)");
|
|
ok(!validate_provider_format("OPENAI"),
|
|
"Uppercase 'OPENAI' rejected (case sensitive)");
|
|
ok(!validate_provider_format("Anthropic"),
|
|
"Uppercase 'Anthropic' rejected (case sensitive)");
|
|
ok(!validate_provider_format("ANTHROPIC"),
|
|
"Uppercase 'ANTHROPIC' rejected (case sensitive)");
|
|
|
|
// Test provider names with whitespace
|
|
ok(!validate_provider_format(" openai"),
|
|
"Provider with leading space rejected");
|
|
ok(!validate_provider_format("openai "),
|
|
"Provider with trailing space rejected");
|
|
ok(!validate_provider_format(" openai "),
|
|
"Provider with leading and trailing spaces rejected");
|
|
ok(!validate_provider_format("open ai"),
|
|
"Provider with internal space rejected");
|
|
|
|
// Test empty and NULL cases
|
|
ok(!validate_provider_format(""),
|
|
"Empty provider format rejected");
|
|
ok(!validate_provider_format(NULL),
|
|
"NULL provider format rejected");
|
|
|
|
// Test similar but invalid provider names
|
|
ok(!validate_provider_format("openai2"),
|
|
"Similar but invalid provider 'openai2' rejected");
|
|
ok(!validate_provider_format("anthropic2"),
|
|
"Similar but invalid provider 'anthropic2' rejected");
|
|
ok(!validate_provider_format("ollama"),
|
|
"Provider 'ollama' rejected (use 'openai' format instead)");
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test: Edge Cases and Boundary Conditions
|
|
// ============================================================================
|
|
|
|
void test_general_edge_cases() {
|
|
diag("=== General Edge Cases ===");
|
|
|
|
// Test extremely long strings
|
|
char* long_string = (char*)malloc(10000);
|
|
memset(long_string, 'a', 9999);
|
|
long_string[9999] = '\0';
|
|
ok(validate_api_key_format(long_string, "openai"),
|
|
"Extremely long API key accepted");
|
|
free(long_string);
|
|
|
|
// Test strings with special Unicode characters (if supported)
|
|
// Note: This is a basic test - actual Unicode support depends on system
|
|
ok(validate_api_key_format("sk-testkey123", "openai"),
|
|
"Standard ASCII key accepted");
|
|
}
|
|
|
|
// ============================================================================
|
|
// Main
|
|
// ============================================================================
|
|
|
|
int main() {
|
|
// Plan: 35 tests total
|
|
// API key edge cases: 10 tests
|
|
// URL edge cases: 9 tests
|
|
// Numeric range edge cases: 8 tests
|
|
// Provider format edge cases: 8 tests
|
|
plan(35);
|
|
|
|
test_api_key_edge_cases();
|
|
test_url_edge_cases();
|
|
test_numeric_range_edge_cases();
|
|
test_provider_format_edge_cases();
|
|
test_general_edge_cases();
|
|
|
|
return exit_status();
|
|
} |