Add sync test for single diff
This commit is contained in:
parent
3760fc8059
commit
edab2ad684
5 changed files with 79 additions and 39 deletions
|
@ -7,28 +7,34 @@
|
|||
;; Server state
|
||||
(def states (atom []))
|
||||
|
||||
(defn make-client-agent [in >client]
|
||||
(defn make-server-agent [in >client states]
|
||||
(a/go-loop [client-state sync/empty-state]
|
||||
(when-let [msg (<! in)]
|
||||
(condp = (:type msg)
|
||||
:diff
|
||||
(let [{:keys [new-states new-shadow full-sync?]} (sync/apply-diff @states (:diff msg) (:shadow-hash msg))]
|
||||
(if full-sync?
|
||||
(let [state (get-current-state states)]
|
||||
(>! >client message/full-sync state)
|
||||
(recur state))
|
||||
(do (reset! states new-states)
|
||||
(recur new-shadow))))
|
||||
:full-sync
|
||||
(let [state (get-current-state @states)]
|
||||
(>! >client message/full-sync state)
|
||||
(recur state))
|
||||
:new-state
|
||||
(let [{:keys [diff shadow-hash]} (sync/diff-states (:new-states msg) @client-state)]
|
||||
(println "new-state!")
|
||||
(>! >client (message/diff-msg diff shadow-hash)))
|
||||
(do (println "Unknown event")
|
||||
(recur client-state))))))
|
||||
(when-let [msg (<! in)]
|
||||
(condp = (:type msg)
|
||||
:diff
|
||||
(let [{:keys [new-states new-shadow full-sync?]} (sync/apply-diff @states (:diff msg) (:hash msg))]
|
||||
(println "diff!")
|
||||
(if full-sync?
|
||||
(let [state (sync/get-current-state @states)]
|
||||
(println "state not found, full sync!")
|
||||
(>! >client (message/full-sync state))
|
||||
(recur state))
|
||||
(do (println "state found, just send changes")
|
||||
(let [{:keys [diff hash]} (sync/diff-states new-states new-shadow)]
|
||||
(reset! states new-states)
|
||||
(>! >client (message/diff-msg diff hash))
|
||||
(recur new-shadow)))))
|
||||
:full-sync
|
||||
(let [state (sync/get-current-state @states)]
|
||||
(println "got full sync, send full sync")
|
||||
(>! >client (message/full-sync state))
|
||||
(recur state))
|
||||
:new-state
|
||||
(let [{:keys [diff shadow-hash]} (sync/diff-states (:new-states msg) client-state)]
|
||||
(println "new-state!")
|
||||
(>! >client (message/diff-msg diff shadow-hash)))
|
||||
(do (println "Unknown message:" msg)
|
||||
(recur client-state))))))
|
||||
|
||||
;; TODO: Remove watch, close up channels properly
|
||||
(defn sync-new-client! [>client <client]
|
||||
|
@ -38,7 +44,7 @@
|
|||
client-events (chan)]
|
||||
(add-watch states client-id (fn [_ _ _ new-states] (a/put! state-changes new-states)))
|
||||
(a/pipe (a/merge [<client state-change-events]) client-events)
|
||||
(make-client-agent client-events >client)))
|
||||
(make-server-agent client-events >client states)))
|
||||
|
||||
(defn init [to-db grubs recipes]
|
||||
(reset! states (sync/initial-state grubs recipes))
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
(ns grub.state
|
||||
(:require [grub.diff :as diff]
|
||||
[grub.common-state :as cs]
|
||||
[grub.message :as message]
|
||||
[grub.sync :as sync]
|
||||
[cljs.core.async :as a :refer [<! >! chan]]
|
||||
[hasch.core :as hasch])
|
||||
(:require-macros [grub.macros :refer [log logs]]
|
||||
[cljs.core.async.macros :refer [go go-loop]]))
|
||||
|
||||
(def state (atom cs/empty-state))
|
||||
(def server-state (atom cs/empty-state))
|
||||
(def state (atom sync/empty-state))
|
||||
(def server-state (atom sync/empty-state))
|
||||
|
||||
(def unacked-states (atom {}))
|
||||
|
||||
|
@ -36,15 +38,15 @@
|
|||
(let [new-server (swap! server-state #(diff/patch-state % diff))]
|
||||
(if (= (hasch/uuid new-server) hash)
|
||||
(swap! state diff/patch-state diff)
|
||||
(do (log "State update failure --> complete sync")
|
||||
(a/put! from cs/complete-sync-request)))))
|
||||
(do (log "Could not find server state locally --> complete sync")
|
||||
(a/put! from cs/complete-sync-request)))
|
||||
:complete (do
|
||||
(logs "Complete sync")
|
||||
(reset! unacked-states {})
|
||||
(reset! server-state (:state msg))
|
||||
(reset! state (:state msg)))
|
||||
(do (log "State update failure --> full sync")
|
||||
(a/put! from message/full-sync-request)))))
|
||||
(do (log "Could not find server state locally --> full sync")
|
||||
(a/put! from message/full-sync-request)))
|
||||
:full-sync (do
|
||||
(logs "Full sync")
|
||||
(reset! unacked-states {})
|
||||
(reset! server-state (:state msg))
|
||||
(reset! state (:state msg)))
|
||||
(logs "Invalid msg:" msg))
|
||||
(recur))
|
||||
(remove-watch state :state))))
|
||||
|
@ -52,4 +54,4 @@
|
|||
(defn sync-state! [to from reset? state-changes]
|
||||
(send-state-changes-to-server! state-changes from)
|
||||
(handle-received-changes! to from)
|
||||
(a/put! from (if reset? cs/complete-sync-request (cs/diff-states @server-state @state))))
|
||||
(a/put! from (if reset? message/full-sync-request (cs/diff-states @server-state @state))))
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
(ns grub.message)
|
||||
|
||||
(def full-sync-request {:type :complete})
|
||||
(def full-sync-request {:type :full-sync})
|
||||
|
||||
(defn full-sync [state]
|
||||
{:type :complete
|
||||
{:type :full-sync
|
||||
:state state})
|
||||
|
||||
(defn diff-msg [diff shadow-hash]
|
||||
(defn diff-msg [diff hash]
|
||||
{:type :diff
|
||||
:diff diff
|
||||
:shadow-hash shadow-hash})
|
||||
:hash hash})
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
(defn diff-states [states shadow]
|
||||
(let [state (get-current-state states)]
|
||||
{:shadow-hash (hasch/uuid shadow)
|
||||
{:hash (hasch/uuid shadow)
|
||||
:diff (diff/diff-states shadow state)}))
|
||||
|
||||
(defn apply-diff [states diff shadow-hash]
|
||||
|
|
32
src/test/grub/test/unit/state.clj
Normal file
32
src/test/grub/test/unit/state.clj
Normal file
|
@ -0,0 +1,32 @@
|
|||
(ns grub.test.unit.state
|
||||
(:require [grub.state :as state]
|
||||
[clojure.test :refer :all]
|
||||
[hasch.core :as hasch]
|
||||
[clojure.core.async :as a :refer [<!! >!! chan go]]))
|
||||
|
||||
(deftest single-diff
|
||||
;; Returns empty ACK diff
|
||||
(let [in (chan 1)
|
||||
>client (chan 1)
|
||||
state {:grubs {"1" {:text "2 apples" :completed false}}
|
||||
:recipes {}}
|
||||
hash (hasch/uuid state)
|
||||
states* [{:hash hash :state state}]
|
||||
states (atom states*)
|
||||
diff {:grubs {:updated {"1" {:completed true}} :deleted #{}}}
|
||||
diff-msg {:type :diff
|
||||
:diff diff
|
||||
:hash hash}
|
||||
server-agent (state/make-server-agent in >client states)]
|
||||
(>!! in diff-msg)
|
||||
(let [diff-response (<!! >client)]
|
||||
(is (= @states
|
||||
[{:hash #uuid "0cb7ae13-2523-52fa-aa79-4a6f2489cafd"
|
||||
:state {:grubs {"1" {:completed false, :text "2 apples"}}, :recipes {}}}
|
||||
{:hash #uuid "166d7e23-5a7b-5101-8364-0d2c06b8d554"
|
||||
:state {:grubs {"1" {:completed true, :text "2 apples"}}, :recipes {}}}]))
|
||||
(is (= diff-response
|
||||
{:type :diff
|
||||
:diff {:grubs {:deleted #{}, :updated nil}
|
||||
:recipes {:deleted #{}, :updated nil}}
|
||||
:hash #uuid "166d7e23-5a7b-5101-8364-0d2c06b8d554"})))))
|
Loading…
Reference in a new issue