From 9f0b1ad037d6a4cf5629a6213a1d53a3bc2c7fc6 Mon Sep 17 00:00:00 2001 From: Tarun Date: Fri, 8 Dec 2023 17:59:33 +0530 Subject: [PATCH 1/6] Read join to main thread option from config --- .../src/swift_ticketing/components/http_server.clj | 9 +++++---- swift-ticketing/src/swift_ticketing/core.clj | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/swift-ticketing/src/swift_ticketing/components/http_server.clj b/swift-ticketing/src/swift_ticketing/components/http_server.clj index 23cbe7e..4beef04 100644 --- a/swift-ticketing/src/swift_ticketing/components/http_server.clj +++ b/swift-ticketing/src/swift_ticketing/components/http_server.clj @@ -3,7 +3,7 @@ [ring.adapter.jetty :refer [run-jetty]] [swift-ticketing.app :as app])) -(defrecord HTTPServer [port database] +(defrecord HTTPServer [port join? database] component/Lifecycle (start [component] @@ -12,7 +12,7 @@ server (run-jetty (app/swift-ticketing-app connection) {:port port - :join? true})] + :join? join?})] (assoc component :http-server server))) (stop [component] @@ -20,5 +20,6 @@ (.stop (:http-server component)) (assoc component :http-server nil))) -(defn new-http-server [port] - (map->HTTPServer {:port port})) +(defn new-http-server [port join?] + (map->HTTPServer {:port port + :join? join?})) diff --git a/swift-ticketing/src/swift_ticketing/core.clj b/swift-ticketing/src/swift_ticketing/core.clj index 558c015..2e77073 100644 --- a/swift-ticketing/src/swift_ticketing/core.clj +++ b/swift-ticketing/src/swift_ticketing/core.clj @@ -18,7 +18,8 @@ (component/system-map :database (new-database (:database config)) :app (component/using - (new-http-server (get-in config [:server :port])) + (new-http-server (get-in config [:server :port]) + (get-in config [:server :join?])) [:database]) :worker (component/using (new-worker 5 redis-opts) From 3121d8c5a7b7815e2514436a272dfb0666e516dc Mon Sep 17 00:00:00 2001 From: Tarun Date: Fri, 8 Dec 2023 18:22:57 +0530 Subject: [PATCH 2/6] Add fixture to truncate tables before each test --- swift-ticketing/test/swift_ticketing/fixtures.clj | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/swift-ticketing/test/swift_ticketing/fixtures.clj b/swift-ticketing/test/swift_ticketing/fixtures.clj index c01d479..241f1a0 100644 --- a/swift-ticketing/test/swift_ticketing/fixtures.clj +++ b/swift-ticketing/test/swift_ticketing/fixtures.clj @@ -18,3 +18,13 @@ (alter-var-root #'test-env #(assoc % :test-user-id test-user-id))) (tests) (migrations/rollback-with db-config))) + +(defn truncate-tables [db-spec] + (let [tables [:ticket :ticket_type :booking :event] + truncate-fn #(sql/format {:truncate [% [:raw "cascade"]]})] + (doseq [table tables] + (jdbc/execute! db-spec (truncate-fn table))))) + +(defn clear-tables [tests] + (truncate-tables (:db-spec test-env)) + (tests)) From f870a7ceec1c31e6e701e1300bff6c5563fa6dc3 Mon Sep 17 00:00:00 2001 From: Tarun Date: Fri, 8 Dec 2023 18:25:28 +0530 Subject: [PATCH 3/6] Setup test system using components --- .../test/swift_ticketing/fixtures.clj | 45 ++++++++++++++----- .../test/swift_ticketing/handlers_test.clj | 4 +- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/swift-ticketing/test/swift_ticketing/fixtures.clj b/swift-ticketing/test/swift_ticketing/fixtures.clj index 241f1a0..9aa0d5e 100644 --- a/swift-ticketing/test/swift_ticketing/fixtures.clj +++ b/swift-ticketing/test/swift_ticketing/fixtures.clj @@ -1,23 +1,46 @@ (ns swift-ticketing.fixtures (:require - [next.jdbc :as jdbc] - [honey.sql :as sql] - [swift-ticketing.core :refer [create-connection-pool]] + [com.stuartsierra.component :as component] + [swift-ticketing.core :refer [swift-ticketing-system]] [swift-ticketing.factory :as factory] [swift-ticketing.config :refer [read-test-config]] - [swift-ticketing.migrations :as migrations])) + [swift-ticketing.migrations :as migrations] + [next.jdbc :as jdbc] + [honey.sql :as sql])) (def test-env - (let [db-config (:database (read-test-config))] - {:db-spec (create-connection-pool db-config)})) + {:test-user-id nil + :db-spec nil}) + +(def swift-ticketing-test-system + (swift-ticketing-system (read-test-config))) + +(defn start-test-system [] + (alter-var-root #'swift-ticketing-test-system component/start)) + +(defn stop-test-system [] + (alter-var-root #'swift-ticketing-test-system component/stop)) -(defn run-migrations [tests] - (let [db-config (:database (read-test-config))] +(defn setup-test-system [tests] + ;; Init db connection pool, start workers + (start-test-system) + (let [db (:database swift-ticketing-test-system) + db-config (:db-config db) + conn (:connection db)] + ;; setup tables (migrations/migrate-with db-config) - (let [test-user-id (factory/add-user-table-entry (:db-spec test-env))] - (alter-var-root #'test-env #(assoc % :test-user-id test-user-id))) + (let [test-user-id (factory/add-user-table-entry conn)] + ;; add a user, update it in test env + (alter-var-root + #'test-env #(assoc % + :test-user-id test-user-id + :db-spec conn))) + ;; run tests (tests) - (migrations/rollback-with db-config))) + ;; rollback db + (migrations/rollback-with db-config) + ;; stop db connections, workers + (stop-test-system))) (defn truncate-tables [db-spec] (let [tables [:ticket :ticket_type :booking :event] diff --git a/swift-ticketing/test/swift_ticketing/handlers_test.clj b/swift-ticketing/test/swift_ticketing/handlers_test.clj index c3f9c17..1a4ccd4 100644 --- a/swift-ticketing/test/swift_ticketing/handlers_test.clj +++ b/swift-ticketing/test/swift_ticketing/handlers_test.clj @@ -15,7 +15,8 @@ [swift-ticketing.client :as client] [swift-ticketing.specs :as specs])) -(use-fixtures :each fixtures/run-migrations) +(use-fixtures :once fixtures/setup-test-system) +(use-fixtures :each fixtures/clear-tables) (deftest create-event-test (let [{:keys [db-spec]} fixtures/test-env] @@ -116,6 +117,7 @@ (defn create-ticket-test* [event-id ticket-request-fn] (testing "with valid request" (let [{:keys [request response status]} (client/create-tickets event-id (ticket-request-fn)) + {:keys [db-spec test-user-id]} fixtures/test-env ticket-type-id (get response "ticket-type-id") created-tickets (jdbc/execute! db-spec (ticket/get-unbooked-tickets ticket-type-id) {:builder-fn rs/as-unqualified-maps}) tickets (get response "tickets") From 23612a60d81039bba9230266c9733fbfe639b010 Mon Sep 17 00:00:00 2001 From: Tarun Date: Mon, 11 Dec 2023 15:04:12 +0530 Subject: [PATCH 4/6] Update ticket states diagram --- swift-ticketing/diagrams/ticket-states.png | Bin 19627 -> 23017 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/swift-ticketing/diagrams/ticket-states.png b/swift-ticketing/diagrams/ticket-states.png index 8fc69aaa0b2d514f6614353408a461d64769b615..5ebb23686f2bc841c51c37ec68f3cec44fcc9890 100644 GIT binary patch literal 23017 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 literal 19627 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�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 Date: Tue, 19 Dec 2023 15:35:18 +0530 Subject: [PATCH 5/6] Add kaocha test runner --- swift-ticketing/project.clj | 6 ++-- .../test/swift_ticketing/fixtures.clj | 29 ++++++++++++++++++- .../test/swift_ticketing/handlers_test.clj | 11 ++----- swift-ticketing/tests.edn | 6 ++++ 4 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 swift-ticketing/tests.edn diff --git a/swift-ticketing/project.clj b/swift-ticketing/project.clj index 174543a..da223ad 100644 --- a/swift-ticketing/project.clj +++ b/swift-ticketing/project.clj @@ -27,6 +27,8 @@ :plugins [[lein-ring "0.12.6"]] :ring {:handler swift-ticketing.app/swift-ticketing-app} :aliases {"migrate" ["run" "-m" "swift-ticketing.migrations/migrate"] - "rollback" ["run" "-m" "swift-ticketing.migrations/rollback"]} + "rollback" ["run" "-m" "swift-ticketing.migrations/rollback"] + "kaocha" ["run" "-m" "kaocha.runner"]} :profiles {:uberjar {:aot :all - :jvm-opts ["-Dclojure.compiler.direct-linking=true"]}}) + :jvm-opts ["-Dclojure.compiler.direct-linking=true"]} + :dev {:dependencies [[lambdaisland/kaocha "1.87.1366"]]}}) diff --git a/swift-ticketing/test/swift_ticketing/fixtures.clj b/swift-ticketing/test/swift_ticketing/fixtures.clj index 9aa0d5e..f0ff6fe 100644 --- a/swift-ticketing/test/swift_ticketing/fixtures.clj +++ b/swift-ticketing/test/swift_ticketing/fixtures.clj @@ -21,9 +21,11 @@ (defn stop-test-system [] (alter-var-root #'swift-ticketing-test-system component/stop)) -(defn setup-test-system [tests] +(defn run-with-test-system [tests] ;; Init db connection pool, start workers + (println "start-test-system") (start-test-system) + (println "after start-test-system") (let [db (:database swift-ticketing-test-system) db-config (:db-config db) conn (:connection db)] @@ -42,6 +44,31 @@ ;; stop db connections, workers (stop-test-system))) +(defn setup-test-system [test-plan] + ;; Init db connection pool, start workers + (start-test-system) + (let [db (:database swift-ticketing-test-system) + db-config (:db-config db) + conn (:connection db)] + ;; setup tables + (migrations/migrate-with db-config) + (let [test-user-id (factory/add-user-table-entry conn)] + ;; add a user, update it in test env + (alter-var-root + #'test-env #(assoc % + :test-user-id test-user-id + :db-spec conn)))) + test-plan) + +(defn teardown-test-system [test-plan] + (let [db (:database swift-ticketing-test-system) + db-config (:db-config db)] + ;; rollback db + (migrations/rollback-with db-config) + ;; stop db connections, workers + (stop-test-system)) + test-plan) + (defn truncate-tables [db-spec] (let [tables [:ticket :ticket_type :booking :event] truncate-fn #(sql/format {:truncate [% [:raw "cascade"]]})] diff --git a/swift-ticketing/test/swift_ticketing/handlers_test.clj b/swift-ticketing/test/swift_ticketing/handlers_test.clj index 1a4ccd4..94d2e3b 100644 --- a/swift-ticketing/test/swift_ticketing/handlers_test.clj +++ b/swift-ticketing/test/swift_ticketing/handlers_test.clj @@ -4,8 +4,7 @@ [next.jdbc :as jdbc] [clojure.data.json :as json] [next.jdbc.result-set :as rs] - [clojure.set :as s] - [clojure.walk :refer [keywordize-keys stringify-keys]] + [clojure.walk :refer [keywordize-keys]] [swift-ticketing.app :refer [swift-ticketing-app]] [swift-ticketing.fixtures :as fixtures] [swift-ticketing.factory :as factory] @@ -13,9 +12,8 @@ [swift-ticketing.db.event :as db-event] [swift-ticketing.db.ticket :as ticket] [swift-ticketing.client :as client] - [swift-ticketing.specs :as specs])) + )) -(use-fixtures :once fixtures/setup-test-system) (use-fixtures :each fixtures/clear-tables) (deftest create-event-test @@ -152,8 +150,3 @@ (create-ticket-test* event-id factory/general-ticket-request)) (testing "Creating ticket (Seated)" (create-ticket-test* event-id factory/seated-ticket-request)))) - -; (run-tests) -(run-test create-event-test) -(run-test list-events-test) -(run-test get-event-test) diff --git a/swift-ticketing/tests.edn b/swift-ticketing/tests.edn new file mode 100644 index 0000000..0725246 --- /dev/null +++ b/swift-ticketing/tests.edn @@ -0,0 +1,6 @@ +#kaocha/v1 + {:fail-fast? false + :plugins [:hooks] + :kaocha.hooks/pre-run [swift-ticketing.fixtures/setup-test-system] + :kaocha.hooks/post-run [swift-ticketing.fixtures/teardown-test-system] + } From 51a5af6091a5c9ba12183b1e21a6ea944db0fe30 Mon Sep 17 00:00:00 2001 From: Tarun Date: Thu, 21 Dec 2023 15:47:50 +0530 Subject: [PATCH 6/6] Fix formatting --- swift-ticketing/test/swift_ticketing/handlers_test.clj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/swift-ticketing/test/swift_ticketing/handlers_test.clj b/swift-ticketing/test/swift_ticketing/handlers_test.clj index 94d2e3b..7827f5c 100644 --- a/swift-ticketing/test/swift_ticketing/handlers_test.clj +++ b/swift-ticketing/test/swift_ticketing/handlers_test.clj @@ -11,8 +11,7 @@ [swift-ticketing.utils :as utils] [swift-ticketing.db.event :as db-event] [swift-ticketing.db.ticket :as ticket] - [swift-ticketing.client :as client] - )) + [swift-ticketing.client :as client])) (use-fixtures :each fixtures/clear-tables)