diff --git a/.travis.yml b/.travis.yml index 6fc77f6..e15462c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,6 @@ script: - sudo apt install dbus-user-session curl ffmpeg - systemctl --user start dbus - export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus - - lein cloverage --coveralls + - lein coverage --coveralls - curl -F "json_file=@target/coverage/coveralls.json" "https://coveralls.io/api/v1/jobs" - lein uberjar diff --git a/project.clj b/project.clj index d1b066b..3b03488 100644 --- a/project.clj +++ b/project.clj @@ -14,7 +14,8 @@ [com.taoensso/encore "2.122.0"] [com.outpace/config "0.13.2"]] :main ^:skip-aot stream.core - :aliases {"config" ["run" "-m" "outpace.config.generate"]} + :aliases {"config" ["run" "-m" "outpace.config.generate"] + "coverage" ["with-profile" "test" "cloverage"]} :profiles {:test {:jvm-opts ["-Dconfig.edn=resources/test/config.edn"]} :prod {:jvm-opts ["-Dconfig.edn=config.edn"]} :uberjar {:aot :all}} diff --git a/resources/test/config.edn b/resources/test/config.edn new file mode 100644 index 0000000..3c91fce --- /dev/null +++ b/resources/test/config.edn @@ -0,0 +1,3 @@ +{ + stream.commander.api/processdb-directory "./resources/test/processes" +} diff --git a/src/stream/commander/api.clj b/src/stream/commander/api.clj index 9969459..d778699 100644 --- a/src/stream/commander/api.clj +++ b/src/stream/commander/api.clj @@ -28,6 +28,16 @@ (defrecord process [id process-name unit-name monitor supervisor ffmpeg-config problems]) +(defn process= + "Tests `proc-1` and `proc-2` for equality." + [proc-1 proc-2] + (loop [[key & keys] [:id :process-name :config]] + (if key + (if (= (get proc-1 key) (get proc-2 key)) + (recur keys) + false) + true))) + (def ^:private processes (ref {})) (def ^:private dbus-monitor (chan)) (def ^:private master-monitor (chan)) @@ -272,7 +282,7 @@ "Deletes a process from the process map, stops it and deletes the unit file. Returns `true` on success, `false` otherwise." [proc] - (debug "Removing process with ID:" (:id proc)) + (info "Removing process with ID:" (:process-name proc)) (let [{:keys [unit-name monitor]} proc [monitor close] monitor] (close! (:supervisor proc)) @@ -294,7 +304,7 @@ (if-let [proc (get-process! id)] (do (info "Replacing process with ID:" id) (delete-process! proc)) - (info "Creating process with ID:" id)) + (info "Creating process " process-name)) (let [ffmpeg-config (merge default-ffmpeg-config ffmpeg-config) unit-name (str (sanitize-process-name process-name) "-" id) @@ -307,8 +317,7 @@ process (->process id process-name unit-name monitor supervisor ffmpeg-config #{})] (dosync (commute processes assoc id process)) - (go - (save-process! process)) + (save-process! process) process)) ([process-name ffmpeg-config] (create-process! process-name ffmpeg-config (generate-process-id)))) @@ -387,9 +396,10 @@ :version 1})) (defn edn->process! - "Creates a process from its edn serialized version." - [{:keys [name config id]}] - (create-process! name config id)) + "Creates a process from its `edn` serialized version." + [edn] + (let [{:keys [name config id]} (clojure.edn/read-string edn)] + (create-process! name config id))) (defn processdb-filename "Computes the filename of the serialization file for the given process @@ -418,23 +428,18 @@ true (catch Object _ (error (:throwable &throw-context) "could not write process file") - false)))) + (throw+))))) ;; TODO: Global warnings (defn load-process! "Loads a process with the `id` from the processdb directory. - Returns `false` if the db file is not found or can't be read and + Returns `nil` if the db file is not found or can't be read and the loaded process otherwise." [id] (if-let [proc-data - (try+ - (clojure.edn/read-string - (slurp (processdb-filename id))) - (catch Object _ - (error (:throwable &throw-context) "could not read process file") - false))] + (slurp (processdb-filename id))] (edn->process! proc-data) - false)) + nil)) (defn load-processes! "Loads the serialized processes from the processdb directory by @@ -442,30 +447,17 @@ [] (reduce (fn [procs file] (if-let [id (second (re-matches #"(.*)\.edn" file))] - (if-let [proc (load-process! id)] - (conj procs proc) - ) + (try+ (conj procs (load-process! id)) + (catch Object _ + procs)) procs)) [] (.list (File. processdb-directory)))) - -(defn save-processes! - "Saves the process registry to files via [[save-process!]]" - [] - (info "saving processes") - (doseq [[_ proc] @processes] - (save-process! proc))) - (defn delete-processdb-file! "Deletes the processdb file of a process. Returns `false` if the file is not found." [id] - (try+ - (io/delete-file (processdb-filename id)) - true - (catch Object _ - (error (:throwable &throw-context) "could not delete process file") - false))) + (io/delete-file (processdb-filename id))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Init ; diff --git a/test/stream/commander_test.clj b/test/stream/commander_test.clj index 43d6df8..fd6ac72 100644 --- a/test/stream/commander_test.clj +++ b/test/stream/commander_test.clj @@ -170,26 +170,26 @@ (is (not (= :timeout (:event @(api/start-process! proc)))))) (testing "waiting for the process to start" - (let [prom (api/wait-for! - proc - :event :active :timeout 10000)] + (let [prom (api/wait-for! + proc + :event :active :timeout 10000)] (api/start-process! proc) (is (not (= :timeout @prom))))) (testing "waiting for the process to fail" - (let [prom (api/wait-for! - proc - :event :failed - :timeout 100000)] + (let [prom (api/wait-for! + proc + :event :failed + :timeout 100000)] (api/start-process! proc) (is (not (= :timeout @prom))))) (testing "waiting for the process to activate or fail" - (let [prom (api/wait-for! - proc - :matcher #(or (= (:event %1) :active) - (= (:event %1) :failed)) - :timeout 1000)] + (let [prom (api/wait-for! + proc + :matcher #(or (= (:event %1) :active) + (= (:event %1) :failed)) + :timeout 1000)] (api/start-process! proc) (is (not (= :timeout @prom))))) @@ -200,14 +200,14 @@ (a/>!! (first (:monitor proc)) "junk")) (testing "waiting for a timeout" - (let [prom (api/wait-for! + (let [prom (api/wait-for! + proc + :event :one + :timeout 100) + prom1 (api/wait-for! proc - :event :one - :timeout 100) - prom1 (api/wait-for! - proc - :matcher #(and % false) - :timeout 100)] + :matcher #(and % false) + :timeout 100)] (is (= :timeout @prom)) (is (= :timeout @prom1)))) @@ -252,4 +252,55 @@ (testing "deleting all processes" (api/delete-all-processes!) - (is (= 0 (count @@#'api/processes)))))) + (is (= 0 (count @@#'api/processes)))) + + (testing "serialize and load process" + (let [proc (api/create-process! "test" config) + id (:id proc) + saved (api/save-process! proc) + loaded (api/load-process! id) + edn (api/process->edn proc) + fromedn (api/edn->process! edn)] + (is (api/process= proc fromedn)) + (is saved) + (is (api/process= proc loaded)) + (api/delete-all-processes!))) + + (testing "saving a process twice" + (let [proc (api/create-process! "test" config)] + (api/save-process! proc) + (api/save-process! proc) + (api/delete-all-processes!))) + + (testing "loading a nonexistent process" + (try+ + (api/load-process! "nonone") + (is false) + (catch Object _ + (is true)))) + + (testing "deleting a nonexistent process" + (try+ + (api/delete-processdb-file! "nonone") + (is false) + (catch Object _ + (is true)))) + + (testing "automatic saving and loading" + (let [procs [(api/create-process! + "tester" config) + (api/create-process! + "tester2" config)]] + ;; lets put in a random broken edn file-seq + (spit (api/processdb-filename "distract") "bla") + (let [loaded (api/load-processes!)] + (is (= (count loaded) 2)) + (is (reduce (fn [same proc] + (if same + (some #(api/process= proc %) procs) + false)) true + (api/load-processes!))))) + (is (= 2 (count @@#'api/processes))) + (api/delete-all-processes!) + (clojure.java.io/delete-file (api/processdb-filename "distract")) + (is (= "" (reduce str (.list (clojure.java.io/file api/processdb-directory))))))))