Tienson Qin 3 недель назад
Родитель
Сommit
8e815b85b8

+ 0 - 371
deps/db-sync/test/logseq/db_sync/index_test.cljs

@@ -1,371 +0,0 @@
-(ns logseq.db-sync.index-test
-  (:require [cljs.test :refer [deftest is async]]
-            [clojure.string :as string]
-            [logseq.db-sync.index :as index]
-            [promesa.core :as p]))
-
-(defn- js-key [k]
-  (cond
-    (keyword? k) (string/replace (name k) "-" "_")
-    (string? k) k
-    :else (str k)))
-
-(defn- js-row [m]
-  (let [o (js-obj)]
-    (doseq [[k v] m]
-      (aset o (js-key k) v))
-    o))
-
-(defn- js-rows [rows]
-  (into-array (map js-row rows)))
-
-(defn- record-exec! [state sql]
-  (swap! state update :executed conj sql))
-
-(defn- run-sql! [state sql args]
-  (record-exec! state sql)
-  (cond
-    (string/includes? sql "insert into user_rsa_keys")
-    (let [[user-id public-key encrypted-private-key created-at updated-at] args]
-      (swap! state update :user-keys assoc user-id {:user-id user-id
-                                                    :public-key public-key
-                                                    :encrypted-private-key encrypted-private-key
-                                                    :created-at created-at
-                                                    :updated-at updated-at}))
-
-    (string/includes? sql "insert into graph_aes_keys")
-    (let [[graph-id user-id encrypted-aes-key created-at updated-at] args]
-      (swap! state update :graph-keys assoc [graph-id user-id] {:graph-id graph-id
-                                                                :user-id user-id
-                                                                :encrypted-aes-key encrypted-aes-key
-                                                                :created-at created-at
-                                                                :updated-at updated-at}))
-
-    (string/includes? sql "insert into users")
-    (let [[user-id email email-verified username] args]
-      (swap! state update :users assoc user-id {:id user-id
-                                                :email email
-                                                :email-verified email-verified
-                                                :username username}))
-
-    (string/includes? sql "insert into graph_members")
-    (let [[user-id graph-id role invited-by created-at] args]
-      (swap! state update :graph-members
-             (fn [members]
-               (let [k [user-id graph-id]
-                     existing (get members k)
-                     created-at (or (:created-at existing) created-at)]
-                 (assoc members k {:user-id user-id
-                                   :graph-id graph-id
-                                   :role role
-                                   :invited-by invited-by
-                                   :created-at created-at})))))
-
-    (string/includes? sql "insert into graphs")
-    (let [[graph-id graph-name user-id schema-version created-at updated-at] args]
-      (swap! state update :graphs assoc graph-id {:graph-id graph-id
-                                                  :graph-name graph-name
-                                                  :user-id user-id
-                                                  :schema-version schema-version
-                                                  :created-at created-at
-                                                  :updated-at updated-at}))
-
-    (string/includes? sql "update graph_members set role")
-    (let [[role graph-id user-id] args]
-      (swap! state update :graph-members assoc-in [[user-id graph-id] :role] role))
-
-    (string/includes? sql "delete from graph_members")
-    (let [[graph-id user-id] args]
-      (swap! state update :graph-members dissoc [user-id graph-id]))
-
-    (string/includes? sql "delete from graphs")
-    (let [[graph-id] args]
-      (swap! state update :graphs dissoc graph-id))
-
-    :else
-    nil))
-
-(defn- union-access-rows [state sql args]
-  (let [[graph-id user-id] args
-        graph-owner-id (get-in @state [:graphs graph-id :user-id])
-        member (get-in @state [:graph-members [user-id graph-id]])
-        manager-required? (string/includes? sql "role = 'manager'")
-        has-access? (or (= graph-owner-id user-id)
-                        (and member
-                             (or (not manager-required?)
-                                 (= "manager" (:role member)))))]
-    (if has-access?
-      (js-rows [{:graph-id graph-id}])
-      (js-rows []))))
-
-(defn- all-sql [state sql args]
-  (record-exec! state sql)
-  (cond
-    (string/includes? sql "from user_rsa_keys")
-    (if (string/includes? sql "left join users")
-      (let [[email] args
-            user-id (some (fn [[_ row]]
-                            (when (= email (:email row))
-                              (:id row)))
-                          (:users @state))
-            row (when user-id (get-in @state [:user-keys user-id]))]
-        (if row
-          (js-rows [row])
-          (js-rows [])))
-      (let [[user-id] args
-            row (get-in @state [:user-keys user-id])]
-        (if row
-          (js-rows [row])
-          (js-rows []))))
-
-    (string/includes? sql "from graph_aes_keys")
-    (let [[graph-id user-id] args
-          row (get-in @state [:graph-keys [graph-id user-id]])]
-      (if row
-        (js-rows [row])
-        (js-rows [])))
-
-    (string/includes? sql "from graph_members where graph_id")
-    (let [graph-id (first args)
-          members (->> (:graph-members @state)
-                       vals
-                       (filter (fn [row] (= graph-id (:graph-id row))))
-                       (sort-by :created-at))]
-      (js-rows members))
-
-    (string/includes? sql "union select graph_id from graph_members")
-    (union-access-rows state sql args)
-
-    (string/includes? sql "select g.graph_id")
-    (let [[user-id] args
-          owned (->> (:graphs @state)
-                     vals
-                     (filter (fn [row] (= user-id (:user-id row)))))
-          member-ids (->> (:graph-members @state)
-                          vals
-                          (filter (fn [row] (= user-id (:user-id row))))
-                          (map :graph-id)
-                          set)
-          member-graphs (->> (:graphs @state)
-                             vals
-                             (filter (fn [row] (contains? member-ids (:graph-id row)))))
-          rows (concat owned member-graphs)
-          rows (map (fn [row]
-                      (let [member (get-in @state [:graph-members [user-id (:graph-id row)]])]
-                        (cond-> row
-                          member
-                          (assoc :role (:role member)
-                                 :invited-by (:invited-by member)))))
-                    rows)]
-      (js-rows rows))
-
-    (string/includes? sql "select graph_id from graphs where graph_name")
-    (let [[graph-name user-id] args
-          rows (->> (:graphs @state)
-                    vals
-                    (filter (fn [row]
-                              (and (= graph-name (:graph-name row))
-                                   (= user-id (:user-id row)))))
-                    (map (fn [row] {:graph-id (:graph-id row)})))]
-      (js-rows rows))
-
-    :else
-    (js-rows [])))
-
-(defn- make-d1 [state]
-  #js {:prepare (fn [sql]
-                  (let [stmt #js {}]
-                    (set! (.-_sql stmt) sql)
-                    (set! (.-_args stmt) [])
-                    (set! (.-bind stmt)
-                          (fn [& args]
-                            (set! (.-_args stmt) (vec args))
-                            stmt))
-                    (set! (.-run stmt)
-                          (fn []
-                            (run-sql! state (.-_sql stmt) (.-_args stmt))
-                            #js {}))
-                    (set! (.-all stmt)
-                          (fn []
-                            (all-sql state (.-_sql stmt) (.-_args stmt))))
-                    stmt))})
-
-(deftest index-init-schema-test
-  (async done
-         (let [state (atom {:executed []
-                            :users {}
-                            :user-keys {}
-                            :graph-keys {}
-                            :graph-members {}
-                            :graphs {}})
-               db (make-d1 state)]
-           (-> (index/<index-init! db)
-               (p/then (fn [_]
-                         (let [sqls (:executed @state)]
-                           (is (some #(string/includes? % "create table if not exists users") sqls))
-                           (is (some #(string/includes? % "create table if not exists graph_members") sqls))
-                           (is (some #(string/includes? % "create table if not exists user_rsa_keys") sqls))
-                           (is (some #(string/includes? % "create table if not exists graph_aes_keys") sqls)))
-                         (done)))
-               (p/catch (fn [e]
-                          (is false (str e))
-                          (done)))))))
-
-(deftest user-upsert-test
-  (async done
-         (let [state (atom {:executed []
-                            :users {}
-                            :user-keys {}
-                            :graph-keys {}
-                            :graph-members {}
-                            :graphs {}})
-               db (make-d1 state)
-               claims #js {"sub" "user-1"
-                           "email" "[email protected]"
-                           "email_verified" true
-                           "cognito:username" "foo"}]
-           (-> (index/<user-upsert! db claims)
-               (p/then (fn [_]
-                         (let [user (get-in @state [:users "user-1"])]
-                           (is (= "[email protected]" (:email user)))
-                           (is (= 1 (:email-verified user)))
-                           (is (= "foo" (:username user))))
-                         (done)))
-               (p/catch (fn [e]
-                          (is false (str e))
-                          (done)))))))
-
-(deftest graph-name-exists-test
-  (async done
-         (let [state (atom {:executed []
-                            :users {}
-                            :user-keys {}
-                            :graph-keys {}
-                            :graph-members {}
-                            :graphs {}})
-               db (make-d1 state)]
-           (-> (p/do!
-                (index/<index-upsert! db "graph-1" "alpha" "user-1" "1")
-                (index/<index-upsert! db "graph-2" "beta" "user-2" "1"))
-               (p/then (fn [_]
-                         (p/let [exists? (index/<graph-name-exists? db "alpha" "user-1")
-                                 missing? (index/<graph-name-exists? db "alpha" "user-2")
-                                 other? (index/<graph-name-exists? db "beta" "user-1")]
-                           (is (true? exists?))
-                           (is (false? missing?))
-                           (is (false? other?))
-                           (done))))
-               (p/catch (fn [e]
-                          (is false (str e))
-                          (done)))))))
-
-(deftest graph-list-includes-role-and-invited-by-test
-  (async done
-         (let [state (atom {:executed []
-                            :users {}
-                            :user-keys {}
-                            :graph-keys {}
-                            :graph-members {}
-                            :graphs {}})
-               db (make-d1 state)]
-           (-> (p/do!
-                (index/<index-upsert! db "graph-1" "alpha" "user-1" "1")
-                (index/<graph-member-upsert! db "graph-1" "user-1" "manager" "user-2")
-                (index/<index-upsert! db "graph-2" "beta" "user-2" "1")
-                (index/<graph-member-upsert! db "graph-2" "user-1" "member" "user-2"))
-               (p/then (fn [_]
-                         (p/let [graphs (index/<index-list db "user-1")
-                                 alpha (first (filter (fn [g] (= "graph-1" (:graph-id g))) graphs))
-                                 beta (first (filter (fn [g] (= "graph-2" (:graph-id g))) graphs))]
-                           (is (= "manager" (:role alpha)))
-                           (is (= "user-2" (:invited-by alpha)))
-                           (is (= "member" (:role beta)))
-                           (is (= "user-2" (:invited-by beta)))
-                           (done))))
-               (p/catch (fn [e]
-                          (is false (str e))
-                          (done)))))))
-
-(deftest graph-member-upsert-test
-  (async done
-         (let [state (atom {:executed []
-                            :users {}
-                            :user-keys {}
-                            :graph-keys {}
-                            :graph-members {}
-                            :graphs {}})
-               db (make-d1 state)]
-           (-> (index/<graph-member-upsert! db "graph-1" "user-2" "member" "user-1")
-               (p/then (fn [_]
-                         (let [member (get-in @state [:graph-members ["user-2" "graph-1"]])]
-                           (is (= "member" (:role member)))
-                           (is (= "user-1" (:invited-by member))))
-                         (done)))
-               (p/catch (fn [e]
-                          (is false (str e))
-                          (done)))))))
-
-(deftest e2ee-user-rsa-key-pair-upsert-test
-  (async done
-         (let [state (atom {:executed []
-                            :users {}
-                            :user-keys {}
-                            :graph-keys {}
-                            :graph-members {}
-                            :graphs {}})
-               db (make-d1 state)]
-           (-> (p/do!
-                (index/<user-rsa-key-pair-upsert! db "user-1" "public-1" "private-1")
-                (index/<user-rsa-key-pair-upsert! db "user-1" "public-2" "private-2"))
-               (p/then (fn [_]
-                         (p/let [pair (index/<user-rsa-key-pair db "user-1")]
-                           (is (= "public-2" (:public-key pair)))
-                           (is (= "private-2" (:encrypted-private-key pair)))
-                           (done))))
-               (p/catch (fn [e]
-                          (is false (str e))
-                          (done)))))))
-
-(deftest e2ee-user-public-key-by-email-test
-  (async done
-         (let [state (atom {:executed []
-                            :users {}
-                            :user-keys {}
-                            :graph-keys {}
-                            :graph-members {}
-                            :graphs {}})
-               db (make-d1 state)
-               claims #js {"sub" "user-1"
-                           "email" "[email protected]"
-                           "email_verified" true
-                           "cognito:username" "foo"}]
-           (-> (p/do!
-                (index/<user-upsert! db claims)
-                (index/<user-rsa-key-pair-upsert! db "user-1" "public-1" "private-1"))
-               (p/then (fn [_]
-                         (p/let [public-key (index/<user-rsa-public-key-by-email db "[email protected]")]
-                           (is (= "public-1" public-key))
-                           (done))))
-               (p/catch (fn [e]
-                          (is false (str e))
-                          (done)))))))
-
-(deftest e2ee-graph-aes-key-upsert-test
-  (async done
-         (let [state (atom {:executed []
-                            :users {}
-                            :user-keys {}
-                            :graph-keys {}
-                            :graph-members {}
-                            :graphs {}})
-               db (make-d1 state)]
-           (-> (p/do!
-                (index/<graph-encrypted-aes-key-upsert! db "graph-1" "user-1" "aes-1")
-                (index/<graph-encrypted-aes-key-upsert! db "graph-1" "user-1" "aes-2"))
-               (p/then (fn [_]
-                         (p/let [aes-key (index/<graph-encrypted-aes-key db "graph-1" "user-1")]
-                           (is (= "aes-2" aes-key))
-                           (done))))
-               (p/catch (fn [e]
-                          (is false (str e))
-                          (done)))))))

+ 2 - 11
deps/db/src/logseq/db.cljs

@@ -180,15 +180,7 @@
        (if-let [transact-fn @*transact-fn]
          (transact-fn repo-or-conn tx-data tx-meta)
          (transact-sync repo-or-conn tx-data tx-meta))))))
-
-(defn remove-conflict-datoms
-  [datoms]
-  (->> datoms
-       (group-by (fn [d] (take 4 d))) ; group by '(e a v tx)
-       (keep (fn [[_eavt same-eavt-datoms]]
-               (first (rseq same-eavt-datoms))))
-       ;; sort by :tx, use nth to make this fn works on both vector and datom
-       (sort-by #(nth % 3))))
+(def remove-conflict-datoms db-normalize/remove-conflict-datoms)
 
 (defn transact-with-temp-conn!
   "Validate db and store once for a batch transaction, the `temp` conn can still load data from disk,
@@ -217,8 +209,7 @@
                         (if (fn? filter-tx-data)
                           (filter-tx-data temp-after-db tx-data)
                           tx-data)
-                        remove-conflict-datoms
-                        (db-normalize/remove-deleted-add-datoms temp-after-db))]
+                        remove-conflict-datoms)]
           (transact! conn tx-data' tx-meta))))))
 
 (def page? entity-util/page?)

+ 10 - 21
deps/db/src/logseq/db/common/normalize.cljs

@@ -79,31 +79,20 @@
        3))
    datoms))
 
-(defn remove-deleted-add-datoms
-  [db tx-data]
-  (let [deleted (->>
-                 (keep
-                  (fn [d]
-                    (when (and (false? (:added d))
-                               (= :block/uuid (:a d))
-                               (nil? (d/entity db (:e d))))
-                      [(:e d) (:v d)]))
-                  tx-data))
-        deleted-eids (set (map first deleted))
-        deleted-uuids (set (map (fn [item] [:block/uuid (second item)]) deleted))]
-    (if (seq deleted-eids)
-      (remove (fn [d]
-                (or (and (:added d) (contains? deleted-eids (:e d)))
-                    (and (not (= (:a d) :block/uuid))
-                         (or
-                          (contains? deleted-uuids (:e d))
-                          (contains? deleted-uuids (:v d)))))) tx-data)
-      tx-data)))
+(defn remove-conflict-datoms
+  [datoms]
+  (->> datoms
+       (group-by (fn [d] (take 4 d))) ; group by '(e a v tx)
+       (keep (fn [[_eavt same-eavt-datoms]]
+               (first (rseq same-eavt-datoms))))
+       ;; sort by :tx, use nth to make this fn works on both vector and datom
+       (sort-by #(nth % 3))))
 
 (defn normalize-tx-data
   [db-after db-before tx-data]
   (->> tx-data
-       (remove-deleted-add-datoms db-after)
+       remove-conflict-datoms
+       ;; (remove-deleted-add-datoms db-after)
        replace-attr-retract-with-retract-entity
        sort-datoms
        (keep

+ 3 - 89
src/main/frontend/worker/db_sync.cljs

@@ -14,7 +14,6 @@
             [frontend.worker.shared-service :as shared-service]
             [frontend.worker.state :as worker-state]
             [lambdaisland.glogi :as log]
-            [logseq.common.path :as path]
             [logseq.common.util :as common-util]
             [logseq.db :as ldb]
             [logseq.db-sync.cycle :as sync-cycle]
@@ -753,6 +752,7 @@
              (= :block/uuid (first x)))
     (second x)))
 
+;; TODO: is this really needed?
 (defn- keep-last-update
   [tx-data]
   (->> tx-data
@@ -763,51 +763,6 @@
             (take 3 item)
             item)))))
 
-;; Is `ensure-block-parents` really needed?
-(defn- ensure-block-parents
-  "Ensure block entities don't lose :block/parent without becoming pages."
-  [db tx-data]
-  (let [last-parent-op (atom {})
-        page-retracts (atom #{})
-        name-adds (atom #{})
-        retract-entities (atom #{})]
-    (doseq [item tx-data]
-      (when (vector? item)
-        (let [op (first item)]
-          (cond
-            (= op :db/retractEntity)
-            (swap! retract-entities conj (second item))
-
-            (and (contains? #{:db/add :db/retract} op)
-                 (>= (count item) 4))
-            (let [e (second item)
-                  a (nth item 2)]
-              (cond
-                (= a :block/parent)
-                (swap! last-parent-op assoc e {:op op :v (nth item 3)})
-
-                (and (= op :db/retract) (= a :block/page))
-                (swap! page-retracts conj e)
-
-                (and (= op :db/add) (= a :block/name))
-                (swap! name-adds conj e)))))))
-    (let [candidates (->> @last-parent-op
-                          (keep (fn [[e {:keys [op]}]]
-                                  (when (= op :db/retract) e)))
-                          (remove @retract-entities)
-                          (remove @page-retracts)
-                          (remove @name-adds))
-          fixes (keep (fn [e]
-                        (when-let [ent (d/entity db e)]
-                          (when (and (:block/page ent)
-                                     (not (ldb/page? ent)))
-                            (when-let [page-uuid (:block/uuid (:block/page ent))]
-                              [:db/add e :block/parent [:block/uuid page-uuid]]))))
-                      candidates)]
-      (if (seq fixes)
-        (into tx-data fixes)
-        tx-data))))
-
 (defn- sanitize-tx-data
   [db tx-data local-deleted-ids]
   (let [sanitized-tx-data (->> tx-data
@@ -818,8 +773,7 @@
                                                   (contains? #{:block/created-at :block/updated-at :block/title}
                                                              (nth item 2)))
                                              (contains? local-deleted-ids (get-lookup-id (last item))))))
-                               keep-last-update)
-        sanitized-tx-data (ensure-block-parents db sanitized-tx-data)]
+                               keep-last-update)]
     ;; (when (not= tx-data sanitized-tx-data)
     ;;   (prn :debug :tx-data tx-data)
     ;;   (prn :debug :sanitized-tx-data sanitized-tx-data))
@@ -842,8 +796,7 @@
                       tx-data (->> txs
                                    (db-normalize/remove-retract-entity-ref @conn)
                                    keep-last-update
-                                   distinct)
-                      tx-data (ensure-block-parents @conn tx-data)]
+                                   distinct)]
                   ;; (prn :debug :before-keep-last-update txs)
                   ;; (prn :debug :upload :tx-data tx-data)
                   (when (seq txs)
@@ -1042,45 +995,6 @@
     (enqueue-asset-downloads! repo client [asset-uuid])
     (p/resolved nil)))
 
