(ns ird.p2p.db.core-test
"The facade without a network: option checking, canonical ordering, and
what happens when the injected node or database fails."
(:require [cljs.test :refer [deftest is testing]]
[cljs.core.async :as async :refer [go <!]]
[ird.p2p.db.core :as db]
[ird.p2p.db.errors :as err]
[ird.p2p.db.test-util :as tu :refer [deftest-async]]))
(deftest canonical-order
(let [e (fn [t h] {:clock {:id "k" :time t} :hash h})]
(is (= [(e 1 "b") (e 2 "a") (e 2 "c") (e 3 "a")]
(db/canonical-order [(e 2 "c") (e 3 "a") (e 1 "b") (e 2 "a")]))
"by clock time, then by hash for concurrent records")))
(deftest-async option-errors-before-any-node
(let [started (atom 0)
node-fn (fn [_] (swap! started inc) (go {:peer-id "p" :ipfs nil :stop (fn [] (go nil))}))]
(is (err/config-error? (<! (db/open {:app-salt "s" :name "chat" :node-fn node-fn}))) "no secret")
(is (err/config-error? (<! (db/open {:secret "short" :app-salt "s" :name "chat" :node-fn node-fn}))))
(is (err/config-error? (<! (db/open {:secret (db/random-secret) :name "chat" :node-fn node-fn}))) "no salt")
(is (err/config-error? (<! (db/open {:secret (db/random-secret) :app-salt "s" :name "a|b" :node-fn node-fn}))))
(is (err/config-error? (<! (db/open {:secret (db/random-secret) :app-salt "s" :node-fn node-fn}))) "no name")
(is (zero? @started) "nothing was started")))
(deftest-async node-and-database-failures
(let [stopped (atom 0)
fake-node {:peer-id "p" :ipfs nil
:dial (fn [_] (go true))
:stop (fn [] (swap! stopped inc) (go nil))}]
(testing "a node that fails to start"
(let [e (<! (db/open {:secret (db/random-secret) :app-salt "s" :name "chat"
:node-fn (fn [_] (go (err/node-error "boom" {})))}))]
(is (err/node-error? e))))
(testing "a database that fails to open stops the node it started"
(let [e (<! (db/open {:secret (db/random-secret) :app-salt "s" :name "chat"
:node-fn (fn [_] (go fake-node))
:db-fn (fn [_] (go (err/node-error "orbit boom" {})))}))]
(is (err/node-error? e))
(is (= 1 @stopped))))
(testing "a dial that fails stops the node too"
(let [e (<! (db/open {:secret (db/random-secret) :app-salt "s" :name "chat" :dial ["/ip4/127.0.0.1/tcp/1"]
:node-fn (fn [_] (go (assoc fake-node :dial (fn [_] (go (err/dial-error "refused" {}))))))
:db-fn (fn [_] (go {:address "/orbitdb/x"}))}))]
(is (err/dial-error? e))
(is (= 2 @stopped))))))