penpot/common/test/common_tests/exceptions_test.cljc
Andrey Antukh c74d415ddd
🐛 Stop oversized audit events from wedging the archive queue (#12252)
* 🐛 Stop the export-shapes modal event from dumping all exports

The `:export-shapes` modal event carried the full `:exports` vector,
each export embedding its shape (path data, geometry, text content).
One event reached 1.7 MB, which made the audit archive cron POST a
chunk past the proxy body limit and wedge the queue.

Build a compact body for that modal instead: total exports, distinct
shapes and one count per export type, plus the page name. Other modals
keep their props unchanged.

Move the modal `:origin` prop to `::ev/origin` so `make-proto-event`
records it on the event context as `:event-origin`; the UI still reads
the plain prop from the raw state.

Add tests for the summary and for the modal origin.

AI-assisted-by: deepseek-v4.1-flash

* 🐛 Bound exception messages in reports and audit events

A frontend crash whose message embeds a whole payload (a serialized
file) produced a 9.4 MB audit event: the message was repeated in the
`:hint` prop, in the report context and in the stack trace. A single
event that big wedged the audit archive queue.

Bound exception messages at the source: `get-hint` clamps to
`max-message-length` (1000 chars), and the CLJS `format-throwable`
clamps the message line of the stack trace and honors `:trace-length`
(parity with the CLJ version). `report-context` now prints `get-hint`
instead of the raw `:hint` from `ex-data`.

Fix `first-line` on the JVM: `cuerdas/index-of` returns nil when the
substring is missing and `(pos? nil)` throws there (it is false in
CLJS), so single-line messages crashed the backend path.

AI-assisted-by: deepseek-v4.1-flash
2026-10-15 10:19:26 +02:00

58 lines
2.3 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.exceptions-test
"Exception message bounding in `app.common.exceptions`.
A message can carry a whole payload (a serialized file, for instance) and
grow to megabytes. `get-hint` and the CLJS `format-throwable` keep a bounded
head so neither the audit `:hint` prop nor the report can explode."
(:require
#?(:cljs [cuerdas.core :as str])
[app.common.exceptions :as ex]
[clojure.test :as t]))
(defn- huge-string
[n]
(apply str (repeat n "x")))
(t/deftest first-line-keeps-a-single-line-message-intact-test
(t/is (= "boom" (ex/first-line "boom")))
(t/is (= "boom" (ex/first-line "boom\nrest of the message"))))
(t/deftest get-hint-returns-the-first-line-test
(t/is (= "boom" (ex/get-hint (ex-info "boom\nsecond line" {})))))
(t/deftest get-hint-prefers-the-ex-data-hint-test
(t/is (= "from-data" (ex/get-hint (ex-info "from-message" {:hint "from-data"})))))
(t/deftest get-hint-bounds-a-huge-message-test
(let [huge (huge-string (* 4 ex/max-message-length))
hint (ex/get-hint (ex-info huge {}))]
(t/is (string? hint))
(t/is (<= (count hint) (+ ex/max-message-length 3)))
(t/is (= (subs hint 0 32) (subs huge 0 32)))))
(t/deftest get-hint-bounds-a-huge-ex-data-hint-test
(let [huge (huge-string (* 4 ex/max-message-length))
hint (ex/get-hint (ex-info "short" {:hint huge}))]
(t/is (<= (count hint) (+ ex/max-message-length 3)))
(t/is (= (subs hint 0 32) (subs huge 0 32)))))
#?(:cljs
(t/deftest format-throwable-bounds-a-huge-trace-message-test
(let [huge (huge-string (* 4 ex/max-message-length))
out (ex/format-throwable (ex-info huge {}))
msg (some #(when (str/includes? % (subs huge 0 16)) %) (str/lines out))]
(t/is (some? msg))
(t/is (<= (count msg) (+ ex/max-message-length 16))))))
#?(:cljs
(t/deftest format-throwable-honors-trace-length-test
(let [full (ex/format-throwable (ex-info "boom" {}))
short (ex/format-throwable (ex-info "boom" {}) {:trace-length 1})]
(t/is (< (count (str/lines short)) (count (str/lines full)))))))