Merge branch '0.1.5'
This commit is contained in:
commit
fd4d846c3f
14 changed files with 227 additions and 73 deletions
51
README.md
51
README.md
|
|
@ -22,6 +22,7 @@ _**Alan J. Perlis** from [Structure and Interpretation of Computer Programs](htt
|
|||
- [Using State](#using-state)
|
||||
- [Dependencies](#dependencies)
|
||||
- [Talking States](#talking-states)
|
||||
- [Value of Values](#value-of-values)
|
||||
- [The Importance of Being Reloadable](#the-importance-of-being-reloadable)
|
||||
- [Start and Stop Order](#start-and-stop-order)
|
||||
- [Start and Stop Parts of Application](#start-and-stop-parts-of-application)
|
||||
|
|
@ -80,15 +81,15 @@ mount is an alternative to the [component](https://github.com/stuartsierra/compo
|
|||
Creating state is easy:
|
||||
|
||||
```clojure
|
||||
(defstate conn :start (create-conn))
|
||||
(defstate conn :start create-conn)
|
||||
```
|
||||
|
||||
where `(create-conn)` is defined elsewhere, can be right above it.
|
||||
where the `create-conn` function is defined elsewhere, can be right above it.
|
||||
|
||||
In case this state needs to be cleaned / destryed between reloads, there is also `:stop`
|
||||
|
||||
```clojure
|
||||
(defstate conn :start (create-conn)
|
||||
(defstate conn :start create-conn
|
||||
:stop (disconnect conn))
|
||||
```
|
||||
|
||||
|
|
@ -153,6 +154,44 @@ this `app-config`, being top level, can be used in other namespaces, including t
|
|||
[here](https://github.com/tolitius/mount/blob/master/test/app/nyse.clj)
|
||||
is an example of a Datomic connection that "depends" on a similar `app-config`.
|
||||
|
||||
## Value of values
|
||||
|
||||
Lifecycle functions start/stop/suspend/resume 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)
|
||||
```
|
||||
|
||||
Besides scalar values, lifecycle functions can take anonymous functions, partial functions, function references, etc.. Here are some examples:
|
||||
|
||||
```clojure
|
||||
(defn f [n]
|
||||
(fn [m]
|
||||
(+ n m)))
|
||||
|
||||
(defn g [a b]
|
||||
(+ a b))
|
||||
|
||||
(defn- pf [n]
|
||||
(+ 41 n))
|
||||
|
||||
(defn fna []
|
||||
42)
|
||||
|
||||
(defstate scalar :start 42)
|
||||
(defstate fun :start #(inc 41))
|
||||
(defstate with-fun :start (inc 41))
|
||||
(defstate with-partial :start (partial g 41))
|
||||
(defstate f-in-f :start (f 41))
|
||||
(defstate f-no-args-value :start (fna))
|
||||
(defstate f-no-args :start fna)
|
||||
(defstate f-args :start g)
|
||||
(defstate f-value :start (g 41 1))
|
||||
(defstate private-f :start pf)
|
||||
```
|
||||
|
||||
Check out [fun-with-values-test](https://github.com/tolitius/mount/blob/0.1.5/test/check/fun_with_values_test.clj) for more details.
|
||||
|
||||
## The Importance of Being Reloadable
|
||||
|
||||
`mount` has start and stop functions that will walk all the states created with `defstate` and start / stop them
|
||||
|
|
@ -311,9 +350,9 @@ and some other use cases.
|
|||
In additiong 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 ...))
|
||||
(defstate web-server :start start-server
|
||||
:resume resume-server
|
||||
:stop stop-server)
|
||||
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -19,11 +19,9 @@
|
|||
|
||||
(defn start []
|
||||
(with-logging-status)
|
||||
(mount/start-without #'check.start-with-test/test-conn
|
||||
#'check.start-with-test/test-nrepl
|
||||
#'check.parts-test/should-not-start
|
||||
#'check.suspend-resume-test/web-server
|
||||
#'check.suspend-resume-test/q-listener)) ;; example on how to start app without certain states
|
||||
(mount/start #'app.config/app-config
|
||||
#'app.nyse/conn
|
||||
#'app/nrepl)) ;; example on how to start app with certain states
|
||||
|
||||
(defn stop []
|
||||
(mount/stop))
|
||||
|
|
|
|||
|
|
@ -137,8 +137,8 @@ Depending on the number of application components the "extra" size may vary.
|
|||
Mount is pretty much:
|
||||
|
||||
```clojure
|
||||
(defstate name :start (fn)
|
||||
:stop (fn))
|
||||
(defstate name :start fn
|
||||
:stop fn)
|
||||
```
|
||||
|
||||
no "ceremony".
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
# Introduction to statuo
|
||||
|
||||
TODO: write [great documentation](http://jacobian.org/writing/what-to-write/)
|
||||
|
|
@ -84,13 +84,13 @@ In order to demo all of the above, we'll build an uberjar:
|
|||
```bash
|
||||
$ lein do clean, uberjar
|
||||
...
|
||||
Created .. mount/target/mount-0.2.0-SNAPSHOT-standalone.jar
|
||||
Created .. mount/target/mount-0.1.5-SNAPSHOT-standalone.jar
|
||||
```
|
||||
|
||||
Since we have a default for a Datomic URI, it'll work with no arguments:
|
||||
|
||||
```bash
|
||||
$ java -jar target/mount-0.2.0-SNAPSHOT-standalone.jar
|
||||
$ java -jar target/mount-0.1.5-SNAPSHOT-standalone.jar
|
||||
|
||||
22:12:03.290 [main] INFO mount - >> starting.. app-config
|
||||
22:12:03.293 [main] INFO mount - >> starting.. conn
|
||||
|
|
@ -101,7 +101,7 @@ $ java -jar target/mount-0.2.0-SNAPSHOT-standalone.jar
|
|||
Now let's ask it to help us:
|
||||
|
||||
```bash
|
||||
$ java -jar target/mount-0.2.0-SNAPSHOT-standalone.jar --help
|
||||
$ java -jar target/mount-0.1.5-SNAPSHOT-standalone.jar --help
|
||||
|
||||
22:13:48.798 [main] INFO mount - >> starting.. app-config
|
||||
22:13:48.799 [main] INFO app.config -
|
||||
|
|
@ -116,7 +116,7 @@ this is a sample mount app to demo how to pass and read runtime arguments
|
|||
And finally let's connect to the Single Malt Database. It's Friday..
|
||||
|
||||
```bash
|
||||
$ java -jar target/mount-0.2.0-SNAPSHOT-standalone.jar -d datomic:mem://single-malt-database
|
||||
$ java -jar target/mount-0.1.5-SNAPSHOT-standalone.jar -d datomic:mem://single-malt-database
|
||||
|
||||
22:16:10.733 [main] INFO mount - >> starting.. app-config
|
||||
22:16:10.737 [main] INFO mount - >> starting.. conn
|
||||
|
|
|
|||
|
|
@ -38,14 +38,13 @@ where `nyse-app` is _the_ app. It has the usual routes:
|
|||
and the reloadable state:
|
||||
|
||||
```clojure
|
||||
(defn start-nyse []
|
||||
(create-nyse-schema) ;; creating schema (usually done long before the app is started..)
|
||||
(defn start-nyse [{:keys [www]}]
|
||||
(-> (routes mount-example-routes)
|
||||
(handler/site)
|
||||
(run-jetty {:join? false
|
||||
:port (get-in app-config [:www :port])})))
|
||||
:port (:port www)})))
|
||||
|
||||
(defstate nyse-app :start (start-nyse)
|
||||
(defstate nyse-app :start (start-nyse app-config)
|
||||
:stop (.stop nyse-app)) ;; it's a "org.eclipse.jetty.server.Server" at this point
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
(ns mount.core
|
||||
(:require [clojure.tools.macro :as macro]))
|
||||
|
||||
;; (defonce ^:private session-id (System/currentTimeMillis))
|
||||
(defonce ^:private mount-state 42)
|
||||
(defonce ^:private -args (atom :no-args)) ;; mostly for command line args and external files
|
||||
(defonce ^:private state-seq (atom 0))
|
||||
(defonce ^:private state-order (atom {}))
|
||||
(defonce ^:private running (atom {})) ;; to clean dirty states on redefs
|
||||
|
||||
;; supporting tools.namespace: (disable-reload!)
|
||||
(alter-meta! *ns* assoc ::load false) ;; to exclude the dependency
|
||||
|
|
@ -29,17 +29,39 @@
|
|||
(and suspend (not resume)) (throw
|
||||
(IllegalArgumentException. "suspendable state should have a resume function (i.e. missing :resume fn)"))))
|
||||
|
||||
(defn- with-ns [ns name]
|
||||
(str ns "/" name))
|
||||
|
||||
(defn- pounded? [f]
|
||||
(let [pound "(fn* [] "] ;;TODO: think of a better (i.e. typed) way to distinguish #(f params) from (fn [params] (...)))
|
||||
(.startsWith (str f) pound)))
|
||||
|
||||
(defn- unpound [f]
|
||||
(if (pounded? f)
|
||||
(nth f 2) ;; magic 2 is to get the body => ["fn*" "[]" "(fn body)"]
|
||||
f))
|
||||
|
||||
(defn- cleanup-if-dirty
|
||||
"in case a namespace is recompiled without calling (mount/stop),
|
||||
a running state instance will still be running.
|
||||
this function stops this 'lost' state instance.
|
||||
it is meant to be called by defstate before defining a new state"
|
||||
[state]
|
||||
(when-let [stop (@running state)]
|
||||
(stop)))
|
||||
|
||||
(defmacro defstate [state & body]
|
||||
(let [[state params] (macro/name-with-attributes state body)
|
||||
{:keys [start stop suspend resume] :as lifecycle} (apply hash-map params)]
|
||||
(validate lifecycle)
|
||||
(cleanup-if-dirty (with-ns *ns* state))
|
||||
(let [s-meta (cond-> {:mount-state mount-state
|
||||
:order (make-state-seq state)
|
||||
:start `(fn [] (~@start))
|
||||
:started? false}
|
||||
stop (assoc :stop `(fn [] (~@stop)))
|
||||
suspend (assoc :suspend `(fn [] (~@suspend)))
|
||||
resume (assoc :resume `(fn [] (~@resume))))]
|
||||
:order (make-state-seq (with-ns *ns* state))
|
||||
:start `(fn [] ~start)
|
||||
:status #{:stopped}}
|
||||
stop (assoc :stop `(fn [] ~(unpound stop)))
|
||||
suspend (assoc :suspend `(fn [] ~suspend))
|
||||
resume (assoc :resume `(fn [] ~resume)))]
|
||||
`(defonce ~(with-meta state (merge (meta state) s-meta))
|
||||
(NotStartedState. ~(str state))))))
|
||||
|
||||
|
|
@ -48,44 +70,46 @@
|
|||
(swap! done conj (ns-resolve ns name))
|
||||
state))
|
||||
|
||||
(defn- up [var {:keys [ns name start started? resume suspended?] :as state} done]
|
||||
(when-not started?
|
||||
(let [s (try (if suspended?
|
||||
(defn- up [var {:keys [ns name start stop resume status] :as state} done]
|
||||
(when-not (:started status)
|
||||
(let [s (try (if (:suspended status)
|
||||
(record! state resume done)
|
||||
(record! state start done))
|
||||
(catch Throwable t
|
||||
(throw (RuntimeException. (str "could not start [" name "] due to") t))))]
|
||||
(intern ns (symbol name) s)
|
||||
(alter-meta! var assoc :started? true :suspended? false))))
|
||||
(swap! running assoc (with-ns ns name) stop)
|
||||
(alter-meta! var assoc :status #{:started}))))
|
||||
|
||||
(defn- down [var {:keys [ns name stop started? suspended?] :as state} done]
|
||||
(when (or started? suspended?)
|
||||
(defn- down [var {:keys [ns name stop status] :as state} done]
|
||||
(when (some status #{:started :suspended})
|
||||
(when stop
|
||||
(try
|
||||
(record! state stop done)
|
||||
(catch Throwable t
|
||||
(throw (RuntimeException. (str "could not stop [" name "] due to") t)))))
|
||||
(intern ns (symbol name) (NotStartedState. name)) ;; (!) if a state does not have :stop when _should_ this might leak
|
||||
(alter-meta! var assoc :started? false :suspended? false)))
|
||||
(swap! running dissoc (with-ns ns name))
|
||||
(alter-meta! var assoc :status #{:stopped})))
|
||||
|
||||
(defn- sigstop [var {:keys [ns name started? suspend resume] :as state} done]
|
||||
(when (and started? resume) ;; can't have suspend without resume, but the reverse is possible
|
||||
(defn- sigstop [var {:keys [ns name suspend resume status] :as state} 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 (try (record! state suspend done)
|
||||
(catch Throwable t
|
||||
(throw (RuntimeException. (str "could not suspend [" name "] due to") t))))]
|
||||
(intern ns (symbol name) s)))
|
||||
(alter-meta! var assoc :started? false :suspended? true)))
|
||||
(alter-meta! var assoc :status #{:suspended})))
|
||||
|
||||
(defn- sigcont [var {:keys [ns name start started? resume suspended?] :as state} done]
|
||||
(defn- sigcont [var {:keys [ns name start resume status] :as state} done]
|
||||
(when (instance? NotStartedState var)
|
||||
(throw (RuntimeException. (str "could not resume [" name "] since it is stoppped (i.e. not suspended)"))))
|
||||
(when suspended?
|
||||
(when (:suspended status)
|
||||
(let [s (try (record! state resume done)
|
||||
(catch Throwable t
|
||||
(throw (RuntimeException. (str "could not resume [" name "] due to") t))))]
|
||||
(intern ns (symbol name) s)
|
||||
(alter-meta! var assoc :started? true :suspended? false))))
|
||||
(alter-meta! var assoc :status #{:started}))))
|
||||
|
||||
;;TODO args might need more thinking
|
||||
(defn args [] @-args)
|
||||
|
|
@ -110,7 +134,7 @@
|
|||
(defn states-with-deps []
|
||||
(let [all (find-all-states)]
|
||||
(->> (map (comp #(add-deps % all)
|
||||
#(select-keys % [:name :order :ns :started? :suspended?])
|
||||
#(select-keys % [:name :order :ns :status])
|
||||
meta)
|
||||
all)
|
||||
(sort-by :order))))
|
||||
|
|
@ -129,9 +153,9 @@
|
|||
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 suspended?]}]
|
||||
([state origin {:keys [start stop suspend resume status]}]
|
||||
(assoc state :origin origin
|
||||
:suspended? suspended?
|
||||
:status status
|
||||
:start start :stop stop :suspend suspend :resume resume)))
|
||||
|
||||
(defn- rollback! [state]
|
||||
|
|
@ -140,7 +164,7 @@
|
|||
(alter-meta! state #(merge-lifecycles % origin)))))
|
||||
|
||||
(defn- substitute! [state with]
|
||||
(let [lifecycle-fns #(select-keys % [:start :stop :suspend :resume :suspended?])
|
||||
(let [lifecycle-fns #(select-keys % [:start :stop :suspend :resume :status])
|
||||
origin (meta state)
|
||||
sub (meta with)]
|
||||
(alter-meta! with assoc :sub? true)
|
||||
|
|
@ -148,8 +172,7 @@
|
|||
|
||||
(defn- unsub [state]
|
||||
(when (-> (meta state) :sub?)
|
||||
(alter-meta! state assoc :sub? nil
|
||||
:started false)))
|
||||
(alter-meta! state dissoc :sub?)))
|
||||
|
||||
(defn- all-without-subs []
|
||||
(remove (comp :sub? meta) (find-all-states)))
|
||||
|
|
@ -167,11 +190,8 @@
|
|||
|
||||
(defn stop-except [& states]
|
||||
(let [all (set (find-all-states))
|
||||
states (remove (set states) all)
|
||||
_ (dorun (map unsub states)) ;; unmark substitutions marked by "start-with"
|
||||
stopped (bring states down >)]
|
||||
(dorun (map rollback! states)) ;; restore to origin from "start-with"
|
||||
{:stopped stopped}))
|
||||
states (remove (set states) all)]
|
||||
(apply stop states)))
|
||||
|
||||
(defn start-with-args [xs & states]
|
||||
(reset! -args xs)
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@
|
|||
"mount.core$sigcont" :resume
|
||||
:noop)))
|
||||
|
||||
(defn whatcha-doing? [{:keys [started? suspended? suspend]} action]
|
||||
(defn whatcha-doing? [{:keys [status suspend]} action]
|
||||
(case action
|
||||
:up (if suspended? ">> resuming"
|
||||
(if-not started? ">> starting"))
|
||||
:down (if (or started? suspended?) "<< stopping")
|
||||
:suspend (if (and started? suspend) "<< suspending")
|
||||
:resume (if suspended? ">> resuming")))
|
||||
:up (if (status :suspended) ">> resuming"
|
||||
(if-not (status :started) ">> starting"))
|
||||
:down (if (or (status :started) (status :suspended)) "<< stopping")
|
||||
:suspend (if (and (status :started) suspend) "<< suspending")
|
||||
:resume (if (status :suspended) ">> resuming")))
|
||||
|
||||
(defn log-status [f & args]
|
||||
(let [{:keys [ns name] :as state} (second args)
|
||||
|
|
|
|||
13
test/check/cleanup_dirty_states_test.clj
Normal file
13
test/check/cleanup_dirty_states_test.clj
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
(ns check.cleanup_dirty_states_test
|
||||
(:require [mount.core :as mount]
|
||||
[app]
|
||||
[clojure.test :refer :all]))
|
||||
|
||||
(deftest cleanup-dirty-states
|
||||
(let [_ (mount/start)]
|
||||
(is (not (.isClosed (:server-socket app/nrepl))))
|
||||
(require 'app :reload)
|
||||
(mount/start) ;; should not result in "BindException Address already in use" since the clean up will stop the previous instance
|
||||
(is (not (.isClosed (:server-socket app/nrepl))))
|
||||
(mount/stop)
|
||||
(is (instance? mount.core.NotStartedState app/nrepl))))
|
||||
55
test/check/fun_with_values_test.clj
Normal file
55
test/check/fun_with_values_test.clj
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
(ns check.fun-with-values-test
|
||||
(:require [mount.core :as mount :refer [defstate]]
|
||||
[clojure.test :refer :all]))
|
||||
|
||||
(defn f [n]
|
||||
(fn [m]
|
||||
(+ n m)))
|
||||
|
||||
(defn g [a b]
|
||||
(+ a b))
|
||||
|
||||
(defn- pf [n]
|
||||
(+ 41 n))
|
||||
|
||||
(defn fna []
|
||||
42)
|
||||
|
||||
(defstate scalar :start 42)
|
||||
(defstate fun :start #(inc 41))
|
||||
(defstate with-fun :start (inc 41))
|
||||
(defstate with-partial :start (partial g 41))
|
||||
(defstate f-in-f :start (f 41))
|
||||
(defstate f-no-args-value :start (fna))
|
||||
(defstate f-no-args :start fna)
|
||||
(defstate f-args :start g)
|
||||
(defstate f-value :start (g 41 1))
|
||||
(defstate private-f :start pf)
|
||||
|
||||
(defn with-fun-and-values [f]
|
||||
(mount/start #'check.fun-with-values-test/scalar
|
||||
#'check.fun-with-values-test/fun
|
||||
#'check.fun-with-values-test/with-fun
|
||||
#'check.fun-with-values-test/with-partial
|
||||
#'check.fun-with-values-test/f-in-f
|
||||
#'check.fun-with-values-test/f-args
|
||||
#'check.fun-with-values-test/f-no-args-value
|
||||
#'check.fun-with-values-test/f-no-args
|
||||
#'check.fun-with-values-test/private-f
|
||||
#'check.fun-with-values-test/f-value)
|
||||
(f)
|
||||
(mount/stop))
|
||||
|
||||
(use-fixtures :each with-fun-and-values)
|
||||
|
||||
(deftest fun-with-values
|
||||
(is (= scalar 42))
|
||||
(is (= (fun) 42))
|
||||
(is (= with-fun 42))
|
||||
(is (= (with-partial 1) 42))
|
||||
(is (= (f-in-f 1) 42))
|
||||
(is (= f-no-args-value 42))
|
||||
(is (= (f-no-args) 42))
|
||||
(is (= (f-args 41 1) 42))
|
||||
(is (= (private-f 1) 42))
|
||||
(is (= f-value 42)))
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
[app.nyse :refer [conn]]
|
||||
[clojure.test :refer :all]))
|
||||
|
||||
(defstate should-not-start :start (constantly 42))
|
||||
(defstate should-not-start :start #(constantly 42))
|
||||
|
||||
(defn with-parts [f]
|
||||
(m/start #'app.config/app-config #'app.nyse/conn)
|
||||
|
|
|
|||
14
test/check/private_fun_test.clj
Normal file
14
test/check/private_fun_test.clj
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
(ns check.private-fun-test
|
||||
(:require [mount.core :as mount :refer [defstate]]
|
||||
[check.fun-with-values-test :refer [private-f]]
|
||||
[clojure.test :refer :all]))
|
||||
|
||||
(defn with-fun-and-values [f]
|
||||
(mount/start #'check.fun-with-values-test/private-f)
|
||||
(f)
|
||||
(mount/stop))
|
||||
|
||||
(use-fixtures :each with-fun-and-values)
|
||||
|
||||
(deftest fun-with-valuesj
|
||||
(is (= (private-f 1) 42)))
|
||||
|
|
@ -5,10 +5,10 @@
|
|||
[app :refer [nrepl]]
|
||||
[clojure.test :refer :all]))
|
||||
|
||||
(defstate test-conn :start (long 42)
|
||||
:stop (constantly 0))
|
||||
(defstate test-conn :start 42
|
||||
:stop #(constantly 0))
|
||||
|
||||
(defstate test-nrepl :start (vector))
|
||||
(defstate test-nrepl :start [])
|
||||
|
||||
(deftest start-with
|
||||
|
||||
|
|
@ -44,3 +44,4 @@
|
|||
(is (instance? mount.core.NotStartedState test-conn))
|
||||
(is (instance? mount.core.NotStartedState test-nrepl))
|
||||
(mount/stop))))
|
||||
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@
|
|||
:suspend (suspend :q)
|
||||
:resume (resume :q))
|
||||
|
||||
(deftest suspendable
|
||||
(defstate randomizer :start (rand-int 42))
|
||||
|
||||
;; lifecycle
|
||||
(deftest suspendable-lifecycle
|
||||
|
||||
(testing "should suspend _only suspendable_ states that are currently started"
|
||||
(let [_ (mount/start)
|
||||
|
|
@ -66,9 +66,10 @@
|
|||
(is (instance? mount.core.NotStartedState app-config))
|
||||
(is (instance? mount.core.NotStartedState nrepl))
|
||||
(is (instance? mount.core.NotStartedState conn))
|
||||
(is (instance? mount.core.NotStartedState web-server))))
|
||||
(is (instance? mount.core.NotStartedState web-server)))))
|
||||
|
||||
;; start-with
|
||||
|
||||
(deftest suspendable-start-with
|
||||
|
||||
(testing "when replacing a non suspendable state with a suspendable one,
|
||||
the later should be able to suspend/resume,
|
||||
|
|
@ -85,7 +86,24 @@
|
|||
(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 one,
|
||||
;; 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 {#'check.suspend-resume-test/web-server #'check.suspend-resume-test/randomizer})
|
||||
_ (mount/suspend)]
|
||||
(is (integer? web-server))
|
||||
(is (instance? mount.core.NotStartedState randomizer))
|
||||
(mount/stop)
|
||||
(mount/start)
|
||||
(mount/suspend)
|
||||
(is (integer? randomizer))
|
||||
(is (= 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)
|
||||
|
|
@ -93,7 +111,7 @@
|
|||
_ (mount/start-with {#'check.suspend-resume-test/web-server #'app.nyse/conn}) ;; TODO: good to WARN on started states during "start-with"
|
||||
_ (mount/suspend)]
|
||||
(is (instance? datomic.peer.LocalConnection conn))
|
||||
(is (instance? datomic.peer.LocalConnection web-server))
|
||||
(is (= 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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue