Skip to content

Surface var-less errors in JUnit output - #50

Merged
nemanjaglumac merged 4 commits into
mainfrom
dev-2429-hawk-var-less-junit-errors
Jul 28, 2026
Merged

Surface var-less errors in JUnit output#50
nemanjaglumac merged 4 commits into
mainfrom
dev-2429-hawk-var-less-junit-errors

Conversation

@nemanjaglumac

Copy link
Copy Markdown
Member

Resolves DEV-2429

Premise

Fixture-init throws (:once/:each) and namespace load/compile errors reach the JUnit reporter with no associated test var. clojure.test/eftest still counts them toward the run's error total, and mb.hawk.core derives the exit code from that total, so such an error fails the run -- but the namespace->var keyed writer had nowhere to put an error with no var, so it was dropped from JUnit entirely. The exit code and the JUnit output then disagreed, and any consumer reconstructing the failed set from JUnit (e.g. to compute a narrow rerun selector) would silently miss the error.

Summary

Collect var-less errors during the run and write them to their own file (mb_hawk_var_less_errors.xml) at :summary. Each is emitted as a with a non-empty name but deliberately no classname, so a consumer that attributes failures by resolving classname/name to ns/var treats it as unattributable rather than targeting a nonexistent var.

Fixture-init throws (:once/:each) and namespace load/compile errors reach
the JUnit reporter with no associated test var. clojure.test/eftest still
counts them toward the run's error total, and mb.hawk.core derives the exit
code from that total, so such an error fails the run -- but the
namespace->var keyed writer had nowhere to put an error with no var, so it
was dropped from JUnit entirely. The exit code and the JUnit output then
disagreed, and any consumer reconstructing the failed set from JUnit (e.g.
to compute a narrow rerun selector) would silently miss the error.

Collect var-less errors during the run and write them to their own file
(mb_hawk_var_less_errors.xml) at :summary. Each is emitted as a <testcase>
with a non-empty name but deliberately no classname, so a consumer that
attributes failures by resolving classname/name to ns/var treats it as
unattributable rather than targeting a nonexistent var.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@bronsa bronsa left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks solid to me, just a few implementation notes

Comment thread src/mb/hawk/junit/write.clj Outdated
(write-element!
w "testcase"
;; NOTE: intentionally no `classname` -- see `var-less-error-name`.
{:name (var-less-error-name result)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should decolorize-and-escape

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in a063d8e.

Comment thread src/mb/hawk/junit/write.clj Outdated
(str (or (not-empty message) "Uncaught error with no associated test var")
(when where (format " (%s)" where)))))

(defn- throwable->string

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be (with-out-str (clojure.stacktrace/print-cause-trace t))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 048bbb8.

Comment thread src/mb/hawk/junit/write.clj Outdated
;;;; We collect them here and emit them into their own file at `:summary`. Each becomes a `<testcase>` with a
;;;; non-empty `name` but deliberately NO `classname` -- see `var-less-error-name`.

(defonce ^:private var-less-errors (atom []))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feels a bit weird to hold error states in this write namespace. I'd move it to the junit instead, and have the write functions take collected errors as args, e.g.

;; in mb.hawk.junit
  (defonce ^:private var-less-errors (atom []))

  (defmethod handle-event!* :begin-test-run
    [_]
    (write/clean-output-dir!)
    (reset! var-less-errors [])
    (write/create-thread-pool!))

  (defmethod handle-event!* :summary
    [_]
    (write/write-var-less-errors! @var-less-errors)
    (write/wait-for-writes-to-finish))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to mb.hawk.junit in b8cf402write-var-less-errors! now takes the errors as an arg.

nemanjaglumac and others added 3 commits July 27, 2026 18:06
Replace the hand-rolled throwable->string helper with the standard
`(with-out-str (clojure.stacktrace/print-cause-trace t))`, which also
walks the cause chain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The name is built from the exception message, which may carry ANSI color
codes and unprintable characters; run it through decolorize-and-escape
like the other JUnit text.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The write namespace is otherwise stateless XML-writing logic; the atom
accumulating var-less errors fits better alongside the event handlers
that produce them. Move it to mb.hawk.junit and have
write-var-less-errors! take the collected errors as an argument.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@camsaul camsaul left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like there's too much duplication here with existing code but after looking at it for a bit I don't have a ton of concrete suggestions about how to minimize it so I'm going to go ahead an approve it for now.

@nemanjaglumac
nemanjaglumac merged commit 49f5bf1 into main Jul 28, 2026
2 checks passed
@nemanjaglumac
nemanjaglumac deleted the dev-2429-hawk-var-less-junit-errors branch July 28, 2026 14:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants