(ns ird.p2p.db.test-util
"Shared test tooling: `eventually` polling, collectors, temporary
directories and the environment. Tests may use JS interop freely; the
purity rule applies to src/ only."
(:require-macros [ird.p2p.db.test-util])
(:require [clojure.string :as str]
[cljs.core.async :as async :refer [go go-loop <!]]
[ird.p2p.async :as a]))
;; lazy: this namespace is shared with the browser test build, where these
;; are never touched (tmp-dir/rm-rf/env are Node-only)
(def ^:private fs (delay (js/require "node:fs")))
(def ^:private os (delay (js/require "node:os")))
(def ^:private path (delay (js/require "node:path")))
(defn env [name]
(let [v (aget (.-env js/process) name)]
(when (and (string? v) (not (str/blank? v))) v)))
(defn skip-nodes?
"True when the real-node suites should skip themselves (a sandbox that
cannot bind loopback sockets sets IRD_P2P_DB_NO_NODE=1)."
[]
(some? (env "IRD_P2P_DB_NO_NODE")))
;; ---- files -------------------------------------------------------------------------
(defn tmp-dir
"A fresh empty directory under the OS temp dir."
[prefix]
(let [^js fs @fs ^js path @path ^js os @os]
(.mkdtempSync fs (.join path (.tmpdir os) (str prefix "-")))))
(defn rm-rf [dir]
(let [^js fs @fs]
(.rmSync fs dir #js {:recursive true :force true})))
;; ---- polling -------------------------------------------------------------------------
(defn eventually
"Channel of true once (pred) is truthy, polling every 5 ms of real time
up to TIMEOUT-MS (default 5000); false otherwise."
([pred] (eventually pred 5000))
([pred timeout-ms]
(let [deadline (+ (js/Date.now) timeout-ms)]
(go-loop []
(cond
(pred) true
(>= (js/Date.now) deadline) (boolean (pred))
:else (do (<! (async/timeout 5)) (recur)))))))
(defn collector
"Drain CH into an atom vector; returns the atom."
[ch]
(let [seen (atom [])]
(go-loop []
(when-let [v (<! ch)]
(swap! seen conj v)
(recur)))
seen))
(defn wait-for
"Channel of the first collected event satisfying PRED (real-time polling), or nil."
([seen pred] (wait-for seen pred 5000))
([seen pred timeout-ms]
(go
(<! (eventually #(some pred @seen) timeout-ms))
(some #(when (pred %) %) @seen))))
(defn count-of [seen pred] (count (filter pred @seen)))
(def error? a/error?)