diff --git a/deps.edn b/deps.edn index 39c29550..363c0459 100644 --- a/deps.edn +++ b/deps.edn @@ -9,6 +9,7 @@ "feature-spec-alpha" "feature-rewrite-clj" "feature-selmer" + "feature-logging" "pods/src" "babashka.nrepl/src" "depstar/src" "process/src" @@ -88,7 +89,8 @@ crispin/crispin {:mvn/version "0.3.8"} org.clojure/data.json {:mvn/version "2.4.0"} clj-commons/multigrep {:mvn/version "0.5.0"} - amperity/vault-clj {:mvn/version "1.0.4"}} + amperity/vault-clj {:mvn/version "1.0.4"} + java-http-clj/java-http-clj {:mvn/version "0.4.3"}} :classpath-overrides {org.clojure/clojure nil org.clojure/spec.alpha nil org.clojure/core.specs.alpha nil}} diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 39075dc5..98d59b72 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -2,6 +2,7 @@ {:no-doc true} (:require [babashka.impl.features :as features] + [sci.impl.types :as t] [cheshire.core :as json])) (def custom-map @@ -444,7 +445,11 @@ (instance? java.nio.channels.FileChannel v) java.nio.channels.FileChannel (instance? java.net.CookieStore v) - java.net.CookieStore))))) + java.net.CookieStore + ;; this makes interop on reified classes work + ;; see java_net_http_test/interop-test + (instance? sci.impl.types.IReified v) + (first (t/getInterfaces v))))))) (def class-map (gen-class-map)) diff --git a/test-resources/lib_tests/babashka/run_all_libtests.clj b/test-resources/lib_tests/babashka/run_all_libtests.clj index bda377ee..1d65e503 100644 --- a/test-resources/lib_tests/babashka/run_all_libtests.clj +++ b/test-resources/lib_tests/babashka/run_all_libtests.clj @@ -250,6 +250,10 @@ #_'vault.secrets.kvv1-test #_'vault.secrets.kvv2-test) +;; we don't really run any tests for java-http-clj yet, but we require the +;; namespaces to see if they at least load correctly +(test-namespaces 'java-http-clj.smoke-test) + ;;;; final exit code (let [{:keys [:test :fail :error] :as m} @status] diff --git a/test-resources/lib_tests/java_http_clj/smoke_test.clj b/test-resources/lib_tests/java_http_clj/smoke_test.clj new file mode 100644 index 00000000..30d5c7e9 --- /dev/null +++ b/test-resources/lib_tests/java_http_clj/smoke_test.clj @@ -0,0 +1,41 @@ +(ns java-http-clj.smoke-test + (:require [clojure.test :refer [deftest is] :as t] + [java-http-clj.core :as client] + [java-http-clj.websocket :as ws-client] + [org.httpkit.server :as httpkit.server])) + +(deftest general-smoke-test + (is (= 200 (:status (client/get "https://www.clojure.org")))) + (is (instance? java.net.http.WebSocket$Builder (ws-client/websocket-builder)))) + + +(defn ws-handler [{:keys [init] :as opts} req] + (when init (init req)) + (httpkit.server/as-channel + req + (select-keys opts [:on-close :on-ping :on-receive]))) + +(def ^:dynamic *ws-port* 1234) + +(defmacro with-ws-server + [opts & body] + `(let [s# (httpkit.server/run-server (partial ws-handler ~opts) {:port ~*ws-port*})] + (try ~@body (finally (s# :timeout 100))))) + +(deftest websockets-smoke-test + (with-ws-server {:on-receive #(httpkit.server/send! %1 %2)} + (is (= "zomg websockets!" + (let [p (promise) + ws (ws-client/build-websocket "ws://localhost:1234" + {:on-binary (fn [_ data last?] (deliver p data)) + :on-text (fn [ws data last?] (deliver p data)) + :on-error (fn [ws throwable] (deliver p throwable)) + :on-ping (fn [ws data] (deliver p data)) + :on-pong (fn [ws data] (deliver p data)) + :on-open (fn [ws] nil) + :on-close (fn [ws status-code reason] nil)})] + (-> ws + (ws-client/send "zomg websockets!")) + (try (deref p 5000 ::timeout) + (finally + (ws-client/close ws)))))))) diff --git a/test/babashka/java_net_http_test.clj b/test/babashka/java_net_http_test.clj index 9700ed50..6e68c896 100644 --- a/test/babashka/java_net_http_test.clj +++ b/test/babashka/java_net_http_test.clj @@ -6,11 +6,20 @@ [clojure.test :as test :refer [deftest is]] [org.httpkit.server :as httpkit.server])) -(defn bb [expr] - (edn/read-string (apply test-utils/bb nil [(str expr)]))) +(defn bb [& exprs] + (edn/read-string (apply test-utils/bb nil (map str exprs)))) ;; HttpClient +(deftest interop-test + (is (= :hello + (bb "-e" + (binding [*print-meta* true] + '(do + (def res (atom nil)) + (def x (reify java.net.http.WebSocket$Listener (onOpen [this ws] (reset! res :hello)))) + (.onOpen ^java.net.http.WebSocket$Listener x nil) @res)))))) + (deftest send-test (is (= [200 true] (bb @@ -34,22 +43,22 @@ (deftest send-async-test (is (= [200 true] (bb - '(do - (ns net - (:import - (java.net URI) - (java.net.http HttpClient - HttpRequest - HttpResponse$BodyHandlers) - (java.util.function Function))) + '(do + (ns net + (:import + (java.net URI) + (java.net.http HttpClient + HttpRequest + HttpResponse$BodyHandlers) + (java.util.function Function))) - (let [client (HttpClient/newHttpClient) - req (-> (HttpRequest/newBuilder (URI. "https://www.clojure.org")) - (.GET) - (.build))] - (-> (.sendAsync client req (HttpResponse$BodyHandlers/ofString)) - (.thenApply (reify Function (apply [_ res] [(.statusCode res) (string? (.body res))]))) - (deref)))))))) + (let [client (HttpClient/newHttpClient) + req (-> (HttpRequest/newBuilder (URI. "https://www.clojure.org")) + (.GET) + (.build))] + (-> (.sendAsync client req (HttpResponse$BodyHandlers/ofString)) + (.thenApply (reify Function (apply [_ res] [(.statusCode res) (string? (.body res))]))) + (deref)))))))) ;; HttpClient options @@ -115,89 +124,89 @@ (deftest connect-timeout-test (is (= "java.net.http.HttpConnectTimeoutException" (bb - '(do - (ns net - (:import - (java.net URI) - (java.net.http HttpClient - HttpRequest - HttpResponse$BodyHandlers) - (java.time Duration))) + '(do + (ns net + (:import + (java.net URI) + (java.net.http HttpClient + HttpRequest + HttpResponse$BodyHandlers) + (java.time Duration))) - (let [client (-> (HttpClient/newBuilder) - (.connectTimeout (Duration/ofMillis 1)) - (.build)) - req (-> (HttpRequest/newBuilder (URI. "Https://www.postman-echo.com/get")) - (.GET) - (.build))] - (try - (.send client req (HttpResponse$BodyHandlers/discarding)) - (catch Throwable t - (-> (Throwable->map t) - :via - first - :type - name))))))))) + (let [client (-> (HttpClient/newBuilder) + (.connectTimeout (Duration/ofMillis 1)) + (.build)) + req (-> (HttpRequest/newBuilder (URI. "Https://www.postman-echo.com/get")) + (.GET) + (.build))] + (try + (.send client req (HttpResponse$BodyHandlers/discarding)) + (catch Throwable t + (-> (Throwable->map t) + :via + first + :type + name))))))))) (deftest executor-test (is (= 200 (bb - '(do - (ns net - (:import - (java.net URI) - (java.net.http HttpClient - HttpRequest - HttpResponse$BodyHandlers) - (java.util.concurrent Executors))) + '(do + (ns net + (:import + (java.net URI) + (java.net.http HttpClient + HttpRequest + HttpResponse$BodyHandlers) + (java.util.concurrent Executors))) - (let [uri (URI. "https://www.postman-echo.com/get") - req (-> (HttpRequest/newBuilder uri) - (.GET) - (.build)) - client (-> (HttpClient/newBuilder) - (.executor (Executors/newSingleThreadExecutor)) - (.build)) - res (.send client req (HttpResponse$BodyHandlers/discarding))] - (.statusCode res))))))) + (let [uri (URI. "https://www.postman-echo.com/get") + req (-> (HttpRequest/newBuilder uri) + (.GET) + (.build)) + client (-> (HttpClient/newBuilder) + (.executor (Executors/newSingleThreadExecutor)) + (.build)) + res (.send client req (HttpResponse$BodyHandlers/discarding))] + (.statusCode res))))))) (deftest proxy-test (is (= true (bb - '(do - (ns net - (:import - (java.net ProxySelector) - (java.net.http HttpClient))) + '(do + (ns net + (:import + (java.net ProxySelector) + (java.net.http HttpClient))) - (let [bespoke-proxy (proxy [ProxySelector] [] - (connectFailed [_ _ _]) - (select [_ _])) - client (-> (HttpClient/newBuilder) - (.proxy bespoke-proxy) - (.build))] - (= bespoke-proxy (-> (.proxy client) - (.get)))))))) + (let [bespoke-proxy (proxy [ProxySelector] [] + (connectFailed [_ _ _]) + (select [_ _])) + client (-> (HttpClient/newBuilder) + (.proxy bespoke-proxy) + (.build))] + (= bespoke-proxy (-> (.proxy client) + (.get)))))))) (is (= 200 (bb - '(do - (ns net - (:import - (java.net ProxySelector - URI) - (java.net.http HttpClient - HttpRequest - HttpResponse$BodyHandlers))) + '(do + (ns net + (:import + (java.net ProxySelector + URI) + (java.net.http HttpClient + HttpRequest + HttpResponse$BodyHandlers))) - (let [uri (URI. "https://www.postman-echo.com/get") - req (-> (HttpRequest/newBuilder uri) - (.build)) - client (-> (HttpClient/newBuilder) - (.proxy (ProxySelector/getDefault)) - (.build)) - res (.send client req (HttpResponse$BodyHandlers/discarding))] - (.statusCode res))))))) + (let [uri (URI. "https://www.postman-echo.com/get") + req (-> (HttpRequest/newBuilder uri) + (.build)) + client (-> (HttpClient/newBuilder) + (.proxy (ProxySelector/getDefault)) + (.build)) + res (.send client req (HttpResponse$BodyHandlers/discarding))] + (.statusCode res))))))) (deftest redirect-test (let [redirect-prog @@ -353,7 +362,7 @@ client (HttpClient/newHttpClient) res (.send client req (HttpResponse$BodyHandlers/ofString)) body-data (-> (.body res) (json/parse-string true) :data)] - (str/includes? body-data "babashka")))))) + (str/includes? body-data "babashka")))))) (let [body "with love from java.net.http"] (is (= {:of-input-stream body @@ -375,7 +384,7 @@ (let [body "with love from java.net.http" publishers {:of-input-stream (HttpRequest$BodyPublishers/ofInputStream - (reify Supplier (get [_] (io/input-stream (.getBytes body))))) + (reify Supplier (get [_] (io/input-stream (.getBytes body))))) :of-byte-array (HttpRequest$BodyPublishers/ofByteArray (.getBytes body)) :of-byte-arrays (HttpRequest$BodyPublishers/ofByteArrays [(.getBytes body)])} client (-> (HttpClient/newBuilder) @@ -424,28 +433,28 @@ (deftest request-timeout-test (is (= "java.net.http.HttpTimeoutException" (bb - '(do - (ns net - (:import - (java.net URI) - (java.net.http HttpClient - HttpRequest - HttpResponse$BodyHandlers) - (java.time Duration))) + '(do + (ns net + (:import + (java.net URI) + (java.net.http HttpClient + HttpRequest + HttpResponse$BodyHandlers) + (java.time Duration))) - (let [client (HttpClient/newHttpClient) - req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/delay/1")) - (.GET) - (.timeout (Duration/ofMillis 200)) - (.build))] - (try - (.send client req (HttpResponse$BodyHandlers/discarding)) - (catch Throwable t - (-> (Throwable->map t) - :via - first - :type - name))))))))) + (let [client (HttpClient/newHttpClient) + req (-> (HttpRequest/newBuilder (URI. "https://www.postman-echo.com/delay/1")) + (.GET) + (.timeout (Duration/ofMillis 200)) + (.build))] + (try + (.send client req (HttpResponse$BodyHandlers/discarding)) + (catch Throwable t + (-> (Throwable->map t) + :via + first + :type + name))))))))) (deftest body-handlers-test (is (= true @@ -482,8 +491,8 @@ (defn ws-handler [{:keys [init] :as opts} req] (when init (init req)) (httpkit.server/as-channel - req - (select-keys opts [:on-close :on-ping :on-receive]))) + req + (select-keys opts [:on-close :on-ping :on-receive]))) (def ^:dynamic *ws-port* 1234)