mirror of
https://github.com/penpot/penpot.git
synced 2026-09-24 12:56:15 +00:00
103 lines
3.9 KiB
Clojure
103 lines
3.9 KiB
Clojure
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
;;
|
|
;; Copyright (c) KALEIDOS SUBSIDIARY SL
|
|
|
|
(ns frontend-tests.util-queue-test
|
|
(:require
|
|
[app.util.queue :as q]
|
|
[beicon.v2.core :as rx]
|
|
[cljs.test :as t :include-macros true]
|
|
[frontend-tests.helpers.async :as async]))
|
|
|
|
(defn- same-key?
|
|
[request item]
|
|
(= (unchecked-get request "key")
|
|
(unchecked-get item "key")))
|
|
|
|
(defn- new-queue
|
|
[]
|
|
;; A high threshold lets queued items run back to back.
|
|
(q/create same-key? 10000))
|
|
|
|
(defn- request
|
|
[key tag]
|
|
#js {:key key :tag tag})
|
|
|
|
(defn- work
|
|
"Returns a render fn that records `id` in `calls` and emits it."
|
|
[calls id]
|
|
(fn []
|
|
(swap! calls conj id)
|
|
(rx/of id)))
|
|
|
|
(defn- collect
|
|
"Returns a promise resolving with the values `ob` emitted."
|
|
[ob]
|
|
(let [values (atom [])]
|
|
(-> (async/observe ob :on-next #(swap! values conj %) :timeout-ms 5000)
|
|
(.then (fn [_] @values)))))
|
|
|
|
(defn- pending
|
|
[queue]
|
|
(.-length (unchecked-get queue "items")))
|
|
|
|
(t/deftest ^:async matching-requests-share-one-run-of-the-latest-work
|
|
;; Scenario: two requests for the same key are queued before the queue
|
|
;; runs. Proves: one item is queued, only the latest work runs, and
|
|
;; both callers receive its result.
|
|
(let [queue (new-queue)
|
|
calls (atom [])
|
|
req-1 (q/enqueue-unique queue (request "a" "component") (work calls :first))
|
|
req-2 (q/enqueue-unique queue (request "a" "component") (work calls :second))]
|
|
(t/is (= 1 (pending queue)))
|
|
(let [results (await (js/Promise.all #js [(collect req-1) (collect req-2)]))]
|
|
(t/is (= [[:second] [:second]] (js->clj results)))
|
|
(t/is (= [:second] @calls)))
|
|
(q/clear! queue)))
|
|
|
|
(t/deftest ^:async different-requests-run-separately
|
|
;; Scenario: two requests with different keys. Proves: both are queued
|
|
;; and each caller receives its own result.
|
|
(let [queue (new-queue)
|
|
calls (atom [])
|
|
a (q/enqueue-unique queue (request "a" "component") (work calls :a))
|
|
b (q/enqueue-unique queue (request "b" "component") (work calls :b))]
|
|
(t/is (= 2 (pending queue)))
|
|
(let [results (await (js/Promise.all #js [(collect a) (collect b)]))]
|
|
(t/is (= [[:a] [:b]] (js->clj results)))
|
|
(t/is (= [:a :b] @calls)))
|
|
(q/clear! queue)))
|
|
|
|
(t/deftest ^:async frame-requests-run-first-and-merge
|
|
;; Scenario: a component request, then two frame requests for the same
|
|
;; key. Proves: the frames merge into one item that runs before the
|
|
;; component, using the latest frame work.
|
|
(let [queue (new-queue)
|
|
calls (atom [])
|
|
component (q/enqueue-unique queue (request "a" "component") (work calls :component))
|
|
frame-1 (q/enqueue-unique queue (request "b" "frame") (work calls :frame-1))
|
|
frame-2 (q/enqueue-unique queue (request "b" "frame") (work calls :frame-2))]
|
|
(t/is (= 2 (pending queue)))
|
|
(let [results (await (js/Promise.all #js [(collect component)
|
|
(collect frame-1)
|
|
(collect frame-2)]))]
|
|
(t/is (= [[:component] [:frame-2] [:frame-2]] (js->clj results)))
|
|
(t/is (= [:frame-2 :component] @calls)))
|
|
(q/clear! queue)))
|
|
|
|
(t/deftest ^:async request-after-run-starts-is-queued-again
|
|
;; Scenario: a second matching request arrives once the first one has
|
|
;; left the queue. Proves: it is queued as new work, not merged into
|
|
;; work that already ran.
|
|
(let [queue (new-queue)
|
|
calls (atom [])
|
|
req-1 (q/enqueue-unique queue (request "a" "component") (work calls :first))]
|
|
(t/is (= [:first] (await (collect req-1))))
|
|
(let [req-2 (q/enqueue-unique queue (request "a" "component") (work calls :second))]
|
|
(t/is (= 1 (pending queue)))
|
|
(t/is (= [:second] (await (collect req-2))))
|
|
(t/is (= [:first :second] @calls)))
|
|
(q/clear! queue)))
|