From 110f6d76447f1d21736f8d7e204a0db8afcd9742 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 8 Apr 2020 21:18:25 +0200 Subject: [PATCH] [#336] Add java.lang.Runtime to support shutdown hooks (#338) --- src/babashka/impl/classes.clj | 1 + src/babashka/impl/sigint_handler.clj | 14 +++++++++++ src/babashka/main.clj | 3 +++ test/babashka/http_connection_test.clj | 10 ++++---- test/babashka/main_test.clj | 9 +++++-- .../scripts/download_and_extract_zip.bb | 7 +++--- test/babashka/scripts/interrupt_handler.bb | 6 +++++ test/babashka/shutdown_hook_test.clj | 24 +++++++++++++++++++ 8 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 src/babashka/impl/sigint_handler.clj create mode 100644 test/babashka/scripts/interrupt_handler.bb create mode 100644 test/babashka/shutdown_hook_test.clj diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index fc500fe1..64e04cdc 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -39,6 +39,7 @@ java.lang.Long java.lang.NumberFormatException java.lang.Math + java.lang.Runtime java.lang.RuntimeException java.util.concurrent.LinkedBlockingQueue java.lang.Object diff --git a/src/babashka/impl/sigint_handler.clj b/src/babashka/impl/sigint_handler.clj new file mode 100644 index 00000000..9708bc59 --- /dev/null +++ b/src/babashka/impl/sigint_handler.clj @@ -0,0 +1,14 @@ +(ns babashka.impl.sigint-handler + {:no-doc true} + (:import [sun.misc Signal] + [sun.misc SignalHandler])) + +(set! *warn-on-reflection* true) + +(defn handle-sigint! [] + (Signal/handle + (Signal. "INT") + (reify SignalHandler + (handle [_ _] + ;; This is needed to run shutdown hooks on interrupt, System/exit triggers those + (System/exit 0))))) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index e893bd52..caa3ebdd 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -18,6 +18,7 @@ [babashka.impl.nrepl-server :as nrepl-server] [babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]] [babashka.impl.repl :as repl] + [babashka.impl.sigint-handler :as sigint-handler] [babashka.impl.socket-repl :as socket-repl] [babashka.impl.test :as t] [babashka.impl.tools.cli :refer [tools-cli-namespace]] @@ -303,6 +304,7 @@ Everything after that is bound to *command-line-args*.")) (defn main [& args] (handle-pipe!) + (sigint-handler/handle-sigint!) #_(binding [*out* *err*] (prn "M" (meta (get bindings 'future)))) (binding [*unrestricted* true] @@ -368,6 +370,7 @@ Everything after that is bound to *command-line-args*.")) Math java.lang.Math NumberFormatException java.lang.NumberFormatException Object java.lang.Object + Runtime java.lang.Runtime RuntimeException java.lang.RuntimeException ProcessBuilder java.lang.ProcessBuilder String java.lang.String diff --git a/test/babashka/http_connection_test.clj b/test/babashka/http_connection_test.clj index ec78fa12..25a5338e 100644 --- a/test/babashka/http_connection_test.clj +++ b/test/babashka/http_connection_test.clj @@ -1,14 +1,14 @@ (ns babashka.http-connection-test (:require [babashka.test-utils :as tu] - [clojure.test :as t :refer [deftest is]] - [clojure.string :as str])) + [clojure.string :as str] + [clojure.test :as t :refer [deftest is]])) (defn bb [& args] (apply tu/bb nil (map str args))) (deftest open-connection-test - (is (= "\"1\"" (str/trim (bb "-e" " + (is (try (= "\"1\"" (str/trim (bb "-e" " (require '[cheshire.core :as json]) (let [conn ^java.net.HttpURLConnection (.openConnection (java.net.URL. \"https://postman-echo.com/get?foo=1\"))] (.setConnectTimeout conn 1000) @@ -18,4 +18,6 @@ err (.getErrorStream conn) response (json/decode (slurp is) true)] (-> response :args :foo))) -"))))) +"))) + (catch Exception e + (str/includes? (str e) "timed out"))))) diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index 12c9d514..749f5ce3 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -9,6 +9,9 @@ [clojure.test :as test :refer [deftest is testing]] [sci.core :as sci])) +#_(defmethod clojure.test/report :begin-test-var [m] + (println (-> m :var meta :name))) + (defn bb [input & args] (edn/read-string (apply test-utils/bb (when (some? input) (str input)) (map str args)))) @@ -164,7 +167,7 @@ (deftest future-test (is (= 6 (bb nil "@(future (+ 1 2 3))")))) - + (deftest promise-test (is (= :timeout (bb nil "(deref (promise) 1 :timeout)"))) (is (= :ok (bb nil "(let [x (promise)] @@ -376,7 +379,9 @@ (is v)))) (deftest download-and-extract-test - (is (= 6 (bb nil (io/file "test" "babashka" "scripts" "download_and_extract_zip.bb"))))) + (is (try (= 6 (bb nil (io/file "test" "babashka" "scripts" "download_and_extract_zip.bb"))) + (catch Exception e + (is (str/includes? (str e) "timed out")))))) (deftest get-message-on-exception-info-test (is "foo" (bb nil "(try (throw (ex-info \"foo\" {})) (catch Exception e (.getMessage e)))"))) diff --git a/test/babashka/scripts/download_and_extract_zip.bb b/test/babashka/scripts/download_and_extract_zip.bb index fd2bc150..befe9258 100644 --- a/test/babashka/scripts/download_and_extract_zip.bb +++ b/test/babashka/scripts/download_and_extract_zip.bb @@ -11,7 +11,9 @@ tmp-dir (System/getProperty "java.io.tmpdir") zip-file (io/file tmp-dir "bb-0.0.78.zip") source (URL. (format "https://github.com/borkdude/babashka/releases/download/v0.0.78/babashka-0.0.78-%s-amd64.zip" os)) - conn ^HttpURLConnection (.openConnection ^URL source)] + conn ^HttpURLConnection (.openConnection ^URL source) + _ (.setConnectTimeout conn 2000) + _ (.setReadTimeout conn 2000)] (.connect conn) (with-open [is (.getInputStream conn)] (io/copy is zip-file)) @@ -26,6 +28,3 @@ (.delete bb-file) (.delete zip-file) (println out)))) - - - diff --git a/test/babashka/scripts/interrupt_handler.bb b/test/babashka/scripts/interrupt_handler.bb new file mode 100644 index 00000000..02291139 --- /dev/null +++ b/test/babashka/scripts/interrupt_handler.bb @@ -0,0 +1,6 @@ +(require '[babashka.signal :as signal]) + +(signal/add-interrupt-handler! :quit (fn [k] (println "bye1" k))) +(signal/add-interrupt-handler! :quit2 (fn [k] (println "bye2" k))) + +(System/exit 0) diff --git a/test/babashka/shutdown_hook_test.clj b/test/babashka/shutdown_hook_test.clj new file mode 100644 index 00000000..8c2c1f82 --- /dev/null +++ b/test/babashka/shutdown_hook_test.clj @@ -0,0 +1,24 @@ +(ns babashka.shutdown-hook-test + {:no-doc true} + (:import [java.nio.charset Charset]) + (:require [babashka.test-utils :as tu] + [clojure.java.io :as io] + [clojure.test :refer [deftest is]])) + +(defn- stream-to-string + ([in] (stream-to-string in (.name (Charset/defaultCharset)))) + ([in enc] + (with-open [bout (java.io.StringWriter.)] + (io/copy in bout :encoding enc) + (.toString bout)))) + +(deftest interrupt-handler-test + (let [script "(-> (Runtime/getRuntime) (.addShutdownHook (Thread. #(println \"bye\"))))" + pb (ProcessBuilder. (if tu/jvm? + ["lein" "bb" "-e" script] + ["./bb" "-e" script])) + process (.start pb) + output (.getInputStream process)] + (when-let [s (not-empty (stream-to-string (.getErrorStream process)))] + (prn "ERROR:" s)) + (is (= "bye\n" (stream-to-string output)))))