#46: removing :suspend and :resume... [done]
This commit is contained in:
parent
4787ae12f5
commit
dc91a44f72
7 changed files with 21 additions and 352 deletions
102
README.md
102
README.md
|
|
@ -35,10 +35,6 @@ _**Alan J. Perlis** from [Structure and Interpretation of Computer Programs](htt
|
|||
- [Swapping Alternate Implementations](#swapping-alternate-implementations)
|
||||
- [Swapping States with Values](#swapping-states-with-values)
|
||||
- [Swapping States with States](#swapping-states-with-states)
|
||||
- [Suspending and Resuming](#suspending-and-resuming)
|
||||
- [Suspendable Lifecycle](#suspendable-lifecycle)
|
||||
- [Plugging into (reset)](#plugging-into-reset)
|
||||
- [Suspendable Example Application](#suspendable-example-application)
|
||||
- [ClojureScript is Clojure](doc/clojurescript.md#managing-state-in-clojurescript)
|
||||
- [Packaging](#packaging)
|
||||
- [Affected States](#affected-states)
|
||||
|
|
@ -168,7 +164,7 @@ is an example of a web server that "depends" on a similar `config`.
|
|||
|
||||
## Value of values
|
||||
|
||||
Lifecycle functions start/stop/suspend/resume can take both functions and values. This is "valuable" and also works:
|
||||
Lifecycle functions start/stop can take both functions and values. This is "valuable" and also works:
|
||||
|
||||
```clojure
|
||||
(defstate answer-to-the-ultimate-question-of-life-the-universe-and-everything :start 42)
|
||||
|
|
@ -263,7 +259,7 @@ You can see examples of start and stop flows in the [example app](README.md#moun
|
|||
|
||||
In REPL or during testing it is often very useful to work with / start / stop _only a part_ of an application, i.e. "only these two states".
|
||||
|
||||
`mount`'s lifecycle functions, i.e. start/stop/suspend/resume, can _optionally_ take states as vars (i.e. prefixed with their namespaces):
|
||||
`mount`'s lifecycle functions, i.e. start/stop, can _optionally_ take states as vars (i.e. prefixed with their namespaces):
|
||||
|
||||
```clojure
|
||||
(mount/start #'app.config/config #'app.nyse/conn)
|
||||
|
|
@ -378,80 +374,6 @@ dev=> (mount/start)
|
|||
|
||||
Notice that the `nyse-app` is not started the second time (hence no more accidental `java.net.BindException: Address already in use`). It is already up and running.
|
||||
|
||||
## Suspending and Resuming
|
||||
|
||||
Besides starting and stopping states can also be suspended and resumed. While this is not needed most of the time, it does comes really handy _when_ this need is there. For example:
|
||||
|
||||
* while working in REPL, you only want to truly restart a web server/queue listener/db connection _iff_ something changed, all other times `(mount/stop)` / `(mount/start)` or `(reset)` is called, these states should not be restarted. This might have to do with time to connect / bound ports / connection timeouts, etc..
|
||||
|
||||
* when taking an application out of rotation in a data center, and then phasing it back in, it might be handy to still keep it _up_, but suspend all the client / novelty facing components in between.
|
||||
|
||||
and some other use cases.
|
||||
|
||||
### Suspendable Lifecycle
|
||||
|
||||
In addition to `start` / `stop` functions, a state can also have `resume` and, if needed, `suspend` ones:
|
||||
|
||||
```clojure
|
||||
(defstate web-server :start start-server
|
||||
:resume resume-server
|
||||
:stop stop-server)
|
||||
|
||||
```
|
||||
|
||||
`suspend` function is optional. Combining this with [(mount/stop-except)](#stop-an-application-except-certain-states), can result in an interesting restart behavior where everything is restared, but this `web-server` is _resumed_ instead (in this case `#'app.www/nyse-app` is an example of the above `web-server`):
|
||||
|
||||
```clojure
|
||||
dev=> (mount/stop-except #'app.www/nyse-app)
|
||||
14:44:33.991 [nREPL-worker-1] INFO mount.core - << stopping.. nrepl
|
||||
14:44:33.992 [nREPL-worker-1] INFO mount.core - << stopping.. conn
|
||||
14:44:33.992 [nREPL-worker-1] INFO app.db - disconnecting from datomic:mem://mount
|
||||
14:44:33.992 [nREPL-worker-1] INFO mount.core - << stopping.. config
|
||||
:stopped
|
||||
dev=>
|
||||
|
||||
dev=> (mount/suspend)
|
||||
14:44:52.467 [nREPL-worker-1] INFO mount.core - >> suspending.. nyse-app
|
||||
:suspended
|
||||
dev=>
|
||||
|
||||
dev=> (mount/start)
|
||||
14:45:00.297 [nREPL-worker-1] INFO mount.core - >> starting.. config
|
||||
14:45:00.297 [nREPL-worker-1] INFO mount.core - >> starting.. conn
|
||||
14:45:00.298 [nREPL-worker-1] INFO app.db - creating a connection to datomic: datomic:mem://mount
|
||||
14:45:00.315 [nREPL-worker-1] INFO mount.core - >> resuming.. nyse-app
|
||||
14:45:00.316 [nREPL-worker-1] INFO mount.core - >> starting.. nrepl
|
||||
:started
|
||||
```
|
||||
|
||||
Notice `>> resuming.. nyse-app`, which in [this case](https://github.com/tolitius/mount/blob/suspendable/test/app/www.clj#L32) just recreates Datomic schema vs. doing that _and_ starting the actual web server.
|
||||
|
||||
### Plugging into (reset)
|
||||
|
||||
In case `tools.namespace` is used, this lifecycle can be easily hooked up with `dev.clj`:
|
||||
|
||||
```clojure
|
||||
(defn start []
|
||||
(mount/start))
|
||||
|
||||
(defn stop []
|
||||
(mount/suspend)
|
||||
(mount/stop-except #'app.www/nyse-app))
|
||||
|
||||
(defn reset []
|
||||
(stop)
|
||||
(tn/refresh :after 'dev/start))
|
||||
```
|
||||
|
||||
### Suspendable Example Application
|
||||
|
||||
An [example application](https://github.com/tolitius/mount/tree/suspendable/test/app) with a suspendable web server and `dev.clj` lives in the `suspendable` branch. You can clone mount and try it out:
|
||||
|
||||
```
|
||||
$ git checkout suspendable
|
||||
Switched to branch 'suspendable'
|
||||
```
|
||||
|
||||
## Recompiling Namespaces with Running States
|
||||
|
||||
Mount will detect when a namespace with states (i.e. with `(defstate ...)`) was reloaded/recompiled,
|
||||
|
|
@ -566,28 +488,22 @@ In practice only a few namespaces need to be `:require`d, since others will be b
|
|||
|
||||
## Affected States
|
||||
|
||||
Every time a lifecycle function (start/stop/suspend/resume) is called mount will return all the states that were affected:
|
||||
Every time a lifecycle function (start/stop) is called mount will return all the states that were affected:
|
||||
|
||||
```clojure
|
||||
dev=> (mount/start)
|
||||
{:started [#'app.config/config
|
||||
#'app.nyse/conn
|
||||
#'app/nrepl
|
||||
#'check.suspend-resume-test/web-server
|
||||
#'check.suspend-resume-test/q-listener]}
|
||||
#'app/nrepl]}
|
||||
```
|
||||
```clojure
|
||||
dev=> (mount/suspend)
|
||||
{:suspended [#'check.suspend-resume-test/web-server
|
||||
#'check.suspend-resume-test/q-listener]}
|
||||
```
|
||||
```clojure
|
||||
dev=> (mount/start)
|
||||
{:started [#'check.suspend-resume-test/web-server
|
||||
#'check.suspend-resume-test/q-listener]}
|
||||
dev=> (mount/stop)
|
||||
{:started [#'app/nrepl
|
||||
#'app.nyse/conn
|
||||
#'app.config/config]}
|
||||
```
|
||||
|
||||
An interesting bit here is a vector vs. a set: all the states are returned _in the order they were changed_.
|
||||
An interesting bit here is a vector vs. a set: all the states are returned _in the order they were affected_.
|
||||
|
||||
## Logging
|
||||
|
||||
|
|
|
|||
|
|
@ -34,9 +34,7 @@
|
|||
|
||||
(defonce lifecycle-fns
|
||||
#{#'mount.core/up
|
||||
#'mount.core/down
|
||||
#'mount.core/sigstop
|
||||
#'mount.core/sigcont})
|
||||
#'mount.core/down})
|
||||
|
||||
(defn without-logging-status []
|
||||
(doall (map #(clear-hooks %) lifecycle-fns)))
|
||||
|
|
|
|||
|
|
@ -197,7 +197,6 @@ Testing is not alien to Mount and it knows how to do a thing or two:
|
|||
* [start an application without certain states](https://github.com/tolitius/mount#start-an-application-without-certain-states)
|
||||
* [swapping alternate implementations](https://github.com/tolitius/mount#swapping-alternate-implementations)
|
||||
* [stop an application except certain states](https://github.com/tolitius/mount#stop-an-application-except-certain-states)
|
||||
* [suspending and resuming](https://github.com/tolitius/mount#suspending-and-resuming)
|
||||
|
||||
After [booting mount](http://www.dotkam.com/2015/12/22/the-story-of-booting-mount/) I was secretly thinking of achieving multiple separate systems by running them in different [Boot Pods](https://github.com/boot-clj/boot/wiki/Pods).
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@
|
|||
(defn- validate [{:keys [start stop suspend resume] :as lifecycle}]
|
||||
(cond
|
||||
(not start) (throw-runtime "can't start a stateful thing without a start function. (i.e. missing :start fn)")
|
||||
(and suspend
|
||||
(not resume)) (throw-runtime "suspendable state should have a resume function (i.e. missing :resume fn)")))
|
||||
(or suspend resume) (throw-runtime "suspend / resume lifecycle support was removed in \"0.1.10\" in favor of (mount/stop-except)")))
|
||||
|
||||
(defn- with-ns [ns name]
|
||||
(str "#'" ns "/" name))
|
||||
|
|
@ -86,18 +85,16 @@
|
|||
(swap! done conj state-name)
|
||||
state))
|
||||
|
||||
(defn- up [state {:keys [start stop resume status] :as current} done]
|
||||
(defn- up [state {:keys [start stop status] :as current} done]
|
||||
(when-not (:started status)
|
||||
(let [s (on-error (str "could not start [" state "] due to")
|
||||
(if (:suspended status)
|
||||
(record! state resume done)
|
||||
(record! state start done)))]
|
||||
(record! state start done))]
|
||||
(alter-state! current s)
|
||||
(swap! running assoc state {:stop stop})
|
||||
(update-meta! [state :status] #{:started}))))
|
||||
|
||||
(defn- down [state {:keys [stop status] :as current} done]
|
||||
(when (some status #{:started :suspended})
|
||||
(when (some status #{:started})
|
||||
(when stop
|
||||
(on-error (str "could not stop [" state "] due to")
|
||||
(record! state stop done)))
|
||||
|
|
@ -105,21 +102,6 @@
|
|||
(swap! running dissoc state)
|
||||
(update-meta! [state :status] #{:stopped})))
|
||||
|
||||
(defn- sigstop [state {:keys [resume suspend status] :as current} done]
|
||||
(when (and (:started status) resume) ;; can't have suspend without resume, but the reverse is possible
|
||||
(when suspend ;; don't suspend if there is only resume function (just mark it :suspended?)
|
||||
(let [s (on-error (str "could not suspend [" state "] due to")
|
||||
(record! state suspend done))]
|
||||
(alter-state! current s)))
|
||||
(update-meta! [state :status] #{:suspended})))
|
||||
|
||||
(defn- sigcont [state {:keys [resume status] :as current} done]
|
||||
(when (:suspended status)
|
||||
(let [s (on-error (str "could not resume [" state "] due to")
|
||||
(record! state resume done))]
|
||||
(alter-state! current s)
|
||||
(update-meta! [state :status] #{:started}))))
|
||||
|
||||
(deftype DerefableState [name]
|
||||
#?(:clj clojure.lang.IDeref
|
||||
:cljs IDeref)
|
||||
|
|
@ -151,16 +133,14 @@
|
|||
#?(:clj
|
||||
(defmacro defstate [state & body]
|
||||
(let [[state params] (macro/name-with-attributes state body)
|
||||
{:keys [start stop suspend resume] :as lifecycle} (apply hash-map params)
|
||||
{:keys [start stop] :as lifecycle} (apply hash-map params)
|
||||
state-name (with-ns *ns* state)
|
||||
order (make-state-seq state-name)]
|
||||
(validate lifecycle)
|
||||
(let [s-meta (cond-> {:order order
|
||||
:start `(fn [] ~start)
|
||||
:status #{:stopped}}
|
||||
stop (assoc :stop `(fn [] ~stop))
|
||||
suspend (assoc :suspend `(fn [] ~suspend))
|
||||
resume (assoc :resume `(fn [] ~resume)))]
|
||||
stop (assoc :stop `(fn [] ~stop)))]
|
||||
`(do
|
||||
(~'defonce ~state (DerefableState. ~state-name))
|
||||
(mount-it (~'var ~state) ~state-name ~s-meta)
|
||||
|
|
@ -226,14 +206,14 @@
|
|||
|
||||
(defn- merge-lifecycles
|
||||
"merges with overriding _certain_ non existing keys.
|
||||
i.e. :suspend is in a 'state', but not in a 'substitute': it should be overriden with nil
|
||||
i.e. :stop is in a 'state', but not in a 'substitute': it should be overriden with nil
|
||||
however other keys of 'state' (such as :ns,:name,:order) should not be overriden"
|
||||
([state sub]
|
||||
(merge-lifecycles state nil sub))
|
||||
([state origin {:keys [start stop suspend resume status]}]
|
||||
([state origin {:keys [start stop status]}]
|
||||
(assoc state :origin origin
|
||||
:status status
|
||||
:start start :stop stop :suspend suspend :resume resume)))
|
||||
:start start :stop stop)))
|
||||
|
||||
(defn- rollback! [state]
|
||||
(let [{:keys [origin] :as sub} (@meta-state state)]
|
||||
|
|
@ -241,7 +221,7 @@
|
|||
(update-meta! [state] (merge-lifecycles sub origin)))))
|
||||
|
||||
(defn- substitute! [state with mode]
|
||||
(let [lifecycle-fns #(select-keys % [:start :stop :suspend :resume :status])
|
||||
(let [lifecycle-fns #(select-keys % [:start :stop :status])
|
||||
origin (@meta-state state)
|
||||
sub (if (= :value mode)
|
||||
{:start (fn [] with) :status :stopped}
|
||||
|
|
@ -299,11 +279,3 @@
|
|||
without (remove (set states) app)]
|
||||
(apply start without))
|
||||
(start)))
|
||||
|
||||
(defn suspend [& states]
|
||||
(let [states (or (seq states) (all-without-subs))]
|
||||
{:suspended (bring states sigstop <)}))
|
||||
|
||||
(defn resume [& states]
|
||||
(let [states (or (seq states) (all-without-subs))]
|
||||
{:resumed (bring states sigcont <)}))
|
||||
|
|
|
|||
|
|
@ -34,9 +34,7 @@
|
|||
|
||||
(defonce lifecycle-fns
|
||||
#{#'mount.core/up
|
||||
#'mount.core/down
|
||||
#'mount.core/sigstop
|
||||
#'mount.core/sigcont})
|
||||
#'mount.core/down})
|
||||
|
||||
(defn without-logging-status []
|
||||
(doall (map clear-hooks lifecycle-fns)))
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
mount.test.start-without
|
||||
mount.test.start-with
|
||||
mount.test.start-with-states
|
||||
mount.test.suspend-resume
|
||||
))
|
||||
|
||||
#?(:clj (alter-meta! *ns* assoc ::load false))
|
||||
|
|
@ -32,7 +31,6 @@
|
|||
'mount.test.start-without
|
||||
'mount.test.start-with
|
||||
'mount.test.start-with-states
|
||||
'mount.test.suspend-resume
|
||||
))
|
||||
|
||||
(defn run-tests []
|
||||
|
|
|
|||
|
|
@ -1,212 +0,0 @@
|
|||
(ns mount.test.suspend-resume
|
||||
(:require
|
||||
#?@(:cljs [[cljs.test :as t :refer-macros [is are deftest testing use-fixtures]]
|
||||
[mount.core :as mount :refer-macros [defstate]]
|
||||
[tapp.websockets :refer [system-a]]
|
||||
[tapp.conf :refer [config]]
|
||||
[tapp.audit-log :refer [log]]]
|
||||
:clj [[clojure.test :as t :refer [is are deftest testing use-fixtures]]
|
||||
[mount.core :as mount :refer [defstate]]
|
||||
[tapp.conf :refer [config]]
|
||||
[tapp.nyse :refer [conn]]
|
||||
[tapp.example :refer [nrepl]]])
|
||||
[mount.test.helper :refer [dval]]))
|
||||
|
||||
#?(:clj (alter-meta! *ns* assoc ::load false))
|
||||
|
||||
(defn koncat [k s]
|
||||
(-> (name k)
|
||||
(str "-" (name s))
|
||||
keyword))
|
||||
|
||||
(defn start [s] (koncat s :started))
|
||||
(defn stop [s] (koncat s :stopped))
|
||||
(defn suspend [s] (koncat s :suspended))
|
||||
(defn resume [s] (koncat s :resumed))
|
||||
|
||||
(defstate web-server :start (start :w)
|
||||
:stop (stop :w)
|
||||
:suspend (suspend :w)
|
||||
:resume (resume :w))
|
||||
|
||||
(defstate q-listener :start (start :q)
|
||||
:stop (stop :q)
|
||||
:suspend (suspend :q)
|
||||
:resume (resume :q))
|
||||
|
||||
(defstate randomizer :start (rand-int 42))
|
||||
|
||||
#?(:cljs
|
||||
(deftest suspendable-lifecycle
|
||||
|
||||
(testing "should suspend _only suspendable_ states that are currently started"
|
||||
(let [_ (mount/start)
|
||||
_ (mount/suspend)]
|
||||
(is (map? (dval config)))
|
||||
(is (instance? datascript.db/DB @(dval log)))
|
||||
(is (instance? js/WebSocket (dval system-a)))
|
||||
(is (= (dval web-server) :w-suspended))
|
||||
(mount/stop)))
|
||||
|
||||
(testing "should resume _only suspendable_ states that are currently suspended"
|
||||
(let [_ (mount/start)
|
||||
_ (mount/stop #'tapp.websockets/system-a)
|
||||
_ (mount/suspend)
|
||||
_ (mount/resume)]
|
||||
(is (map? (dval config)))
|
||||
(is (instance? mount.core.NotStartedState (dval system-a)))
|
||||
(is (instance? datascript.db/DB @(dval log)))
|
||||
(is (= (dval web-server) :w-resumed))
|
||||
(mount/stop)))
|
||||
|
||||
(testing "should start all the states, except the ones that are currently suspended, should resume them instead"
|
||||
(let [_ (mount/start)
|
||||
_ (mount/suspend)
|
||||
_ (mount/start)]
|
||||
(is (map? (dval config)))
|
||||
(is (instance? js/WebSocket (dval system-a)))
|
||||
(is (instance? datascript.db/DB @(dval log)))
|
||||
(is (= (dval web-server) :w-resumed))
|
||||
(mount/stop)))
|
||||
|
||||
(testing "should stop all: started and suspended"
|
||||
(let [_ (mount/start)
|
||||
_ (mount/suspend)
|
||||
_ (mount/stop)]
|
||||
(is (instance? mount.core.NotStartedState (dval config)))
|
||||
(is (instance? mount.core.NotStartedState (dval system-a)))
|
||||
(is (instance? mount.core.NotStartedState (dval log)))
|
||||
(is (instance? mount.core.NotStartedState (dval web-server)))))))
|
||||
|
||||
#?(:cljs
|
||||
(deftest suspendable-start-with-states
|
||||
|
||||
(testing "when replacing a non suspendable state with a suspendable one,
|
||||
the later should be able to suspend/resume,
|
||||
the original should not be suspendable after resume and preserve its lifecycle fns after rollback/stop"
|
||||
(let [_ (mount/start-with-states {#'tapp.websockets/system-a #'mount.test.suspend-resume/web-server})
|
||||
_ (mount/suspend)]
|
||||
(is (= (dval system-a) :w-suspended))
|
||||
(is (instance? mount.core.NotStartedState (dval web-server)))
|
||||
(mount/stop)
|
||||
(mount/start)
|
||||
(mount/suspend)
|
||||
(is (instance? js/WebSocket (dval system-a)))
|
||||
(is (= (dval web-server) :w-suspended))
|
||||
(mount/stop)))))
|
||||
|
||||
#?(:clj
|
||||
(deftest suspendable-lifecycle
|
||||
|
||||
(testing "should suspend _only suspendable_ states that are currently started"
|
||||
(let [_ (mount/start)
|
||||
_ (mount/suspend)]
|
||||
(is (map? (dval config)))
|
||||
(is (instance? clojure.tools.nrepl.server.Server (dval nrepl)))
|
||||
(is (instance? datomic.peer.LocalConnection (dval conn)))
|
||||
(is (= (dval web-server) :w-suspended))
|
||||
(mount/stop)))
|
||||
|
||||
(testing "should resume _only suspendable_ states that are currently suspended"
|
||||
(let [_ (mount/start)
|
||||
_ (mount/stop #'tapp.example/nrepl)
|
||||
_ (mount/suspend)
|
||||
_ (mount/resume)]
|
||||
(is (map? (dval config)))
|
||||
(is (instance? mount.core.NotStartedState (dval nrepl)))
|
||||
(is (instance? datomic.peer.LocalConnection (dval conn)))
|
||||
(is (= (dval web-server) :w-resumed))
|
||||
(mount/stop)))
|
||||
|
||||
(testing "should start all the states, except the ones that are currently suspended, should resume them instead"
|
||||
(let [_ (mount/start)
|
||||
_ (mount/suspend)
|
||||
_ (mount/start)]
|
||||
(is (map? (dval config)))
|
||||
(is (instance? clojure.tools.nrepl.server.Server (dval nrepl)))
|
||||
(is (instance? datomic.peer.LocalConnection (dval conn)))
|
||||
(is (= (dval web-server) :w-resumed))
|
||||
(mount/stop)))
|
||||
|
||||
(testing "should stop all: started and suspended"
|
||||
(let [_ (mount/start)
|
||||
_ (mount/suspend)
|
||||
_ (mount/stop)]
|
||||
(is (instance? mount.core.NotStartedState (dval config)))
|
||||
(is (instance? mount.core.NotStartedState (dval nrepl)))
|
||||
(is (instance? mount.core.NotStartedState (dval conn)))
|
||||
(is (instance? mount.core.NotStartedState (dval web-server)))))))
|
||||
|
||||
|
||||
#?(:clj
|
||||
(deftest suspendable-start-with-states
|
||||
|
||||
(testing "when replacing a non suspendable state with a suspendable one,
|
||||
the later should be able to suspend/resume,
|
||||
the original should not be suspendable after resume and preserve its lifecycle fns after rollback/stop"
|
||||
(let [_ (mount/start-with-states {#'tapp.example/nrepl #'mount.test.suspend-resume/web-server})
|
||||
_ (mount/suspend)]
|
||||
(is (= (dval nrepl) :w-suspended))
|
||||
(is (instance? mount.core.NotStartedState (dval web-server)))
|
||||
(mount/stop)
|
||||
(mount/start)
|
||||
(mount/suspend)
|
||||
(is (instance? clojure.tools.nrepl.server.Server (dval nrepl)))
|
||||
(is (= (dval web-server) :w-suspended))
|
||||
(mount/stop)))
|
||||
|
||||
;; this is a messy use case, but can still happen especially at REPL time
|
||||
;; it also messy, because usually :stop function refers the _original_ state by name (i.e. #(disconnect conn))
|
||||
;; (unchanged/not substituted in its lexical scope), and original state won't be started
|
||||
(testing "when replacing a suspendable state with a non suspendable one,
|
||||
the later should not be suspendable,
|
||||
the original should still be suspendable and preserve its lifecycle fns after the rollback/stop"
|
||||
(let [_ (mount/start-with-states {#'mount.test.suspend-resume/web-server #'mount.test.suspend-resume/randomizer})
|
||||
_ (mount/suspend)]
|
||||
(is (integer? (dval web-server)))
|
||||
(is (instance? mount.core.NotStartedState (dval randomizer)))
|
||||
(mount/stop)
|
||||
(mount/start)
|
||||
(mount/suspend)
|
||||
(is (integer? (dval randomizer)))
|
||||
(is (= (dval web-server) :w-suspended))
|
||||
(mount/stop)))
|
||||
|
||||
;; this is a messy use case, but can still happen especially at REPL time
|
||||
(testing "when replacing a suspended state with a non suspendable started one,
|
||||
the later should not be suspendable,
|
||||
the original should still be suspended and preserve its lifecycle fns after the rollback/stop"
|
||||
(let [_ (mount/start)
|
||||
_ (mount/suspend)
|
||||
_ (mount/start-with-states {#'mount.test.suspend-resume/web-server #'tapp.nyse/conn}) ;; TODO: good to WARN on started states during "start-with-states"
|
||||
_ (mount/suspend)]
|
||||
(is (instance? datomic.peer.LocalConnection (dval conn)))
|
||||
(is (= (dval web-server) :w-suspended)) ;; since the "conn" does not have a resume method, so web-server was not started
|
||||
(mount/stop)
|
||||
(mount/start)
|
||||
(mount/suspend)
|
||||
(is (instance? datomic.peer.LocalConnection (dval conn)))
|
||||
(is (= (dval web-server) :w-suspended))
|
||||
(mount/stop)))
|
||||
|
||||
;; this is a messy use case, but can still happen especially at REPL time
|
||||
(testing "when replacing a suspended state with a suspendable one,
|
||||
the later should be suspendable,
|
||||
the original should still be suspended and preserve its lifecycle fns after the rollback/stop"
|
||||
(let [_ (mount/start)
|
||||
_ (mount/suspend)
|
||||
_ (mount/start-with-states {#'mount.test.suspend-resume/web-server
|
||||
#'mount.test.suspend-resume/q-listener})] ;; TODO: good to WARN on started states during "start-with-states"
|
||||
(is (= (dval q-listener) :q-suspended))
|
||||
(is (= (dval web-server) :q-resumed))
|
||||
(mount/suspend)
|
||||
(is (= (dval q-listener) :q-suspended))
|
||||
(is (= (dval web-server) :q-suspended))
|
||||
(mount/stop)
|
||||
(is (instance? mount.core.NotStartedState (dval web-server)))
|
||||
(is (instance? mount.core.NotStartedState (dval q-listener)))
|
||||
(mount/start)
|
||||
(mount/suspend)
|
||||
(is (= (dval q-listener) :q-suspended))
|
||||
(is (= (dval web-server) :w-suspended))
|
||||
(mount/stop)))))
|
||||
Loading…
Reference in a new issue