Skip to content

AsyncAPI 3.x: the kill switch is off by default for message-driven services - #1868

Open
LautaroPetaccio wants to merge 1 commit into
feature/asyncapi-e2e-kafkafrom
feature/asyncapi-kill-switch
Open

LautaroPetaccio wants to merge 1 commit into
feature/asyncapi-e2e-kafkafrom
feature/asyncapi-kill-switch

Conversation

@LautaroPetaccio

@LautaroPetaccio LautaroPetaccio commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

First in the AsyncAPI white-box stack, on top of #1810. It makes a white-box run of a message-driven service work without --killSwitch false.

Why

The kill switch stops SUT code that is still running once the coverage of a test has been collected. It assumes a request handled on a thread of its own. A message-driven service consumes on long-lived threads instead. In NCS, the first line probe of the raw consumer loop inside that window throws KillSwitchException, the thread dies, and every later message goes unanswered. A Spring Kafka listener container survives, since its poll loop is not instrumented, but the records that arrive inside the window are retried by the default error handler while the switch is still on, and then dropped. Every AsyncAPI E2E so far had to pass --killSwitch false.

What it changes

For --problemType ASYNCAPI the kill switch is off unless the user set it explicitly, on the command line or in the configuration file. Every other problem type is unchanged.

  • EMConfig.isKillSwitchOn() decides, and is what RemoteControllerImplementation.getTestResults sends to the driver. That is the only place in the core that reads the option: schedule tasks never send it.
  • EMConfig.explicitlySetOptions keeps the options the user set, as properties, accumulated over every call to updateProperties. The modified options were computed there already, for the experimental-settings warning and the dependency checks, but after checkMultiFieldConstraints() and then discarded. They are computed just before it and kept.
  • The @Cfg text of killSwitch says it is off by default for AsyncAPI; docs/options.md is regenerated.
  • NcsKafkaEMTest drops --killSwitch false from its three runs.

The one decision: decide when asked, not while checking

The obvious place for a per-problem-type default is checkMultiFieldConstraints(), where DEFAULT enums are resolved. It does not work here, for two reasons:

  • problemType may still be DEFAULT while the options are checked. In white-box mode it is resolved from the driver later, in Main, which is exactly what the E2E does.
  • A boolean has no sentinel value, so there is no telling at that point whether true is the user's choice or the default.

So the option itself is never changed. isKillSwitchOn() is killSwitch && (problemType != ASYNCAPI || EMConfig::killSwitch in explicitlySetOptions), evaluated each time the core talks to the driver. A value assigned to config.killSwitch directly in code, rather than through an option, does not count as explicit; the KDoc says so.

What this changes outside AsyncAPI

EMConfig.updateProperties computes the modified options a few lines earlier than before and keeps the matching properties. Their other uses (experimental and internal-settings warnings, checkDependsOn) get the same map as before. RemoteControllerImplementation reads isKillSwitchOn(), which equals killSwitch for every other problem type.

Not here

Black-box AsyncAPI runs still ask the driver for coverage, and with it for the kill switch; the next PR stops that.

Testing

  • EMConfigTest, 3 new tests: the default for REST and AsyncAPI; --killSwitch true and false given explicitly for AsyncAPI and REST, and true given in a configuration file; and the problem type resolved after the options were checked, as Main does it, with and without an explicit --killSwitch true.
  • NcsKafkaEMTest (Docker): 3 tests, 0 failures, without --killSwitch false.
  • All AsyncAPI suites plus the config ones (AsyncApi*Test, EMConfigTest, ConfigToMarkdownTest, ConfigPathCheckTest, ConfigUtilTest): 276 tests, 0 failures.

…rvices

The kill switch stops SUT code that is still running once the coverage
of a test has been collected. It assumes a request handled on a thread
of its own. A message-driven service consumes on long-lived threads
instead: the first line probe executed by a raw consumer loop inside
that window throws, the thread dies, and every later message goes
unanswered. A Spring Kafka listener container survives, but the records
that arrive inside the window are retried while the switch is still on
and then dropped. So far every AsyncAPI E2E had to pass
--killSwitch false to get anything done.

For AsyncAPI the switch is off unless the user set it explicitly. Two
things make this less direct than flipping a default:

 - problemType may still be DEFAULT when the options are checked, and
   only become ASYNCAPI once resolved from the driver in Main. So the
   option itself is never changed; EMConfig.isKillSwitchOn() decides
   when asked, and that is what the core sends to the driver with
   every coverage fetch.
 - A boolean option has no sentinel value, so EMConfig keeps the
   options set on the command line or in the configuration file, as
   properties, accumulated over every updateProperties call. They were
   computed already, for the experimental-settings warning and the
   dependency checks, but after the multi-field checks and then
   discarded.

RemoteControllerImplementation.getTestResults is the only place in the
core that reads the option. Schedule tasks never send it.

EMConfigTest covers the default and the explicit cases, with the
problem type given on the command line, resolved later as Main does
it, and the switch set in a configuration file. NcsKafkaEMTest drops
--killSwitch false.

No change for any other problem type: isKillSwitchOn() is the option
itself there.
@LautaroPetaccio
LautaroPetaccio force-pushed the feature/asyncapi-kill-switch branch from 0074e97 to cf91e01 Compare October 12, 2026 02:54
@jgaleotti
jgaleotti requested a review from arcuri82 October 13, 2026 18:00
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.

2 participants