From 77e2537fcca72d2e4e525fd48da5e27b4c25f147 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Wed, 11 Oct 2023 16:50:37 -0400 Subject: [PATCH 01/12] Expand success statuses to all 2xx statuses --- src/main/com/yetanalytics/datasim/client.clj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/com/yetanalytics/datasim/client.clj b/src/main/com/yetanalytics/datasim/client.clj index fd5d6d00..7a1402e0 100644 --- a/src/main/com/yetanalytics/datasim/client.clj +++ b/src/main/com/yetanalytics/datasim/client.clj @@ -62,9 +62,8 @@ (if-let [batch (first batches)] (let [{:keys [status body] :as response} @(post-batch endpoint http-options batch)] - (if (= 200 status) + (if (<= 200 status 299) ;; Success! - ;; FIXME: Shouldn't other codes like 204 be supported? (let [statement-ids (decode-body body)] (when print-ids? (dio/println-coll statement-ids)) From a529500ab75afd0a93e24caeeb1fd4ceb377886d Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Wed, 11 Oct 2023 17:49:43 -0400 Subject: [PATCH 02/12] Expand valid statuses for async post --- src/main/com/yetanalytics/datasim/client.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/com/yetanalytics/datasim/client.clj b/src/main/com/yetanalytics/datasim/client.clj index 7a1402e0..acb05368 100644 --- a/src/main/com/yetanalytics/datasim/client.clj +++ b/src/main/com/yetanalytics/datasim/client.clj @@ -103,7 +103,8 @@ in-chan (a/chan buffer-in (partition-all batch-size)) out-chan (a/chan buffer-out) ; is this.. backpressure? callback (fn [port {:keys [status body error] :as ret}] - (if (or (not= 200 status) error) + (if (or (not (<= 200 status 299)) + error) ;; Error: Stop further processing (do (swap! run? not) From 79a3bee124678a67d3e4b7427a79d402cb9f06cd Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Wed, 11 Oct 2023 17:50:07 -0400 Subject: [PATCH 03/12] Only bail in -main function --- src/cli/com/yetanalytics/datasim/cli.clj | 12 ++++++----- .../com/yetanalytics/datasim/cli/generate.clj | 21 +++++++++++-------- .../com/yetanalytics/datasim/cli/input.clj | 15 ++++++------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/cli/com/yetanalytics/datasim/cli.clj b/src/cli/com/yetanalytics/datasim/cli.clj index 714141b0..bf4ec9e2 100644 --- a/src/cli/com/yetanalytics/datasim/cli.clj +++ b/src/cli/com/yetanalytics/datasim/cli.clj @@ -31,8 +31,10 @@ (not subcommand) (print "No subcommand entered.\n\n" summary) :else - (case subcommand - "validate-input" (cli-input/validate-input rest-args) - "generate" (cli-gen/generate rest-args) - "generate-post" (cli-gen/generate-post rest-args) - (u/bail! errors))))) + (let [results (case subcommand + "validate-input" (cli-input/validate-input! rest-args) + "generate" (cli-gen/generate! rest-args) + "generate-post" (cli-gen/generate-post! rest-args) + (u/bail! errors))] + (when-some [errors (:errors results)] + (u/bail! errors)))))) diff --git a/src/cli/com/yetanalytics/datasim/cli/generate.clj b/src/cli/com/yetanalytics/datasim/cli/generate.clj index 2077773c..41dcc58b 100644 --- a/src/cli/com/yetanalytics/datasim/cli/generate.clj +++ b/src/cli/com/yetanalytics/datasim/cli/generate.clj @@ -130,7 +130,7 @@ (case tag :fail (let [{:keys [status error]} ret] - (u/bail! [(client/post-error-message status error)])) + {:errors [(client/post-error-message status error)]}) :success (do (dio/println-coll ret) ; Statement ID strings @@ -145,8 +145,9 @@ (take post-limit)) {:keys [fail]} (client/post-statements post-options statements)] (when (not-empty fail) - (u/bail! (for [{:keys [status error]} fail] - (client/post-error-message status error)))))) + {:errors (map (fn [{:keys [status error]}] + (client/post-error-message status error)) + fail)}))) (defn- post-sim! [input options] @@ -172,7 +173,7 @@ ;; Subcommands ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defn generate +(defn generate! "Generate statements based on simulation `args` and print them to stdout." [args] (u/exec-subcommand @@ -181,11 +182,12 @@ [["-h" "--help"]]) (fn [options] (let [input (cli-input/sim-input options)] - (cli-input/assert-valid-input input) - (print-sim! input options))) + (if-some [errors (cli-input/validate-input* input)] + {:errors errors} + (print-sim! input options)))) args)) -(defn generate-post +(defn generate-post! "Generate statements based on simulation `args` and POST them to an LRS (whose endpoint and other properties are also in `args`)." [args] @@ -196,6 +198,7 @@ [["-h" "--help"]]) (fn [options] (let [input (cli-input/sim-input options)] - (cli-input/assert-valid-input input) - (post-sim! input options))) + (if-some [errors (cli-input/validate-input* input)] + {:errors errors} + (post-sim! input options)))) args)) diff --git a/src/cli/com/yetanalytics/datasim/cli/input.clj b/src/cli/com/yetanalytics/datasim/cli/input.clj index 2e8d28a8..b27508a5 100644 --- a/src/cli/com/yetanalytics/datasim/cli/input.clj +++ b/src/cli/com/yetanalytics/datasim/cli/input.clj @@ -113,7 +113,7 @@ (random/rand-unbound-int (random/rng)) override-seed))))) -(defn assert-valid-input +(defn validate-input* "Perform validation on `input` and fail w/ early termination if it is not valid. @@ -122,7 +122,7 @@ comprehensive spec from the options and check that." [input] (when-let [errors (not-empty (input/validate :input input))] - (u/bail! (errors/map-coll->strs errors)))) + (errors/map-coll->strs errors))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Subcommand @@ -135,7 +135,7 @@ (input/to-file input :json location) (println (format "Input specification written to %s" location)))) -(defn validate-input +(defn validate-input! "Combine and validate the arguments given in `args` and write them to `location` (if `location` is provided)." [args] @@ -144,8 +144,9 @@ ["-h" "--help"]) (fn [{:keys [validated-input] :as options}] (let [input (sim-input options)] - (assert-valid-input input) - (if validated-input - (write-input! input validated-input) - (write-input! input)))) + (if-some [errors (validate-input* input)] + {:errors errors} + (if validated-input + (write-input! input validated-input) + (write-input! input))))) args)) From 6eff6e36cf248aaef172bdbb834f74881c3f8a34 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Wed, 11 Oct 2023 17:50:16 -0400 Subject: [PATCH 04/12] Add testcontainers to deps --- deps.edn | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deps.edn b/deps.edn index 404c5371..b7238c48 100644 --- a/deps.edn +++ b/deps.edn @@ -25,10 +25,13 @@ incanter/incanter-charts {:mvn/version "1.9.3"} criterium/criterium {:mvn/version "0.4.5"}}} :test {:extra-paths ["src/test" "src/test_onyx"] - :extra-deps {same/ish {:mvn/version "0.1.6"}}} + :extra-deps {same/ish {:mvn/version "0.1.6"} + clj-test-containers/clj-test-containers {:mvn/version "0.7.4"}}} :run-tests {:extra-paths ["src/test"] :extra-deps {same/ish {:mvn/version "0.1.6"} + ; org.testcontainers/testcontainers {:mvn/version "1.19.1"} + clj-test-containers/clj-test-containers {:mvn/version "0.7.4"} io.github.cognitect-labs/test-runner {:git/tag "v0.5.1" :git/sha "dfb30dd"}} :main-opts ["-m" "cognitect.test-runner" From 4580c8f1ffbae746f07c8bcc51250f08fa2838fb Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Wed, 11 Oct 2023 17:57:23 -0400 Subject: [PATCH 05/12] Add CLI test suite --- src/test/com/yetanalytics/cli_test.clj | 108 +++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/test/com/yetanalytics/cli_test.clj diff --git a/src/test/com/yetanalytics/cli_test.clj b/src/test/com/yetanalytics/cli_test.clj new file mode 100644 index 00000000..7c1a1ef3 --- /dev/null +++ b/src/test/com/yetanalytics/cli_test.clj @@ -0,0 +1,108 @@ +(ns com.yetanalytics.cli-test + "Integration tests for the DATASIM CLI." + (:require [clojure.test :refer [deftest testing is]] + [clj-test-containers.core :as tc] + [org.httpkit.client :as http] + [com.yetanalytics.datasim.cli.input :as cli-input] + [com.yetanalytics.datasim.cli.generate :as cli-gen] + [com.yetanalytics.datasim.input :as input] + [clojure.string :as cstr])) + +(def server-validate-command + ["/persephone/bin/server.sh" "validate" + "-p" "dev-resources/profiles/cmi5/fixed.json"]) + +(def server-match-command + ["/persephone/bin/server.sh" "match" + "-p" "dev-resources/profiles/cmi5/fixed.json"]) + +(def container-map + {:image-name "yetanalytics/persephone:v0.9.1" + :exposed-ports [8080]}) + +(def filesystem-map + {:host-path "dev-resources/" + :container-path "/persephone/dev-resources/" + :mode :read-only}) + +(def validate-server-container + (-> (assoc container-map :command server-validate-command) + tc/create + (tc/bind-filesystem! filesystem-map))) + +(def match-server-container + (-> (assoc container-map :command server-match-command) + tc/create + (tc/bind-filesystem! filesystem-map))) + +(deftest validate-input-test + (testing "validate-input subcommand" + (cli-input/validate-input! + ["-p" "dev-resources/profiles/cmi5/fixed.json" + "-a" "dev-resources/personae/simple.json" + "-m" "dev-resources/models/simple.json" + "-o" "dev-resources/parameters/simple.json" + "-v" "dev-resources/input/simple2.json"]) + (let [input* (input/from-location + :input :json + "dev-resources/input/simple2.json")] + (is (nil? (input/validate :input input*)))))) + +(deftest generate-test + (let [cont (tc/start! validate-server-container) + host (:host cont) + port (get (:mapped-ports cont) 8080)] + (testing "generate subcommand" + (let [results + (with-out-str + (cli-gen/generate! + ["-i" "dev-resources/input/simple.json"]))] + (is (string? results)) + (is (every? + (fn [stmt-str] + (let [validate-res + #_{:clj-kondo/ignore [:unresolved-var]} + @(http/post + (format "http://%s:%d/statements" host port) + {:headers {"X-Experience-Api-Version" "1.0.3" + "Content-Type" "application/json"} + :body stmt-str + :as :stream})] + (= 204 (:status validate-res)))) + (take 25 (cstr/split-lines results)))))) + (testing "generate-post subcommand - sync" + (let [results + (cli-gen/generate-post! + ["-i" "dev-resources/input/simple.json" + "-E" (format "http://%s:%d" host port) + "-B" "1" + "-L" "1" + "--no-async"])] + ;; Errors would indicate 4xx response from Persephone server + (is (nil? (:errors results))))) + (testing "generate-post subcommand - async" + (let [cont (tc/start! validate-server-container) + host (:host cont) + port (get (:mapped-ports cont) 8080) + res (cli-gen/generate-post! + ["-i" "dev-resources/input/simple.json" + "-E" (format "http://%s:%d" host port) + "-B" "1" + "-L" "1" + "--async"])] + (is (nil? (:errors res))))) + (tc/stop! cont))) + +(deftest generate-test-2 + (testing "generate-post subcommand on match serever" + (let [cont (tc/start! match-server-container) + host (:host cont) + port (get (:mapped-ports cont) 8080) + res (cli-gen/generate-post! + ["-i" "dev-resources/input/simple.json" + "-E" (format "http://%s:%d" host port) + "-B" "25" + "-L" "25" + "--no-async"])] + (is (nil? (:errors res))) + (tc/stop! cont)))) From 5d9158cb65148fa976fac7393d61fb8fc7643c21 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 12 Oct 2023 15:17:48 -0400 Subject: [PATCH 06/12] Separate out validate-input into its own fn --- src/main/com/yetanalytics/datasim/input.clj | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/com/yetanalytics/datasim/input.clj b/src/main/com/yetanalytics/datasim/input.clj index d8f97e20..65138e97 100644 --- a/src/main/com/yetanalytics/datasim/input.clj +++ b/src/main/com/yetanalytics/datasim/input.clj @@ -141,8 +141,8 @@ (defmethod validate :default [type-k _] (throw-unknown-key type-k)) -(defmethod validate :input - [_ {:keys [profiles personae-array models parameters] :as input}] +(defn- validate-input + [{:keys [profiles personae-array models parameters] :as input}] (-> (concat (profile/validate-profiles profiles) (personae/validate-personae-array personae-array) (models/validate-models models) @@ -151,6 +151,9 @@ vec not-empty)) +(defmethod validate :input [_ input] + (validate-input input)) + (defmethod validate :profile [_ profile] (profile/validate-profile profile)) From 0596251fbedfc332b797755d5edf5d90cae990d2 Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 12 Oct 2023 15:34:25 -0400 Subject: [PATCH 07/12] Make username:password the default creds --- README.md | 14 ++++---- .../com/yetanalytics/datasim/server.clj | 34 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index eb0408dc..49b68259 100644 --- a/README.md +++ b/README.md @@ -295,13 +295,13 @@ By default the server starts at http://localhost:9090 The API is configurable with the following runtime environment variables: -| Variable | Default | Notes | Example | -|---------------------|--------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|-------------------| -| CREDENTIALS | | Basic Authentication credentials required to call the API endpoints in the form of `username:password` | `datasim:datasim` | -| API_ROOT_PATH | | Root path to prefix API routes. Must begin with a `/`, cannot end with a `/`. | `/foo` | -| API_HOST | `0.0.0.0` | Host on which to bind the API server. | `localhost` | -| API_PORT | `9090` | Port on which to bind the API server. | `8080` | -| API_ALLOWED_ORIGINS |
`https://yetanalytics.github.io,http://localhost:9091`(URLs)
| CORS allowed origins for the API server, separated by commas. | `*` | +| Variable | Default | Notes | Example | +|---|---|---|---| +| CREDENTIALS | `username:password` | Basic Authentication credentials required to call the API endpoints in the form of `username:password` | `datasim:datasim` | +| API_ROOT_PATH | | Root path to prefix API routes. Must begin with a `/`, cannot end with a `/`. | `/foo` | +| API_HOST | `0.0.0.0`| Host on which to bind the API server. | `localhost` | +| API_PORT | `9090` | Port on which to bind the API server. | `8080` | +| API_ALLOWED_ORIGINS |
`https://yetanalytics.github.io,http://localhost:9091`(URLs)
| CORS allowed origins for the API server, separated by commas. | `*` | Currently defaults are configured to work with the default settings in the DATASIM-UI project locally. diff --git a/src/server/com/yetanalytics/datasim/server.clj b/src/server/com/yetanalytics/datasim/server.clj index c6aae62e..c932b1b0 100644 --- a/src/server/com/yetanalytics/datasim/server.clj +++ b/src/server/com/yetanalytics/datasim/server.clj @@ -103,23 +103,25 @@ ;; Auth data and fns ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(def default-creds ["username:password"]) + ;; Reach into the environment and grab all of the user credentials from there ;; that will be used in basic auth. (defonce users (delay - (let [credentials (env :credentials "") - users' (cstr/split credentials #",")] - (if (not= [""] users') - ;; Create a map of every allowed credential - (reduce (fn [m cred] - (let [[user pass] (cstr/split cred #":")] - (assoc m user {:username user - :password pass}))) - {} - users') - (do - (log/info :msg "No Basic-Auth Credentials were set.") - {}))))) + (let [creds (env :credentials "") + users' (cstr/split creds #",") + users (if (not= [""] users') + users' + (do (log/info :msg "Using default Basic Auth credentials!") + default-creds))] + ;; Create a map of every allowed credential + (reduce (fn [m cred] + (let [[user pass] (cstr/split cred #":")] + (assoc m user {:username user + :password pass}))) + {} + users)))) ;; `request` is unused but is needed for `backends/basic` (defn auth-fn @@ -157,9 +159,8 @@ :enter (fn [ctx] (update ctx :request middleware/authentication-request backend))})) -(defn authorization-interceptor +(def authorization-interceptor "Port of buddy-auth's wrap-authorization middleware." - [backend] #_{:clj-kondo/ignore [:unresolved-symbol]} (error/error-dispatch [ctx ex] @@ -173,8 +174,7 @@ (assoc ctx ::chain/error ex))) (def common-interceptors - [authentication-interceptor - (authorization-interceptor backend)]) + [authentication-interceptor authorization-interceptor]) ;; Generate response to stream simulation to the client. ;; Return a json file, and set it to be downloaded by the user. From e86b5757eab5ea22548aef5a6b992489856285cc Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 12 Oct 2023 15:34:35 -0400 Subject: [PATCH 08/12] Add tests for server --- src/test/com/yetanalytics/cli_test.clj | 49 +++------ .../yetanalytics/datasim/test_containers.clj | 29 +++++ src/test/com/yetanalytics/server_test.clj | 100 ++++++++++++++++++ 3 files changed, 142 insertions(+), 36 deletions(-) create mode 100644 src/test/com/yetanalytics/datasim/test_containers.clj create mode 100644 src/test/com/yetanalytics/server_test.clj diff --git a/src/test/com/yetanalytics/cli_test.clj b/src/test/com/yetanalytics/cli_test.clj index 7c1a1ef3..144289fe 100644 --- a/src/test/com/yetanalytics/cli_test.clj +++ b/src/test/com/yetanalytics/cli_test.clj @@ -1,39 +1,17 @@ (ns com.yetanalytics.cli-test "Integration tests for the DATASIM CLI." (:require [clojure.test :refer [deftest testing is]] - [clj-test-containers.core :as tc] + [clojure.string :as cstr] [org.httpkit.client :as http] + [clj-test-containers.core :as tc] + [com.yetanalytics.datasim.input :as input] [com.yetanalytics.datasim.cli.input :as cli-input] [com.yetanalytics.datasim.cli.generate :as cli-gen] - [com.yetanalytics.datasim.input :as input] - [clojure.string :as cstr])) - -(def server-validate-command - ["/persephone/bin/server.sh" "validate" - "-p" "dev-resources/profiles/cmi5/fixed.json"]) - -(def server-match-command - ["/persephone/bin/server.sh" "match" - "-p" "dev-resources/profiles/cmi5/fixed.json"]) - -(def container-map - {:image-name "yetanalytics/persephone:v0.9.1" - :exposed-ports [8080]}) - -(def filesystem-map - {:host-path "dev-resources/" - :container-path "/persephone/dev-resources/" - :mode :read-only}) - -(def validate-server-container - (-> (assoc container-map :command server-validate-command) - tc/create - (tc/bind-filesystem! filesystem-map))) + [com.yetanalytics.datasim.test-containers :as ds-tc])) -(def match-server-container - (-> (assoc container-map :command server-match-command) - tc/create - (tc/bind-filesystem! filesystem-map))) +(def json-post-header + {"X-Experience-Api-Version" "1.0.3" + "Content-Type" "application/json"}) (deftest validate-input-test (testing "validate-input subcommand" @@ -49,7 +27,7 @@ (is (nil? (input/validate :input input*)))))) (deftest generate-test - (let [cont (tc/start! validate-server-container) + (let [cont (tc/start! ds-tc/validate-server-container) host (:host cont) port (get (:mapped-ports cont) 8080)] (testing "generate subcommand" @@ -64,10 +42,9 @@ #_{:clj-kondo/ignore [:unresolved-var]} @(http/post (format "http://%s:%d/statements" host port) - {:headers {"X-Experience-Api-Version" "1.0.3" - "Content-Type" "application/json"} - :body stmt-str - :as :stream})] + {:headers json-post-header + :body stmt-str + :as :stream})] (= 204 (:status validate-res)))) (take 25 (cstr/split-lines results)))))) (testing "generate-post subcommand - sync" @@ -81,7 +58,7 @@ ;; Errors would indicate 4xx response from Persephone server (is (nil? (:errors results))))) (testing "generate-post subcommand - async" - (let [cont (tc/start! validate-server-container) + (let [cont (tc/start! ds-tc/validate-server-container) host (:host cont) port (get (:mapped-ports cont) 8080) res (cli-gen/generate-post! @@ -95,7 +72,7 @@ (deftest generate-test-2 (testing "generate-post subcommand on match serever" - (let [cont (tc/start! match-server-container) + (let [cont (tc/start! ds-tc/match-server-container) host (:host cont) port (get (:mapped-ports cont) 8080) res (cli-gen/generate-post! diff --git a/src/test/com/yetanalytics/datasim/test_containers.clj b/src/test/com/yetanalytics/datasim/test_containers.clj new file mode 100644 index 00000000..3bff78db --- /dev/null +++ b/src/test/com/yetanalytics/datasim/test_containers.clj @@ -0,0 +1,29 @@ +(ns com.yetanalytics.datasim.test-containers + (:require [clj-test-containers.core :as tc])) + +(def server-validate-command + ["/persephone/bin/server.sh" "validate" + "-p" "dev-resources/profiles/cmi5/fixed.json"]) + +(def server-match-command + ["/persephone/bin/server.sh" "match" + "-p" "dev-resources/profiles/cmi5/fixed.json"]) + +(def container-map + {:image-name "yetanalytics/persephone:v0.9.1" + :exposed-ports [8080]}) + +(def filesystem-map + {:host-path "dev-resources/" + :container-path "/persephone/dev-resources/" + :mode :read-only}) + +(def validate-server-container + (-> (assoc container-map :command server-validate-command) + tc/create + (tc/bind-filesystem! filesystem-map))) + +(def match-server-container + (-> (assoc container-map :command server-match-command) + tc/create + (tc/bind-filesystem! filesystem-map))) diff --git a/src/test/com/yetanalytics/server_test.clj b/src/test/com/yetanalytics/server_test.clj new file mode 100644 index 00000000..1b495705 --- /dev/null +++ b/src/test/com/yetanalytics/server_test.clj @@ -0,0 +1,100 @@ +(ns com.yetanalytics.server-test + "Integration tests for the DATASIM server." + (:require [clojure.test :refer [deftest testing is]] + [clojure.string :as cstr] + [io.pedestal.http :as http] + [org.httpkit.client :as httpkit] + [clj-test-containers.core :as tc] + [com.yetanalytics.datasim.test-constants :as const] + [com.yetanalytics.datasim.test-containers :as ds-tc] + [com.yetanalytics.datasim.server :as server])) + +(def server + (server/create-server)) + +(def profile-string + (format "[%s]" (slurp const/cmi5-profile-filepath))) + +(def personaes-string + (format "[%s]" (slurp const/simple-personae-filepath))) + +(def models-string + (slurp const/simple-models-filepath)) + +(def parameters-string + (slurp const/simple-parameters-filepath)) + +(def post-header + {"X-Experience-Api-Version" "1.0.3" + "Content-Type" "multipart/form-data"}) + +(def json-post-header + {"X-Experience-Api-Version" "1.0.3" + "Content-Type" "application/json"}) + +(def multipart-content + [{:name "profiles" + :content profile-string} + {:name "personae-array" + :content personaes-string} + {:name "models" + :content models-string} + {:name "parameters" + :content parameters-string}]) + +(defn- multipart-post-content [lrs-endpoint api-key api-secret] + (into multipart-content + [{:name "lrs-endpoint" + :content lrs-endpoint} + {:name "api-key" + :content api-key} + {:name "api-secret-key" + :content api-secret} + {:name "send-to-lrs" + :content "true"}])) + +(deftest server-test + (testing "server" + (let [_ (http/start server) + cont (tc/start! ds-tc/validate-server-container) + host (:host cont) + post (get (:mapped-ports cont) 8080) + lrs-url (format "http://%s:%d/statements" host post)] + (testing "GET /health endpoint" + (let [{:keys [status]} + #_{:clj-kondo/ignore [:unresolved-var]} + @(httpkit/get + "http://0.0.0.0:9090/health")] + (is (= 200 status)))) + (testing "POST /api/v1/generate endpoint" + (let [{:keys [status body]} + #_{:clj-kondo/ignore [:unresolved-var]} + @(httpkit/post + "http://0.0.0.0:9090/api/v1/generate" + {:headers post-header + :basic-auth ["username" "password"] + :multipart multipart-content})] + (is (= 200 status)) + (is (every? + (fn [stmt-str] + (let [validate-res + #_{:clj-kondo/ignore [:unresolved-var]} + @(httpkit/post + lrs-url + {:headers json-post-header + :body stmt-str + :as :stream})] + (= 204 (:status validate-res)))) + (take 25 (rest (cstr/split-lines body))))))) + (testing "POST /api/v1/generate endpoint w/ LRS" + (let [endpoint (format "http://%s:%d" host post) + {:keys [status]} + #_{:clj-kondo/ignore [:unresolved-var]} + @(httpkit/post + "http://0.0.0.0:9090/api/v1/generate" + {:headers post-header + :basic-auth ["username" "password"] + :multipart (multipart-post-content endpoint "foo" "bar")})] + (is (= 200 status)))) + (tc/stop! cont) + (http/stop server)))) From 7ddae6f37d71dcad46da1611becb560eb44c751c Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 12 Oct 2023 16:17:35 -0400 Subject: [PATCH 09/12] Update deps.edn aliases --- Makefile | 12 ++--- deps.edn | 149 +++++++++++++++++++++++-------------------------------- 2 files changed, 67 insertions(+), 94 deletions(-) diff --git a/Makefile b/Makefile index ab4d4c40..e1b91b00 100644 --- a/Makefile +++ b/Makefile @@ -37,19 +37,19 @@ bundle: target/bundle # Tests test-unit: - clojure -Adev:cli:run-tests + clojure -Adev:test:run-test test-unit-onyx: - clojure -Adev:cli:onyx:run-onyx-tests + clojure -Adev:cli:onyx:run-onyx-test test-cli: - clojure -A:cli:run validate-input -p dev-resources/profiles/cmi5/fixed.json -a dev-resources/personae/simple.json -m dev-resources/models/simple.json -o dev-resources/parameters/simple.json -v dev-resources/input/simple.json + clojure -A:cli:run-cli validate-input -p dev-resources/profiles/cmi5/fixed.json -a dev-resources/personae/simple.json -m dev-resources/models/simple.json -o dev-resources/parameters/simple.json -v dev-resources/input/simple.json test-cli-comprehensive: - clojure -A:cli:run validate-input -i dev-resources/input/simple.json -v dev-resources/input/simple.json + clojure -A:cli:run-cli validate-input -i dev-resources/input/simple.json -v dev-resources/input/simple.json test-cli-output: - clojure -A:cli:run generate -i dev-resources/input/simple.json + clojure -A:cli:run-cli generate -i dev-resources/input/simple.json test-bundle-output: bundle cd target/bundle; bin/run.sh generate -i ../../dev-resources/input/simple.json @@ -63,4 +63,4 @@ validate-template: ci: test-unit test-unit-onyx test-cli validate-template server: - clojure -A:server + clojure -A:server:run-server diff --git a/deps.edn b/deps.edn index b7238c48..f75eee14 100644 --- a/deps.edn +++ b/deps.edn @@ -16,94 +16,67 @@ http-kit/http-kit {:mvn/version "2.7.0"} cheshire/cheshire {:mvn/version "5.11.0"}} :aliases - {:cli {:extra-paths ["src/cli"] - :extra-deps {org.clojure/tools.cli {:mvn/version "1.0.219"}}} - ;; TODO: More CLI-specific name for :run alias - :run {:main-opts ["-m" "com.yetanalytics.datasim.cli"]} - :dev {:extra-paths ["dev-resources" "src/dev"] - :extra-deps {incanter/incanter-core {:mvn/version "1.9.3"} - incanter/incanter-charts {:mvn/version "1.9.3"} - criterium/criterium {:mvn/version "0.4.5"}}} - :test {:extra-paths ["src/test" "src/test_onyx"] - :extra-deps {same/ish {:mvn/version "0.1.6"} - clj-test-containers/clj-test-containers {:mvn/version "0.7.4"}}} - :run-tests - {:extra-paths ["src/test"] - :extra-deps {same/ish {:mvn/version "0.1.6"} - ; org.testcontainers/testcontainers {:mvn/version "1.19.1"} - clj-test-containers/clj-test-containers {:mvn/version "0.7.4"} - io.github.cognitect-labs/test-runner {:git/tag "v0.5.1" - :git/sha "dfb30dd"}} - :main-opts ["-m" "cognitect.test-runner" - "-d" "src/test"]} - :run-onyx-tests - {:extra-paths ["src/test_onyx"] - :extra-deps {io.github.cognitect-labs/test-runner {:git/tag "v0.5.1" - :git/sha "dfb30dd"}} - :main-opts ["-m" "cognitect.test-runner" - "-d" "src/test_onyx"]} - :server - {:extra-paths ["src/server"] - :extra-deps - {;; Jetty deps - need to exclude and use v9.4.52 due to CVEs - io.pedestal/pedestal.jetty - {:mvn/version "0.6.0" - :exclusions [org.eclipse.jetty/jetty-server - org.eclipse.jetty/jetty-servlet - org.eclipse.jetty.alpn/alpn-api - org.eclipse.jetty/jetty-alpn-server - org.eclipse.jetty.http2/http2-server - org.eclipse.jetty.websocket/websocket-api - org.eclipse.jetty.websocket/websocket-servlet - org.eclipse.jetty.websocket/websocket-server]} - org.eclipse.jetty/jetty-server {:mvn/version "9.4.52.v20230823"} - org.eclipse.jetty/jetty-servlet {:mvn/version "9.4.52.v20230823"} - org.eclipse.jetty.alpn/alpn-api {:mvn/version "1.1.3.v20160715"} - org.eclipse.jetty/jetty-alpn-server {:mvn/version "9.4.52.v20230823"} - org.eclipse.jetty.http2/http2-server {:mvn/version "9.4.52.v20230823"} - ;; Other server deps - io.pedestal/pedestal.service {:mvn/version "0.6.0"} - org.slf4j/slf4j-simple {:mvn/version "1.7.28"} - clj-http/clj-http {:mvn/version "3.12.3"} - environ/environ {:mvn/version "1.1.0"} - ;; Buddy/BouncyCastle deps - buddy/buddy-auth {:mvn/version "3.0.323" - :exclusions [cheshire/cheshire - buddy/buddy-sign]} - buddy/buddy-sign {:mvn/version "3.5.346" - :exclusions [org.bouncycastle/bcprov-jdk18on]} - org.bouncycastle/bcprov-jdk18on {:mvn/version "1.75"}} - :main-opts ["-m" "com.yetanalytics.datasim.server"]} - :onyx - {:extra-paths ["onyx-resources" "src/onyx"] - :extra-deps {com.amazonaws/aws-java-sdk-s3 {:mvn/version "1.11.899"} - com.amazonaws/aws-java-sdk-core {:mvn/version "1.11.899"} - org.onyxplatform/onyx {:mvn/version "0.14.6" - :exclusions - ;; TODO: More exclusions probably - [org.clojure/clojure - org.clojure/core.async - org.slf4j/slf4j-nop - com.amazonaws/aws-java-sdk-s3]} - aleph/aleph {:mvn/version "0.4.7-alpha7"} - com.fzakaria/slf4j-timbre {:mvn/version "0.3.20"} - org.onyxplatform/lib-onyx {:mvn/version "0.14.1.0"} - org.onyxplatform/onyx-http {:mvn/version "0.14.5.0" - :exclusions [aleph/aleph - io.netty/netty-all]} - ;; for local repl - com.bhauman/rebel-readline {:mvn/version "0.1.4"} - ;; for remote repl - nrepl/nrepl {:mvn/version "0.8.3"} - cider/cider-nrepl {:mvn/version "0.25.6"} - org.onyxplatform/onyx-peer-http-query {:mvn/version "0.14.5.1-SNAPSHOT"} - org.onyxplatform/onyx-amazon-s3 {:mvn/version "0.14.5.0" - :exclusions [org.clojure/clojure - org.onyxplatform/onyx - com.amazonaws/aws-java-sdk-s3]}}} - :onyx-dev - {:extra-paths ["src/onyx_dev"]} - + {:dev {:extra-paths ["dev-resources" "src/dev"] + :extra-deps {incanter/incanter-core {:mvn/version "1.9.3"} + incanter/incanter-charts {:mvn/version "1.9.3"} + criterium/criterium {:mvn/version "0.4.5"}}} + :test {:extra-paths ["src/test" "src/test_onyx"] + :extra-deps {same/ish {:mvn/version "0.1.6"} + clj-test-containers/clj-test-containers {:mvn/version "0.7.4"}}} + :run-test {:extra-deps {io.github.cognitect-labs/test-runner {:git/tag "v0.5.1" + :git/sha "dfb30dd"}} + :main-opts ["-m" "cognitect.test-runner" + "-d" "src/test"]} + :cli {:extra-paths ["src/cli"] + :extra-deps {org.clojure/tools.cli {:mvn/version "1.0.219"}}} + :run-cli {:main-opts ["-m" "com.yetanalytics.datasim.cli"]} + :server {:extra-paths ["src/server"] + :extra-deps + {io.pedestal/pedestal.jetty {:mvn/version "0.6.1"} + io.pedestal/pedestal.service {:mvn/version "0.6.0"} + org.slf4j/slf4j-simple {:mvn/version "1.7.28"} + clj-http/clj-http {:mvn/version "3.12.3"} + environ/environ {:mvn/version "1.1.0"} + ;; Buddy/BouncyCastle deps + buddy/buddy-auth {:mvn/version "3.0.323" + :exclusions [cheshire/cheshire + buddy/buddy-sign]} + buddy/buddy-sign {:mvn/version "3.5.346" + :exclusions [org.bouncycastle/bcprov-jdk18on]} + org.bouncycastle/bcprov-jdk18on {:mvn/version "1.75"}}} + :run-server {:main-opts ["-m" "com.yetanalytics.datasim.server"]} + :onyx {:extra-paths ["onyx-resources" "src/onyx"] + :extra-deps {com.amazonaws/aws-java-sdk-s3 {:mvn/version "1.11.899"} + com.amazonaws/aws-java-sdk-core {:mvn/version "1.11.899"} + org.onyxplatform/onyx {:mvn/version "0.14.6" + :exclusions + ;; TODO: More exclusions probably + [org.clojure/clojure + org.clojure/core.async + org.slf4j/slf4j-nop + com.amazonaws/aws-java-sdk-s3]} + aleph/aleph {:mvn/version "0.4.7-alpha7"} + com.fzakaria/slf4j-timbre {:mvn/version "0.3.20"} + org.onyxplatform/lib-onyx {:mvn/version "0.14.1.0"} + org.onyxplatform/onyx-http {:mvn/version "0.14.5.0" + :exclusions [aleph/aleph + io.netty/netty-all]} + ;; for local repl + com.bhauman/rebel-readline {:mvn/version "0.1.4"} + ;; for remote repl + nrepl/nrepl {:mvn/version "0.8.3"} + cider/cider-nrepl {:mvn/version "0.25.6"} + org.onyxplatform/onyx-peer-http-query {:mvn/version "0.14.5.1-SNAPSHOT"} + org.onyxplatform/onyx-amazon-s3 {:mvn/version "0.14.5.0" + :exclusions [org.clojure/clojure + org.onyxplatform/onyx + com.amazonaws/aws-java-sdk-s3]}}} + :onyx-dev {:extra-paths ["src/onyx_dev"]} + :onyx-test {:extra-paths ["src/test_onyx"]} + :run-onyx-test {:extra-deps {io.github.cognitect-labs/test-runner {:git/tag "v0.5.1" + :git/sha "dfb30dd"}} + :main-opts ["-m" "cognitect.test-runner" + "-d" "src/test_onyx"]} :depstar {:replace-deps ; tool usage is new in 2.x {seancorfield/depstar {:mvn/version "2.0.165"}} :ns-default hf.depstar From 8211316b7c3eebce72a3648db06b7f4a4eca133e Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 12 Oct 2023 16:18:18 -0400 Subject: [PATCH 10/12] Add CLI and server aliases to test-unit --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e1b91b00..21c45c38 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ bundle: target/bundle # Tests test-unit: - clojure -Adev:test:run-test + clojure -Adev:cli:server:test:run-test test-unit-onyx: clojure -Adev:cli:onyx:run-onyx-test From d7b8b0e95e9081b2a8b0daad5d955d0a5c8d602b Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 12 Oct 2023 16:25:30 -0400 Subject: [PATCH 11/12] Forgot onyx-test alias in test-unit-onyx --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 21c45c38..ff23d3f4 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ test-unit: clojure -Adev:cli:server:test:run-test test-unit-onyx: - clojure -Adev:cli:onyx:run-onyx-test + clojure -Adev:cli:onyx:onyx-test:run-onyx-test test-cli: clojure -A:cli:run-cli validate-input -p dev-resources/profiles/cmi5/fixed.json -a dev-resources/personae/simple.json -m dev-resources/models/simple.json -o dev-resources/parameters/simple.json -v dev-resources/input/simple.json From 19151872daa8cc7d7d73059fe5a3c4096c2f325d Mon Sep 17 00:00:00 2001 From: kelvinqian00 Date: Thu, 12 Oct 2023 16:40:19 -0400 Subject: [PATCH 12/12] Add DockerHub login step --- .github/workflows/test.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0b9b4f75..3d1bc623 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,6 +25,13 @@ jobs: - name: Setup CI environment uses: yetanalytics/actions/setup-env@v0.0.4 + - name: Log into DockerHub + if: ${{ matrix.target == 'test-unit' }} + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Run Makefile Target ${{ matrix.target }} run: make ${{ matrix.target }}