|
7 | 7 | [eca.secrets :as secrets] |
8 | 8 | [matcher-combinators.test :refer [match?]]) |
9 | 9 | (:import |
10 | | - [java.io ByteArrayInputStream])) |
| 10 | + [java.io ByteArrayInputStream] |
| 11 | + [java.net ConnectException SocketTimeoutException UnknownHostException] |
| 12 | + [javax.net.ssl SSLException SSLHandshakeException])) |
11 | 13 |
|
12 | 14 | (deftest event-data-seq-test |
13 | 15 | (testing "when there is a event line and another data line" |
|
185 | 187 |
|
186 | 188 | (testing "returns nil for blank url" |
187 | 189 | (with-redefs [config/get-env (constantly nil)] |
188 | | - (is (nil? (llm-util/provider-api-url "openai" {:providers {"openai" {:url " "}}})))))) |
| 190 | + (is (nil? (llm-util/provider-api-url "openai" {:providers {"openai" {:url " "}}})))))) |
| 191 | + |
| 192 | +(deftest classify-connection-exception-test |
| 193 | + (testing "PKIX path building failed -> :tls-untrusted with actionable hint" |
| 194 | + (let [e (SSLHandshakeException. "PKIX path building failed: unable to find valid certification path to requested target") |
| 195 | + {:keys [kind message]} (llm-util/classify-connection-exception e)] |
| 196 | + (is (= :tls-untrusted kind)) |
| 197 | + (is (re-find #"TLS certificate not trusted" message)) |
| 198 | + (is (re-find #"network\.caCertFile" message)) |
| 199 | + (is (re-find #"SSL_CERT_FILE" message)) |
| 200 | + (is (re-find #"docs/config/network\.md" message)))) |
| 201 | + |
| 202 | + (testing "PKIX detected even when wrapped in a non-SSL outer exception" |
| 203 | + (let [root (Exception. "PKIX path building failed: unable to find valid certification path to requested target") |
| 204 | + wrapped (RuntimeException. "wrapper" root) |
| 205 | + {:keys [kind message]} (llm-util/classify-connection-exception wrapped)] |
| 206 | + (is (= :tls-untrusted kind)) |
| 207 | + (is (re-find #"network\.caCertFile" message)))) |
| 208 | + |
| 209 | + (testing "Generic SSLException (no PKIX) -> :tls-other" |
| 210 | + (let [e (SSLException. "handshake_failure") |
| 211 | + {:keys [kind message]} (llm-util/classify-connection-exception e)] |
| 212 | + (is (= :tls-other kind)) |
| 213 | + (is (re-find #"TLS error" message)) |
| 214 | + (is (re-find #"docs/config/network\.md" message)))) |
| 215 | + |
| 216 | + (testing "UnknownHostException -> :dns" |
| 217 | + (let [e (UnknownHostException. "no-such-host.example") |
| 218 | + {:keys [kind message]} (llm-util/classify-connection-exception e)] |
| 219 | + (is (= :dns kind)) |
| 220 | + (is (re-find #"DNS resolution failed" message)))) |
| 221 | + |
| 222 | + (testing "ConnectException (e.g. Connection refused) -> :connect-refused" |
| 223 | + (let [e (ConnectException. "Connection refused") |
| 224 | + {:keys [kind message]} (llm-util/classify-connection-exception e)] |
| 225 | + (is (= :connect-refused kind)) |
| 226 | + (is (re-find #"Could not connect" message)) |
| 227 | + (is (re-find #"HTTP_PROXY" message)))) |
| 228 | + |
| 229 | + (testing "SocketTimeoutException -> :timeout" |
| 230 | + (let [e (SocketTimeoutException. "Read timed out") |
| 231 | + {:keys [kind message]} (llm-util/classify-connection-exception e)] |
| 232 | + (is (= :timeout kind)) |
| 233 | + (is (re-find #"Connection timed out" message)))) |
| 234 | + |
| 235 | + (testing "Unknown exception falls back to legacy 'Connection error:' format" |
| 236 | + (let [e (Exception. "boom") |
| 237 | + {:keys [kind message]} (llm-util/classify-connection-exception e)] |
| 238 | + (is (= :unknown kind)) |
| 239 | + (is (= "Connection error: boom" message)))) |
| 240 | + |
| 241 | + (testing "Exception with nil message uses class name as fallback" |
| 242 | + (let [e (Exception.) |
| 243 | + {:keys [kind message]} (llm-util/classify-connection-exception e)] |
| 244 | + (is (= :unknown kind)) |
| 245 | + (is (re-find #"Connection error: java\.lang\.Exception" message))))) |
| 246 | + |
| 247 | +(deftest connection-error-message-test |
| 248 | + (testing "returns the :message from classify-connection-exception" |
| 249 | + (is (re-find #"TLS certificate not trusted" |
| 250 | + (llm-util/connection-error-message |
| 251 | + (SSLHandshakeException. "PKIX path building failed: ..."))))) |
| 252 | + (testing "is non-nil for any exception" |
| 253 | + (is (string? (llm-util/connection-error-message (Exception. "x")))) |
| 254 | + (is (string? (llm-util/connection-error-message (Exception.)))))) |
| 255 | + |
0 commit comments