mirror of
https://github.com/penpot/penpot.git
synced 2026-10-03 09:16:15 +00:00
* ✨ Add size limits to profile props and plugin registry Bound the total serialized size of profile settings to 2 MiB (:profile-props-max-size), checked on the merged result before persisting, with a controlled :props-too-large error. Profiles that already exceed the limit can still shrink but cannot grow. Cap plugin registry entries in the shared schema (code 1 MiB, 50 plugins max, bounded name/host/description/icon) and restore rate limiting on the plugin RPCs (profile-mutations bucket, one write at a time per profile). The plugin manager now asks for confirmation before removal and ignores repeated clicks while a persist request is in flight. Closes #11592 AI-assisted-by: muse-spark-1.3-contributor * 🐛 Enforce plugin count cap, byte sizes and removal guard Enforce the declared 50-plugin cap in add-profile-plugin with a specific :too-many-plugins error (updates of existing entries still pass); the cap lives in a shared max-plugins constant. Measure profile props size in UTF-8 bytes instead of chars so multibyte content cannot slip past the limit. Cover install/remove persist logic with mocked-RPC frontend tests (release semantics, in-flight dedupe, validation vs rollback split) and add the missing boundary tests in common. Expose the in-flight persist set from the plugin registry and disable the remove button of entries being saved. Closes #11592 AI-assisted-by: muse-spark-1.3-contributor * 🐛 Fix rollback loops and restore paths in plugin registry Restore the previous plugin version instead of dropping the entry when a validation error rejects an update of an installed plugin. Make compensating writes one-shot with terminal callbacks so a persistent failure cannot ping-pong between install and remove. Restores keep the original list position; the unused public plugin-persisting? predicate is removed. Pin count-before-size precedence with a dedicated test and fix translation source refs to their canonical lines. Closes #11592 AI-assisted-by: muse-spark-1.3-contributor * 🐛 Guard notifications write and fix restore ordering Route update-profile-notifications through check-props-size! so oversized profiles cannot grow through that path; document the exempt system writers. Remove the duplicated stale entries in en.po, keeping the canonical translation refs. Restore rejected plugin updates at their original list position instead of leaving the optimistic move in place. Closes #11592 AI-assisted-by: muse-spark-1.3-contributor * 🐛 Skip no-op plugin removal and clarify size comments Return early from remove-profile-plugin when the id is absent: no wasted write, no size check, and no manufactured :plugins key that could spuriously fail on oversized profiles. Clarify that per-field string caps count chars while the byte budget is enforced by profile-props-max-size. Closes #11592 AI-assisted-by: muse-spark-1.3-contributor * 📎 Fix formatting in rlimit.edn for profile operations Signed-off-by: Andrey Antukh <niwi@niwi.nz> * 📎 Fix formatting of import-binfile/global entry Signed-off-by: Andrey Antukh <niwi@niwi.nz> * ♻️ Simplify props size check and tighten plugin entry caps Measure props with transit bytes directly instead of the PGobject string roundtrip. Rename check-props-size! to check-props-size: single hard limit on the merged props, no growth comparison, and return props so writers thread the check into the update. Move the 2 MiB default into default-props-max-size on the profile namespace, still overridable with the optional :profile-props-max-size config entry. Tighten registry-entry :code and :icon to 500 chars: they hold manifest paths, not content. Closes #11592 AI-assisted-by: muse-spark-1.3-contributor * 🐛 Fix compatibility problems --------- Signed-off-by: Andrey Antukh <niwi@niwi.nz> Co-authored-by: alonso.torres <alonso.torres@kaleidos.net>
352 lines
13 KiB
Clojure
352 lines
13 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 SUBSIDIARY SL
|
|
|
|
(ns common-tests.runner
|
|
(:require
|
|
#?(:clj [common-tests.fressian-test])
|
|
#?(:cljs [app.common.logging :as l])
|
|
#?(:cljs [clojure.string :as str])
|
|
#?(:cljs [clojure.tools.cli :refer [parse-opts]])
|
|
#?(:cljs [goog.object :as gobj])
|
|
[clojure.test :as t]
|
|
[common-tests.attrs-test]
|
|
[common-tests.buffer-test]
|
|
[common-tests.colors-test]
|
|
[common-tests.data-test]
|
|
[common-tests.files-builder-test]
|
|
[common-tests.files-changes-test]
|
|
[common-tests.files-migrations-0025-test]
|
|
[common-tests.files-migrations-0026-test]
|
|
[common-tests.files-migrations-test]
|
|
[common-tests.files.helpers-test]
|
|
[common-tests.files.shapes-builder-test]
|
|
[common-tests.files.validate-test]
|
|
[common-tests.geom-align-test]
|
|
[common-tests.geom-bounds-layout-nil-test]
|
|
[common-tests.geom-bounds-map-test]
|
|
[common-tests.geom-flex-layout-test]
|
|
[common-tests.geom-grid-layout-test]
|
|
[common-tests.geom-grid-test]
|
|
[common-tests.geom-image-bounds-resize-test]
|
|
[common-tests.geom-line-test]
|
|
[common-tests.geom-modif-tree-test]
|
|
[common-tests.geom-modifiers-test]
|
|
[common-tests.geom-point-test]
|
|
[common-tests.geom-proportions-test]
|
|
[common-tests.geom-rect-test]
|
|
[common-tests.geom-shapes-common-test]
|
|
[common-tests.geom-shapes-constraints-test]
|
|
[common-tests.geom-shapes-corners-test]
|
|
[common-tests.geom-shapes-effects-test]
|
|
[common-tests.geom-shapes-intersect-test]
|
|
[common-tests.geom-shapes-strokes-test]
|
|
[common-tests.geom-shapes-test]
|
|
[common-tests.geom-shapes-text-test]
|
|
[common-tests.geom-shapes-tree-seq-test]
|
|
[common-tests.geom-snap-test]
|
|
[common-tests.geom-test]
|
|
[common-tests.logging-test]
|
|
[common-tests.logic.chained-propagation-test]
|
|
[common-tests.logic.comp-creation-test]
|
|
[common-tests.logic.comp-detach-with-nested-test]
|
|
[common-tests.logic.comp-main-edit-breaks-copy-slots-test]
|
|
[common-tests.logic.comp-remove-swap-slots-test]
|
|
[common-tests.logic.comp-reset-test]
|
|
[common-tests.logic.comp-sync-test]
|
|
[common-tests.logic.comp-touched-test]
|
|
[common-tests.logic.copying-and-duplicating-test]
|
|
[common-tests.logic.duplicated-pages-test]
|
|
[common-tests.logic.move-shapes-test]
|
|
[common-tests.logic.multiple-nesting-levels-test]
|
|
[common-tests.logic.swap-and-reset-test]
|
|
[common-tests.logic.swap-as-override-test]
|
|
[common-tests.logic.token-test]
|
|
[common-tests.logic.variants-switch-test]
|
|
[common-tests.math-test]
|
|
[common-tests.media-test]
|
|
[common-tests.path-names-test]
|
|
[common-tests.record-test]
|
|
[common-tests.schema-test]
|
|
[common-tests.spec-test]
|
|
[common-tests.svg-path-test]
|
|
[common-tests.svg-test]
|
|
[common-tests.text-test]
|
|
[common-tests.time-test]
|
|
[common-tests.types.absorb-assets-test]
|
|
[common-tests.types.color-test]
|
|
[common-tests.types.components-test]
|
|
[common-tests.types.container-test]
|
|
[common-tests.types.fill-test]
|
|
[common-tests.types.modifiers-test]
|
|
[common-tests.types.objects-map-test]
|
|
[common-tests.types.organization-test]
|
|
[common-tests.types.path-data-test]
|
|
[common-tests.types.plugins-test]
|
|
[common-tests.types.shape-decode-encode-test]
|
|
[common-tests.types.shape-interactions-test]
|
|
[common-tests.types.shape-layout-test]
|
|
[common-tests.types.stroke-test]
|
|
[common-tests.types.token-test]
|
|
[common-tests.types.tokens-lib-test]
|
|
[common-tests.types.tokens-status-test]
|
|
[common-tests.undo-stack-test]
|
|
[common-tests.uuid-test]))
|
|
|
|
(def test-namespaces
|
|
[#?(:clj 'common-tests.fressian-test)
|
|
'common-tests.attrs-test
|
|
'common-tests.buffer-test
|
|
'common-tests.colors-test
|
|
'common-tests.data-test
|
|
'common-tests.files-changes-test
|
|
'common-tests.files-builder-test
|
|
'common-tests.files.helpers-test
|
|
'common-tests.files-migrations-0025-test
|
|
'common-tests.files-migrations-0026-test
|
|
'common-tests.files-migrations-test
|
|
'common-tests.files.validate-test
|
|
'common-tests.geom-align-test
|
|
'common-tests.geom-bounds-layout-nil-test
|
|
'common-tests.geom-bounds-map-test
|
|
'common-tests.geom-flex-layout-test
|
|
'common-tests.geom-grid-layout-test
|
|
'common-tests.geom-grid-test
|
|
'common-tests.geom-image-bounds-resize-test
|
|
'common-tests.geom-line-test
|
|
'common-tests.geom-modif-tree-test
|
|
'common-tests.geom-modifiers-test
|
|
'common-tests.geom-point-test
|
|
'common-tests.geom-proportions-test
|
|
'common-tests.geom-rect-test
|
|
'common-tests.geom-shapes-common-test
|
|
'common-tests.geom-shapes-constraints-test
|
|
'common-tests.geom-shapes-corners-test
|
|
'common-tests.geom-shapes-effects-test
|
|
'common-tests.geom-shapes-intersect-test
|
|
'common-tests.geom-shapes-strokes-test
|
|
'common-tests.geom-shapes-test
|
|
'common-tests.geom-shapes-text-test
|
|
'common-tests.geom-shapes-tree-seq-test
|
|
'common-tests.geom-snap-test
|
|
'common-tests.geom-test
|
|
'common-tests.logging-test
|
|
'common-tests.logic.chained-propagation-test
|
|
'common-tests.logic.comp-creation-test
|
|
'common-tests.logic.comp-detach-with-nested-test
|
|
'common-tests.logic.comp-main-edit-breaks-copy-slots-test
|
|
'common-tests.logic.comp-remove-swap-slots-test
|
|
'common-tests.logic.comp-reset-test
|
|
'common-tests.logic.comp-sync-test
|
|
'common-tests.logic.comp-touched-test
|
|
'common-tests.logic.copying-and-duplicating-test
|
|
'common-tests.logic.duplicated-pages-test
|
|
'common-tests.logic.move-shapes-test
|
|
'common-tests.logic.multiple-nesting-levels-test
|
|
'common-tests.logic.swap-and-reset-test
|
|
'common-tests.logic.swap-as-override-test
|
|
'common-tests.logic.token-test
|
|
'common-tests.logic.variants-switch-test
|
|
'common-tests.math-test
|
|
'common-tests.media-test
|
|
'common-tests.path-names-test
|
|
'common-tests.record-test
|
|
'common-tests.schema-test
|
|
'common-tests.spec-test
|
|
'common-tests.svg-path-test
|
|
'common-tests.svg-test
|
|
'common-tests.text-test
|
|
'common-tests.time-test
|
|
'common-tests.types.absorb-assets-test
|
|
'common-tests.types.color-test
|
|
'common-tests.types.components-test
|
|
'common-tests.types.container-test
|
|
'common-tests.types.fill-test
|
|
'common-tests.types.modifiers-test
|
|
'common-tests.types.objects-map-test
|
|
'common-tests.types.organization-test
|
|
'common-tests.types.path-data-test
|
|
'common-tests.types.plugins-test
|
|
'common-tests.types.shape-decode-encode-test
|
|
'common-tests.types.shape-interactions-test
|
|
'common-tests.types.shape-layout-test
|
|
'common-tests.types.stroke-test
|
|
'common-tests.types.token-test
|
|
'common-tests.types.tokens-lib-test
|
|
'common-tests.types.tokens-status-test
|
|
'common-tests.undo-stack-test
|
|
'common-tests.uuid-test])
|
|
|
|
#?(:cljs
|
|
(assert (every? find-ns-obj test-namespaces)
|
|
"test-namespaces contains a namespace that isn't required in runner.cljc"))
|
|
|
|
#?(:cljs (enable-console-print!))
|
|
|
|
#?(:cljs
|
|
(defmethod cljs.test/report [:cljs.test/default :end-run-tests] [m]
|
|
(if (cljs.test/successful? m)
|
|
(.exit js/process 0)
|
|
(.exit js/process 1))))
|
|
#?(:cljs
|
|
(defmethod t/report [:cljs.test/default :begin-test-var] [m]
|
|
(let [v (:var m)]
|
|
(println (str " ▸ " (:ns (meta v)) "/" (:name (meta v)))))))
|
|
|
|
#?(:cljs
|
|
(do
|
|
;; This runner intentionally mirrors frontend-tests.runner. Both runners need
|
|
;; forwarded CLI args, focused namespace/var execution, fixture preservation,
|
|
;; and app log-level setup. A shared helper could own those mechanics, but we
|
|
;; keep the logic local while there are only two test targets because sharing
|
|
;; it would add cross-module test classpath coupling.
|
|
(def ^:private log-levels
|
|
#{:trace :debug :info :warn :error})
|
|
|
|
(def cli-options
|
|
[["-f" "--focus FOCUS" "Run one test namespace or one test var, e.g. common-tests.logic.comp-sync-test/test-sync-when-changing-attribute"]
|
|
["-l" "--log-level LEVEL" "Set app logger level: trace|debug|info|warn|error"
|
|
:parse-fn keyword
|
|
:validate [log-levels "must be one of trace, debug, info, warn, error"]]
|
|
["-h" "--help"]])
|
|
|
|
(defn- argv
|
|
[]
|
|
(let [args (->> (.-argv js/process)
|
|
(array-seq)
|
|
(drop 2))]
|
|
(cond-> args
|
|
(= "--" (first args)) rest)))
|
|
|
|
(defn- usage
|
|
[summary]
|
|
(str "Usage: pnpm run test:js -- [options]\n\n"
|
|
"Options:\n"
|
|
summary "\n\n"
|
|
"Focus examples:\n"
|
|
" pnpm run test:js -- --focus common-tests.logic.comp-sync-test\n"
|
|
" pnpm run test:js -- --focus common-tests.logic.comp-sync-test/test-sync-when-changing-attribute\n\n"
|
|
"Log level example (quiets app logging during the run):\n"
|
|
" pnpm run test:js -- --focus common-tests.logic.comp-sync-test --log-level warn"))
|
|
|
|
(defn- fail!
|
|
[message]
|
|
(js/console.error message)
|
|
(.exit js/process 1))
|
|
|
|
(defn- parse-focus
|
|
[focus]
|
|
(let [[ns-name test-name & extra] (str/split focus #"/")]
|
|
(cond
|
|
(or (str/blank? ns-name) (seq extra))
|
|
(fail! (str "Invalid --focus value: " focus))
|
|
|
|
(some? test-name)
|
|
{:ns (symbol ns-name) :test test-name}
|
|
|
|
:else
|
|
{:ns (symbol ns-name)})))
|
|
|
|
(defn- fixture-value
|
|
[ns-obj fixture-name]
|
|
(let [value (gobj/get ns-obj (munge fixture-name))]
|
|
(when-not (undefined? value)
|
|
value)))
|
|
|
|
(defn- ns-test-vars
|
|
[ns-sym]
|
|
(when-let [ns-obj (find-ns-obj ns-sym)]
|
|
(->> (js-keys ns-obj)
|
|
(keep (fn [key]
|
|
(some-> (gobj/get ns-obj key)
|
|
(.-cljs$lang$var))))
|
|
(filter (comp :test meta))
|
|
(sort-by (comp :line meta)))))
|
|
|
|
(defn- ns-fixtures
|
|
[ns-sym vars]
|
|
(when-let [ns-obj (find-ns-obj ns-sym)]
|
|
(let [ns-key (or (some-> vars first meta :ns) ns-sym)
|
|
once-fixtures (fixture-value ns-obj "cljs-test-once-fixtures")
|
|
each-fixtures (fixture-value ns-obj "cljs-test-each-fixtures")]
|
|
{:once (when once-fixtures {ns-key once-fixtures})
|
|
:each (when each-fixtures {ns-key each-fixtures})})))
|
|
|
|
(defn- selected-tests
|
|
[{:keys [ns test]}]
|
|
(when-not (some #{ns} test-namespaces)
|
|
(fail! (str "Unknown test namespace: " ns)))
|
|
(let [vars (vec (ns-test-vars ns))]
|
|
(when (empty? vars)
|
|
(fail! (str "No tests found in namespace: " ns)))
|
|
(if test
|
|
(let [test-sym (symbol test)
|
|
test-var (some #(when (= test-sym (:name (meta %))) %) vars)]
|
|
(if test-var
|
|
{:vars [test-var]
|
|
:fixtures (ns-fixtures ns [test-var])}
|
|
(fail! (str "Unknown test var: " ns "/" test))))
|
|
{:vars vars
|
|
:fixtures (ns-fixtures ns vars)})))
|
|
|
|
(defn- merge-fixtures
|
|
[fixtures]
|
|
{:once (apply merge (keep :once fixtures))
|
|
:each (apply merge (keep :each fixtures))})
|
|
|
|
(defn- run-test-vars!
|
|
[tests]
|
|
(let [vars (vec (mapcat :vars tests))
|
|
fixtures (merge-fixtures (map :fixtures tests))
|
|
env (assoc (t/empty-env)
|
|
:once-fixtures (:once fixtures)
|
|
:each-fixtures (:each fixtures))
|
|
summary (volatile! {:test 0 :pass 0 :fail 0 :error 0 :type :summary})]
|
|
|
|
(t/set-env! env)
|
|
|
|
(t/run-block
|
|
(concat (t/test-vars-block vars)
|
|
[(fn []
|
|
(vswap! summary
|
|
(partial merge-with +)
|
|
(:report-counters (t/get-and-clear-env!))))
|
|
(fn []
|
|
(t/set-env! env)
|
|
(t/report @summary)
|
|
(t/report (assoc @summary :type :end-run-tests))
|
|
(t/clear-env!))]))))
|
|
|
|
(defn- run-focused-test!
|
|
[focus]
|
|
(run-test-vars! [(selected-tests (parse-focus focus))]))
|
|
|
|
(defn- run-all-tests!
|
|
[]
|
|
(run-test-vars! (map #(selected-tests {:ns %}) test-namespaces)))))
|
|
|
|
(defn -main
|
|
[& _args]
|
|
#?(:cljs
|
|
(let [{:keys [options errors summary]} (parse-opts (argv) cli-options)]
|
|
(cond
|
|
(seq errors)
|
|
(fail! (str/join "\n" errors))
|
|
|
|
(:help options)
|
|
(do
|
|
(println (usage summary))
|
|
(.exit js/process 0))
|
|
|
|
:else
|
|
(do
|
|
(when-let [level (:log-level options)]
|
|
(l/setup! {:app level}))
|
|
(if (:focus options)
|
|
(run-focused-test! (:focus options))
|
|
(run-all-tests!)))))
|
|
:clj
|
|
(apply t/run-tests test-namespaces)))
|