11package com .ibm .cldk ;
22
3+ import com .google .gson .Gson ;
4+ import com .google .gson .JsonArray ;
5+ import com .google .gson .JsonElement ;
6+ import com .google .gson .JsonObject ;
7+ import org .json .JSONArray ;
38import org .junit .jupiter .api .BeforeAll ;
49import org .junit .jupiter .api .Test ;
510import org .junit .jupiter .api .Assertions ;
611import org .testcontainers .containers .BindMode ;
712import org .testcontainers .containers .GenericContainer ;
13+ import org .testcontainers .containers .startupcheck .OneShotStartupCheckStrategy ;
814import org .testcontainers .junit .jupiter .Container ;
915import org .testcontainers .junit .jupiter .Testcontainers ;
1016import org .testcontainers .utility .MountableFile ;
1319import java .io .FileInputStream ;
1420import java .io .IOException ;
1521import java .nio .file .Paths ;
22+ import java .time .Duration ;
1623import java .util .Properties ;
24+ import java .util .stream .StreamSupport ;
1725
1826
1927@ Testcontainers
@@ -25,7 +33,7 @@ public class CodeAnalyzerIntegrationTest {
2533 */
2634 static String codeanalyzerVersion ;
2735 static final String javaVersion = "17" ;
28-
36+ static String javaHomePath ;
2937 static {
3038 // Build project first
3139 try {
@@ -41,16 +49,14 @@ public class CodeAnalyzerIntegrationTest {
4149 }
4250
4351 @ Container
44- static final GenericContainer <?> container = new GenericContainer <>("openjdk:17-jdk " )
52+ static final GenericContainer <?> container = new GenericContainer <>("ubuntu:latest " )
4553 .withCreateContainerCmdModifier (cmd -> cmd .withEntrypoint ("sh" ))
4654 .withCommand ("-c" , "while true; do sleep 1; done" )
47- .withFileSystemBind (
48- String .valueOf (Paths .get (System .getProperty ("user.dir" )).resolve ("build/libs" )),
49- "/opt/jars" ,
50- BindMode .READ_WRITE )
55+ .withCopyFileToContainer (MountableFile .forHostPath (Paths .get (System .getProperty ("user.dir" )).resolve ("build/libs" )), "/opt/jars" )
5156 .withCopyFileToContainer (MountableFile .forHostPath (Paths .get (System .getProperty ("user.dir" )).resolve ("build/libs" )), "/opt/jars" )
5257 .withCopyFileToContainer (MountableFile .forHostPath (Paths .get (System .getProperty ("user.dir" )).resolve ("src/test/resources/test-applications/mvnw-corrupt-test" )), "/test-applications/mvnw-corrupt-test" )
5358 .withCopyFileToContainer (MountableFile .forHostPath (Paths .get (System .getProperty ("user.dir" )).resolve ("src/test/resources/test-applications/plantsbywebsphere" )), "/test-applications/plantsbywebsphere" )
59+ .withCopyFileToContainer (MountableFile .forHostPath (Paths .get (System .getProperty ("user.dir" )).resolve ("src/test/resources/test-applications/call-graph-test" )), "/test-applications/call-graph-test" )
5460 .withCopyFileToContainer (MountableFile .forHostPath (Paths .get (System .getProperty ("user.dir" )).resolve ("src/test/resources/test-applications/mvnw-working-test" )), "/test-applications/mvnw-working-test" );
5561
5662 @ Container
@@ -62,8 +68,29 @@ public class CodeAnalyzerIntegrationTest {
6268 .withCopyFileToContainer (MountableFile .forHostPath (Paths .get (System .getProperty ("user.dir" )).resolve ("src/test/resources/test-applications/mvnw-working-test" )), "/test-applications/mvnw-working-test" )
6369 .withCopyFileToContainer (MountableFile .forHostPath (Paths .get (System .getProperty ("user.dir" )).resolve ("src/test/resources/test-applications/daytrader8" )), "/test-applications/daytrader8" );
6470
71+ public CodeAnalyzerIntegrationTest () throws IOException , InterruptedException {
72+ }
73+
6574 @ BeforeAll
6675 static void setUp () {
76+ // Install Java 17 in the base container
77+ try {
78+ container .execInContainer ("apt-get" , "update" );
79+ container .execInContainer ("apt-get" , "install" , "-y" , "openjdk-17-jdk" );
80+
81+ // Get JAVA_HOME dynamically
82+ var javaHomeResult = container .execInContainer ("bash" , "-c" ,
83+ "dirname $(dirname $(readlink -f $(which java)))"
84+ );
85+ javaHomePath = javaHomeResult .getStdout ().trim ();
86+ Assertions .assertFalse (javaHomePath .isEmpty (), "Failed to determine JAVA_HOME" );
87+
88+ } catch (IOException | InterruptedException e ) {
89+ throw new RuntimeException (e );
90+ }
91+
92+
93+ // Get the version of the codeanalyzer jar
6794 Properties properties = new Properties ();
6895 try (FileInputStream fis = new FileInputStream (
6996 Paths .get (System .getProperty ("user.dir" ), "gradle.properties" ).toFile ())) {
@@ -92,18 +119,42 @@ void shouldHaveCodeAnalyzerJar() throws Exception {
92119 @ Test
93120 void shouldBeAbleToRunCodeAnalyzer () throws Exception {
94121 var runCodeAnalyzerJar = container .execInContainer (
95- "java" ,
96- "-jar" ,
97- String .format ("/opt/jars/codeanalyzer-%s.jar" , codeanalyzerVersion ),
98- "--help"
99- );
122+ "bash" , "-c" ,
123+ String .format ("export JAVA_HOME=%s && java -jar /opt/jars/codeanalyzer-%s.jar --help" ,
124+ javaHomePath , codeanalyzerVersion
125+ ));
100126
101127 Assertions .assertEquals (0 , runCodeAnalyzerJar .getExitCode (),
102128 "Command should execute successfully" );
103129 Assertions .assertTrue (runCodeAnalyzerJar .getStdout ().length () > 0 ,
104130 "Should have some output" );
105131 }
106132
133+ @ Test
134+ void callGraphShouldHaveKnownEdges () throws Exception {
135+ var runCodeAnalyzerOnCallGraphTest = container .execInContainer (
136+ "bash" , "-c" ,
137+ String .format (
138+ "export JAVA_HOME=%s && java -jar /opt/jars/codeanalyzer-%s.jar --input=/test-applications/call-graph-test --analysis-level=2" ,
139+ javaHomePath , codeanalyzerVersion
140+ )
141+ );
142+
143+
144+ // Read the output JSON
145+ Gson gson = new Gson ();
146+ JsonObject jsonObject = gson .fromJson (runCodeAnalyzerOnCallGraphTest .getStdout (), JsonObject .class );
147+ JsonArray systemDepGraph = jsonObject .getAsJsonArray ("system_dependency_graph" );
148+ Assertions .assertTrue (StreamSupport .stream (systemDepGraph .spliterator (), false )
149+ .map (JsonElement ::getAsJsonObject )
150+ .anyMatch (entry ->
151+ "CALL_DEP" .equals (entry .get ("type" ).getAsString ()) &&
152+ "1" .equals (entry .get ("weight" ).getAsString ()) &&
153+ entry .getAsJsonObject ("source" ).get ("signature" ).getAsString ().equals ("helloString()" ) &&
154+ entry .getAsJsonObject ("target" ).get ("signature" ).getAsString ().equals ("log()" )
155+ ), "Expected edge not found in the system dependency graph" );
156+ }
157+
107158 @ Test
108159 void corruptMavenShouldNotBuildWithWrapper () throws IOException , InterruptedException {
109160 // Make executable
@@ -131,42 +182,44 @@ void corruptMavenShouldProduceAnalysisArtifactsWhenMVNCommandIsInPath() throws I
131182
132183 @ Test
133184 void corruptMavenShouldNotTerminateWithErrorWhenMavenIsNotPresentUnlessAnalysisLevel2 () throws IOException , InterruptedException {
134- // When javaee level 2, we should get a Runtime Exception
185+ // When analysis level 2, we should get a Runtime Exception
135186 var runCodeAnalyzer = container .execInContainer (
136- "java" ,
137- "-jar" ,
138- String .format ("/opt/jars/codeanalyzer-%s.jar" , codeanalyzerVersion ),
139- "--input=/test-applications/mvnw-corrupt-test" ,
140- "--output=/tmp/" ,
141- "--analysis-level=2"
187+ "bash" , "-c" ,
188+ String .format (
189+ "export JAVA_HOME=%s && java -jar /opt/jars/codeanalyzer-%s.jar --input=/test-applications/mvnw-corrupt-test --output=/tmp/ --analysis-level=2" ,
190+ javaHomePath , codeanalyzerVersion
191+ )
142192 );
193+
143194 Assertions .assertEquals (1 , runCodeAnalyzer .getExitCode ());
144195 Assertions .assertTrue (runCodeAnalyzer .getStderr ().contains ("java.lang.RuntimeException" ));
145196 }
146197
147198 @ Test
148199 void shouldBeAbleToGenerateAnalysisArtifactForDaytrader8 () throws Exception {
149200 var runCodeAnalyzerOnDaytrader8 = mavenContainer .execInContainer (
150- "java " ,
151- "-jar" ,
152- String . format ( " /opt/jars/codeanalyzer-%s.jar" , codeanalyzerVersion ) ,
153- "--input=/test-applications/daytrader8" ,
154- "--analysis-level=1"
201+ "bash" , "-c " ,
202+ String . format (
203+ "export JAVA_HOME=%s && java -jar /opt/jars/codeanalyzer-%s.jar --input=/test-applications/daytrader8 --analysis-level=1" ,
204+ javaHomePath , codeanalyzerVersion
205+ )
155206 );
207+
156208 Assertions .assertTrue (runCodeAnalyzerOnDaytrader8 .getStdout ().contains ("\" is_entrypoint_class\" : true" ), "No entry point classes found" );
157209 Assertions .assertTrue (runCodeAnalyzerOnDaytrader8 .getStdout ().contains ("\" is_entrypoint\" : true" ), "No entry point methods found" );
158210 }
159211
160212 @ Test
161213 void shouldBeAbleToDetectCRUDOperationsAndQueriesForPlantByWebsphere () throws Exception {
162214 var runCodeAnalyzerOnPlantsByWebsphere = container .execInContainer (
163- "java " ,
164- "-jar" ,
165- String . format ( " /opt/jars/codeanalyzer-%s.jar" , codeanalyzerVersion ) ,
166- "--input=/test-applications/plantsbywebsphere" ,
167- "--analysis-level=1" , "--verbose"
215+ "bash" , "-c " ,
216+ String . format (
217+ "export JAVA_HOME=%s && java -jar /opt/jars/codeanalyzer-%s.jar --input=/test-applications/plantsbywebsphere --analysis-level=1 --verbose" ,
218+ javaHomePath , codeanalyzerVersion
219+ )
168220 );
169221
222+
170223 String output = runCodeAnalyzerOnPlantsByWebsphere .getStdout ();
171224
172225 Assertions .assertTrue (output .contains ("\" query_type\" : \" NAMED\" " ), "No entry point classes found" );
0 commit comments