(ns ird.p2p.db.close-test
"Closing releases everything (node stopped, streams closed, calls refused)
and is idempotent; with :path the database survives a restart."
(:require [cljs.test :refer [deftest is testing]]
[cljs.core.async :as async :refer [<!]]
[ird.p2p.db.core :as db]
[ird.p2p.db.errors :as err]
[ird.p2p.db.test-util :as tu :refer [deftest-async]]))
(defn- drain
"Channel of everything CH delivers until it closes."
[ch]
(async/go-loop [acc []]
(if-let [v (<! ch)] (recur (conj acc v)) acc)))
(deftest-async close-stops-everything
{:timeout-ms 30000}
(if (tu/skip-nodes?)
(is true "IRD_P2P_DB_NO_NODE set — skipping")
(let [a (<! (db/open {:secret (db/random-secret) :app-salt "test/v1" :name "chat"}))
_ (is (not (tu/error? a)) (some-> a ex-message))
es (db/entries-stream a)
ps (db/peers-stream a)
r (<! (db/append a {:n 1}))]
(is (not (tu/error? r)))
(<! (db/close a))
(is (= :closed @(:state a)))
(is (= "stopped" (.-status (:ipfs (:node a)))) "the Helia node is stopped")
(is (err/closed? (<! (db/append a {:n 2}))))
(is (err/closed? (<! (db/entries a))))
(is (err/closed? (<! (db/dial a ["/ip4/127.0.0.1/tcp/1"]))))
(is (err/closed? (<! (db/multiaddrs a))))
(is (= [] (db/peers a)))
(is (= [{:n 1}] (mapv :payload (<! (drain es)))) "the stream delivers what was queued, then closes")
(is (= [] (<! (drain ps))))
(<! (db/close a))
(is (= :closed @(:state a)) "a second close is a no-op"))))
(deftest-async path-persists-across-restart
{:timeout-ms 30000}
(if (tu/skip-nodes?)
(is true "IRD_P2P_DB_NO_NODE set — skipping")
(let [dir (tu/tmp-dir "ird-p2p-db")
secret (db/random-secret)
a (<! (db/open {:secret secret :app-salt "test/v1" :name "notes" :path dir}))]
(is (not (tu/error? a)) (some-> a ex-message))
(let [pid (db/peer-id a)
addr (db/address a)
r1 (<! (db/append a {:n 1}))
r2 (<! (db/append a {:n 2}))]
(is (and (:hash r1) (:hash r2)))
(<! (db/close a))
(let [b (<! (db/open {:secret secret :app-salt "test/v1" :name "notes" :path dir}))]
(is (not (tu/error? b)) (some-> b ex-message))
(is (= pid (db/peer-id b)) "the peer id lives in the persisted datastore")
(is (= addr (db/address b)))
(is (= [1 2] (mapv #(get-in % [:payload :n]) (<! (db/entries b)))) "records survived the restart")
(is (= [(:hash r1) (:hash r2)] (mapv :hash (<! (db/entries b)))))
(let [c (tu/collector (db/entries-stream b))]
(is (some? (<! (tu/wait-for c #(= 2 (get-in % [:payload :n])))))
"the stream replays the persisted history"))
(<! (db/close b))))
(tu/rm-rf dir))))