[SUREFIRE-2049] Fix SHUTDOWN type lost during command serialization.#3270
Conversation
|
For the record, take a look at the old public static Command decode(DataInputStream is) throws IOException {
...
String data = command.toDataTypeAsString(buffer);
return new Command(command, data); // stores raw string directly
}The old protocol created The new binary protocol (introduced in SUREFIRE-1847) added |
|
Would appreciate a second opinion. This is highly needed as our CIs often suffer from long hanging tests :( |
Indeed we're suffering from the same issue as well; and it's been like this since we upgraded to the latest version. Change looks good to me. do you think we can include it in the 3.5.6 milestone @olamy @Tibor17? |
|
Yes that's the goal. |
|
Sounds great :) What's the ETA on that generally? |
you PR looks great. I'm ready to merge. I'm just waiting a bit to see if there any other comments (valuable, interesting or nitpicking...) |
|
@aghoussaini thanks for the fix. backport PR to 3.5.x #3289 |
Problem
When
forkedProcessTimeoutInSecondsis configured, the plugin correctly detects the timeout and sends aSHUTDOWN(KILL)command to the forked JVM through the binary command channel. However, the forked JVM receivesSHUTDOWN(DEFAULT)instead ofSHUTDOWN(KILL)due to a data format mismatch in the serialization. This causes the forked JVM to ignore the kill signal entirely — the build hangs for the full duration of the test instead of terminating after the configured timeout.Root Cause
The
Shutdownenum has two string representations:name()(Java enum name)getParam()(wire protocol value)DEFAULT"DEFAULT""testset"EXIT"EXIT""exit"KILL"KILL""kill"The sending side and receiving side used different representations:
Sending side (plugin):
Command.toShutdown(Shutdown.KILL)storedshutdownType.name()→"KILL", which was then serialized byCommandEncoder.sendShutdown("KILL")and sent over the binary command channel.Receiving side (forked JVM):
CommandDecoder.toMessage()extracted the string"KILL"from the wire and passed it toShutdown.parameterOf("KILL"), which iterates through enum values comparing againstshutdown.param:"testset".equals("KILL")→ false"exit".equals("KILL")→ false"kill".equals("KILL")→ false (case mismatch)Since nothing matched,
parameterOf()fell through and returnedShutdown.DEFAULT. The forked JVM'sForkedBooter.createExitHandler()then entered the else branch (neitherisKill()norisExit()), which only dumps a thread trace — the JVM continues running.Fix
toShutdown(): ChangedshutdownType.name()toshutdownType.getParam()so the wire protocol sends"kill"instead of"KILL"toShutdownData(): ChangedShutdown.valueOf(data)toShutdown.parameterOf(data)so the reverse conversion is consistentThis makes the sending side consistent with what the receiving side's
CommandDecoderalready expects viaShutdown.parameterOf().Verification
Tested with a project containing a single test that sleeps for 5 minutes with
forkedProcessTimeoutInSeconds=5. For the record, it is the sample that was shared here: #2049.Surefire is going to kill self fork JVM. Received SHUTDOWN {KILL} command from Maven shutdown hook.Checklist
Following this checklist to help us incorporate your contribution quickly and easily:
mvn clean installto make sure basic checks pass. A more thorough check will be performed on your pull request automatically.mvn -Prun-its clean install).If your pull request is about ~20 lines of code you don't need to sign an
Individual Contributor License Agreement if you are unsure
please ask on the developers list.
To make clear that you license your contribution under
the Apache License Version 2.0, January 2004
you have to acknowledge this by using the following check-box.