From 0546b09cfc6433f431461ec9f30ad9ae0e4c3f7e Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Fri, 10 Jan 2025 09:25:16 +0100 Subject: [PATCH] Excluding performance and integration tests from `build` task (#1925) This PR moves all tests in `cpg-neo4j` that depend on external frontends to an integration test and moves integration tests and performance tests out of the `build` task. Fixes #1915 --- .github/workflows/build.yml | 6 +- .gitignore | 2 + .../kotlin/cpg.common-conventions.gradle.kts | 93 +++++++-------- ...frontend-dependency-conventions.gradle.kts | 10 -- cpg-all/build.gradle.kts | 5 - .../fraunhofer/aisec/cpg/graph/WalkerTest.kt | 16 +-- .../cxx/PerformanceRegressionTest.kt | 108 ++++++++++++++++++ .../aisec/cpg/PerformanceRegressionTest.kt | 85 -------------- cpg-neo4j/build.gradle.kts | 11 +- .../fraunhofer/aisec/neo4j/IntegrationTest.kt | 108 ++++++++++++++++++ .../de/fraunhofer/aisec/neo4j}/Neo4JTest.kt | 2 +- .../resources/Implementor1.java | 0 .../resources/client.cpp | 0 .../resources/test.py | 0 .../resources/very_long.cpp | 0 .../aisec/cpg_vis_neo4j/ApplicationTest.kt | 77 +------------ cpg-neo4j/src/test/resources/log4j2.xml | 1 - settings.gradle.kts | 8 ++ 18 files changed, 298 insertions(+), 234 deletions(-) rename cpg-core/src/{test => performanceTest}/kotlin/de/fraunhofer/aisec/cpg/graph/WalkerTest.kt (90%) create mode 100644 cpg-language-cxx/src/performanceTest/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/PerformanceRegressionTest.kt create mode 100644 cpg-neo4j/src/integrationTest/kotlin/de/fraunhofer/aisec/neo4j/IntegrationTest.kt rename cpg-neo4j/src/{test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j => integrationTest/kotlin/de/fraunhofer/aisec/neo4j}/Neo4JTest.kt (98%) rename cpg-neo4j/src/{test => integrationTest}/resources/Implementor1.java (100%) rename cpg-neo4j/src/{test => integrationTest}/resources/client.cpp (100%) rename cpg-neo4j/src/{test => integrationTest}/resources/test.py (100%) rename cpg-neo4j/src/{test => integrationTest}/resources/very_long.cpp (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6e4eb15de5..47c3362df77 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,13 +72,13 @@ jobs: # See https://github.com/codecov/feedback/issues/564 and https://github.com/Kotlin/kotlinx-kover/issues/699. # Actually these lines should just not exist in the coverage XML file, since they are only structural elements, such # as brackets. - cat cpg-all/build/reports/kover/report.xml | grep -v 'mi="0" ci="0" mb="0" cb="0"' > cpg-all/build/reports/kover/report-codecov.xml - rm cpg-all/build/reports/kover/report.xml + cat ./build/reports/kover/report.xml | grep -v 'mi="0" ci="0" mb="0" cb="0"' > ./build/reports/kover/report-codecov.xml + rm ./build/reports/kover/report.xml - name: Upload Code Coverage uses: codecov/codecov-action@v5 with: fail_ci_if_error: true - files: ./cpg-all/build/reports/kover/report-codecov.xml + files: ./build/reports/kover/report-codecov.xml token: ${{ secrets.CODECOV_TOKEN }} verbose: true - name: Prepare test and coverage reports diff --git a/.gitignore b/.gitignore index 99d9338d5c1..5e328d74908 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ logs *.log gradle.properties +LibrariesTest.kt + diff --git a/buildSrc/src/main/kotlin/cpg.common-conventions.gradle.kts b/buildSrc/src/main/kotlin/cpg.common-conventions.gradle.kts index f3bd20c5bb1..c3ffde19690 100644 --- a/buildSrc/src/main/kotlin/cpg.common-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/cpg.common-conventions.gradle.kts @@ -1,20 +1,18 @@ import org.gradle.accessors.dm.LibrariesForLibs +import org.gradle.api.services.BuildServiceParameters.None import org.jetbrains.dokka.gradle.DokkaTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.gradle.api.services.BuildService; -import org.gradle.api.services.BuildServiceParameters; -import org.gradle.api.services.BuildServiceParameters.None; plugins { id("cpg.formatting-conventions") `java-library` + `jvm-test-suite` jacoco signing `maven-publish` kotlin("jvm") id("org.jetbrains.dokka") - id("org.jetbrains.kotlinx.kover") } java { @@ -112,64 +110,69 @@ tasks.withType { } } -// -// common testing configuration -// -tasks.test { - useJUnitPlatform() { - excludeTags("integration") - excludeTags("performance") - } +// Configure our test suites +@Suppress("UnstableApiUsage") +testing { + suites { + // The default unit-test suite + val test by getting(JvmTestSuite::class) { + useJUnitJupiter() + } - maxHeapSize = "4048m" -} + // Our integration tests + val integrationTest by registering(JvmTestSuite::class) { + description = "Runs the integration tests" + dependencies { + implementation(project()) + implementation(testFixtures(project(":cpg-core"))) + } -val integrationTest = tasks.register("integrationTest") { - description = "Runs integration tests." - group = "verification" - useJUnitPlatform() { - includeTags("integration") - } + // For legacy reasons we also include the unit-test resources in the integration tests, + // because some of them are shared + sources { + resources { + srcDirs("src/test/resources") + } + } - maxHeapSize = "4048m" + testType = TestSuiteType.INTEGRATION_TEST + } - shouldRunAfter(tasks.test) -} + // Our performance tests + val performanceTest by registering(JvmTestSuite::class) { + description = "Runs the performance tests" + dependencies { + implementation(project()) + implementation(testFixtures(project(":cpg-core"))) + } -val performanceTest = tasks.register("performanceTest") { - description = "Runs performance tests." - group = "verification" - useJUnitPlatform() { - includeTags("performance") + testType = TestSuiteType.PERFORMANCE_TEST + targets { + all { + testTask.configure { + // do not parallelize tests within the task + maxParallelForks = 1 + // make sure that several performance tests (e.g. in different frontends) also do NOT run in parallel + usesService(serialExecutionService) + } + } + } + } } - - maxHeapSize = "4048m" - - // do not parallelize tests within the task - maxParallelForks = 1 - // make sure that several performance tests (e.g. in different frontends) also do NOT run in parallel - usesService(serialExecutionService) } // A build service that ensures serial execution of a group of tasks -abstract class SerialExecutionService : BuildService +abstract class SerialExecutionService : BuildService val serialExecutionService = gradle.sharedServices.registerIfAbsent("serialExecution", SerialExecutionService::class.java) { this.maxParallelUsages.set(1) } -kover { - currentProject { - instrumentation { - disabledForTestTasks.add("performanceTest") - } - } -} - // Common dependencies that we need for all modules val libs = the() // necessary to be able to use the version catalog in buildSrc dependencies { implementation(libs.apache.commons.lang3) implementation(libs.neo4j.ogm.core) implementation(libs.jackson) -} \ No newline at end of file +} + diff --git a/buildSrc/src/main/kotlin/cpg.frontend-dependency-conventions.gradle.kts b/buildSrc/src/main/kotlin/cpg.frontend-dependency-conventions.gradle.kts index f482eecd480..0fa760fc5fe 100644 --- a/buildSrc/src/main/kotlin/cpg.frontend-dependency-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/cpg.frontend-dependency-conventions.gradle.kts @@ -1,7 +1,6 @@ plugins { kotlin("jvm") `java-library` - id("org.jetbrains.kotlinx.kover") } val enableJavaFrontend: Boolean by rootProject.extra @@ -17,38 +16,29 @@ val enableINIFrontend: Boolean by rootProject.extra dependencies { if (enableJavaFrontend) { api(project(":cpg-language-java")) - kover(project(":cpg-language-java")) } if (enableJVMFrontend) { api(project(":cpg-language-jvm")) - kover(project(":cpg-language-jvm")) } if (enableCXXFrontend) { api(project(":cpg-language-cxx")) - kover(project(":cpg-language-cxx")) } if (enableGoFrontend) { api(project(":cpg-language-go")) - kover(project(":cpg-language-go")) } if (enablePythonFrontend) { api(project(":cpg-language-python")) - kover(project(":cpg-language-python")) } if (enableLLVMFrontend) { api(project(":cpg-language-llvm")) - kover(project(":cpg-language-llvm")) } if (enableTypeScriptFrontend) { api(project(":cpg-language-typescript")) - kover(project(":cpg-language-typescript")) } if (enableRubyFrontend) { api(project(":cpg-language-ruby")) - kover(project(":cpg-language-ruby")) } if (enableINIFrontend) { api(project(":cpg-language-ini")) - kover(project(":cpg-language-ini")) } } diff --git a/cpg-all/build.gradle.kts b/cpg-all/build.gradle.kts index 18bd65c219c..46509d733c9 100644 --- a/cpg-all/build.gradle.kts +++ b/cpg-all/build.gradle.kts @@ -28,9 +28,4 @@ dependencies { api(projects.cpgCore) api(projects.cpgAnalysis) api(projects.cpgNeo4j) - - kover(projects.cpgConsole) - kover(projects.cpgCore) - kover(projects.cpgAnalysis) - kover(projects.cpgNeo4j) } diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/WalkerTest.kt b/cpg-core/src/performanceTest/kotlin/de/fraunhofer/aisec/cpg/graph/WalkerTest.kt similarity index 90% rename from cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/WalkerTest.kt rename to cpg-core/src/performanceTest/kotlin/de/fraunhofer/aisec/cpg/graph/WalkerTest.kt index 75c3bde6923..9699c13e090 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/WalkerTest.kt +++ b/cpg-core/src/performanceTest/kotlin/de/fraunhofer/aisec/cpg/graph/WalkerTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Fraunhofer AISEC. All rights reserved. + * Copyright (c) 2025, Fraunhofer AISEC. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,23 +25,23 @@ */ package de.fraunhofer.aisec.cpg.graph -import de.fraunhofer.aisec.cpg.graph.declarations.* +import de.fraunhofer.aisec.cpg.graph.declarations.FieldDeclaration +import de.fraunhofer.aisec.cpg.graph.declarations.MethodDeclaration +import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration +import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration +import de.fraunhofer.aisec.cpg.graph.declarations.VariableDeclaration import de.fraunhofer.aisec.cpg.graph.edges.astEdges import de.fraunhofer.aisec.cpg.graph.statements.DeclarationStatement import de.fraunhofer.aisec.cpg.graph.statements.expressions.Block import de.fraunhofer.aisec.cpg.graph.statements.expressions.Literal import de.fraunhofer.aisec.cpg.helpers.Benchmark import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker -import de.fraunhofer.aisec.cpg.test.* +import de.fraunhofer.aisec.cpg.test.BaseTest import java.time.Duration import java.time.temporal.ChronoUnit -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull -import org.junit.jupiter.api.Tag +import kotlin.test.* import org.junit.jupiter.api.assertTimeout -@Tag("performance") class WalkerTest : BaseTest() { @Test fun testWalkerSpeed() { diff --git a/cpg-language-cxx/src/performanceTest/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/PerformanceRegressionTest.kt b/cpg-language-cxx/src/performanceTest/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/PerformanceRegressionTest.kt new file mode 100644 index 00000000000..1bc636b658e --- /dev/null +++ b/cpg-language-cxx/src/performanceTest/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/PerformanceRegressionTest.kt @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025, Fraunhofer AISEC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $$$$$$\ $$$$$$$\ $$$$$$\ + * $$ __$$\ $$ __$$\ $$ __$$\ + * $$ / \__|$$ | $$ |$$ / \__| + * $$ | $$$$$$$ |$$ |$$$$\ + * $$ | $$ ____/ $$ |\_$$ | + * $$ | $$\ $$ | $$ | $$ | + * \$$$$$ |$$ | \$$$$$ | + * \______/ \__| \______/ + * + */ +package de.fraunhofer.aisec.cpg.frontends.cxx + +import de.fraunhofer.aisec.cpg.frontends.TestLanguageFrontend +import de.fraunhofer.aisec.cpg.graph.Node +import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration +import de.fraunhofer.aisec.cpg.graph.declarations.VariableDeclaration +import de.fraunhofer.aisec.cpg.graph.edges.ast.AstEdge +import de.fraunhofer.aisec.cpg.graph.newLiteral +import de.fraunhofer.aisec.cpg.graph.primitiveType +import de.fraunhofer.aisec.cpg.graph.statements.expressions.InitializerListExpression +import de.fraunhofer.aisec.cpg.helpers.Benchmark +import de.fraunhofer.aisec.cpg.test.analyzeAndGetFirstTU +import java.time.Duration +import java.time.temporal.ChronoUnit +import kotlin.io.path.createTempFile +import kotlin.io.path.writeText +import kotlin.test.* +import org.junit.jupiter.api.assertTimeout + +class PerformanceRegressionTest { + /** + * This test demonstrates two performance bottlenecks. + * * First, we want to make a large initializer list with literals and make sure we parse this + * in reasonable time. We had issues with literals and their hashcode when they were inserted + * into a set. + * * Second, we want to make that list essentially a one-liner because we had issues when + * populating the [de.fraunhofer.aisec.cpg.graph.Node.location] property using + * [CXXLanguageFrontend.locationOf]. + */ + @Test + fun testParseLargeList() { + val range = 0..40000 + // intentionally make this one very long line, because we had problems with that + val string = "static int my_array[] = {" + range.toList().joinToString(", ") + "};" + + val tmp = createTempFile("c_range", ".c") + tmp.writeText(string) + + // this should not exceed 30 seconds (it takes about 2800ms on a good machine, about + // 10-20s on GitHub, depending on the slowness of the runner) + assertTimeout(Duration.of(30, ChronoUnit.SECONDS)) { + val tu = + analyzeAndGetFirstTU(listOf(tmp.toFile()), tmp.parent, true) { + // No need for parallel processing for a single file. this might make it fast + // enough for those special moments where for some reasons the GitHub runners + // are slowing down (maybe because of some hidden quota). + it.useParallelFrontends(false) + it.registerLanguage() + } + assertNotNull(tu) + } + } + + @Test + fun testTraversal() { + with(TestLanguageFrontend()) { + val tu = TranslationUnitDeclaration() + val decl = VariableDeclaration() + val list = InitializerListExpression() + + for (i in 0 until 50000) { + list.initializerEdges.add(AstEdge(list, newLiteral(i, primitiveType("int"), null))) + } + + decl.initializer = list + tu.addDeclaration(decl) + + // Even on a slow machine, this should not exceed 1 second (it should be more like + // 200-300ms) + assertTimeout(Duration.of(1, ChronoUnit.SECONDS)) { + val b = Benchmark(PerformanceRegressionTest::class.java, "getAstChildren") + doNothing(tu) + b.addMeasurement() + } + } + } + + fun doNothing(node: Node) { + for (child in node.astChildren) { + doNothing(child) + } + } +} diff --git a/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/PerformanceRegressionTest.kt b/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/PerformanceRegressionTest.kt index a1afbe40ffc..d23b7b7a8a4 100644 --- a/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/PerformanceRegressionTest.kt +++ b/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/PerformanceRegressionTest.kt @@ -24,88 +24,3 @@ * */ package de.fraunhofer.aisec.cpg - -import de.fraunhofer.aisec.cpg.frontends.TestLanguageFrontend -import de.fraunhofer.aisec.cpg.frontends.cxx.CLanguage -import de.fraunhofer.aisec.cpg.frontends.cxx.CXXLanguageFrontend -import de.fraunhofer.aisec.cpg.graph.Node -import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration -import de.fraunhofer.aisec.cpg.graph.declarations.VariableDeclaration -import de.fraunhofer.aisec.cpg.graph.edges.ast.AstEdge -import de.fraunhofer.aisec.cpg.graph.newLiteral -import de.fraunhofer.aisec.cpg.graph.primitiveType -import de.fraunhofer.aisec.cpg.graph.statements.expressions.InitializerListExpression -import de.fraunhofer.aisec.cpg.helpers.Benchmark -import de.fraunhofer.aisec.cpg.test.* -import java.time.Duration -import java.time.temporal.ChronoUnit -import kotlin.io.path.writeText -import kotlin.test.Test -import kotlin.test.assertNotNull -import org.junit.jupiter.api.Tag -import org.junit.jupiter.api.assertTimeout - -@Tag("performance") -class PerformanceRegressionTest { - /** - * This test demonstrates two performance bottlenecks. - * * First, we want to make a large initializer list with literals and make sure we parse this - * in reasonable time. We had issues with literals and their hashcode when they were inserted - * into a set. - * * Second, we want to make that list essentially a one-liner because we had issues when - * populating the [Node.location] property using [CXXLanguageFrontend.locationOf]. - */ - @Test - fun testParseLargeList() { - val range = 0..40000 - // intentionally make this one very long line, because we had problems with that - val string = "static int my_array[] = {" + range.toList().joinToString(", ") + "};" - - val tmp = kotlin.io.path.createTempFile("c_range", ".c") - tmp.writeText(string) - - // this should not exceed 30 seconds (it takes about 2800ms on a good machine, about - // 10-20s on GitHub, depending on the slowness of the runner) - assertTimeout(Duration.of(30, ChronoUnit.SECONDS)) { - val tu = - analyzeAndGetFirstTU(listOf(tmp.toFile()), tmp.parent, true) { - // No need for parallel processing for a single file. this might make it fast - // enough for those special moments where for some reasons the GitHub runners - // are slowing down (maybe because of some hidden quota). - it.useParallelFrontends(false) - it.registerLanguage() - } - assertNotNull(tu) - } - } - - @Test - fun testTraversal() { - with(TestLanguageFrontend()) { - val tu = TranslationUnitDeclaration() - val decl = VariableDeclaration() - val list = InitializerListExpression() - - for (i in 0 until 50000) { - list.initializerEdges.add(AstEdge(list, newLiteral(i, primitiveType("int"), null))) - } - - decl.initializer = list - tu.addDeclaration(decl) - - // Even on a slow machine, this should not exceed 1 second (it should be more like - // 200-300ms) - assertTimeout(Duration.of(1, ChronoUnit.SECONDS)) { - val b = Benchmark(PerformanceRegressionTest::class.java, "getAstChildren") - doNothing(tu) - b.addMeasurement() - } - } - } - - fun doNothing(node: Node) { - for (child in node.astChildren) { - doNothing(child) - } - } -} diff --git a/cpg-neo4j/build.gradle.kts b/cpg-neo4j/build.gradle.kts index 8a626188037..d9c1e0b4b75 100644 --- a/cpg-neo4j/build.gradle.kts +++ b/cpg-neo4j/build.gradle.kts @@ -48,13 +48,16 @@ publishing { } dependencies { - // neo4j + // Neo4j OGM. This will be removed at some point implementation(libs.bundles.neo4j) - implementation(libs.neo4j.driver) + integrationTestImplementation(libs.bundles.neo4j) + + // Neo4J Driver + api(libs.neo4j.driver) // Command line interface support - implementation(libs.picocli) + api(libs.picocli) annotationProcessor(libs.picocli.codegen) - testImplementation(testFixtures(projects.cpgCore)) + integrationTestImplementation(libs.kotlin.reflect) } diff --git a/cpg-neo4j/src/integrationTest/kotlin/de/fraunhofer/aisec/neo4j/IntegrationTest.kt b/cpg-neo4j/src/integrationTest/kotlin/de/fraunhofer/aisec/neo4j/IntegrationTest.kt new file mode 100644 index 00000000000..a13b4e44490 --- /dev/null +++ b/cpg-neo4j/src/integrationTest/kotlin/de/fraunhofer/aisec/neo4j/IntegrationTest.kt @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025, Fraunhofer AISEC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $$$$$$\ $$$$$$$\ $$$$$$\ + * $$ __$$\ $$ __$$\ $$ __$$\ + * $$ / \__|$$ | $$ |$$ / \__| + * $$ | $$$$$$$ |$$ |$$$$\ + * $$ | $$ ____/ $$ |\_$$ | + * $$ | $$\ $$ | $$ | $$ | + * \$$$$$ |$$ | \$$$$$ | + * \______/ \__| \______/ + * + */ +package de.fraunhofer.aisec.neo4j + +import de.fraunhofer.aisec.cpg.TranslationManager +import de.fraunhofer.aisec.cpg.TranslationResult +import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration +import de.fraunhofer.aisec.cpg.graph.functions +import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression +import de.fraunhofer.aisec.cpg_vis_neo4j.Application +import java.nio.file.Paths +import kotlin.io.path.createTempFile +import kotlin.reflect.jvm.javaField +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.neo4j.ogm.annotation.Relationship +import picocli.CommandLine + +fun createTranslationResult(file: String = "client.cpp"): Pair { + val topLevel = Paths.get("src").resolve("integrationTest").resolve("resources").toAbsolutePath() + val path = topLevel.resolve(file).toAbsolutePath() + + val cmd = CommandLine(Application::class.java) + cmd.parseArgs(path.toString()) + val application = cmd.getCommand() + + val translationConfiguration = application.setupTranslationConfiguration() + val translationResult = + TranslationManager.builder().config(translationConfiguration).build().analyze().get() + return application to translationResult +} + +/** + * A class for integration tests. They depend on the C++ frontend, so we classify them as an + * integration test. This might be replaced with a language-neutral test at some point. + */ +@Tag("integration") +class IntegrationTest { + + @Test + fun testBuildJsonGraph() { + val (application, translationResult) = createTranslationResult() + + // 22 inferred functions, 1 inferred method, 2 inferred constructors, 11 regular functions + assertEquals(36, translationResult.functions.size) + + val (nodes, edges) = application.translateCPGToOGMBuilders(translationResult) + val graph = application.buildJsonGraph(nodes, edges) + val connectToFuncDel = + graph.nodes.firstOrNull { + it.labels.contains(FunctionDeclaration::class.simpleName) && + it.properties["name"] == "connectTo" + } + assertNotNull(connectToFuncDel) + + val connectToCallExpr = + graph.nodes.firstOrNull { + it.labels.contains(CallExpression::class.simpleName) && + it.properties["name"] == "connectTo" + } + assertNotNull(connectToCallExpr) + + val invokesEdge = + graph.edges.firstOrNull { + it.type == + (CallExpression::invokeEdges.javaField?.getAnnotation(Relationship::class.java)) + ?.value && + it.startNode == connectToCallExpr.id && + it.endNode == connectToFuncDel.id + } + assertNotNull(invokesEdge) + } + + @Test + fun testExportToJson() { + val (application, translationResult) = createTranslationResult() + // 22 inferred functions, 1 inferred method, 2 inferred constructors, 11 regular functions + assertEquals(36, translationResult.functions.size) + val path = createTempFile().toFile() + application.exportToJson(translationResult, path) + assert(path.length() > 0) + } +} diff --git a/cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/Neo4JTest.kt b/cpg-neo4j/src/integrationTest/kotlin/de/fraunhofer/aisec/neo4j/Neo4JTest.kt similarity index 98% rename from cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/Neo4JTest.kt rename to cpg-neo4j/src/integrationTest/kotlin/de/fraunhofer/aisec/neo4j/Neo4JTest.kt index de614e54db8..6d1100384b0 100644 --- a/cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/Neo4JTest.kt +++ b/cpg-neo4j/src/integrationTest/kotlin/de/fraunhofer/aisec/neo4j/Neo4JTest.kt @@ -23,7 +23,7 @@ * \______/ \__| \______/ * */ -package de.fraunhofer.aisec.cpg_vis_neo4j +package de.fraunhofer.aisec.neo4j import de.fraunhofer.aisec.cpg.graph.* import de.fraunhofer.aisec.cpg.graph.concepts.Concept diff --git a/cpg-neo4j/src/test/resources/Implementor1.java b/cpg-neo4j/src/integrationTest/resources/Implementor1.java similarity index 100% rename from cpg-neo4j/src/test/resources/Implementor1.java rename to cpg-neo4j/src/integrationTest/resources/Implementor1.java diff --git a/cpg-neo4j/src/test/resources/client.cpp b/cpg-neo4j/src/integrationTest/resources/client.cpp similarity index 100% rename from cpg-neo4j/src/test/resources/client.cpp rename to cpg-neo4j/src/integrationTest/resources/client.cpp diff --git a/cpg-neo4j/src/test/resources/test.py b/cpg-neo4j/src/integrationTest/resources/test.py similarity index 100% rename from cpg-neo4j/src/test/resources/test.py rename to cpg-neo4j/src/integrationTest/resources/test.py diff --git a/cpg-neo4j/src/test/resources/very_long.cpp b/cpg-neo4j/src/integrationTest/resources/very_long.cpp similarity index 100% rename from cpg-neo4j/src/test/resources/very_long.cpp rename to cpg-neo4j/src/integrationTest/resources/very_long.cpp diff --git a/cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/ApplicationTest.kt b/cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/ApplicationTest.kt index e121a98116d..8fb229702e8 100644 --- a/cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/ApplicationTest.kt +++ b/cpg-neo4j/src/test/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/ApplicationTest.kt @@ -26,83 +26,16 @@ package de.fraunhofer.aisec.cpg_vis_neo4j import com.fasterxml.jackson.databind.ObjectMapper -import de.fraunhofer.aisec.cpg.TranslationManager -import de.fraunhofer.aisec.cpg.TranslationResult import de.fraunhofer.aisec.cpg.graph.* -import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration -import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression import java.io.File import java.nio.file.Files -import java.nio.file.Paths import kotlin.io.path.Path -import kotlin.io.path.createTempFile -import kotlin.reflect.jvm.javaField import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull -import org.neo4j.ogm.annotation.Relationship -import picocli.CommandLine - -fun createTranslationResult(file: String = "client.cpp"): Pair { - val topLevel = Paths.get("src").resolve("test").resolve("resources").toAbsolutePath() - val path = topLevel.resolve(file).toAbsolutePath() - - val cmd = CommandLine(Application::class.java) - cmd.parseArgs(path.toString()) - val application = cmd.getCommand() - - val translationConfiguration = application.setupTranslationConfiguration() - val translationResult = - TranslationManager.builder().config(translationConfiguration).build().analyze().get() - return application to translationResult -} +import kotlin.test.assertIs +import kotlin.test.assertTrue class ApplicationTest { - @Test - fun testSerializeCpgViaOGM() { - val (application, translationResult) = createTranslationResult() - - // 22 inferred functions, 1 inferred method, 2 inferred constructors, 11 regular functions - assertEquals(36, translationResult.functions.size) - - val (nodes, edges) = application.translateCPGToOGMBuilders(translationResult) - val graph = application.buildJsonGraph(nodes, edges) - val connectToFuncDel = - graph.nodes.firstOrNull { - it.labels.contains(FunctionDeclaration::class.simpleName) && - it.properties["name"] == "connectTo" - } - assertNotNull(connectToFuncDel) - - val connectToCallExpr = - graph.nodes.firstOrNull { - it.labels.contains(CallExpression::class.simpleName) && - it.properties["name"] == "connectTo" - } - assertNotNull(connectToCallExpr) - - val invokesEdge = - graph.edges.firstOrNull { - it.type == - (CallExpression::invokeEdges.javaField?.getAnnotation(Relationship::class.java)) - ?.value && - it.startNode == connectToCallExpr.id && - it.endNode == connectToFuncDel.id - } - assertNotNull(invokesEdge) - } - - @Test - fun testExportToJson() { - val (application, translationResult) = createTranslationResult() - // 22 inferred functions, 1 inferred method, 2 inferred constructors, 11 regular functions - assertEquals(36, translationResult.functions.size) - val path = createTempFile().toFile() - application.exportToJson(translationResult, path) - assert(path.length() > 0) - } - @Test fun testExportMarkdownSchema() { val path = "./tmp.md" @@ -118,10 +51,10 @@ class ApplicationTest { val path = "./tmp.json" Application().printSchema(listOf(path), Schema.Format.JSON) val file = File(path) - val objectMapper: ObjectMapper = ObjectMapper() + val objectMapper = ObjectMapper() val schema = objectMapper.readValue(file, List::class.java) - assert(schema is ArrayList) - assert((schema as ArrayList).size > 0) + assertIs>(schema) + assertTrue(schema.isNotEmpty()) Files.deleteIfExists(Path(path)) } } diff --git a/cpg-neo4j/src/test/resources/log4j2.xml b/cpg-neo4j/src/test/resources/log4j2.xml index 7f97d16dbdb..7ccfa262f56 100644 --- a/cpg-neo4j/src/test/resources/log4j2.xml +++ b/cpg-neo4j/src/test/resources/log4j2.xml @@ -7,7 +7,6 @@ - diff --git a/settings.gradle.kts b/settings.gradle.kts index 78d929ce31f..dea0da5cfef 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,9 @@ rootProject.name = "cpg" +plugins { + id("org.jetbrains.kotlinx.kover.aggregation") version "0.9.0" +} + enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") include(":cpg-all") @@ -55,3 +59,7 @@ if (enableTypeScriptFrontend) include(":cpg-language-typescript") if (enableRubyFrontend) include(":cpg-language-ruby") if (enableJVMFrontend) include(":cpg-language-jvm") if (enableINIFrontend) include(":cpg-language-ini") + +kover { + enableCoverage() +} \ No newline at end of file