mirror of
https://github.com/penpot/penpot.git
synced 2026-11-05 17:40:39 +00:00
277 lines
16 KiB
Clojure
277 lines
16 KiB
Clojure
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
;;
|
|
;; Copyright (c) KALEIDOS INC
|
|
|
|
(ns performance-tests.render-wasm.cli-test
|
|
(:require
|
|
[app.common.schema :as sm]
|
|
[benches.render-wasm.node.cli :as cli]
|
|
[benches.render-wasm.node.request :as request]
|
|
[cljs.test :as t :include-macros true]
|
|
[clojure.string :as str]))
|
|
|
|
(def ^:private measurement-defaults
|
|
{:seed 42 :filter nil :warmups 3 :repetitions 10
|
|
:timeout-ms 30000 :startup-timeout-ms 30000 :output-dir nil
|
|
:screenshots false :require-gpu false})
|
|
|
|
(def ^:private comparison-defaults
|
|
{:allow-build-differences false :allow-scene-differences false
|
|
:allow-all-differences false})
|
|
|
|
(defn- resolved
|
|
[command options]
|
|
{:command command :console {:level :info :color :auto} :options options})
|
|
|
|
(defn- failure
|
|
[argv]
|
|
(try
|
|
(cli/parse-resolve argv)
|
|
nil
|
|
(catch :default cause cause)))
|
|
|
|
(t/deftest commands-resolve-complete-requests
|
|
(doseq [[argv expected]
|
|
[[["build"]
|
|
(resolved "build" {:default-features true :features [] :build-timeout-ms 300000})]
|
|
[["run"]
|
|
(resolved "run" (assoc measurement-defaults :remove false
|
|
:build {:kind :prepare :default-features true
|
|
:features [] :build-timeout-ms 300000}))]
|
|
[["run" "--build" "ready-build"]
|
|
(resolved "run" (assoc measurement-defaults :remove false
|
|
:build {:kind :existing :id "ready-build"}))]
|
|
[["ab" "--features" "cache" "--dry-run"]
|
|
(resolved "ab" (merge measurement-defaults comparison-defaults
|
|
{:features ["cache"] :max-features 3 :confirm false
|
|
:dry-run true :build-timeout-ms 300000}))]
|
|
[["compare" "base" "candidate"]
|
|
(resolved "compare" (assoc comparison-defaults :baseline-path "base"
|
|
:candidate-path "candidate" :case-pair nil))]
|
|
[["compare" "base" "candidate" "--allow-build-differences"
|
|
"--allow-scene-differences" "--allow-all-differences"]
|
|
(resolved "compare" {:baseline-path "base" :candidate-path "candidate" :case-pair nil
|
|
:allow-build-differences true :allow-scene-differences true
|
|
:allow-all-differences true})]
|
|
[["ab" "--features" "cache" "--filter" "rects" "--require-gpu" "--screenshots"
|
|
"--allow-build-differences" "--allow-scene-differences" "--allow-all-differences"]
|
|
(resolved "ab" (assoc measurement-defaults :filter "rects" :require-gpu true
|
|
:screenshots true :features ["cache"] :max-features 3
|
|
:confirm false :dry-run false :build-timeout-ms 300000
|
|
:allow-build-differences true :allow-scene-differences true
|
|
:allow-all-differences true))]
|
|
[["merge" "base" "extra"]
|
|
(resolved "merge" {:base-path "base" :additional-path "extra" :output-dir nil})]
|
|
[["merge" " ./base " " ./extra " "--output-dir" " ./merged "]
|
|
(resolved "merge" {:base-path " ./base " :additional-path " ./extra "
|
|
:output-dir " ./merged "})]
|
|
[["purge" "comparisons"] (resolved "purge" {:target :comparisons})]
|
|
[["--help"] (resolved "help" {:topic nil})]]]
|
|
(t/testing (pr-str argv)
|
|
(t/is (= expected (cli/parse-resolve argv))))))
|
|
|
|
(t/deftest console-flags-compose-with-every-command
|
|
(doseq [argv [["build"] ["run"] ["ab" "--features" "cache" "--dry-run"]
|
|
["compare" "base" "candidate"] ["merge" "base" "extra"]
|
|
["purge" "runs"] ["--help"]]
|
|
[flags console] [[["-q" "--no-color"] {:level :warn :color :never}
|
|
[["-v" "--color"] {:level :debug :color :always}]]]]
|
|
(t/is (= console (:console (cli/parse-resolve (into argv flags))))))
|
|
(doseq [argv [["run" "-qv"] ["build" "--quiet" "--verbose"]
|
|
["compare" "--help" "-qv"] ["--help" "-qv"]]]
|
|
(let [error (failure argv)]
|
|
(t/is (= ::cli/invalid-args (:type (ex-data error))))
|
|
(t/is (str/includes? (ex-message error) "mutually exclusive")))))
|
|
|
|
(t/deftest explicit-build-and-measurement-values-survive-resolution
|
|
(t/is (= (resolved "build" {:default-features false :features ["a" "b"]
|
|
:build-timeout-ms 1000})
|
|
(cli/parse-resolve ["--" "build" "--no-default-features"
|
|
"--features=b,a,b" "--build-timeout-ms" "1e3"])))
|
|
(t/is (= {:command "run" :console {:level :info :color :never}
|
|
:options {:build {:kind :prepare :default-features false
|
|
:features ["a" "b"] :build-timeout-ms 5000}
|
|
:seed 0 :filter " rects " :warmups 0 :repetitions 2
|
|
:timeout-ms 1000 :startup-timeout-ms 2000 :output-dir " ./runs "
|
|
:screenshots true :remove true :require-gpu true}}
|
|
(cli/parse-resolve
|
|
["run" "--no-default-features" "--features" " b,a,b "
|
|
"--build-timeout-ms" "5000" "--seed" "0" "--filter" " rects "
|
|
"--warmups" "0" "--repetitions" "2" "--timeout-ms" "1000"
|
|
"--startup-timeout-ms" "2000" "--output-dir" " ./runs "
|
|
"--screenshots" "--remove" "--require-gpu" "--no-color"]))))
|
|
|
|
(t/deftest retained-build-conflicts-use-supplied-flags
|
|
(doseq [flags [["--features" "cache"] ["--default-features"]
|
|
["--no-default-features"] ["--build-timeout-ms=300000"]]
|
|
argv [(into ["run" "--build" "ready"] flags)
|
|
(into (into ["run"] flags) ["--build=ready"])]]
|
|
(t/is (str/includes? (ex-message (failure argv)) "--build cannot be combined")))
|
|
(t/is (= (resolved "run" (assoc measurement-defaults :remove false :warmups 0
|
|
:build {:kind :existing :id "ready"}))
|
|
(cli/parse-resolve ["run" "--build" "ready" "--warmups" "0"]))))
|
|
|
|
(t/deftest parsers-reject-options-owned-by-other-commands
|
|
(doseq [[argv flags]
|
|
[[["build"] ["--warmups" "--cases" "--confirm"]]
|
|
[["run"] ["--cases" "--dry-run" "--allow-build-differences"]]
|
|
[["ab" "--features" "cache" "--dry-run"]
|
|
["--build" "--remove" "--default-features" "--no-default-features" "--cases"]]
|
|
[["compare" "base" "candidate"] ["--output-dir" "--seed" "--features"]]
|
|
[["merge" "base" "extra"] ["--warmups" "--cases" "--allow-all-differences"]]
|
|
[["purge" "runs"] ["--features" "--seed" "--only-runs"]]]
|
|
flag flags]
|
|
(doseq [args [(conj argv flag) (conj argv "--help" flag)]]
|
|
(let [error (failure args)]
|
|
(t/is (= ::cli/invalid-args (:type (ex-data error))))
|
|
(t/is (str/includes? (ex-message error) "Unknown option"))))))
|
|
|
|
(t/deftest command-first-syntax-and-positional-arguments-are-checked
|
|
(doseq [argv [[] ["unknown" "--help"] ["--help" "run"] ["-q" "build"]
|
|
["build" "extra"] ["run" "extra"]
|
|
["compare"] ["compare" "one"] ["compare" "one" "two" "three"]
|
|
["compare" "" "candidate"] ["merge" "base"] ["merge" "base" " "]
|
|
["run" "--build" "../escape"] ["run" "--output-dir" " "]]]
|
|
(t/testing (pr-str argv)
|
|
(t/is (= ::cli/invalid-args (:type (ex-data (failure argv)))))))
|
|
(doseq [target ["builds" "runs" "comparisons" "all"]]
|
|
(t/is (= (resolved "purge" {:target (keyword target)})
|
|
(cli/parse-resolve ["purge" target]))))
|
|
(doseq [args [[] ["unknown"] ["runs" "builds"]]]
|
|
(let [error (failure (into ["purge"] args))]
|
|
(t/is (= ::cli/invalid-args (:type (ex-data error))))
|
|
(t/is (str/includes? (ex-message error) "runner purge builds|runs|comparisons|all")))))
|
|
|
|
(t/deftest argument-errors-include-command-and-validation-details
|
|
(let [data (ex-data (failure ["unknown" "--help"]))]
|
|
(t/is (= "unknown" (:command data)))
|
|
(t/is (= "runner COMMAND [options]" (:usage data))))
|
|
(doseq [[argv path] [[["compare" "" "candidate"] [:options :baseline-path]]
|
|
[["merge" "base" " "] [:options :additional-path]]]]
|
|
(let [data (ex-data (failure argv))]
|
|
(t/is (= ::cli/invalid-args (:type data)))
|
|
(t/is (= ::request/invalid-request (:cause-type data)))
|
|
(t/is (some #(= path (:in %)) (:errors (::sm/explain data)))))))
|
|
|
|
(t/deftest literal-paths-selectors-and-option-looking-values-are-preserved
|
|
(t/is (= (resolved "compare" (assoc comparison-defaults :baseline-path " ./base "
|
|
:candidate-path " ./candidate "
|
|
:case-pair [" rects/load " "other/load"]))
|
|
(cli/parse-resolve ["compare" " ./base " " ./candidate "
|
|
"--cases" " rects/load ,other/load"])))
|
|
(t/is (= (resolved "compare" (assoc comparison-defaults :baseline-path "--seed"
|
|
:candidate-path "-candidate" :case-pair nil))
|
|
(cli/parse-resolve ["compare" "--" "--seed" "-candidate"])))
|
|
(doseq [text ["" " " "--allow-all-differences" "--" "-h"]]
|
|
(t/is (= (resolved "run" (assoc measurement-defaults :filter text :remove false
|
|
:build {:kind :prepare :default-features true
|
|
:features [] :build-timeout-ms 300000}))
|
|
(cli/parse-resolve ["run" "--filter" text])))))
|
|
|
|
(t/deftest malformed-selector-pairs-fail-before-record-loading
|
|
(doseq [text ["" "one" "one,two,three" ",two" "one," " ,two" "one, "]]
|
|
(let [error (failure ["compare" "base" "candidate" (str "--cases=" text)])]
|
|
(t/is (= ::cli/invalid-args (:type (ex-data error))))
|
|
(t/is (str/includes? (ex-message error) "--cases"))))
|
|
(t/is (= ::cli/invalid-args
|
|
(:type (ex-data (failure ["compare" "base" "candidate" "--cases"]))))))
|
|
|
|
(t/deftest numeric-values-use-integer-and-timer-bounds
|
|
(doseq [[flag values]
|
|
[["--seed" ["0" "4294967295"]]
|
|
["--warmups" ["0" "9007199254740991"]]
|
|
["--repetitions" ["1" "9007199254740991"]]
|
|
["--timeout-ms" ["1" "2147483647"]]
|
|
["--startup-timeout-ms" ["1" "2147483647"]]
|
|
["--build-timeout-ms" ["1" " 1000 " "1e3" "0x3e8" "0o1750" "0b1111101000" "2147483647"]]]
|
|
value values]
|
|
(t/is (= (js/Number value)
|
|
(let [options (:options (cli/parse-resolve ["run" flag value]))]
|
|
(if (= flag "--build-timeout-ms")
|
|
(get-in options [:build :build-timeout-ms])
|
|
(get options (keyword (subs flag 2))))))))
|
|
(doseq [[flag values]
|
|
[["--seed" ["-1" "4294967296" "1.5"]]
|
|
["--warmups" ["-1" "9007199254740992" "0.5"]]
|
|
["--repetitions" ["0" "9007199254740992" "1.5"]]
|
|
["--timeout-ms" ["0" "2147483648" "1.5"]]
|
|
["--startup-timeout-ms" ["0" "2147483648"]]
|
|
["--build-timeout-ms" ["0" "2147483648" "1.5" "1000ms"]]]
|
|
value (concat values ["" " " "NaN" "Infinity"])]
|
|
(t/testing (str flag " " value)
|
|
(t/is (= ::cli/invalid-args (:type (ex-data (failure ["run" flag value]))))))))
|
|
|
|
(t/deftest feature-selection-and-ab-policy-use-domain-rules
|
|
(doseq [command ["build" "run" "ab"]
|
|
[feature message] [["stats" "diagnostic Cargo features"]
|
|
["profile" "diagnostic Cargo features"]
|
|
["profile-macros" "diagnostic Cargo features"]
|
|
["profile-raf" "diagnostic Cargo features"]
|
|
["" "invalid Cargo feature selection"]
|
|
["a,,b" "invalid Cargo feature selection"]
|
|
["a/b" "invalid Cargo feature selection"]]]
|
|
(let [argv (cond-> [command "--features" feature] (= command "ab") (conj "--dry-run"))
|
|
error (failure argv)]
|
|
(t/is (= ::cli/invalid-args (:type (ex-data error))))
|
|
(t/is (str/includes? (ex-message error) message))))
|
|
(doseq [argv [["ab"] ["ab" "--features" "cache"]
|
|
["ab" "--features" "cache" "--filter" " "]
|
|
["ab" "--features" "a,b,c,d" "--dry-run"]
|
|
["ab" "--features" "a,b,c,d" "--max-features" "4" "--filter" "rects"]]]
|
|
(t/is (= ::cli/invalid-args (:type (ex-data (failure argv))))))
|
|
(doseq [limit ["" " " "0" "7" "1.5" "NaN" "Infinity" "3x"]]
|
|
(t/is (= ::cli/invalid-args
|
|
(:type (ex-data (failure ["ab" "--features" "cache" "--dry-run"
|
|
"--max-features" limit]))))))
|
|
(doseq [flags [["--confirm"] ["--dry-run"] ["--filter" "rects"]]]
|
|
(t/is (= ["a" "b" "c"]
|
|
(get-in (cli/parse-resolve (into ["ab" "--features" "c,b,a,c"] flags))
|
|
[:options :features]))))
|
|
(let [error (failure ["ab" "--features" "cache"])]
|
|
(t/is (str/includes? (ex-message (ex-cause error)) "--confirm"))))
|
|
|
|
(t/deftest help-skips-required-command-arguments-and-keeps-syntax-checks
|
|
(doseq [command ["build" "run" "ab" "compare" "merge" "purge"]]
|
|
(t/is (= (resolved "help" {:topic command})
|
|
(cli/parse-resolve [command "--help"]))))
|
|
(t/is (= (assoc (resolved "help" {:topic "compare"})
|
|
:console {:level :debug :color :never})
|
|
(cli/parse-resolve ["compare" "--help" "--verbose" "--no-color"])))
|
|
(doseq [argv [["--help" "--unknown"] ["run" "--help" "--warmups" "bad"]
|
|
["compare" "--help" "--cases="] ["ab" "--help" "--features"]]]
|
|
(t/is (= ::cli/invalid-args (:type (ex-data (failure argv)))))))
|
|
|
|
(t/deftest help-shows-command-options-and-schema-defaults
|
|
(doseq [[topic flags]
|
|
[["build" #{"--[no-]default-features" "--features" "--build-timeout-ms"}]
|
|
["run" #{"--build" "--[no-]default-features" "--features" "--build-timeout-ms"
|
|
"--seed" "--filter" "--warmups" "--repetitions" "--timeout-ms"
|
|
"--startup-timeout-ms" "--output-dir" "--screenshots" "--require-gpu" "--remove"}]
|
|
["ab" #{"--features" "--max-features" "--confirm" "--dry-run" "--build-timeout-ms"
|
|
"--seed" "--filter" "--warmups" "--repetitions" "--timeout-ms"
|
|
"--startup-timeout-ms" "--output-dir" "--screenshots" "--require-gpu"
|
|
"--allow-build-differences" "--allow-scene-differences" "--allow-all-differences"}]
|
|
["compare" #{"--cases" "--allow-build-differences"
|
|
"--allow-scene-differences" "--allow-all-differences"}]
|
|
["merge" #{"--output-dir"}]
|
|
["purge" #{}]]]
|
|
(let [text (cli/get-help topic)]
|
|
(t/is (str/includes? text (str "Usage: runner " topic)))
|
|
(t/is (= (into #{"--help" "--quiet" "--verbose" "--[no-]color"} flags)
|
|
(set (re-seq #"--(?:\[no-\])?[a-z][a-z-]*" text))))))
|
|
(t/is (= ["build" "run" "ab" "compare" "merge" "purge"]
|
|
(mapv second (re-seq #"(?m)^ runner ([a-z]+)" (cli/get-help nil)))))
|
|
(doseq [[topic pattern] [["build" #"--build-timeout-ms MS\s+300000"]
|
|
["run" #"--warmups N\s+3"]
|
|
["run" #"--seed N\s+42"]
|
|
["run" #"--repetitions N\s+10"]
|
|
["run" #"--features FEATURES\s+\[\]"]
|
|
["run" #"--\[no-\]default-features\s+true"]
|
|
["run" #"--build-timeout-ms MS\s+300000"]
|
|
["ab" #"--max-features N\s+3"]
|
|
["merge" #"--output-dir DIR\s+nil"]
|
|
["compare" #"--cases A,B\s+nil"]]]
|
|
(t/is (re-find pattern (cli/get-help topic)))))
|