mirror of
https://github.com/logseq/logseq.git
synced 2026-05-23 12:14:06 +00:00
Merge branch 'master' into enhance/rtc-migrate
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{;; Only lint production namespaces as most dev
|
||||
;; namespaces are unused
|
||||
:paths ["src/main" "src/electron" "src/test" "src/rtc_e2e_test"]
|
||||
:paths ["src/main" "src/electron" "src/test"]
|
||||
:api-namespaces [;; Ignore b/c too many false positives
|
||||
frontend.db
|
||||
;; Used for debugging
|
||||
|
||||
3
bb.edn
3
bb.edn
@@ -164,9 +164,6 @@
|
||||
dev:lint-and-test
|
||||
logseq.tasks.dev/lint-and-test
|
||||
|
||||
dev:rtc-e2e-test
|
||||
logseq.tasks.dev/rtc-e2e-test
|
||||
|
||||
dev:gen-malli-kondo-config
|
||||
logseq.tasks.dev/gen-malli-kondo-config
|
||||
|
||||
|
||||
@@ -18,4 +18,6 @@
|
||||
:extra-deps {org.clojure/test.check {:mvn/version "1.1.1"}
|
||||
io.github.cognitect-labs/test-runner
|
||||
{:git/tag "v0.5.1" :git/sha "dfb30dd"}}}
|
||||
:dev {:extra-paths ["dev" "test"]}}}
|
||||
:dev {:extra-paths ["dev" "test"]}
|
||||
:dev-run-rtc-extra-test {:extra-paths ["dev" "test"]
|
||||
:exec-fn user/run-rtc-extra-test2}}}
|
||||
|
||||
@@ -74,6 +74,10 @@
|
||||
(->> (future (run-tests 'logseq.e2e.rtc-extra-test))
|
||||
(swap! *futures assoc :rtc-extra-test)))
|
||||
|
||||
(defn run-rtc-extra-test2
|
||||
[& _args]
|
||||
(run-tests 'logseq.e2e.rtc-extra-test))
|
||||
|
||||
(defn run-editor-basic-test
|
||||
[]
|
||||
(->> (future (run-tests 'logseq.e2e.editor-basic-test))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns logseq.e2e.outliner-basic-test
|
||||
(:require
|
||||
[clojure.test :refer [deftest testing is use-fixtures]]
|
||||
[logseq.e2e.assert :as assert]
|
||||
[logseq.e2e.block :as b]
|
||||
[logseq.e2e.fixtures :as fixtures]
|
||||
[logseq.e2e.keyboard :as k]
|
||||
@@ -124,3 +125,52 @@
|
||||
|
||||
(deftest delete-test-with-children-test
|
||||
(delete-test-with-children))
|
||||
|
||||
(deftest delete-concat-test-2-blocks
|
||||
(testing "Delete concat with empty block"
|
||||
(b/new-blocks ["" "b2"])
|
||||
(b/indent)
|
||||
(k/arrow-up)
|
||||
(k/delete)
|
||||
(util/wait-editor-visible)
|
||||
(is (= "b2" (util/get-edit-content)))
|
||||
(util/exit-edit)
|
||||
(is (= ["b2"] (util/get-page-blocks-contents)))))
|
||||
|
||||
(deftest delete-concat-test-3-blocks
|
||||
(testing "Delete concat with empty block"
|
||||
(b/new-blocks ["" "b2" "b3"])
|
||||
(b/indent)
|
||||
(k/arrow-up)
|
||||
(k/arrow-up)
|
||||
(k/delete)
|
||||
(util/wait-editor-visible)
|
||||
(is (= "b2" (util/get-edit-content)))
|
||||
(util/exit-edit)
|
||||
(is (= ["b2" "b3"] (util/get-page-blocks-contents)))))
|
||||
|
||||
(deftest delete-concat-test-with-children
|
||||
(testing "Delete concat with children blocks"
|
||||
(b/new-blocks ["" "b2" "b3"])
|
||||
(b/indent)
|
||||
(k/arrow-up)
|
||||
(b/indent)
|
||||
(k/arrow-up)
|
||||
(k/delete)
|
||||
(util/wait-editor-visible)
|
||||
(is (= "" (util/get-edit-content)))
|
||||
(is (= 3 (util/page-blocks-count)))))
|
||||
|
||||
(deftest delete-concat-test-with-tag
|
||||
(testing "Delete concat with tag"
|
||||
(b/new-blocks ["" "b2"])
|
||||
(b/indent)
|
||||
(util/set-tag "tag1")
|
||||
(k/arrow-up)
|
||||
(k/delete)
|
||||
(util/wait-editor-visible)
|
||||
(is (= "b2" (util/get-edit-content)))
|
||||
(util/exit-edit)
|
||||
(assert/assert-is-visible
|
||||
".ls-block a.tag:has-text('tag1')")
|
||||
(is (= ["b2"] (util/get-page-blocks-contents)))))
|
||||
|
||||
4
deps.edn
4
deps.edn
@@ -68,10 +68,6 @@
|
||||
cider/cider-nrepl {:mvn/version "0.55.1"}}
|
||||
:main-opts ["-m" "shadow.cljs.devtools.cli"]}
|
||||
|
||||
:rtc-e2e-test {:extra-paths ["src/rtc_e2e_test"]
|
||||
:extra-deps {cider/cider-nrepl {:mvn/version "0.50.2"}}
|
||||
:main-opts ["-m" "shadow.cljs.devtools.cli"]}
|
||||
|
||||
:bench {:extra-paths ["src/bench/"]
|
||||
:extra-deps {olical/cljs-test-runner {:mvn/version "3.8.0"}
|
||||
fipp/fipp {:mvn/version "0.6.26"}}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
browsers: ['Chrome'],
|
||||
// The directory where the output file lives
|
||||
basePath: 'static/rtc-e2e-test',
|
||||
// The file itself
|
||||
files: ['main.js'],
|
||||
frameworks: ['cljs-test'],
|
||||
plugins: ['karma-cljs-test', 'karma-chrome-launcher'],
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
client: {
|
||||
args: ["shadow.test.karma.init"],
|
||||
singleRun: true,
|
||||
testvar: config.testvar,
|
||||
seed: config.seed
|
||||
}
|
||||
})
|
||||
};
|
||||
@@ -26,17 +26,6 @@
|
||||
(dev-lint/dev)
|
||||
(test "-e" "long" "-e" "fix-me"))
|
||||
|
||||
(defn rtc-e2e-test
|
||||
"Run karma rtc-e2e-test"
|
||||
[& [skip-compile?]]
|
||||
(let [seed (hash (rand))
|
||||
r0 (when-not skip-compile? (shell (str "clj -M:rtc-e2e-test compile rtc-e2e-test")))
|
||||
c1 (async/go (shell (str "npx karma start --testvar=client1 --single-run --seed=" seed)))
|
||||
c2 (async/go (shell (str "npx karma start --testvar=client2 --single-run --seed=" seed)))]
|
||||
(when (and r0 (not= 0 (:exit r0)))
|
||||
(throw (ex-info "compile failed" {:r r0})))
|
||||
(prn :exit-code :client1 (:exit (async/<!! c1)) :client2 (:exit (async/<!! c2)))))
|
||||
|
||||
(defn gen-malli-kondo-config
|
||||
"Generate clj-kondo type-mismatch config from malli schema
|
||||
.clj-kondo/metosin/malli-types/config.edn"
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
;; "." for /static
|
||||
:dev-http {3001 ["static" "."]
|
||||
3002 "static/mobile"
|
||||
8021 "static/rtc-e2e-test"}
|
||||
3002 "static/mobile"}
|
||||
|
||||
:js-options {:js-package-dirs ["node_modules" "packages/tldraw/apps"]}
|
||||
|
||||
@@ -174,14 +173,6 @@
|
||||
:compiler-options {:static-fns false}
|
||||
:main frontend.test.frontend-node-test-runner/main}
|
||||
|
||||
:rtc-e2e-test {:target :karma
|
||||
:closure-defines {frontend.worker.rtc.const/RTC-E2E-TEST* true}
|
||||
:output-to "static/rtc-e2e-test/main.js"
|
||||
:devtools {:enabled true}
|
||||
:compiler-options {:source-map true
|
||||
:warnings {:fn-deprecated false
|
||||
:redef false}}}
|
||||
|
||||
:gen-malli-kondo-config {:target :node-script
|
||||
:closure-defines {frontend.util/NODETEST true}
|
||||
:devtools {:enabled false}
|
||||
|
||||
@@ -131,11 +131,12 @@
|
||||
(let [cancel (task (or succ (constantly nil)) (or fail fail-case-default-handler))]
|
||||
#(cancel)))
|
||||
|
||||
(defn run-task-throw
|
||||
"Return the canceler"
|
||||
[key' task & {:keys [succ]}]
|
||||
(let [cancel (task (or succ #(log/info :key key' :succ %)) #(throw (ex-info "task stopped" {:key key' :e %})))]
|
||||
#(cancel)))
|
||||
(comment
|
||||
(defn run-task-throw
|
||||
"Return the canceler"
|
||||
[key' task & {:keys [succ]}]
|
||||
(let [cancel (task (or succ #(log/info :key key' :succ %)) #(throw (ex-info "task stopped" {:key key' :e %})))]
|
||||
#(cancel))))
|
||||
|
||||
(defonce ^:private *background-task-cancelers ; key -> canceler
|
||||
(volatile! {}))
|
||||
|
||||
@@ -1162,7 +1162,10 @@
|
||||
{:data-ref (str uuid-or-title)}
|
||||
(when (and brackets? (not blank-title?))
|
||||
[:span.text-gray-500.bracket page-ref/left-brackets])
|
||||
(when (and (config/db-based-graph?) (ldb/class-instance? (db/entity :logseq.class/Task) block))
|
||||
(when (and (config/db-based-graph?)
|
||||
(or (ldb/class-instance? (db/entity :logseq.class/Task) block)
|
||||
(:logseq.property/status block)
|
||||
(:logseq.property/priority block)))
|
||||
[:div.inline-block
|
||||
{:style {:margin-right 1
|
||||
:margin-top -2
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
:style {:display "ruby"}}
|
||||
(cond
|
||||
(not (db/page? page))
|
||||
(block/inline-text :markdown (:block/title page))
|
||||
(block/inline-text :markdown (string/replace (apply str (take 64 (:block/title page))) "\n" " "))
|
||||
untitled? (t :untitled)
|
||||
:else (let [title' (pdf-utils/fix-local-asset-pagename title)
|
||||
parent (:block/parent page)]
|
||||
|
||||
@@ -801,10 +801,11 @@
|
||||
(declare expand-block!)
|
||||
|
||||
(defn delete-block-inner!
|
||||
[repo {:keys [block-id value format config block-container]}]
|
||||
[repo {:keys [block-id value format config block-container current-block next-block delete-concat?]}]
|
||||
(when block-id
|
||||
(when-let [block-e (db/entity [:block/uuid block-id])]
|
||||
(let [prev-block (db-model/get-prev (db/get-db) (:db/id block-e))]
|
||||
(let [prev-block (db-model/get-prev (db/get-db) (:db/id block-e))
|
||||
input-empty? (string/blank? (state/get-edit-content))]
|
||||
(cond
|
||||
(and (nil? prev-block)
|
||||
(nil? (:block/parent block-e)))
|
||||
@@ -836,6 +837,27 @@
|
||||
(db-model/hidden-page? (:block/page block))) ; embed page
|
||||
nil
|
||||
|
||||
(and concat-prev-block? input-empty? delete-concat?)
|
||||
(let [children (:block/_parent (db/entity (:db/id current-block)))]
|
||||
(p/do!
|
||||
(ui-outliner-tx/transact!
|
||||
transact-opts
|
||||
(when (= (:db/id current-block) (:db/id (:block/parent next-block)))
|
||||
(property-handler/set-block-properties!
|
||||
repo
|
||||
(:block/uuid next-block)
|
||||
{:block/parent (:db/id (:block/parent current-block))
|
||||
:block/order (:block/order current-block)}))
|
||||
|
||||
(when (seq children)
|
||||
(outliner-op/move-blocks!
|
||||
(remove (fn [c] (= (:db/id c) (:db/id next-block))) children)
|
||||
next-block
|
||||
{:sibling? false}))
|
||||
|
||||
(delete-block-aux! current-block))
|
||||
(edit-block! (db/entity (:db/id next-block)) 0)))
|
||||
|
||||
concat-prev-block?
|
||||
(let [children (:block/_parent (db/entity (:db/id block)))]
|
||||
(p/do!
|
||||
@@ -2745,7 +2767,10 @@
|
||||
:value (:block/title next-block)
|
||||
:block-container (util/get-next-block-non-collapsed
|
||||
(util/rec-get-node (state/get-input) "ls-block")
|
||||
{:exclude-property? true}))]
|
||||
{:exclude-property? true})
|
||||
:current-block current-block
|
||||
:next-block next-block
|
||||
:delete-concat? true)]
|
||||
(delete-block-inner! repo editor-state)))))
|
||||
|
||||
(defn keydown-delete-handler
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
([content status clear? uid timeout]
|
||||
(show! content status clear? uid timeout nil))
|
||||
([content status clear? uid timeout close-cb]
|
||||
(assert (keyword? status) "status should be a keyword")
|
||||
(let [contents (state/get-notification-contents)
|
||||
uid (or uid (keyword (util/unique-id)))]
|
||||
(state/set-state! :notification/contents (assoc contents
|
||||
|
||||
@@ -295,7 +295,7 @@
|
||||
(icon "info-circle" {:class "text-indigo-500" :size "20"}))
|
||||
status)]
|
||||
[:div.ui__notifications-content
|
||||
{:class (str "notification-" (name (or status :info)))
|
||||
{:class (str "notification-" (name (or (when (keyword? status) status) :info)))
|
||||
:style
|
||||
(when (or (= state "exiting")
|
||||
(= state "exited"))
|
||||
|
||||
@@ -179,8 +179,8 @@
|
||||
[op e a v])))
|
||||
datoms))
|
||||
|
||||
(defn- moved-block-or-target-deleted?
|
||||
[conn e->datoms e moved-blocks redo?]
|
||||
(defn- block-moved-and-target-deleted?
|
||||
[conn e->datoms e moved-blocks tx-data]
|
||||
(let [datoms (get e->datoms e)]
|
||||
(and (moved-blocks e)
|
||||
(let [b (d/entity @conn e)
|
||||
@@ -188,16 +188,17 @@
|
||||
move-datoms (filter (fn [d] (contains? #{:block/parent} (:a d))) datoms)]
|
||||
(when cur-parent
|
||||
(let [before-parent (some (fn [d] (when (and (= :block/parent (:a d)) (not (:added d))) (:v d))) move-datoms)
|
||||
after-parent (some (fn [d] (when (and (= :block/parent (:a d)) (:added d)) (:v d))) move-datoms)]
|
||||
(and before-parent after-parent ; parent changed
|
||||
(if redo?
|
||||
(or (not= cur-parent before-parent)
|
||||
(nil? (d/entity @conn after-parent)))
|
||||
(or (not= cur-parent after-parent)
|
||||
(nil? (d/entity @conn before-parent)))))))))))
|
||||
not-exists-in-current-db (nil? (d/entity @conn before-parent))
|
||||
;; reverse tx-data will add parent before back
|
||||
removed-before-parent (some (fn [d] (and (= :block/uuid (:a d))
|
||||
(= before-parent (:e d))
|
||||
(not (:added d)))) tx-data)]
|
||||
(and before-parent
|
||||
not-exists-in-current-db
|
||||
(not removed-before-parent))))))))
|
||||
|
||||
(defn get-reversed-datoms
|
||||
[conn undo? {:keys [tx-data added-ids retracted-ids] :as op} _tx-meta]
|
||||
[conn undo? {:keys [tx-data added-ids retracted-ids] :as op} tx-meta]
|
||||
(try
|
||||
(let [redo? (not undo?)
|
||||
e->datoms (->> (if redo? tx-data (reverse tx-data))
|
||||
@@ -218,16 +219,18 @@
|
||||
:undo? undo?})))
|
||||
|
||||
;; new children blocks have been added
|
||||
(or (and (contains? retracted-ids e) redo?
|
||||
(other-children-exist? entity retracted-ids)) ; redo delete-blocks
|
||||
(and (contains? added-ids e) undo? ; undo insert-blocks
|
||||
(other-children-exist? entity added-ids)))
|
||||
(and
|
||||
(not (:local-tx? tx-meta))
|
||||
(or (and (contains? retracted-ids e) redo?
|
||||
(other-children-exist? entity retracted-ids)) ; redo delete-blocks
|
||||
(and (contains? added-ids e) undo? ; undo insert-blocks
|
||||
(other-children-exist? entity added-ids))))
|
||||
(throw (ex-info "Children still exists"
|
||||
(merge op {:error :block-children-exists
|
||||
:undo? undo?})))
|
||||
|
||||
;; block has been moved or target got deleted by another client
|
||||
(moved-block-or-target-deleted? conn e->datoms e moved-blocks redo?)
|
||||
(block-moved-and-target-deleted? conn e->datoms e moved-blocks tx-data)
|
||||
(throw (ex-info "This block has been moved or its target has been deleted"
|
||||
(merge op {:error :block-moved-or-target-deleted
|
||||
:undo? undo?})))
|
||||
@@ -238,7 +241,6 @@
|
||||
(and (contains? added-ids e) undo?))) ; undo insert-blocks
|
||||
[[:db/retractEntity e]]
|
||||
|
||||
;; reverse datoms
|
||||
:else
|
||||
(reverse-datoms conn datoms schema added-ids retracted-ids undo? redo?))))
|
||||
e->datoms)
|
||||
|
||||
@@ -537,7 +537,7 @@
|
||||
(catch :default e
|
||||
(prn :debug :error)
|
||||
(js/console.error e)
|
||||
(prn :debug :tx-data @conn tx-data)))))
|
||||
(prn :debug :tx-meta tx-meta :tx-data tx-data)))))
|
||||
|
||||
(def-thread-api :thread-api/get-initial-data
|
||||
[repo]
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
[logseq.db.frontend.kv-entity :as kv-entity]
|
||||
[logseq.db.frontend.property :as db-property]))
|
||||
|
||||
(goog-define RTC-E2E-TEST* false)
|
||||
(def RTC-E2E-TEST RTC-E2E-TEST*)
|
||||
|
||||
(defkeywords
|
||||
:rtc/ignore-attr-when-init-upload
|
||||
{:doc "keyword option for RTC. ignore this *attr* when initial uploading graph. Default false"}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
[frontend.common.thread-api :as thread-api]
|
||||
[frontend.worker-common.util :as worker-util]
|
||||
[frontend.worker.crypt :as crypt]
|
||||
[frontend.worker.db-listener :as db-listener]
|
||||
[frontend.worker.db-metadata :as worker-db-metadata]
|
||||
[frontend.worker.rtc.client-op :as client-op]
|
||||
[frontend.worker.rtc.const :as rtc-const]
|
||||
@@ -20,8 +19,6 @@
|
||||
[lambdaisland.glogi :as log]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.db.frontend.malli-schema :as db-malli-schema]
|
||||
[logseq.db.frontend.schema :as db-schema]
|
||||
[logseq.db.sqlite.create-graph :as sqlite-create-graph]
|
||||
[logseq.db.sqlite.util :as sqlite-util]
|
||||
[logseq.outliner.pipeline :as outliner-pipeline]
|
||||
[malli.core :as ma]
|
||||
@@ -161,8 +158,7 @@
|
||||
(client-op/remove-local-tx repo)
|
||||
(client-op/add-all-exists-asset-as-ops repo)
|
||||
(crypt/store-graph-keys-jwk repo aes-key-jwk)
|
||||
(when-not rtc-const/RTC-E2E-TEST
|
||||
(c.m/<? (worker-db-metadata/<store repo (pr-str {:kv/value graph-uuid}))))
|
||||
(c.m/<? (worker-db-metadata/<store repo (pr-str {:kv/value graph-uuid})))
|
||||
(rtc-log-and-state/rtc-log :rtc.log/upload {:sub-type :upload-completed
|
||||
:message "upload-graph completed"})
|
||||
{:graph-uuid graph-uuid})
|
||||
@@ -269,29 +265,6 @@
|
||||
[schema-blocks (conj normal-blocks block)]))
|
||||
[[] []] blocks))
|
||||
|
||||
(defn- create-graph-for-rtc-test
|
||||
"TODO: remove this fn
|
||||
it's complex to setup db-worker related stuff, when I only want to test rtc related logic"
|
||||
[repo init-tx-data other-tx-data]
|
||||
(let [conn (d/create-conn db-schema/schema)
|
||||
db-initial-data (sqlite-create-graph/build-db-initial-data "")]
|
||||
(swap! worker-state/*datascript-conns assoc repo conn)
|
||||
(d/transact! conn db-initial-data {:initial-db? true
|
||||
:frontend.worker.pipeline/skip-store-conn rtc-const/RTC-E2E-TEST})
|
||||
(db-listener/listen-db-changes! repo conn)
|
||||
(d/transact! conn init-tx-data {:rtc-download-graph? true
|
||||
:gen-undo-ops? false
|
||||
;; only transact db schema, skip validation to avoid warning
|
||||
:frontend.worker.pipeline/skip-validate-db? true
|
||||
:frontend.worker.pipeline/skip-store-conn rtc-const/RTC-E2E-TEST
|
||||
:persist-op? false})
|
||||
(d/transact! conn other-tx-data {:rtc-download-graph? true
|
||||
:gen-undo-ops? false
|
||||
:frontend.worker.pipeline/skip-store-conn rtc-const/RTC-E2E-TEST
|
||||
:persist-op? false})
|
||||
(transact-remote-schema-version! repo)
|
||||
(<transact-block-refs! repo nil)))
|
||||
|
||||
(defn- blocks-resolve-temp-id
|
||||
[schema-blocks blocks]
|
||||
(let [uuids (map :block/uuid blocks)
|
||||
@@ -388,37 +361,35 @@
|
||||
(client-op/update-local-tx repo remote-t)
|
||||
(rtc-log-and-state/update-local-t graph-uuid remote-t)
|
||||
(rtc-log-and-state/update-remote-t graph-uuid remote-t)
|
||||
(if rtc-const/RTC-E2E-TEST
|
||||
(create-graph-for-rtc-test repo init-tx-data tx-data)
|
||||
(c.m/<?
|
||||
(p/do!
|
||||
((@thread-api/*thread-apis :thread-api/create-or-open-db) repo {:close-other-db? false})
|
||||
((@thread-api/*thread-apis :thread-api/export-db) repo)
|
||||
(rtc-log-and-state/rtc-log :rtc.log/download {:sub-type :transact-graph-data-to-db-1
|
||||
:message (str "transacting init data(" (count init-tx-data) ")")
|
||||
:graph-uuid graph-uuid})
|
||||
((@thread-api/*thread-apis :thread-api/transact)
|
||||
repo init-tx-data
|
||||
{:rtc-download-graph? true
|
||||
:gen-undo-ops? false
|
||||
(c.m/<?
|
||||
(p/do!
|
||||
((@thread-api/*thread-apis :thread-api/create-or-open-db) repo {:close-other-db? false})
|
||||
((@thread-api/*thread-apis :thread-api/export-db) repo)
|
||||
(rtc-log-and-state/rtc-log :rtc.log/download {:sub-type :transact-graph-data-to-db-1
|
||||
:message (str "transacting init data(" (count init-tx-data) ")")
|
||||
:graph-uuid graph-uuid})
|
||||
((@thread-api/*thread-apis :thread-api/transact)
|
||||
repo init-tx-data
|
||||
{:rtc-download-graph? true
|
||||
:gen-undo-ops? false
|
||||
;; only transact db schema, skip validation to avoid warning
|
||||
:frontend.worker.pipeline/skip-validate-db? true
|
||||
:persist-op? false}
|
||||
(worker-state/get-context))
|
||||
(rtc-log-and-state/rtc-log :rtc.log/download {:sub-type :transact-graph-data-to-db-2
|
||||
:message (str "transacting other data(" (count tx-data) ")")
|
||||
:graph-uuid graph-uuid})
|
||||
(p/doseq [tx-data* (partition-all 500 tx-data)]
|
||||
((@thread-api/*thread-apis :thread-api/transact)
|
||||
repo tx-data* {:rtc-download-graph? true
|
||||
:gen-undo-ops? false
|
||||
:persist-op? false} (worker-state/get-context))
|
||||
(p/delay 10))
|
||||
(rtc-log-and-state/rtc-log :rtc.log/download {:sub-type :transact-graph-data-to-db-3
|
||||
:message "transacting remote schema version"
|
||||
:graph-uuid graph-uuid})
|
||||
(transact-remote-schema-version! repo)
|
||||
(<transact-block-refs! repo graph-uuid))))
|
||||
:frontend.worker.pipeline/skip-validate-db? true
|
||||
:persist-op? false}
|
||||
(worker-state/get-context))
|
||||
(rtc-log-and-state/rtc-log :rtc.log/download {:sub-type :transact-graph-data-to-db-2
|
||||
:message (str "transacting other data(" (count tx-data) ")")
|
||||
:graph-uuid graph-uuid})
|
||||
(p/doseq [tx-data* (partition-all 500 tx-data)]
|
||||
((@thread-api/*thread-apis :thread-api/transact)
|
||||
repo tx-data* {:rtc-download-graph? true
|
||||
:gen-undo-ops? false
|
||||
:persist-op? false} (worker-state/get-context))
|
||||
(p/delay 10))
|
||||
(rtc-log-and-state/rtc-log :rtc.log/download {:sub-type :transact-graph-data-to-db-3
|
||||
:message "transacting remote schema version"
|
||||
:graph-uuid graph-uuid})
|
||||
(transact-remote-schema-version! repo)
|
||||
(<transact-block-refs! repo graph-uuid)))
|
||||
(shared-service/broadcast-to-clients! :add-repo {:repo repo}))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -490,8 +461,7 @@
|
||||
:message "transacted all blocks"
|
||||
:graph-uuid graph-uuid})
|
||||
(client-op/update-graph-uuid repo graph-uuid)
|
||||
(when-not rtc-const/RTC-E2E-TEST
|
||||
(c.m/<? (worker-db-metadata/<store repo (pr-str {:kv/value graph-uuid}))))
|
||||
(c.m/<? (worker-db-metadata/<store repo (pr-str {:kv/value graph-uuid})))
|
||||
(worker-state/set-rtc-downloading-graph! false)
|
||||
(rtc-log-and-state/rtc-log :rtc.log/download {:sub-type :download-completed
|
||||
:message "download completed"
|
||||
@@ -600,7 +570,4 @@
|
||||
datoms)))]
|
||||
(prn ::count (count refs-tx))
|
||||
;; (prn ::take-20 (take 20 (sort-by second > (into [] (frequencies (map last refs-tx))))))
|
||||
)
|
||||
|
||||
|
||||
)
|
||||
))
|
||||
|
||||
@@ -9,10 +9,6 @@
|
||||
|
||||
(def ^:private *rtc-log (atom nil))
|
||||
|
||||
(def rtc-log-flow
|
||||
"used by rtc-e2e-test"
|
||||
(m/watch *rtc-log))
|
||||
|
||||
(def ^:private rtc-log-type-schema
|
||||
(vec
|
||||
(concat
|
||||
|
||||
@@ -618,8 +618,7 @@ so need to pull earlier remote-data from websocket."})
|
||||
(js/console.groupCollapsed "rtc/apply-remote-ops-log")
|
||||
(batch-tx/with-batch-tx-mode conn {:rtc-tx? true
|
||||
:persist-op? false
|
||||
:gen-undo-ops? false
|
||||
:frontend.worker.pipeline/skip-store-conn rtc-const/RTC-E2E-TEST}
|
||||
:gen-undo-ops? false}
|
||||
(worker-util/profile :ensure-refed-blocks-exist (ensure-refed-blocks-exist repo conn refed-blocks))
|
||||
(worker-util/profile :apply-remote-update-page-ops (apply-remote-update-page-ops repo conn update-page-ops))
|
||||
(worker-util/profile :apply-remote-move-ops (apply-remote-move-ops repo conn sorted-move-ops))
|
||||
|
||||
@@ -49,10 +49,11 @@
|
||||
blocking-scroll? (atom false)
|
||||
sidebar-initial-open? (atom false)
|
||||
max-x (atom 0)
|
||||
max-y (atom 0)
|
||||
min-y (atom 0)
|
||||
swipe-trigger-distance 50 ;; distance to actually open/close
|
||||
horiz-intent-threshold 10 ;; start blocking scroll when horizontal intent is clear
|
||||
max-vertical-drift 50
|
||||
|
||||
max-vertical-drift 30
|
||||
on-touch-start (fn [^js e]
|
||||
(when-not (sidebar-not-allowed-to-open?)
|
||||
(let [t (aget e "touches" 0)]
|
||||
@@ -61,14 +62,18 @@
|
||||
(reset! touch-start-y (.-pageY t))
|
||||
(reset! has-triggered? false)
|
||||
(reset! blocking-scroll? false)
|
||||
(reset! max-x 0))))
|
||||
(reset! max-x 0)
|
||||
(reset! max-y (.-pageY t))
|
||||
(reset! min-y (.-pageY t)))))
|
||||
|
||||
on-touch-move (fn [^js e]
|
||||
(when-not (sidebar-not-allowed-to-open?)
|
||||
(let [t (aget e "touches" 0)
|
||||
_ (reset! max-x (max (.-pageX t) @max-x))
|
||||
_ (reset! max-y (max (.-pageY t) @max-y))
|
||||
_ (reset! min-y (min (.-pageY t) @min-y))
|
||||
dx (- (.-pageX t) @touch-start-x)
|
||||
dy (js/Math.abs (- (.-pageY t) @touch-start-y))
|
||||
dy (js/Math.abs (- @max-y @min-y))
|
||||
abs-dx (js/Math.abs dx)
|
||||
horizontal-intent (and (> abs-dx horiz-intent-threshold)
|
||||
(> abs-dx dy))
|
||||
@@ -79,7 +84,7 @@
|
||||
(> (- @max-x (.-pageX t)) swipe-trigger-distance)
|
||||
(< dy max-vertical-drift))]
|
||||
|
||||
;; Block vertical scroll as soon as horizontal intent is clear
|
||||
;; Block vertical scroll as soon as horizontal intent is clear
|
||||
(when (or @blocking-scroll? (and horizontal-intent
|
||||
(not @sidebar-initial-open?)
|
||||
(mobile-state/left-sidebar-open?)))
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
(rum/defc mobile-bar < rum/reactive
|
||||
[]
|
||||
(when (and (util/mobile?)
|
||||
(not (state/sub :editor/code-block-context))
|
||||
(or (state/sub :editor/editing?)
|
||||
(= "app-keep-keyboard-open-input" (some-> js/document.activeElement (.-id)))))
|
||||
(let [commands' (commands)]
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
[]
|
||||
[:div.w-full.app-silk-popup-content-inner.px-2
|
||||
[:div.left-sidebar-inner
|
||||
[:div.sidebar-contents-container.mt-8
|
||||
[:div.sidebar-contents-container.mt-11
|
||||
{:class "!gap-4"}
|
||||
(app-left-sidebar/sidebar-favorites)
|
||||
(app-left-sidebar/sidebar-recent-pages)]]])
|
||||
|
||||
@@ -35,6 +35,70 @@
|
||||
:class "-ml-2"}
|
||||
(shui/tabler-icon (if back? "arrow-left" "chevron-down") {:size 24}))))
|
||||
|
||||
(defn- skip-touch-check?
|
||||
[]
|
||||
(or (seq @mobile-state/*popup-data)
|
||||
(:mobile/show-action-bar? @state/state)
|
||||
(state/editing?)))
|
||||
|
||||
(defn- setup-sidebar-touch-swipe!
|
||||
[ref]
|
||||
(let [touch-start-x (atom 0)
|
||||
touch-start-y (atom 0)
|
||||
has-triggered? (atom false)
|
||||
blocking-scroll? (atom false)
|
||||
max-y (atom 0)
|
||||
min-y (atom 0)
|
||||
swipe-trigger-distance 50 ;; when to actually open sidebar
|
||||
horiz-intent-threshold 10 ;; when to start blocking scroll
|
||||
max-vertical-drift 50
|
||||
on-touch-start (fn [^js e]
|
||||
(when-not (skip-touch-check?)
|
||||
(let [t (aget e "touches" 0)]
|
||||
(reset! touch-start-x (.-pageX t))
|
||||
(reset! touch-start-y (.-pageY t))
|
||||
(reset! has-triggered? false)
|
||||
(reset! blocking-scroll? false)
|
||||
(reset! max-y (.-pageY t))
|
||||
(reset! min-y (.-pageY t)))))
|
||||
|
||||
on-touch-move (fn [^js e]
|
||||
(when-not (skip-touch-check?)
|
||||
(let [t (aget e "touches" 0)
|
||||
dx (- (.-pageX t) @touch-start-x)
|
||||
dy (js/Math.abs (- @max-y @min-y))
|
||||
_ (reset! max-y (max (.-pageY t) @max-y))
|
||||
_ (reset! min-y (min (.-pageY t) @min-y))
|
||||
horizontal-intent (and (> dx horiz-intent-threshold)
|
||||
(> dx dy))
|
||||
is-horizontal-swipe (and (> dx swipe-trigger-distance)
|
||||
(< dy max-vertical-drift))]
|
||||
;; as soon as we detect horizontal intent, block vertical scrolling
|
||||
(when (or @blocking-scroll? horizontal-intent)
|
||||
(reset! blocking-scroll? true)
|
||||
(.preventDefault e)) ;; <-- stops page from scrolling
|
||||
|
||||
(when (and (not @has-triggered?)
|
||||
is-horizontal-swipe)
|
||||
(reset! has-triggered? true)
|
||||
(mobile-state/pop-navigation-history!)))))
|
||||
|
||||
on-touch-end (fn [_]
|
||||
(reset! blocking-scroll? false))]
|
||||
|
||||
;; IMPORTANT: passive:false so preventDefault actually works
|
||||
(.addEventListener ref "touchstart" on-touch-start #js {:passive false})
|
||||
(.addEventListener ref "touchmove" on-touch-move #js {:passive false})
|
||||
(.addEventListener ref "touchend" on-touch-end #js {:passive false})
|
||||
(.addEventListener ref "touchcancel" on-touch-end #js {:passive false})
|
||||
|
||||
;; cleanup
|
||||
#(do
|
||||
(.removeEventListener ref "touchstart" on-touch-start)
|
||||
(.removeEventListener ref "touchmove" on-touch-move)
|
||||
(.removeEventListener ref "touchend" on-touch-end)
|
||||
(.removeEventListener ref "touchcancel" on-touch-end))))
|
||||
|
||||
(rum/defc block-cp
|
||||
[block]
|
||||
[:div.app-silk-scroll-content-inner
|
||||
@@ -43,59 +107,6 @@
|
||||
(mobile-ui/classic-app-container-wrap
|
||||
(page/page-cp (db/entity [:block/uuid (:block/uuid block)])))]])
|
||||
|
||||
(defn- setup-sidebar-touch-swipe!
|
||||
[]
|
||||
(let [touch-start-x (atom 0)
|
||||
touch-start-y (atom 0)
|
||||
has-triggered? (atom false)
|
||||
blocking-scroll? (atom false)
|
||||
|
||||
swipe-trigger-distance 50 ;; when to actually open sidebar
|
||||
horiz-intent-threshold 10 ;; when to start blocking scroll
|
||||
max-vertical-drift 50
|
||||
|
||||
on-touch-start (fn [^js e]
|
||||
(let [t (aget e "touches" 0)]
|
||||
(reset! touch-start-x (.-pageX t))
|
||||
(reset! touch-start-y (.-pageY t))
|
||||
(reset! has-triggered? false)
|
||||
(reset! blocking-scroll? false)))
|
||||
|
||||
on-touch-move (fn [^js e]
|
||||
(let [t (aget e "touches" 0)
|
||||
dx (- (.-pageX t) @touch-start-x)
|
||||
dy (js/Math.abs (- (.-pageY t) @touch-start-y))
|
||||
horizontal-intent (and (> dx horiz-intent-threshold)
|
||||
(> dx dy))
|
||||
is-horizontal-swipe (and (> dx swipe-trigger-distance)
|
||||
(< dy max-vertical-drift))]
|
||||
|
||||
;; as soon as we detect horizontal intent, block vertical scrolling
|
||||
(when (or @blocking-scroll? horizontal-intent)
|
||||
(reset! blocking-scroll? true)
|
||||
(.preventDefault e)) ;; <-- stops page from scrolling
|
||||
|
||||
(when (and (not @has-triggered?)
|
||||
is-horizontal-swipe)
|
||||
(reset! has-triggered? true)
|
||||
(mobile-state/pop-navigation-history!))))
|
||||
|
||||
on-touch-end (fn [_]
|
||||
(reset! blocking-scroll? false))]
|
||||
|
||||
;; IMPORTANT: passive:false so preventDefault actually works
|
||||
(.addEventListener js/document "touchstart" on-touch-start #js {:passive false})
|
||||
(.addEventListener js/document "touchmove" on-touch-move #js {:passive false})
|
||||
(.addEventListener js/document "touchend" on-touch-end #js {:passive false})
|
||||
(.addEventListener js/document "touchcancel" on-touch-end #js {:passive false})
|
||||
|
||||
;; cleanup
|
||||
#(do
|
||||
(.removeEventListener js/document "touchstart" on-touch-start)
|
||||
(.removeEventListener js/document "touchmove" on-touch-move)
|
||||
(.removeEventListener js/document "touchend" on-touch-end)
|
||||
(.removeEventListener js/document "touchcancel" on-touch-end))))
|
||||
|
||||
(rum/defc block-sheet-topbar
|
||||
[block {:keys [favorited? set-favorited!]}]
|
||||
|
||||
@@ -150,18 +161,34 @@
|
||||
:type :action-sheet}))}
|
||||
(shui/tabler-icon "dots-vertical" {:size 20}))]]))
|
||||
|
||||
(rum/defc sheet-content
|
||||
[block favorited? set-favorited!]
|
||||
(let [*ref (hooks/use-ref nil)]
|
||||
(hooks/use-effect!
|
||||
(fn []
|
||||
(when-let [ref (rum/deref *ref)]
|
||||
(setup-sidebar-touch-swipe! ref)))
|
||||
[(rum/deref *ref)])
|
||||
(silkhq/depth-sheet-content
|
||||
{:class "app-silk-depth-sheet-content"
|
||||
:ref *ref}
|
||||
(block-sheet-topbar block {:favorited? favorited?
|
||||
:set-favorited! set-favorited!})
|
||||
(silkhq/scroll
|
||||
{:as-child true}
|
||||
(silkhq/scroll-view
|
||||
{:class "app-silk-scroll-view"
|
||||
:scrollGestureTrap {:yEnd true}}
|
||||
(silkhq/scroll-content
|
||||
{:class "app-silk-scroll-content"}
|
||||
(block-cp block)))))))
|
||||
|
||||
(rum/defc block-sheet
|
||||
[block]
|
||||
(let [block (when-let [id (:block/uuid block)]
|
||||
(db/entity [:block/uuid id]))
|
||||
open? (boolean block)
|
||||
[favorited? set-favorited!] (hooks/use-state false)]
|
||||
|
||||
(hooks/use-effect!
|
||||
(fn []
|
||||
(setup-sidebar-touch-swipe!))
|
||||
[])
|
||||
|
||||
(hooks/use-effect!
|
||||
(fn []
|
||||
(set-favorited! (page-handler/favorited? (str (:block/uuid block)))))
|
||||
@@ -188,19 +215,7 @@
|
||||
:onClickOutside (bean/->js {:dismiss false
|
||||
:stopOverlayPropagation false})}
|
||||
(silkhq/depth-sheet-backdrop)
|
||||
(silkhq/depth-sheet-content
|
||||
{:class "app-silk-depth-sheet-content"}
|
||||
(block-sheet-topbar block {:favorited? favorited?
|
||||
:set-favorited! set-favorited!})
|
||||
(silkhq/scroll
|
||||
{:as-child true}
|
||||
(silkhq/scroll-view
|
||||
{:class "app-silk-scroll-view"
|
||||
:scrollGestureTrap {:yEnd true}}
|
||||
(silkhq/scroll-content
|
||||
{:class "app-silk-scroll-content"}
|
||||
|
||||
(block-cp block))))))))))
|
||||
(sheet-content block favorited? set-favorited!))))))
|
||||
|
||||
(rum/defc blocks-modal < rum/reactive
|
||||
[]
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
(ns basic-edits-test
|
||||
(:require [client-steps]
|
||||
[cljs.test :as t :refer [deftest]]
|
||||
[const]
|
||||
[fixture]
|
||||
[helper]
|
||||
[missionary.core :as m]))
|
||||
|
||||
(t/use-fixtures :once
|
||||
fixture/install-some-consts
|
||||
fixture/install-example-db-fixture
|
||||
fixture/clear-test-remote-graphs-fixture
|
||||
fixture/upload-example-graph-fixture
|
||||
fixture/build-conn-by-download-example-graph-fixture)
|
||||
|
||||
(deftest basic-edits-test
|
||||
(t/async
|
||||
done
|
||||
(js/Promise.
|
||||
(if const/is-client1?
|
||||
(m/sp
|
||||
(doseq [task client-steps/client1-steps]
|
||||
(m/? task))
|
||||
(done))
|
||||
(m/sp
|
||||
(doseq [task client-steps/client2-steps]
|
||||
(m/? task))
|
||||
(done))))))
|
||||
@@ -1,264 +0,0 @@
|
||||
(ns client-steps
|
||||
(:require [cljs.test :as t :refer [is]]
|
||||
[const]
|
||||
[datascript.core :as d]
|
||||
[frontend.worker.rtc.client-op :as client-op]
|
||||
[frontend.worker.rtc.core :as rtc-core]
|
||||
[helper]
|
||||
[frontend.common.missionary :as c.m]
|
||||
[logseq.db :as ldb]
|
||||
[missionary.core :as m]))
|
||||
|
||||
(def ^:private step0
|
||||
{:client1
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)
|
||||
tx-data (const/tx-data-map :create-page)]
|
||||
(helper/transact! conn tx-data)
|
||||
(is (=
|
||||
#{[:update-page const/page1-uuid]
|
||||
[:update const/page1-uuid
|
||||
[[:block/title "[\"~#'\",\"basic-edits-test\"]" true]
|
||||
[:block/created-at "[\"~#'\",1724836490809]" true]
|
||||
[:block/updated-at "[\"~#'\",1724836490809]" true]
|
||||
[:block/type "[\"~#'\",\"page\"]" true]]]
|
||||
[:move const/block1-uuid]
|
||||
[:update const/block1-uuid
|
||||
[[:block/updated-at "[\"~#'\",1724836490810]" true]
|
||||
[:block/created-at "[\"~#'\",1724836490810]" true]
|
||||
[:block/title "[\"~#'\",\"block1\"]" true]]]}
|
||||
(set (map helper/simplify-client-op (client-op/get-all-block-ops const/downloaded-test-repo)))))))
|
||||
:client2 nil})
|
||||
|
||||
(def ^:private step1
|
||||
"client1: start rtc, wait page1, client1->remote
|
||||
client2: start rtc, wait page1, remote->client2"
|
||||
{:client1
|
||||
(m/sp
|
||||
(let [r (m/? (rtc-core/new-task--rtc-start false))]
|
||||
(is (nil? r))
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))))
|
||||
:client2
|
||||
(m/sp
|
||||
(let [r (m/? (rtc-core/new-task--rtc-start false))]
|
||||
(is (nil? r)))
|
||||
(m/?
|
||||
(c.m/backoff
|
||||
{}
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)
|
||||
page1 (d/pull @conn '[*] [:block/uuid const/page1-uuid])
|
||||
block1 (d/pull @conn '[*] [:block/uuid const/block1-uuid])]
|
||||
(when-not (:block/uuid page1)
|
||||
(throw (ex-info "wait page1 synced" {:missionary/retry true})))
|
||||
(is
|
||||
(= {:block/title "basic-edits-test"
|
||||
:block/name "basic-edits-test"
|
||||
:block/type "page"}
|
||||
(select-keys page1 [:block/title :block/name :block/type])))
|
||||
(is
|
||||
(= {:block/title "block1"
|
||||
:block/order "a0"
|
||||
:block/parent {:db/id (:db/id page1)}}
|
||||
(select-keys block1 [:block/title :block/order :block/parent]))))))))})
|
||||
|
||||
(def ^:private step2
|
||||
"client1: insert 500 blocks, wait for changes to sync to remote
|
||||
client2: wait for blocks to sync from remote"
|
||||
{:client1
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)]
|
||||
(helper/transact! conn (const/tx-data-map :insert-500-blocks))
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))))
|
||||
:client2
|
||||
(c.m/backoff
|
||||
{}
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)
|
||||
page (d/pull @conn '[*] [:block/uuid const/page2-uuid])]
|
||||
(when-not (:block/uuid page)
|
||||
(throw (ex-info "wait page to be synced" {:missionary/retry true})))
|
||||
(let [blocks (ldb/sort-by-order (ldb/get-page-blocks @conn (:db/id page)))]
|
||||
(is (= 500 (count blocks)))
|
||||
(is (= (map #(str "x" %) (range 500))
|
||||
(map :block/title blocks)))))))})
|
||||
|
||||
(def ^:private step3
|
||||
"client1:
|
||||
1. add #task properties to block1 (`const/block1-uuid`)
|
||||
2. wait to be synced
|
||||
3. toggle block1 status to TODO
|
||||
4. wait to be synced
|
||||
5. toggle block1 status to DOING
|
||||
6. wait to be synced
|
||||
client2:
|
||||
1. wait the block&its properties to be synced"
|
||||
{:client1
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)
|
||||
tx-data1 (const/tx-data-map :step3-add-task-properties-to-block1)
|
||||
tx-data2 (const/tx-data-map :step3-toggle-status-TODO)
|
||||
tx-data3 (const/tx-data-map :step3-toggle-status-DOING)]
|
||||
(helper/transact! conn tx-data1)
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))
|
||||
(helper/transact! conn tx-data2)
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))
|
||||
(helper/transact! conn tx-data3)
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))))
|
||||
:client2
|
||||
(c.m/backoff
|
||||
{}
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)
|
||||
block1 (d/pull @conn
|
||||
[{:block/tags [:db/ident]}
|
||||
{:logseq.property/status [:db/ident]}
|
||||
{:logseq.property/deadline [:block/journal-day]}]
|
||||
[:block/uuid const/block1-uuid])]
|
||||
(when-not (= :logseq.property/status.doing (:db/ident (:logseq.property/status block1)))
|
||||
(throw (ex-info "wait block1's task properties to be synced" {:missionary/retry true})))
|
||||
(is (= {:block/tags [{:db/ident :logseq.class/Task}],
|
||||
:logseq.property/status {:db/ident :logseq.property/status.doing}
|
||||
:logseq.property/deadline {:block/journal-day 20240907}}
|
||||
block1)))))})
|
||||
(def ^:private step4
|
||||
"client1:
|
||||
|
||||
client2:
|
||||
"
|
||||
{:client1
|
||||
(m/sp nil)
|
||||
:client2
|
||||
(m/sp nil)})
|
||||
|
||||
(def ^:private step5
|
||||
"client1:
|
||||
- insert some blocks in page2
|
||||
- wait to be synced
|
||||
- wait a signal from client2
|
||||
- send a signal to client2
|
||||
- stop rtc
|
||||
- move some blocks
|
||||
- start rtc
|
||||
- wait to be synced
|
||||
- wait client2's message, which contains the result of client2's block tree,
|
||||
and compare them with blocks in client1
|
||||
client2:
|
||||
- wait inserted blocks synced
|
||||
- send a signal to client1
|
||||
- wait a signal from client1
|
||||
- stop rtc
|
||||
- move some blocks
|
||||
- start rtc
|
||||
- wait to be synced
|
||||
- send a message to client1 contains client2's block tree to client1"
|
||||
{:client1
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)
|
||||
tx-data1 (const/tx-data-map :move-blocks-concurrently-1)
|
||||
tx-data2 (const/tx-data-map :move-blocks-concurrently-client1)]
|
||||
(helper/transact! conn tx-data1)
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))
|
||||
(m/? (helper/new-task--client1-sync-barrier-2->1 "move-blocks-concurrently-signal"))
|
||||
(m/? helper/new-task--stop-rtc)
|
||||
(helper/transact! conn tx-data2)
|
||||
(is (nil? (m/? (rtc-core/new-task--rtc-start false))))
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))
|
||||
(m/? (helper/new-task--client1-sync-barrier-2->1 "step5"))
|
||||
(let [message (m/? (helper/new-task--wait-message-from-other-client
|
||||
(fn [message] (= "move-blocks-concurrently-page-blocks" (:id message)))
|
||||
:retry-message "move-blocks-concurrently-page-blocks"))
|
||||
client2-page-blocks (:page-blocks message)
|
||||
client1-page-blocks (ldb/get-page-blocks @conn (:db/id (d/entity @conn [:block/uuid const/page3-uuid]))
|
||||
:pull-keys '[:block/uuid :block/title :block/order
|
||||
{:block/parent [:block/uuid]}])]
|
||||
(is (= (set client1-page-blocks) (set client2-page-blocks))))))
|
||||
:client2
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)]
|
||||
(m/?
|
||||
(c.m/backoff
|
||||
(take 4 c.m/delays)
|
||||
(m/sp
|
||||
(let [page3 (d/pull @conn '[*] [:block/uuid const/page3-uuid])
|
||||
page3-blocks (some->> (:db/id page3)
|
||||
(ldb/get-page-blocks @conn))]
|
||||
(when-not (:block/uuid page3)
|
||||
(throw (ex-info "wait page3 synced" {:missionary/retry true})))
|
||||
(is (= 6 (count page3-blocks)))))))
|
||||
(m/? (helper/new-task--client2-sync-barrier-2->1 "move-blocks-concurrently-signal"))
|
||||
(m/? helper/new-task--stop-rtc)
|
||||
(helper/transact! conn (const/tx-data-map :move-blocks-concurrently-client2))
|
||||
(is (nil? (m/? (rtc-core/new-task--rtc-start false))))
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))
|
||||
(m/? (helper/new-task--client2-sync-barrier-2->1 "step5"))
|
||||
(m/? (helper/new-task--send-message-to-other-client
|
||||
{:id "move-blocks-concurrently-page-blocks"
|
||||
:page-blocks (ldb/get-page-blocks @conn (:db/id (d/entity @conn [:block/uuid const/page3-uuid]))
|
||||
:pull-keys '[:block/uuid :block/title :block/order
|
||||
{:block/parent [:block/uuid]}])}))))})
|
||||
|
||||
(def ^:private step6
|
||||
"Delete blocks test-1
|
||||
client1:
|
||||
- insert some blocks
|
||||
- wait to be synced
|
||||
- stop rtc
|
||||
- delete blocks
|
||||
- start rtc
|
||||
- wait to be synced
|
||||
|
||||
client2:
|
||||
- wait blocks from client1
|
||||
- wait delete-blocks changes synced from client1
|
||||
- check block-tree"
|
||||
{:client1
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)
|
||||
tx-data1 (const/tx-data-map :step6-delete-blocks-client1-1)
|
||||
tx-data2 (const/tx-data-map :step6-delete-blocks-client1-2)]
|
||||
(helper/transact! conn tx-data1)
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent))
|
||||
(m/? (helper/new-task--client1-sync-barrier-1->2 "step6"))
|
||||
(m/? helper/new-task--stop-rtc)
|
||||
(helper/transact! conn tx-data2)
|
||||
(let [r (m/? (rtc-core/new-task--rtc-start false))]
|
||||
(is (nil? r))
|
||||
(m/? (helper/new-task--wait-all-client-ops-sent)))))
|
||||
:client2
|
||||
(m/sp
|
||||
(let [conn (helper/get-downloaded-test-conn)]
|
||||
(m/? (helper/new-task--client2-sync-barrier-1->2 "step6"))
|
||||
(m/?
|
||||
(c.m/backoff
|
||||
{}
|
||||
(m/sp
|
||||
(let [page (d/pull @conn '[*] [:block/uuid const/step6-page-uuid])
|
||||
page-blocks (when-let [page-id (:db/id page)]
|
||||
(ldb/get-page-blocks @conn page-id
|
||||
:pull-keys '[:block/uuid {:block/parent [:block/uuid]}]))]
|
||||
(when-not (= 1 (count page-blocks))
|
||||
(throw (ex-info "wait delete-blocks changes synced"
|
||||
{:missionary/retry true
|
||||
:page-blocks page-blocks})))
|
||||
(is (= {:block/uuid const/step6-block3-uuid
|
||||
:block/parent {:block/uuid const/step6-page-uuid}}
|
||||
(select-keys (first page-blocks) [:block/uuid :block/parent])))))))))})
|
||||
|
||||
(defn- wrap-print-step-info
|
||||
[steps client]
|
||||
(map-indexed
|
||||
(fn [idx step]
|
||||
(m/sp
|
||||
(helper/log "start step" idx)
|
||||
(some-> (get step client) m/?)
|
||||
(helper/log "end step" idx)))
|
||||
steps))
|
||||
|
||||
(def ^:private all-steps [step0 step1 step2 step3 step4 step5 step6])
|
||||
|
||||
(def client1-steps
|
||||
(wrap-print-step-info all-steps :client1))
|
||||
|
||||
(def client2-steps
|
||||
(wrap-print-step-info all-steps :client2))
|
||||
@@ -1,229 +0,0 @@
|
||||
(ns const
|
||||
"Consts for rtc e2e tests"
|
||||
(:require [logseq.db.common.order :as db-order]))
|
||||
|
||||
(assert (exists? js/__karma__))
|
||||
(def seed js/__karma__.config.seed)
|
||||
(def testvar js/__karma__.config.testvar)
|
||||
(prn :karma-config :seed seed :testvar testvar)
|
||||
|
||||
(def is-client1? (= "client1" testvar))
|
||||
|
||||
(def test-token "TEST-TOKEN")
|
||||
(def test-graph-name (str "TEST-REPO-" seed))
|
||||
(def test-repo (str "logseq_db_TEST-REPO-" seed))
|
||||
|
||||
(def downloaded-test-graph-name "TEST-REPO-downloaded")
|
||||
(def downloaded-test-repo "logseq_db_TEST-REPO-downloaded")
|
||||
|
||||
;;; tests data
|
||||
(def message-page-uuid #uuid "a3da426a-4202-4a79-8e97-13f4862b0270")
|
||||
|
||||
(def page1-uuid #uuid "c051d36f-98b3-4afb-b52a-d5a06bd8591d")
|
||||
(def page2-uuid #uuid "91d3e320-d2a6-47ae-96a7-8a366ab96cbb")
|
||||
(def page3-uuid #uuid "9a846640-2b63-4298-9ad6-8ca6c1285016")
|
||||
|
||||
(def block1-uuid #uuid "aa6d5e60-5d3a-4468-812f-bd60dc9639fb")
|
||||
|
||||
;;; ----- move-blocks-concurrently case -----
|
||||
(def block2-uuid #uuid "a78e19fc-7e9a-4f61-8988-0e9a649bc875")
|
||||
(def block3-uuid #uuid "226166d8-1380-4d7a-9fe1-f98e2d583259")
|
||||
(def block4-uuid #uuid "fb8f05d2-9d91-492e-81e2-8a0b65f09d8c")
|
||||
(def block5-uuid #uuid "f3c48e62-1726-4492-b42a-a36f4de7b32f")
|
||||
(def block6-uuid #uuid "23f51a53-db85-465a-9f18-6ca94e59f56c")
|
||||
(def block7-uuid #uuid "83f99937-fe0a-4d33-81ce-7fe5837baad3")
|
||||
;;; ----- delete-blocks case ---------
|
||||
(def step6-page-uuid #uuid "e22dafa5-b3b4-405d-b93d-470caa420e10")
|
||||
(def step6-block1-uuid #uuid "776acd4a-d011-4985-bfc2-14ee7bbd6a28")
|
||||
(def step6-block2-uuid #uuid "ba3998c2-8059-4f9e-9e76-2760d2f14512")
|
||||
(def step6-block3-uuid #uuid "f9ce5393-370a-43dd-a721-aaa5ef83d3ff")
|
||||
(def step6-block4-uuid #uuid "db00bb0d-2bef-49e7-96ed-b4882cdf5686")
|
||||
(def step6-block5-uuid #uuid "d34e8a9c-5e87-4511-b982-2bf2ebc82607")
|
||||
|
||||
(def ^:large-vars/data-var tx-data-map
|
||||
{:create-page
|
||||
[{:db/id "page"
|
||||
:block/name "basic-edits-test"
|
||||
:block/title "basic-edits-test"
|
||||
:block/uuid page1-uuid
|
||||
:block/created-at 1724836490809
|
||||
:block/updated-at 1724836490809
|
||||
:block/type "page"}
|
||||
{:block/uuid block1-uuid
|
||||
:block/updated-at 1724836490810
|
||||
:block/created-at 1724836490810
|
||||
:block/title "block1"
|
||||
:block/parent "page"
|
||||
:block/order "a0"
|
||||
:block/page "page"}]
|
||||
:insert-500-blocks
|
||||
(cons {:db/id "page"
|
||||
:block/uuid page2-uuid
|
||||
:block/name "insert-500-blocks"
|
||||
:block/title "insert-500-blocks"
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/type "page"}
|
||||
(map (fn [i order]
|
||||
{:block/uuid (random-uuid)
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title (str "x" i)
|
||||
:block/parent "page"
|
||||
:block/order order
|
||||
:block/page "page"})
|
||||
(range 500) (db-order/gen-n-keys 500 "a0" "a1")))
|
||||
:step3-add-task-properties-to-block1
|
||||
[{:db/id "id-0907"
|
||||
:block/uuid #uuid "00000001-2024-0907-0000-000000000000"
|
||||
:block/updated-at 1725455235108
|
||||
:block/created-at 1725455235108
|
||||
:block/journal-day 20240907
|
||||
:block/title "Sep 7th, 2024"
|
||||
:block/name "sep 7th, 2024"
|
||||
:block/type "journal"}
|
||||
{:block/uuid block1-uuid
|
||||
:block/updated-at 1725454876718
|
||||
:block/tags :logseq.class/Task
|
||||
:logseq.property/status :logseq.property/status.done
|
||||
:logseq.property/deadline "id-0907"}]
|
||||
:step3-toggle-status-TODO
|
||||
[{:block/uuid block1-uuid
|
||||
:logseq.property/status :logseq.property/status.todo}]
|
||||
:step3-toggle-status-DOING
|
||||
[{:block/uuid block1-uuid
|
||||
:logseq.property/status :logseq.property/status.doing}]
|
||||
:move-blocks-concurrently-1
|
||||
[{:db/id "page"
|
||||
:block/uuid page3-uuid
|
||||
:block/name "move-blocks-concurrently"
|
||||
:block/title "move-blocks-concurrently"
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/type "page"}
|
||||
{:block/uuid block2-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x1"
|
||||
:block/parent "page"
|
||||
:block/order "a0"
|
||||
:block/page "page"}
|
||||
{:block/uuid block3-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x2"
|
||||
:block/parent "page"
|
||||
:block/order "a1"
|
||||
:block/page "page"}
|
||||
{:block/uuid block4-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x3"
|
||||
:block/parent "page"
|
||||
:block/order "a2"
|
||||
:block/page "page"}
|
||||
{:block/uuid block5-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x4"
|
||||
:block/parent "page"
|
||||
:block/order "a3"
|
||||
:block/page "page"}
|
||||
{:block/uuid block6-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x5"
|
||||
:block/parent "page"
|
||||
:block/order "a4"
|
||||
:block/page "page"}
|
||||
{:block/uuid block7-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x6"
|
||||
:block/parent "page"
|
||||
:block/order "a5"
|
||||
:block/page "page"}]
|
||||
:move-blocks-concurrently-client1
|
||||
[{:block/uuid block6-uuid
|
||||
:block/parent [:block/uuid block3-uuid]
|
||||
:block/order "a0"}
|
||||
{:block/uuid block5-uuid
|
||||
:block/parent [:block/uuid block6-uuid]
|
||||
:block/order "a0"}
|
||||
{:block/uuid block4-uuid
|
||||
:block/parent [:block/uuid block2-uuid]
|
||||
:block/order "a0"}
|
||||
{:block/uuid block7-uuid
|
||||
:block/parent [:block/uuid page3-uuid]
|
||||
:block/order (db-order/gen-key "a0" "a1")}]
|
||||
:move-blocks-concurrently-client2
|
||||
[{:block/uuid block2-uuid
|
||||
:block/order "a2V"}
|
||||
{:block/uuid block5-uuid
|
||||
:block/parent [:block/uuid block3-uuid]
|
||||
:block/order "a0"}
|
||||
{:block/uuid block6-uuid
|
||||
:block/parent [:block/uuid block5-uuid]
|
||||
:block/order "a0"}
|
||||
{:block/uuid block4-uuid
|
||||
:block/parent [:block/uuid block7-uuid]
|
||||
:block/order "a0"}]
|
||||
:step6-delete-blocks-client1-1
|
||||
;; - 1
|
||||
;; - 2
|
||||
;; - 3
|
||||
;; - 4
|
||||
;; - 5
|
||||
[{:db/id "page"
|
||||
:block/uuid step6-page-uuid
|
||||
:block/name "step6-delete-blocks"
|
||||
:block/title "step6-delete-blocks"
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/type "page"}
|
||||
{:db/id "b1"
|
||||
:block/uuid step6-block1-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x1"
|
||||
:block/parent "page"
|
||||
:block/order "a0"
|
||||
:block/page "page"}
|
||||
{:db/id "b2"
|
||||
:block/uuid step6-block2-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x2"
|
||||
:block/parent "b1"
|
||||
:block/order "a0"
|
||||
:block/page "page"}
|
||||
{:db/id "b3"
|
||||
:block/uuid step6-block3-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x3"
|
||||
:block/parent "page"
|
||||
:block/order "a1"
|
||||
:block/page "page"}
|
||||
{:db/id "b4"
|
||||
:block/uuid step6-block4-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x4"
|
||||
:block/parent "b3"
|
||||
:block/order "a0"
|
||||
:block/page "page"}
|
||||
{:db/id "b5"
|
||||
:block/uuid step6-block5-uuid
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/title "x5"
|
||||
:block/parent "b4"
|
||||
:block/order "a0"
|
||||
:block/page "page"}]
|
||||
:step6-delete-blocks-client1-2
|
||||
;; only block3 left
|
||||
[[:db/retractEntity [:block/uuid step6-block1-uuid]]
|
||||
[:db/retractEntity [:block/uuid step6-block2-uuid]]
|
||||
[:db/retractEntity [:block/uuid step6-block4-uuid]]
|
||||
[:db/retractEntity [:block/uuid step6-block5-uuid]]]})
|
||||
File diff suppressed because one or more lines are too long
@@ -1,82 +0,0 @@
|
||||
(ns fixture
|
||||
(:require [cljs.test :as t]
|
||||
[const]
|
||||
[datascript.core :as d]
|
||||
[example]
|
||||
[frontend.common.missionary :as c.m]
|
||||
[frontend.worker.rtc.client-op :as client-op]
|
||||
[frontend.worker.rtc.db-listener]
|
||||
[frontend.worker.state :as worker-state]
|
||||
[helper]
|
||||
[missionary.core :as m]))
|
||||
|
||||
(def graph-schema-version "0")
|
||||
|
||||
(defn- transact-graph-schema-version
|
||||
[conn]
|
||||
(d/transact! conn [{:db/ident :logseq.kv/schema-version
|
||||
:kv/value graph-schema-version}]))
|
||||
|
||||
(def install-some-consts
|
||||
{:before
|
||||
(fn []
|
||||
(reset! worker-state/*rtc-ws-url "wss://ws-dev.logseq.com/rtc-sync?token=%s"))})
|
||||
|
||||
(def install-example-db-fixture
|
||||
{:before
|
||||
(fn []
|
||||
(prn :test-repo const/test-repo)
|
||||
(swap! worker-state/*client-ops-conns assoc const/test-repo (d/create-conn client-op/schema-in-db))
|
||||
(let [conn (d/conn-from-db example/example-db)]
|
||||
(transact-graph-schema-version conn)
|
||||
(swap! worker-state/*datascript-conns assoc const/test-repo conn)))
|
||||
:after
|
||||
(fn []
|
||||
(swap! worker-state/*datascript-conns dissoc const/test-repo)
|
||||
(swap! worker-state/*client-ops-conns dissoc const/test-repo))})
|
||||
|
||||
(def clear-test-remote-graphs-fixture
|
||||
{:before
|
||||
#(when const/is-client1?
|
||||
(t/async
|
||||
done
|
||||
(c.m/run-task-throw
|
||||
:clear-test-remote-graphs
|
||||
(m/sp
|
||||
(m/? helper/new-task--clear-all-test-remote-graphs)
|
||||
(done)))))})
|
||||
|
||||
(def upload-example-graph-fixture
|
||||
{:before
|
||||
#(when const/is-client1?
|
||||
(t/async
|
||||
done
|
||||
(c.m/run-task-throw
|
||||
:upload-example-graph-fixture
|
||||
(m/sp
|
||||
(swap! worker-state/*datascript-conns dissoc const/downloaded-test-repo)
|
||||
(swap! worker-state/*client-ops-conns assoc
|
||||
const/downloaded-test-repo (d/create-conn client-op/schema-in-db))
|
||||
(let [{:keys [graph-uuid]} (m/? helper/new-task--upload-example-graph)]
|
||||
(assert (some? graph-uuid))
|
||||
(m/? (helper/new-task--wait-creating-graph graph-uuid))
|
||||
(println :uploaded-graph graph-uuid))
|
||||
(done)))))})
|
||||
|
||||
(def build-conn-by-download-example-graph-fixture
|
||||
{:before
|
||||
#(t/async
|
||||
done
|
||||
(c.m/run-task-throw
|
||||
:build-conn-by-download-example-graph-fixture
|
||||
(m/sp
|
||||
(swap! worker-state/*datascript-conns dissoc const/downloaded-test-repo)
|
||||
(swap! worker-state/*client-ops-conns assoc
|
||||
const/downloaded-test-repo (d/create-conn client-op/schema-in-db))
|
||||
(let [graph-uuid (m/? helper/new-task--get-remote-example-graph-uuid)]
|
||||
(assert (some? graph-uuid))
|
||||
(m/? (helper/new-task--download-graph graph-uuid const/downloaded-test-graph-name)))
|
||||
(done))))
|
||||
:after
|
||||
#(do (swap! worker-state/*datascript-conns dissoc const/downloaded-test-repo)
|
||||
(swap! worker-state/*client-ops-conns dissoc const/downloaded-test-repo))})
|
||||
@@ -1,208 +0,0 @@
|
||||
(ns helper
|
||||
(:require [cljs.test :as t :refer [is]]
|
||||
[const]
|
||||
[datascript.core :as d]
|
||||
[datascript.transit :as dt]
|
||||
[fixture]
|
||||
[frontend.common.missionary :as c.m]
|
||||
[frontend.worker.rtc.client-op :as client-op]
|
||||
[frontend.worker.rtc.core :as rtc.core]
|
||||
[frontend.worker.rtc.log-and-state :as rtc-log-and-state]
|
||||
[frontend.worker.state :as worker-state]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.db.common.order :as db-order]
|
||||
[logseq.outliner.batch-tx :as batch-tx]
|
||||
[meander.epsilon :as me]
|
||||
[missionary.core :as m]))
|
||||
|
||||
(defn log
|
||||
[& objs]
|
||||
(apply println (if const/is-client1? "[client1]" "[client2]") objs))
|
||||
|
||||
(def new-task--upload-example-graph
|
||||
(rtc.core/new-task--upload-graph const/test-token const/test-repo const/test-graph-name))
|
||||
|
||||
(defn new-task--wait-creating-graph
|
||||
[graph-uuid]
|
||||
(c.m/backoff
|
||||
{}
|
||||
(m/sp
|
||||
(let [graphs (m/? (rtc.core/new-task--get-graphs const/test-token))
|
||||
graph (some (fn [graph] (when (= graph-uuid (:graph-uuid graph)) graph)) graphs)]
|
||||
(when-not graph
|
||||
(throw (ex-info "graph not exist" {:graph-uuid graph-uuid})))
|
||||
(log "waiting for graph " graph-uuid " finish creating")
|
||||
(when (= "creating" (:graph-status graph))
|
||||
(throw (ex-info "wait creating-graph" {:missionary/retry true})))))))
|
||||
|
||||
(def new-task--clear-all-test-remote-graphs
|
||||
(m/sp
|
||||
(let [graphs (m/? (rtc.core/new-task--get-graphs const/test-token))
|
||||
test-graphs (filter (fn [graph]
|
||||
(not= "deleting" (:graph-status graph)))
|
||||
graphs)]
|
||||
(doseq [graph test-graphs]
|
||||
(m/? (rtc.core/new-task--delete-graph const/test-token (:graph-uuid graph) fixture/graph-schema-version))
|
||||
(log :deleted-graph (:graph-name graph) (:graph-uuid graph))))))
|
||||
|
||||
(def new-task--get-remote-example-graph-uuid
|
||||
(c.m/backoff
|
||||
{}
|
||||
(m/sp
|
||||
(let [graphs (m/? (rtc.core/new-task--get-graphs const/test-token))
|
||||
graph
|
||||
(some (fn [graph]
|
||||
(when (= const/test-graph-name (:graph-name graph))
|
||||
graph))
|
||||
graphs)]
|
||||
(when (= "deleting" (:graph-status graph))
|
||||
(throw (ex-info "example graph status is \"deleting\", check server's background-upload-graph log"
|
||||
{:graph-name (:graph-name graph)
|
||||
:graph-uuid (:graph-uuid graph)})))
|
||||
(when-not graph
|
||||
(throw (ex-info "wait remote-example-graph" {:missionary/retry true
|
||||
:graphs graphs})))
|
||||
(when (= "creating" (:graph-status graph))
|
||||
(throw (ex-info "wait remote-example-graph (creating)" {:missionary/retry true
|
||||
:graphs graphs})))
|
||||
(:graph-uuid graph)))))
|
||||
|
||||
(defn new-task--download-graph
|
||||
[graph-uuid graph-name]
|
||||
(m/sp
|
||||
(let [download-info-uuid (m/? (rtc.core/new-task--request-download-graph
|
||||
const/test-token graph-uuid fixture/graph-schema-version))
|
||||
result (m/? (rtc.core/new-task--wait-download-info-ready
|
||||
const/test-token download-info-uuid graph-uuid fixture/graph-schema-version 60000))
|
||||
{:keys [_download-info-uuid
|
||||
download-info-s3-url
|
||||
_download-info-tx-instant
|
||||
_download-info-t
|
||||
_download-info-created-at]} result]
|
||||
(when (= result :timeout)
|
||||
(throw (ex-info "wait download-info-ready timeout" {})))
|
||||
(m/? (rtc.core/new-task--download-graph-from-s3
|
||||
graph-uuid graph-name download-info-s3-url)))))
|
||||
|
||||
(defn get-downloaded-test-conn
|
||||
[]
|
||||
{:post [(some? %)]}
|
||||
(worker-state/get-datascript-conn const/downloaded-test-repo))
|
||||
|
||||
(defn simplify-client-op
|
||||
[client-op]
|
||||
#_:clj-kondo/ignore
|
||||
(me/find
|
||||
client-op
|
||||
[?op-type _ {:block-uuid ?block-uuid :av-coll [[!a !v _ !add] ...]}]
|
||||
[?op-type ?block-uuid (map vector !a !v !add)]
|
||||
|
||||
[?op-type _ {:block-uuid ?block-uuid}]
|
||||
[?op-type ?block-uuid]))
|
||||
|
||||
(defn new-task--wait-all-client-ops-sent
|
||||
[& {:keys [timeout] :or {timeout 10000}}]
|
||||
(m/sp
|
||||
(let [r (m/? (m/timeout
|
||||
(m/reduce (fn [_ v]
|
||||
(when (and (= :rtc.log/push-local-update (:type v))
|
||||
(empty? (client-op/get-all-block-ops const/downloaded-test-repo)))
|
||||
(is (nil? (:ex-data v)))
|
||||
(reduced v)))
|
||||
rtc-log-and-state/rtc-log-flow)
|
||||
timeout :timeout))]
|
||||
(is (not= :timeout r)))))
|
||||
|
||||
(defn new-task--send-message-to-other-client
|
||||
[message]
|
||||
(m/sp
|
||||
(let [conn (get-downloaded-test-conn)
|
||||
message-page-id (:db/id (ldb/get-page @conn const/message-page-uuid))
|
||||
sorted-blocks (when message-page-id
|
||||
(ldb/sort-by-order (ldb/get-page-blocks @conn message-page-id)))
|
||||
min-order (db-order/gen-key nil (:block/order (first sorted-blocks)))
|
||||
tx-data [{:db/id "page"
|
||||
:block/uuid const/message-page-uuid
|
||||
:block/name "message-page"
|
||||
:block/title "message-page"
|
||||
:block/created-at 1725024677501
|
||||
:block/updated-at 1725024677501
|
||||
:block/type "page"}
|
||||
{:block/uuid (random-uuid)
|
||||
:block/parent "page"
|
||||
:block/order min-order
|
||||
:block/title (dt/write-transit-str message)
|
||||
:block/page "page"
|
||||
:block/updated-at 1724836490810
|
||||
:block/created-at 1724836490810}]]
|
||||
(batch-tx/with-batch-tx-mode conn {:e2e-test const/downloaded-test-repo :frontend.worker.pipeline/skip-store-conn true}
|
||||
(d/transact! conn tx-data))
|
||||
(m/? (new-task--wait-all-client-ops-sent))
|
||||
(log :sent-message message))))
|
||||
|
||||
(defn new-task--wait-message-from-other-client
|
||||
"Return a task that return message from other client"
|
||||
[block-title-pred-fn & {:keys [retry-message retry-count] :or {retry-count 4}}]
|
||||
(c.m/backoff
|
||||
{:delay-seq (take retry-count c.m/delays)}
|
||||
(m/sp
|
||||
(let [conn (get-downloaded-test-conn)
|
||||
message-page-id (:db/id (ldb/get-page @conn const/message-page-uuid))
|
||||
first-block (when message-page-id
|
||||
(first (ldb/sort-by-order (ldb/get-page-blocks @conn message-page-id))))
|
||||
first-block-title (some->> (:block/title first-block) dt/read-transit-str)]
|
||||
(when-not (and (some? first-block-title)
|
||||
(block-title-pred-fn first-block-title))
|
||||
(throw (ex-info (str "wait message from other client " retry-message) {:missionary/retry true})))
|
||||
first-block-title))))
|
||||
|
||||
(defn new-task--client1-sync-barrier-1->2
|
||||
[message]
|
||||
(m/sp
|
||||
(m/? (new-task--send-message-to-other-client (str message "-client1")))
|
||||
(m/? (new-task--wait-message-from-other-client #(= (str message "-client2") %)))
|
||||
(log "sync-barrier-1->2" message)))
|
||||
|
||||
(defn new-task--client2-sync-barrier-1->2
|
||||
[message]
|
||||
(m/sp
|
||||
(m/? (new-task--wait-message-from-other-client #(= (str message "-client1") %)))
|
||||
(m/? (new-task--send-message-to-other-client (str message "-client2")))
|
||||
(log "sync-barrier-1->2" message)))
|
||||
|
||||
(defn new-task--client1-sync-barrier-2->1
|
||||
[message]
|
||||
(m/sp
|
||||
(m/? (new-task--wait-message-from-other-client #(= (str message "-client2") %)))
|
||||
(m/? (new-task--send-message-to-other-client (str message "-client1")))
|
||||
(log "sync-barrier-2->1" message)))
|
||||
|
||||
(defn new-task--client2-sync-barrier-2->1
|
||||
[message]
|
||||
(m/sp
|
||||
(m/? (new-task--send-message-to-other-client (str message "-client2")))
|
||||
(m/? (new-task--wait-message-from-other-client #(= (str message "-client1") %)))
|
||||
(log "sync-barrier-2->1" message)))
|
||||
|
||||
(defn transact!
|
||||
[conn tx-data]
|
||||
{:pre [(seq tx-data)]}
|
||||
(batch-tx/with-batch-tx-mode conn {:e2e-test const/downloaded-test-repo :frontend.worker.pipeline/skip-store-conn true}
|
||||
(d/transact! conn tx-data)))
|
||||
|
||||
(def new-task--stop-rtc
|
||||
(m/sp
|
||||
(rtc.core/rtc-stop)
|
||||
(let [r (m/?
|
||||
(m/timeout
|
||||
(m/reduce
|
||||
(fn [_ v]
|
||||
(when (= :rtc.log/cancelled (:type v))
|
||||
(log :debug-stop-rtc v)
|
||||
(reduced v)))
|
||||
rtc-log-and-state/rtc-log-flow)
|
||||
3000
|
||||
:timeout))]
|
||||
(is (not= :timeout r))
|
||||
;; sleep 0.1s to ensure *rtc-lock released
|
||||
(m/? (m/sleep 100)))))
|
||||
Reference in New Issue
Block a user