-(defn- enqueue-asset-initial-download!
-  [repo client]
-  (enqueue-asset-task! client
-                       (fn []
-                         (if-let [conn (worker-state/get-datascript-conn repo)]
-                           (let [db @conn
-                                 graph-id (:graph-id client)
-                                 remote-assets (d/q '[:find ?uuid ?type
-                                                      :where
-                                                      [?e :block/uuid ?uuid]
-                                                      [?e :logseq.property.asset/type ?type]
-                                                      [?e :logseq.property.asset/remote-metadata]]
-                                                    db)]
-                             (if (seq graph-id)
-                               (-> (p/let [paths (worker-state/<invoke-main-thread
-                                                  :thread-api/get-all-asset-file-paths
-                                                  repo)]
-                                     (let [local-uuids (into #{}
-                                                             (keep (fn [path]
-                                                                     (let [stem (path/file-stem path)]
-                                                                       (when (seq stem)
-                                                                         stem))))
-                                                             paths)
-                                           missing (remove (fn [[uuid _type]]
-                                                             (contains? local-uuids (str uuid)))
-                                                           remote-assets)]
-                                       (p/loop [entries missing]
-                                         (if (empty? entries)
-                                           nil
-                                           (let [[asset-uuid asset-type] (first entries)]
-                                             (p/do!
-                                              (download-remote-asset! repo graph-id asset-uuid asset-type)
-                                              (p/recur (rest entries))))))))
-                                   (p/catch (fn [e]
-                                              (log/error :db-sync/asset-initial-download-failed
-                                                         {:repo repo :error e}))))
-                               (p/resolved nil)))
-                           (p/resolved nil)))))
-
 (defn- get-local-deleted-blocks
   [reversed-tx-report reversed-tx-data]
   (when (seq reversed-tx-data)

+ 18 - 36
src/test/frontend/worker/db_sync_sim_test.cljs

@@ -47,11 +47,11 @@
       s)))
 
 (defn- rng-uuid [rng]
-  (let [bytes (vec (repeatedly 16 #(rand-int! rng 256)))
-        bytes (-> bytes
-                  (assoc 6 (bit-or 0x40 (bit-and (nth bytes 6) 0x0f)))
-                  (assoc 8 (bit-or 0x80 (bit-and (nth bytes 8) 0x3f))))
-        hexes (map byte->hex bytes)
+  (let [payload (vec (repeatedly 16 #(rand-int! rng 256)))
+        payload (-> payload
+                    (assoc 6 (bit-or 0x40 (bit-and (nth payload 6) 0x0f)))
+                    (assoc 8 (bit-or 0x80 (bit-and (nth payload 8) 0x3f))))
+        hexes (map byte->hex payload)
         uuid-str (str (apply str (take 4 hexes)) "-"
                       (apply str (take 2 (drop 4 hexes))) "-"
                       (apply str (take 2 (drop 6 hexes))) "-"
@@ -169,7 +169,9 @@
 
 (defn- update-title! [conn uuid new-title]
   ;; (prn :debug :update-title uuid :from (:block/title (d/entity @conn [:block/uuid uuid])) :to new-title)
-  (ldb/transact! conn [[:db/add [:block/uuid uuid] :block/title new-title]]))
+  (outliner-core/save-block! conn
+                             {:block/uuid uuid
+                              :block/title new-title}))
 
 (defn- move-block! [conn block parent]
   (let [block (d/entity @conn [:block/uuid (:block/uuid block)])
@@ -211,7 +213,7 @@
          (fn [{:keys [t txs conn] :as state}]
            (if (not= t t-before)
              state
-             (let [{:keys [db-before db-after tx-data]} (ldb/transact! conn tx-data)
+             (let [{:keys [db-before db-after tx-data]} (ldb/transact! conn tx-data {:op :apply-client-tx})
                    normalized-data (->> tx-data
                                         (db-normalize/normalize-tx-data db-after db-before))
                    next-t (inc t)]
@@ -263,7 +265,6 @@
           (recur (inc i))))))
   (let [conns (keep (fn [c] (when (:online? c) (:conn c))) clients)
         block-counts (map #(count (d/datoms (deref %) :avet :block/uuid)) conns)]
-    (when (seq block-counts))
     (when-not (= (count (distinct block-counts)) 1)
       (throw (ex-info "blocks count not equal after sync"
                       {:block-counts block-counts
@@ -377,7 +378,7 @@
                            [base-uuid]))
         ent (rand-nth! rng (vec ents))
         block (d/entity db [:block/uuid (:block/uuid ent)])]
-    (when block
+    (when (and block (not (ldb/page? block)))
       (let [uuid (:block/uuid block)
             title (str "Title-" (rand-int! rng 1000000))]
         (update-title! conn uuid title)
@@ -410,11 +411,13 @@
 ;; TODO: add tag/property/migrate/undo/redo ops
 (def ^:private op-table
   [{:name :create-page :weight 6 :f op-create-page!}
-   ;; {:name :delete-page :weight 2 :f op-delete-page!}
+   {:name :delete-page :weight 2 :f op-delete-page!}
    {:name :create-block :weight 10 :f op-create-block!}
-   ;; {:name :update-title :weight 8 :f op-update-title!}
    {:name :move-block :weight 6 :f op-move-block!}
-   ;; {:name :delete-block :weight 4 :f op-delete-block!}
+   {:name :delete-block :weight 4 :f op-delete-block!}
+
+   ;; Failed ops
+   ;; {:name :update-title :weight 8 :f op-update-title!}
    ])
 
 (defn- pick-op [rng {:keys [disable-ops]}]
@@ -449,28 +452,6 @@
                               repo (assoc :repo repo)
                               context (assoc :context context)))))))
 
-(deftest history-captures-repo-test
-  (testing "history captures repo info for reproduction"
-    (let [seed 99
-          rng (make-rng seed)
-          gen-uuid #(rng-uuid rng)
-          base-uuid (gen-uuid)
-          conn (db-test/create-conn)
-          ops (d/create-conn client-op/schema-in-db)
-          history (atom [])
-          state (atom {:pages #{base-uuid} :blocks #{}})]
-      (with-test-repos {repo-a {:conn conn :ops-conn ops}}
-        (fn []
-          (record-meta! history {:seed seed :base-uuid base-uuid})
-          (ensure-base-page! conn base-uuid)
-          (run-ops! rng {:repo repo-a :conn conn :base-uuid base-uuid :state state :gen-uuid gen-uuid}
-                    1
-                    history
-                    {:pick-op-opts {:disable-ops #{:create-block :move-block}}})
-          (let [entry (first (filter #(= :op (:type %)) @history))]
-            (is (= repo-a (:repo entry)))
-            (is (= :create-page (:op entry)))))))))
-
 (deftest two-clients-online-offline-sim-test
   (testing "db-sync convergence with online/offline client and random ops"
     (prn :debug "run two-clients-online-offline-sim-test")
@@ -532,7 +513,7 @@
               (finally
                 (restore)))))))))
 
-(defonce op-runs 100)
+(defonce op-runs 500)
 
 (defn- run-random-ops!
   [rng server clients repo->state base-uuid history run-ops-opts steps]
@@ -567,7 +548,8 @@
            " a=" (count attrs-a)
            " c=" (count attrs-c)
            " history=" (count @history))))
-(deftest three-clients-single-repo-sim-test
+
+(deftest ^:large-vars/cleanup-todo three-clients-single-repo-sim-test
   (prn :debug "run three-clients-single-repo-sim-test")
   (testing "db-sync convergence with three clients sharing one repo"
     (let [seed (or (env-seed) default-seed)

+ 2 - 184
src/test/frontend/worker/db_sync_test.cljs

@@ -1,15 +1,11 @@
 (ns frontend.worker.db-sync-test
-  (:require [cljs.test :refer [deftest is testing async]]
+  (:require [cljs.test :refer [deftest is testing]]
             [datascript.core :as d]
-            [frontend.common.crypt :as crypt]
             [frontend.worker.db-sync :as db-sync]
             [frontend.worker.rtc.client-op :as client-op]
             [frontend.worker.state :as worker-state]
-            [logseq.db :as ldb]
-            [logseq.db.sqlite.util :as sqlite-util]
             [logseq.db.test.helper :as db-test]
-            [logseq.outliner.core :as outliner-core]
-            [promesa.core :as p]))
+            [logseq.outliner.core :as outliner-core]))
 
 (def ^:private test-repo "test-db-sync-repo")
 
@@ -67,164 +63,6 @@
             (is (= (:db/id child1') (:db/id (:block/parent parent'))))
             (is (= (:db/id page') (:db/id (:block/parent child1'))))))))))
 
-(deftest ensure-block-parents-test
-  (let [{:keys [conn child1 parent]} (setup-parent-child)
-        child-uuid (:block/uuid child1)
-        parent-uuid (:block/uuid parent)
-        page-uuid (:block/uuid (:block/page child1))]
-    (testing "adds parent when a block loses parent without becoming a page"
-      (let [tx-data [[:db/retract [:block/uuid child-uuid] :block/parent [:block/uuid parent-uuid] 1]]
-            fixed (#'db-sync/ensure-block-parents @conn tx-data)]
-        (is (some (fn [item]
-                    (and (= :db/add (first item))
-                         (= [:block/uuid child-uuid] (second item))
-                         (= :block/parent (nth item 2))
-                         (= [:block/uuid page-uuid] (nth item 3))))
-                  fixed))))
-    (testing "does not add parent when converting to page"
-      (let [tx-data [[:db/retract [:block/uuid child-uuid] :block/parent [:block/uuid parent-uuid] 1]
-                     [:db/add [:block/uuid child-uuid] :block/name "page" 1]]
-            fixed (#'db-sync/ensure-block-parents @conn tx-data)]
-        (is (= tx-data fixed))))
-    (testing "does not add parent when entity is retracted"
-      (let [tx-data [[:db/retract [:block/uuid child-uuid] :block/parent [:block/uuid parent-uuid] 1]
-                     [:db/retractEntity [:block/uuid child-uuid]]]
-            fixed (#'db-sync/ensure-block-parents @conn tx-data)]
-        (is (= tx-data fixed))))))
-
-(deftest ensure-block-parents-last-op-retract-test
-  (let [{:keys [conn child1 parent]} (setup-parent-child)
-        child-uuid (:block/uuid child1)
-        parent-uuid (:block/uuid parent)
-        page-uuid (:block/uuid (:block/page child1))]
-    (testing "retract after add still reparents to page"
-      (let [tx-data [[:db/add [:block/uuid child-uuid] :block/parent [:block/uuid parent-uuid] 1]
-                     [:db/retract [:block/uuid child-uuid] :block/parent [:block/uuid parent-uuid] 2]]
-            fixed (#'db-sync/ensure-block-parents @conn tx-data)]
-        (is (some (fn [item]
-                    (and (= :db/add (first item))
-                         (= [:block/uuid child-uuid] (second item))
-                         (= :block/parent (nth item 2))
-                         (= [:block/uuid page-uuid] (nth item 3))))
-                  fixed))))))
-
-(deftest sanitize-tx-data-ensures-parent-test
-  (let [{:keys [conn child1 parent]} (setup-parent-child)
-        child-uuid (:block/uuid child1)
-        parent-uuid (:block/uuid parent)
-        page-uuid (:block/uuid (:block/page child1))]
-    (testing "sanitize-tx-data preserves parent for blocks when last op retracts parent"
-      (let [tx-data [[:db/add [:block/uuid child-uuid] :block/parent [:block/uuid parent-uuid] 1]
-                     [:db/retract [:block/uuid child-uuid] :block/parent [:block/uuid parent-uuid] 2]]
-            fixed (#'db-sync/sanitize-tx-data @conn tx-data #{})]
-        (is (some (fn [item]
-                    (and (= :db/add (first item))
-                         (= [:block/uuid child-uuid] (second item))
-                         (= :block/parent (nth item 2))
-                         (= [:block/uuid page-uuid] (nth item 3))))
-                  fixed))))))
-
-(deftest encrypt-decrypt-tx-data-test
-  (async done
-         (-> (p/let [aes-key (crypt/<generate-aes-key)
-                     tx-data [[:db/add 1 :block/title "hello"]
-                              [:db/add 2 :block/name "page"]
-                              [:db/add 3 :block/uuid (random-uuid)]]
-                     encrypted (#'db-sync/<encrypt-tx-data aes-key tx-data)]
-               (is (not= tx-data encrypted))
-               (is (string? (nth (first encrypted) 3)))
-               (is (string? (nth (second encrypted) 3)))
-               (is (not= (nth (second encrypted) 3) "page"))
-               (p/let [decrypted (#'db-sync/<decrypt-tx-data aes-key encrypted)]
-                 (is (= tx-data decrypted))
-                 (done)))
-             (p/catch (fn [e]
-                        (is false (str e))
-                        (done))))))
-
-(deftest encrypt-decrypt-snapshot-rows-test
-  (async done
-         (-> (p/let [aes-key (crypt/<generate-aes-key)
-                     keys [[1 :block/title "hello" 0]
-                           [1 :block/name "page" 0]
-                           [1 :block/uuid (random-uuid) 0]]
-                     content (sqlite-util/write-transit-str {:keys keys})
-                     encrypted-title (#'db-sync/<encrypt-text-value aes-key "hello")
-                     encrypted-name (#'db-sync/<encrypt-text-value aes-key "page")
-                     encrypted-content (sqlite-util/write-transit-str
-                                        {:keys [[1 :block/title encrypted-title 0]
-                                                [1 :block/name encrypted-name 0]
-                                                [1 :block/uuid (nth (nth keys 2) 2) 0]]})
-                     rows [[1 encrypted-content nil]]]
-               (is (not= content encrypted-content))
-               (p/let [decrypted (#'db-sync/<decrypt-snapshot-rows aes-key rows)
-                       decode (fn [content']
-                                (let [data (ldb/read-transit-str content')]
-                                  (if (map? data)
-                                    (update data :keys (fnil vec []))
-                                    data)))
-                       decoded-original (decode content)
-                       decoded-decrypted (decode (nth (first decrypted) 1))]
-                 (is (= decoded-original decoded-decrypted))
-                 (done)))
-             (p/catch (fn [e]
-                        (is false (str e))
-                        (done))))))
-
-(deftest encrypt-datoms-test
-  (async done
-         (let [conn (db-test/create-conn-with-blocks
-                     {:pages-and-blocks
-                      [{:page {:block/title "page 1"}
-                        :blocks [{:block/title "parent"}]}]})
-               datoms (vec (d/datoms @conn :eavt))
-               title-datom (first (filter (fn [datom] (= :block/title (:a datom))) datoms))
-               name-datom (first (filter (fn [datom] (= :block/name (:a datom))) datoms))
-               uuid-datom (first (filter (fn [datom] (= :block/uuid (:a datom))) datoms))]
-           (-> (p/let [aes-key (crypt/<generate-aes-key)
-                       tx-data (#'db-sync/<encrypt-datoms aes-key datoms)
-                       title-tx (first (filter (fn [item]
-                                                 (and (= (:e title-datom) (:e item))
-                                                      (= :block/title (:a item))))
-                                               tx-data))
-                       name-tx (first (filter (fn [item]
-                                                (and (= (:e name-datom) (:e item))
-                                                     (= :block/name (:a item))))
-                                              tx-data))
-                       uuid-tx (first (filter (fn [item]
-                                                (and (= (:e uuid-datom) (:e item))
-                                                     (= :block/uuid (:a item))))
-                                              tx-data))]
-                 (is (string? (:v title-tx)))
-                 (is (string? (:v name-tx)))
-                 (is (not= (:v title-datom) (:v title-tx)))
-                 (is (= (:v uuid-datom) (:v uuid-tx)))
-                 (done))
-               (p/catch (fn [e]
-                          (is false (str e))
-                          (done)))))))
-
-(deftest ensure-user-rsa-keys-test
-  (async done
-         (let [upload-called (atom nil)]
-           (-> (p/with-redefs [db-sync/e2ee-base (fn [] "http://base")
-                               db-sync/<fetch-user-rsa-key-pair-raw (fn [_] (p/resolved {}))
-                               db-sync/<upload-user-rsa-key-pair! (fn [_ public-key encrypted-private-key]
-                                                                    (reset! upload-called [public-key encrypted-private-key])
-                                                                    (p/resolved {:public-key public-key
-                                                                                 :encrypted-private-key encrypted-private-key}))
-                               crypt/<generate-rsa-key-pair (fn [] (p/resolved #js {:publicKey :pub :privateKey :priv}))
-                               crypt/<export-public-key (fn [_] (p/resolved :pub-export))
-                               crypt/<encrypt-private-key (fn [_ _] (p/resolved :priv-encrypted))
-                               worker-state/<invoke-main-thread (fn [_] (p/resolved {:password "pw"}))]
-                 (p/let [resp (db-sync/ensure-user-rsa-keys!)]
-                   (is (map? resp))
-                   (is (= 2 (count @upload-called)))
-                   (done)))
-               (p/catch (fn [e]
-                          (is false (str e))
-                          (done)))))))
-
 (deftest two-children-cycle-test
   (testing "cycle from remote sync overwrite client (2 children)"
     (let [{:keys [conn client-ops-conn child1 child2]} (setup-parent-child)]
@@ -259,26 +97,6 @@
             (is (= "child 3" (:block/title (:block/parent child2'))))
             (is (= "parent" (:block/title (:block/parent child3'))))))))))
 
-(deftest hello-message-does-not-trigger-initial-asset-download-test
-  (let [called? (atom false)
-        client {:repo test-repo
-                :graph-id "graph-id"
-                :asset-queue (atom (p/resolved nil))
-                :inflight (atom [])
-                :ws {}}
-        raw (js/JSON.stringify (clj->js {:type "hello" :t 0}))]
-    (with-redefs [db-sync/enqueue-asset-initial-download!
-                  (fn [& _]
-                    (reset! called? true)
-                    (p/resolved nil))
-                  db-sync/enqueue-asset-sync! (fn [& _] (p/resolved nil))
-                  db-sync/flush-pending! (fn [& _] (p/resolved nil))
-                  db-sync/send! (fn [& _] nil)
-                  db-sync/broadcast-rtc-state! (fn [& _] nil)
-                  client-op/get-local-tx (fn [& _] 0)]
-      (#'db-sync/handle-message! test-repo client raw)
-      (is (false? @called?)))))
-
 (deftest ignore-missing-parent-update-after-local-delete-test
   (testing "remote parent retracted while local adds another child"
     (let [{:keys [conn client-ops-conn parent child1]} (setup-parent-child)