(ns ird.p2p.descriptor-test
(:require [cljs.test :refer [deftest is testing]]
[cljs.core.async :refer [<!]]
[ird.p2p.descriptor :as desc]
[ird.p2p.test-util :as tu :refer [deftest-async]]))
(deftest parses-the-full-descriptor
(let [d (desc/parse (tu/fixture "descriptor-full.json"))]
(is (= "ap2p-signal" (:protocol d)))
(is (= "1" (:version d)))
(is (= "wss://app.example.test/ws" (get-in d [:endpoints :ws])))
(is (= "https://app.example.test/turn-credentials" (get-in d [:endpoints :turn_credentials])))
(is (= "12D3KooWExampleExampleExampleExampleExampleExampleEx" (get-in d [:relay :peer_id])))
(is (= 1 (count (get-in d [:relay :multiaddrs]))))
(is (= "_peer-discovery._p2p._pubsub" (get-in d [:relay :pubsub_discovery_topic])))
(is (desc/mailbox-enabled? d))
(is (desc/open-mint? d))
(is (= "https://app.example.test/mailbox-credentials" (get-in d [:mailbox :mint_endpoint])))
(is (= 168 (get-in d [:mailbox :ttl_hours])))
(is (= 48 (get-in d [:limits :max_conns_per_ip])))
(is (= 65536 (get-in d [:limits :max_frame_bytes])))
(is (false? (:is-fallback d)))
(is (map? (:compat d)) "unknown blocks are kept")
(is (= {:ws "wss://app.example.test/ws" :turn-credentials "https://app.example.test/turn-credentials"
:mailbox "https://app.example.test/mailbox/v1" :mailbox-mint "https://app.example.test/mailbox-credentials"}
(desc/resolved-endpoints d)))))
(deftest parses-the-minimal-descriptor
(let [d (desc/parse (tu/fixture "descriptor-minimal.json"))]
(is (nil? (:relay d)))
(is (nil? (:mailbox d)))
(is (not (desc/mailbox-enabled? d)))
(is (= 4096 (get-in d [:limits :max_frame_bytes])))
(is (= 7 (get-in d [:limits :brand_new_limit])) "unknown limit keys are kept")
(is (= "https://min.example.test/x" (get-in d [:endpoints :future_endpoint])))
(is (= {:a 1} (:something_new d)))
(is (nil? (:mailbox (desc/resolved-endpoints d))))))
(deftest closed-mint-descriptor
(let [d (desc/parse (tu/fixture "descriptor-closed-mint.json"))]
(is (desc/mailbox-enabled? d))
(is (not (desc/open-mint? d)))
(is (nil? (get-in d [:mailbox :mint_endpoint])))
(is (= "https://closed.example.test/mailbox/v1" (:mailbox (desc/resolved-endpoints d))))
(is (nil? (:mailbox-mint (desc/resolved-endpoints d))))))
(deftest parse-defaults-and-rejects
(is (nil? (desc/parse "not json")))
(is (nil? (desc/parse "{\"limits\":{}}")) "no endpoints: unusable")
(let [d (desc/parse "{\"endpoints\":{\"ws\":\"wss://x/ws\",\"turn_credentials\":\"https://x/t\"},\"mailbox\":{\"endpoint\":5}}")]
(is (= desc/default-limits (:limits d)) "missing limits take the defaults")
(is (= "ap2p-signal" (:protocol d)))
(is (nil? (:mailbox d)) "a malformed mailbox block is dropped"))
(let [d (desc/parse {:endpoints {:ws "wss://x/ws" :turn_credentials "https://x/t"} :limits {:max_rooms "5"}})]
(is (= desc/default-limits (:limits d)) "malformed limits take the defaults")))
(deftest fallback-shape
(let [d (desc/fallback "app.example.test")]
(is (:is-fallback d))
(is (= "wss://app.example.test/ws" (get-in d [:endpoints :ws])))
(is (= "https://app.example.test/turn-credentials" (get-in d [:endpoints :turn_credentials])))
(is (= {:max_rooms 500 :max_room_peers 16 :max_conns_per_ip 20 :max_bytes_per_sec 262144
:messages_per_sec 30 :message_burst 60 :max_frame_bytes 65536}
(:limits d)))
(is (nil? (:mailbox d)))))
(deftest-async fetch-uses-the-descriptor-and-falls-back
(let [captured (atom [])
d (<! (desc/fetch {:host "app.example.test" :origin "https://o.example"
:http-fn (tu/responding captured 200 (tu/fixture "descriptor-full.json"))}))]
(is (= "https://app.example.test/.well-known/ap2p" (:url (first @captured))))
(is (= "https://o.example" (get-in (first @captured) [:headers "Origin"])))
(is (= 3000 (:timeout-ms (first @captured))))
(is (false? (:is-fallback d)))
(is (= 48 (get-in d [:limits :max_conns_per_ip]))))
(let [d (<! (desc/fetch {:host "h.example" :http-fn (tu/responding 404 {:error "unknown_app"})}))]
(is (:is-fallback d))
(is (= "wss://h.example/ws" (get-in d [:endpoints :ws]))))
(let [d (<! (desc/fetch {:host "h.example" :http-fn (tu/failing (js/Error. "ECONNREFUSED"))}))]
(is (:is-fallback d)))
(let [d (<! (desc/fetch {:host "h.example" :http-fn (tu/responding 200 "<html>")}))]
(is (:is-fallback d) "a non-descriptor body falls back")))