fitnesse icon indicating copy to clipboard operation
fitnesse copied to clipboard

`fitnesse.slim.instructions.SystemExitSecurityManager` triggers `NoClassDefFoundError` issue

Open rbastiaansen732 opened this issue 3 years ago • 3 comments

Describe the bug fitnesse.slim.instructions.SystemExitSecurityManager triggers NoClassDefFoundError issues in a dockerized spring-boot SlimServer on JDK11.

Thanks to the prevent.system.exit=false system property, there is a workaround.

Fitnesse is included as maven dependency in my spring-boot app.

<fitnesse.version>20220319</fitnesse.version>
<spring-boot.version>2.6.7</spring-boot.version>
<java.version>11</java.version>
<dependency>
    <groupId>org.fitnesse</groupId>
    <artifactId>fitnesse</artifactId>
    <version>${fitnesse.version}</version>
</dependency>

Workaround In my docker build, I have the option to add an environment variable JAVA_OPTS -Dprevent.system.exit=false to skip fitnesse.slim.instructions.SystemExitSecurityManager. Or else dynamic class loading fails with NoClassDefFoundError in a dockerized spring-boot SlimServer.

Stack Trace

__EXCEPTION__:java.lang.NoClassDefFoundError: fitnesse/slim/SlimSymbol
	at fitnesse.slim.VariableStore.replaceSymbolsInString(VariableStore.java:80) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.SlimExecutionContext.create(SlimExecutionContext.java:51) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.StatementExecutor.create(StatementExecutor.java:88) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.instructions.MakeInstruction.executeInternal(MakeInstruction.java:26) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.instructions.Instruction.execute(Instruction.java:29) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.ListExecutor$Executive.executeStatement(ListExecutor.java:49) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.ListExecutor$Executive.executeStatements(ListExecutor.java:43) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.ListExecutor.execute(ListExecutor.java:85) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.SlimServer.executeInstructions(SlimServer.java:82) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.SlimServer.processOneSetOfInstructions(SlimServer.java:75) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.SlimServer.tryProcessInstructions(SlimServer.java:62) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.SlimServer.serve(SlimServer.java:47) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
__EXCEPTION__:java.lang.NoClassDefFoundError: fitnesse/slim/MethodExecutionResults
	at fitnesse.slim.StatementExecutor.getMethodExecutionResult(StatementExecutor.java:133) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.StatementExecutor.call(StatementExecutor.java:112) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.instructions.CallAndOptionalAssignInstruction.executeInternal(CallAndOptionalAssignInstruction.java:30) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.instructions.Instruction.execute(Instruction.java:29) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.ListExecutor$Executive.executeStatement(ListExecutor.java:49) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.ListExecutor$Executive.executeStatements(ListExecutor.java:43) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.ListExecutor.execute(ListExecutor.java:85) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.SlimServer.executeInstructions(SlimServer.java:82) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.SlimServer.processOneSetOfInstructions(SlimServer.java:75) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.SlimServer.tryProcessInstructions(SlimServer.java:62) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]
	at fitnesse.slim.SlimServer.serve(SlimServer.java:47) [jar:file:/app/app.jar!/BOOT-INF/lib/fitnesse-20220319.jar!/:20220319]

rbastiaansen732 avatar Aug 30 '22 13:08 rbastiaansen732

Can you share a sample Dockerfile and pom.xml so we can reproduce the problem?

On a side note: can you give some background why you create a sprint-boot application including FitNesse? In my understanding sprint-boot is a tool to easily create a Java command line application or web application with server. And FitNesse already is a standalone application that you can either use as a command line tool to run tests or as a web server. Why not put that directly in a docker container, what does sprint-boot add?

fhoeben avatar Aug 31 '22 07:08 fhoeben

Thank you for your response.

It is a requirement for the organization's platform that all apps are build from a specific docker image in CI/CD pipeline. The app contains a SlimServer and a set of domain specific fixtures that depend on domain Spring beans. Another app contains the HtmlSlimTestSystem and it sends the requests to the SlimServer.

The DockerFile is just a one liner with a specific builder docker image. The pom.xml includes the xml in the original post.

I am fine with closing this ticket. The ticket will serve as a note for future reference.

rbastiaansen732 avatar Aug 31 '22 10:08 rbastiaansen732

If I recall correctly sprint boot uses a special/custom classloader. I suspect something goes wrong in the interactions between the FitNesse and Spring classloading.

fhoeben avatar Aug 31 '22 10:08 fhoeben