Skip to content

Commit 2825463

Browse files
authored
Merge pull request #42 from ferdinand-beyer/master
Close output channel on error
2 parents 460f3e0 + ad3952c commit 2825463

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

src/lsp4clj/io_chan.clj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@
128128
(with-open [writer output] ;; close output when channel closes
129129
(loop []
130130
(when-let [msg (async/<!! messages)]
131-
(write-message writer msg)
131+
(try
132+
(write-message writer msg)
133+
(catch Throwable e
134+
(async/close! messages)
135+
(throw e)))
132136
(recur)))))
133137
messages))

test/lsp4clj/io_chan_test.clj

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,34 @@
22
(:require
33
[clojure.core.async :as async]
44
[clojure.string :as string]
5-
[clojure.test :refer [deftest is testing]]
5+
[clojure.test :refer [deftest is testing use-fixtures]]
66
[lsp4clj.io-chan :as io-chan]
77
[lsp4clj.test-helper :as h]))
88

99
(set! *warn-on-reflection* true)
1010

11+
(defn- silence-uncaught-exceptions [f]
12+
(let [handler (Thread/getDefaultUncaughtExceptionHandler)]
13+
(Thread/setDefaultUncaughtExceptionHandler
14+
(reify Thread$UncaughtExceptionHandler
15+
(uncaughtException [_this _thread _e])))
16+
(f)
17+
(Thread/setDefaultUncaughtExceptionHandler handler)))
18+
19+
(use-fixtures :once silence-uncaught-exceptions)
20+
1121
(defn ^:private message-lines [arr]
1222
(string/join "\r\n" arr))
1323

1424
(defn mock-input-stream [^String input]
1525
(.getBytes input "utf-8"))
1626

27+
(defn error-output-stream []
28+
(proxy [java.io.OutputStream] []
29+
(close [] (throw (java.io.IOException. "close failed")))
30+
(flush [] (throw (java.io.IOException. "flush failed")))
31+
(write [& _] (throw (java.io.IOException. "write failed")))))
32+
1733
(deftest output-stream-should-camel-case-output
1834
(let [output-stream (java.io.ByteArrayOutputStream.)
1935
output-ch (io-chan/output-stream->output-chan output-stream)]
@@ -50,6 +66,20 @@
5066
"{\"key\":\"äpfel\"}"])
5167
(.toString output-stream "utf-8")))))
5268

69+
(deftest output-stream-error-should-close-output-channel
70+
(testing "when JSON serialisation fails"
71+
(let [output-stream (java.io.ByteArrayOutputStream.)
72+
output-ch (io-chan/output-stream->output-chan output-stream)]
73+
(async/>!! output-ch {:not-serializable (Object.)})
74+
(Thread/sleep 50)
75+
(is (false? (async/put! output-ch {:test "should be closed"})))))
76+
(testing "when an I/O exception occurs"
77+
(let [output-stream (error-output-stream)
78+
output-ch (io-chan/output-stream->output-chan output-stream)]
79+
(async/>!! output-ch {:test "ok"})
80+
(Thread/sleep 50)
81+
(is (false? (async/put! output-ch {:test "should be closed"}))))))
82+
5383
(deftest input-stream-should-kebab-case-input
5484
(let [input-stream (mock-input-stream
5585
(message-lines

0 commit comments

Comments
 (0)