diff --git a/.clj-kondo/nubank/matcher-combinators/config.edn b/.clj-kondo/nubank/matcher-combinators/config.edn new file mode 100644 index 0000000..ea4ded7 --- /dev/null +++ b/.clj-kondo/nubank/matcher-combinators/config.edn @@ -0,0 +1,4 @@ +{:linters + {:unresolved-symbol + {:exclude [(cljs.test/is [match? thrown-match?]) + (clojure.test/is [match? thrown-match?])]}}} diff --git a/project.clj b/project.clj index aee127d..a5f0f7d 100644 --- a/project.clj +++ b/project.clj @@ -18,5 +18,5 @@ :aliases {"lint" ["do" ["cljfmt" "check"] ["nsorg"] ["kibit"]] "lint-fix" ["do" ["cljfmt" "fix"] ["nsorg" "--replace"] ["kibit" "--replace"]]} :profiles {:uberjar {:aot :all} - :dev {:dependencies [[nubank/matcher-combinators "1.2.7"] - [mockfn "0.5.0"]]}}) + :dev {:dependencies [[nubank/matcher-combinators "3.8.5"] + [nubank/mockfn "0.7.0"]]}}) diff --git a/src/kubernetes_api/core.clj b/src/kubernetes_api/core.clj index 5e148d5..85cc3d8 100644 --- a/src/kubernetes_api/core.clj +++ b/src/kubernetes_api/core.clj @@ -123,4 +123,3 @@ schemas" [k8s params] (martian/explore k8s (internals.client/find-preferred-route k8s (dissoc params :request)))) - diff --git a/src/kubernetes_api/interceptors/raise.clj b/src/kubernetes_api/interceptors/raise.clj index 02633b3..37ba360 100644 --- a/src/kubernetes_api/interceptors/raise.clj +++ b/src/kubernetes_api/interceptors/raise.clj @@ -1,6 +1,6 @@ (ns kubernetes-api.interceptors.raise) -(defn status-error? [status] +(defn- status-error? [status] (or (nil? status) (>= status 400))) (def ^:private error-type->status-code @@ -34,23 +34,30 @@ :gateway-timeout 504 :http-version-not-supported 505}) -(def status-code->error-type (zipmap (vals error-type->status-code) (keys error-type->status-code))) +(def ^:private status-code->error-type (zipmap (vals error-type->status-code) (keys error-type->status-code))) -(defn raise-exception [{:keys [status] :as response}] - (throw (ex-info (str "APIServer error: " status) - {:type (status-code->error-type status) - :response response}))) +(defn- make-exception [{:keys [status] :as response}] + (ex-info (str "APIServer error: " status) + {:type (status-code->error-type status) + :response response})) (defn check-response "Checks the status code. If 400+, raises an exception, returns body otherwise" [response] (cond (:error response) (throw (:error response)) - (status-error? (:status response)) (raise-exception response) + (status-error? (:status response)) (throw (make-exception response)) :else (:body response))) +(defn- maybe-assoc-error [{:keys [error status] :as response}] + (cond + error (assoc response :kubernetes-api.core/error error) + (status-error? status) (assoc response :kubernetes-api.core/error (make-exception response)) + :else response)) + (defn new [_] {:name ::raise - :leave (fn [{:keys [request response] :as _context}] - (with-meta {:response (check-response response)} - {:request request :response response}))}) + :leave (fn [{:keys [request response] :as context}] + (with-meta + (update context :response maybe-assoc-error) + {:response response :request request}))}) diff --git a/src/kubernetes_api/internals/martian.clj b/src/kubernetes_api/internals/martian.clj index 71041ef..542b3f5 100644 --- a/src/kubernetes_api/internals/martian.clj +++ b/src/kubernetes_api/internals/martian.clj @@ -4,7 +4,6 @@ (defn response-for "Workaround to throw exceptions in the client like connection timeout" [& args] - (let [response (deref (apply martian/response-for args))] - (if (instance? Throwable (:error response)) - (throw (:error response)) - response))) + (let [{:kubernetes-api.core/keys [error] :keys [body]} (deref (apply martian/response-for args))] + (when (instance? Throwable error) (throw error)) + body)) diff --git a/src/kubernetes_api/swagger.clj b/src/kubernetes_api/swagger.clj index 51ab14d..ee41b68 100644 --- a/src/kubernetes_api/swagger.clj +++ b/src/kubernetes_api/swagger.clj @@ -1,12 +1,12 @@ (ns kubernetes-api.swagger (:refer-clojure :exclude [read]) (:require [cheshire.core :as json] + [clojure.java.io :as io] [clojure.string :as string] [clojure.walk :as walk] [kubernetes-api.interceptors.auth :as interceptors.auth] [kubernetes-api.interceptors.raise :as interceptors.raise] - [org.httpkit.client :as http] - [clojure.java.io :as io])) + [org.httpkit.client :as http])) (defn remove-watch-endpoints "Watch endpoints doesn't follow the http1.1 specification, so it will not work diff --git a/test/kubernetes_api/interceptors/raise_test.clj b/test/kubernetes_api/interceptors/raise_test.clj index 76aa9b3..8b1b3b7 100644 --- a/test/kubernetes_api/interceptors/raise_test.clj +++ b/test/kubernetes_api/interceptors/raise_test.clj @@ -1,25 +1,31 @@ (ns kubernetes-api.interceptors.raise-test - (:require [clojure.test :refer :all] + (:require [clojure.test :refer [deftest is testing]] [kubernetes-api.interceptors.raise :as interceptors.raise] - [matcher-combinators.test])) + [matcher-combinators.matchers :as m] + [matcher-combinators.test :refer [match?]] + [tripod.context :as tc])) + +(defn- run-interceptor [interceptor input] + (tc/execute (tc/enqueue input interceptor))) (deftest raise-test - (let [{:keys [leave]} (interceptors.raise/new {})] + (let [raise-interceptor (interceptors.raise/new {})] (testing "should raise the body to be the response on 2xx status" - (is (match? - {:response {:my :body}} - (leave {:response {:status 200 - :body {:my :body}}})))) + (is (match? {:response {:status 200 + :body {:my :body}}} + (run-interceptor raise-interceptor {:response {:status 200 :body {:my :body}}})))) + (testing "should have the request/response on metadata" - (is (match? - {:request {:my :request} - :response {:status 200 - :body {:my :body}}} - (meta (leave {:request {:my :request} - :response {:status 200 - :body {:my :body}}}))))) + (is (match? {:request {:my :request} + :response {:status 200 + :body {:my :body}}} + (meta + (run-interceptor raise-interceptor {:request {:my :request} + :response {:status 200 + :body {:my :body}}}))))) - (testing "should raise exception on 4XX responses" - (is (thrown-match? - {:type :unauthorized} - (leave {:response {:status 401}})))))) + (testing "return an exception on 4XX responses" + (is (match? (m/via (comp ex-data :kubernetes-api.core/error :response) + {:type :bad-request, + :response {:status 400}}) + (run-interceptor raise-interceptor {:response {:status 400}})))))) diff --git a/test/kubernetes_api/internals/martian_test.clj b/test/kubernetes_api/internals/martian_test.clj new file mode 100644 index 0000000..5cbe484 --- /dev/null +++ b/test/kubernetes_api/internals/martian_test.clj @@ -0,0 +1,15 @@ +(ns kubernetes-api.internals.martian-test + (:require [clojure.test :refer [deftest is testing]] + [kubernetes-api.internals.martian :as internals.martian] + [martian.core :as martian] + [matcher-combinators.test :refer [thrown-match?]] + [mockfn.macros :refer [providing]]) + (:import [clojure.lang ExceptionInfo])) + +(deftest response-for + (testing "Throws exception from client" + (providing [(martian/response-for 'martian 'testing) + (delay {:kubernetes-api.core/error (ex-info "Test error" {:type :error})})] + (is (thrown-match? ExceptionInfo + {:type :error} + (internals.martian/response-for 'martian 'testing)))))) \ No newline at end of file