Skip to content

Commit 962aca5

Browse files
committed
Make leak detector robust against leaks from preceding tests
[A CI test run](https://app.circleci.com/pipelines/github/clj-commons/aleph/769/workflows/1be2f5bc-92a9-4768-aa93-845365476aaf/jobs/753/parallel-runs/0/steps/0-107) recently failed with this error coming from the resource leak detector: ERROR in (test-basic-auth-value-encoding) (core.clj:2362) expected: (= "Basic Og==" (middleware/basic-auth-value nil)) actual: java.lang.ClassCastException: clojure.lang.Var$Unbound cannot be cast to clojure.lang.IAtom at clojure.core$swap_BANG_.invokeStatic (core.clj:2362) clojure.core$swap_BANG_.invoke (core.clj:2362) aleph.resource_leak_detector$_reportTracedLeak.invokeStatic (resource_leak_detector.clj:138) aleph.resource_leak_detector$_reportTracedLeak.invoke (resource_leak_detector.clj:137) aleph.resource_leak_detector.reportTracedLeak (:-1) However, the test namespace in question isn't even instrumented for leak detection (i.e. there is no `aleph.resource-leak-detector/instrument-tests!` call at its bottom). Immediately before this error, there is another one, though: ERROR in (test-shutdown-timeout-1) (resource_leak_detector.clj:103) Uncaught exception, not in assertion. expected: nil actual: java.lang.RuntimeException: Gave up awaiting leak probe. Try increasing `aleph.resource-leak-detector/max-probe-gc-runs`. This indicates that there was still a pending leak detection probe which was then (attempted to be) reported in the context of the following test. To prevent such red herrings in the future, we now gracefully report such leaked leaks.
1 parent 6465e3a commit 962aca5

File tree

1 file changed

+19
-11
lines changed

1 file changed

+19
-11
lines changed

test/aleph/resource_leak_detector.clj

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@
8888
(.buffer 1)
8989
(.touch hint)))
9090

91-
(def current-leaks)
91+
;; NOTE: Not setting to bare `nil` to appease `clj-kondo`.
92+
(def current-leaks (atom nil))
9293

9394
(defn force-leak-detection! []
9495
(System/gc)
@@ -131,23 +132,30 @@
131132
(await-probe! hint)
132133
(handle-leaks (remove-probes @current-leaks)))))
133134

135+
(defn log-leaks! [leaks]
136+
(doseq [{:keys [resource-type records]} leaks]
137+
;; Log message cribbed from io.netty.util.ResourceLeakDetector's (protected) reportTracedLeak method
138+
(log/error (str "LEAK: " resource-type ".release() was not called before it's garbage-collected.")
139+
(str "See https://netty.io/wiki/reference-counted-objects.html for more information." records))))
140+
134141
(defn -needReport [_this]
135142
true)
136143

144+
(defn report-leak! [leak]
145+
(if @current-leaks
146+
(swap! current-leaks conj leak)
147+
(do
148+
(log/error "NOTE: The following leak occurred outside of a `with-leak-collection` scope.")
149+
(log-leaks! [leak]))))
150+
137151
(defn -reportTracedLeak [_this resource-type records]
138-
(swap! current-leaks conj {:resource-type resource-type
139-
:records records}))
152+
(report-leak! {:resource-type resource-type
153+
:records records}))
140154

141155
;; NOTE: Since we require level PARANOID, this should never be called in practice.
142156
(defn -reportUntracedLeak [_this resource-type]
143-
(swap! current-leaks conj {:resource-type resource-type
144-
:records "[untraced]"}))
145-
146-
(defn log-leaks! [leaks]
147-
(doseq [{:keys [resource-type records]} leaks]
148-
;; Log message cribbed from io.netty.util.ResourceLeakDetector's (protected) reportTracedLeak method
149-
(log/error (str "LEAK: " resource-type ".release() was not called before it's garbage-collected.")
150-
(str "See https://netty.io/wiki/reference-counted-objects.html for more information." records))))
157+
(report-leak! {:resource-type resource-type
158+
:records "[untraced]"}))
151159

152160
(defmacro with-expected-leaks
153161
"Runs `body` and expects it to produce exactly `expected-leak-count` leaks. Intended for use in tests

0 commit comments

Comments
 (0)