<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>eu.exeris</groupId>
        <artifactId>exeris-kernel-parent</artifactId>
        <version>0.12.0</version>
        <relativePath>../exeris-kernel-parent/pom.xml</relativePath>
    </parent>
    <artifactId>exeris-kernel-community</artifactId>

    <name>Exeris Kernel :: Community</name>
    <description>
        Free-tier Community implementations: CommunityMemoryProvider (Arena-based),
        CommunityKernelCryptoProvider (OpenSSL 3.x / TCP-only, no QUIC),
        CommunityTelemetryProvider (Console, JFR, File sinks).
    </description>
    <url>https://github.com/exeris-systems/exeris-kernel</url>

    <properties>
        <exeris.module.name>eu.exeris.kernel.community</exeris.module.name>
        <!-- Empty by default; can be set to run only selected @Tag groups -->
        <includedGroups/>
        <!--
            Flamegraph harness tests run a 1M-VT avalanche and must never execute in CI
            by default. Stress tests (heavy multi-engine concurrency) are excluded from
            default CI gates because constrained runners (2 vCPU GitHub Actions) deadlock
            under thread pressure even when the same test passes deterministically locally
            in <500 ms. See ROADMAP TCK-064 for the underlying investigation.
            They are excluded from all Surefire runs unless explicitly enabled via:
              mvn test -DincludedGroups=flamegraph -DexcludedGroups=
              mvn test -DincludedGroups=stress    -DexcludedGroups=
              mvn test -Dtest=NativeTcpTransportStressTest (targeted-test-run profile)

            transport-pinning-recv (TCK-064 client RECV carrier-pinning regression) is
            also excluded from the default Surefire execution, but UNLIKE flamegraph/stress
            it is NOT skipped in CI: it runs in a dedicated forked Surefire execution
            (id=transport-pinning-recv) below, pinned to the faithful 2-vCPU carrier model
            (-Djdk.virtualThreadScheduler.parallelism=2 / maxPoolSize=2). It must run in its
            own fork because the scarce-carrier VT-scheduler args would otherwise distort
            every other test in the default execution.

            stream-loopback (ADR-043 SSE streaming TCK + JFR — CommunityHttpStreamExchangeTckTest,
            CommunityHttpStreamJfrTest) is excluded from CI like flamegraph/stress, for the same
            reason: each case spins a real NIO server + socket client + per-stream VT emit loop and
            asserts disconnect / backpressure-park / JFR-event timing within a bounded window. On
            constrained 2-vCPU runners the loopback (server reactor + handler VT + client) starves
            and even the happy-path round-trip times out, though it passes deterministically on
            many-core boxes. CI gates the fast, non-loopback streaming layer instead
            (SseEventEncoderTest, HttpRouterTest streaming registration,
            CommunityStreamResolutionDelegationTest, the ArchTest Wall pin), plus one real-boot
            stream test, GeneratedAppStreamRouteReachabilityIntegrationTest: each of its streams
            emits one event and closes and its client reads to end of stream, so it holds no stream
            open and asserts no timing window. It is the default build's only proof that a stream
            route resolves behind a forwarder over a real boot, so it carries neither this tag nor
            integration; docs/subsystems/http.md §Test gating records its 2-carrier measurement.
            Run the loopback suite on demand:
              mvn test -DincludedGroups=stream-loopback -DexcludedGroups=
              mvn test -Dtest=CommunityHttpStreamExchangeTckTest (targeted-test-run profile)
            Making it CI-gateable (reactor/handler scheduling robustness under scarce carriers) is a
            tracked follow-up.

            default-trust (CommunityTlsDefaultTrustTest) runs in its own forked execution below,
            which sets SSL_CERT_FILE and SSL_CERT_DIR for it. openssl-matrix
            (CommunityOpenSslPinnedMajorTest) runs only in the tls-openssl-matrix CI job, which
            selects it by name with -Dexeris.test.expectedOpenSslMajor set; without that property it
            has nothing to assert, and it fails rather than skips.
        -->
        <excludedGroups>flamegraph,integration,stress,transport-pinning-recv,continuity,stream-loopback,default-trust,openssl-matrix</excludedGroups>

        <!--
            v0.8 Sprint 6 (Coverage C-P0-01): LINE coverage floor for the Community bundle.
            Current measurement: ~69% from unit suite + IntegrationTest-named tests.
            Several @Tag("integration") tests live in this module but only the
            persistence-rls-gate CI job runs them (separate jacoco.exec). Ratchet at
            0.55 — keeps headroom for the IT-coverage-not-merged gap, but blocks
            unit-suite regressions.
        -->
        <jacoco.line.minimum>0.55</jacoco.line.minimum>
        <!-- BRANCH baseline 2026-06-10: 57.3% (1940/3385), unit-only (IT not merged).
             Ratchet ~7 pp below. -->
        <jacoco.branch.minimum>0.50</jacoco.branch.minimum>
    </properties>

    <dependencies>
        <!-- SPI contracts — The Wall -->
        <dependency>
            <groupId>eu.exeris</groupId>
            <artifactId>exeris-kernel-spi</artifactId>
        </dependency>
        <!-- AbstractLoanedBuffer lives in core -->
        <dependency>
            <groupId>eu.exeris</groupId>
            <artifactId>exeris-kernel-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jctools</groupId>
            <artifactId>jctools-core</artifactId>
        </dependency>
        <!-- TCK abstract test classes -->
        <dependency>
            <groupId>eu.exeris</groupId>
            <artifactId>exeris-kernel-tck</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- JMH — required for JMH @State / @Benchmark annotations in benchmark classes -->
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-core</artifactId>
            <scope>test</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-generator-annprocess</artifactId>
            <scope>test</scope>
            <optional>true</optional>
        </dependency>
        <!-- Test framework -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>eu.exeris</groupId>
            <artifactId>exeris-kernel-community-testkit</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Community persistence: HikariCP connection pool -->
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </dependency>
        <!-- JWT validation: JWKS key selection and claims validation -->
        <dependency>
            <groupId>com.nimbusds</groupId>
            <artifactId>nimbus-jose-jwt</artifactId>
        </dependency>
        <!-- JSON serialization for JsonBodyEncoder -->
        <dependency>
            <groupId>tools.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <!-- Argon2id password hashing via Bouncy Castle -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk18on</artifactId>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk18on</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Community persistence: PostgreSQL JDBC driver (optional runtime) -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.neo4j.driver</groupId>
            <artifactId>neo4j-java-driver</artifactId>
        </dependency>
        <!-- Test: Mockito for persistence/crypto unit tests with mocked SPI -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.5.252</version>
            <scope>test</scope>
        </dependency>
        <!-- Testcontainers: JUnit 5 integration + Neo4j module for parity IT -->
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>neo4j</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>postgresql</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.tngtech.archunit</groupId>
            <artifactId>archunit-junit5</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.2.5</version>
                <configuration>
                    <!-- Inherit common JVM flags (ZGC + JFR + preview) from the parent POM. -->
                    <argLine>@{coverage.argLine} ${jvm.args} --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED</argLine>
                    <!-- Optional include filter, e.g. -DincludedGroups=flamegraph -->
                    <groups>${includedGroups}</groups>
                    <!-- Exclude @Tag("flamegraph") tests from regular CI runs -->
                    <excludedGroups>${excludedGroups}</excludedGroups>
                    <!--
                        Pick up *IT.java alongside the Surefire defaults, so the persistence-rls-gate
                        CI job (`-DincludedGroups=integration -DexcludedGroups=` against this module)
                        actually discovers the classes its name promises.

                        Surefire 3.2.5 defaults to Test*.java / *Test.java / *Tests.java /
                        *TestCase.java only. Every integration test in this module ends in IT, so the
                        gate selected none of them: not the persistence isolation suite it is named
                        after, nor the JDBC event-stream TCK bindings, the graph parity/churn ITs, the
                        S3 blob TCK, or the Keycloak OIDC conformance test. The job was green because
                        it ran three unrelated *Test classes that happen to carry the tag.

                        exeris-kernel-community-kafka fixed exactly this in v0.8 Sprint 6 (Coverage
                        C-P0-02) and the same block never reached this module. Default tag-exclusion
                        still keeps these out of `mvn test` / `mvn install` — every one of them is
                        @Tag("integration"), so no Testcontainers start without the group override.
                    -->
                    <includes>
                        <include>**/Test*.java</include>
                        <include>**/*Test.java</include>
                        <include>**/*Tests.java</include>
                        <include>**/*TestCase.java</include>
                        <include>**/*IT.java</include>
                    </includes>
                </configuration>
                <executions>
                    <!--
                        TCK-064 regression: the client RECV carrier-pinning test
                        (CommunityClientIngressCarrierPinningTest, @Tag("transport-pinning-recv"))
                        must run under the faithful 2-vCPU carrier model so the scarce-carrier
                        deadlock would re-manifest if a client recv path ever blocks a carrier
                        again. parallelism=2/maxPoolSize=2 forces exactly two VT carriers; the
                        client-stream count (32) far exceeds that. Run in its own fork so these
                        scheduler args never leak into the default test execution.
                    -->
                    <execution>
                        <id>transport-pinning-recv</id>
                        <phase>test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <argLine>@{coverage.argLine} ${jvm.args} --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED -Djdk.virtualThreadScheduler.parallelism=2 -Djdk.virtualThreadScheduler.maxPoolSize=2</argLine>
                            <includes>
                                <include>**/CommunityClientIngressCarrierPinningTest.java</include>
                            </includes>
                            <!--
                                Re-include the transport-pinning-recv tag here (the plugin-level
                                ${excludedGroups} excludes it for the default execution). The
                                other heavy tags stay excluded so this fork runs ONLY the recv
                                regression class.
                            -->
                            <groups>transport-pinning-recv</groups>
                            <excludedGroups>flamegraph,integration,stress</excludedGroups>
                        </configuration>
                    </execution>
                    <!--
                        Client TLS against OpenSSL's default trust (CommunityTlsDefaultTrustTest,
                        @Tag("default-trust")). SSL_CERT_FILE and SSL_CERT_DIR decide what that
                        default is, and they can only be set for a whole JVM, so the class runs in its
                        own fork where they name a CA file the test writes and an empty directory.
                        Elsewhere the tag is excluded, and the class fails rather than skips if it is
                        run without these variables. Run alone with
                        `mvn -pl exeris-kernel-community surefire:test@default-trust`.
                    -->
                    <execution>
                        <id>default-trust</id>
                        <phase>test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <includes>
                                <include>**/CommunityTlsDefaultTrustTest.java</include>
                            </includes>
                            <groups>default-trust</groups>
                            <excludedGroups>flamegraph</excludedGroups>
                            <failIfNoSpecifiedTests>false</failIfNoSpecifiedTests>
                            <environmentVariables>
                                <SSL_CERT_FILE>${project.build.directory}/default-trust/ca.pem</SSL_CERT_FILE>
                                <SSL_CERT_DIR>${project.build.directory}/default-trust/empty</SSL_CERT_DIR>
                            </environmentVariables>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <!-- =====================================================================
         benchmarks profile — runs JMH against the Community memory/transport stack.

          Usage:
           mvn clean install -P benchmarks
           mvn verify -P benchmarks "-Dbenchmark.includes=CommunityMemoryAllocatorBenchmark"

          Results written to target/jmh-results.json.
         NOT bound to the default lifecycle — only runs with explicit -P benchmarks.
         ===================================================================== -->
    <profiles>
        <profile>
            <id>targeted-test-run</id>
            <activation>
                <property>
                    <name>test</name>
                </property>
            </activation>
            <properties>
                <!-- Keep flamegraph excluded, but allow explicit -Dtest integration classes. -->
                <excludedGroups>flamegraph</excludedGroups>
            </properties>
        </profile>
        <profile>
            <id>benchmarks</id>
            <properties>
                <benchmark.skip>false</benchmark.skip>
                <benchmark.warmuptime>2s</benchmark.warmuptime>
                <benchmark.iterationstime>2s</benchmark.iterationstime>
                <benchmark.jvm.gc>-XX:+UseZGC</benchmark.jvm.gc>
                <benchmark.jvmArgs></benchmark.jvmArgs>
                <benchmark.jvmArgsAppend/>
            </properties>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <!--
                            ADR-066: no plugin-level compilerArgs here. Plugin level applies to
                            default-compile too, so this profile handed the preview flag to MAIN
                            sources as well; the root POM's pluginManagement already puts it on
                            default-testCompile, which is the only place it belongs.

                            It was NOT producing preview-stamped main classes. Measured both ways:
                            307 main classes, 0 stamped. javac stamps minor_version 0xFFFF on
                            classes that actually USE a preview feature, not on everything compiled
                            under the flag, and main sources use none. What the plugin-level
                            placement did produce is a profile that silently disagreed with the
                            default build about what main sources may contain: the day a preview
                            feature lands in one, the normal build refuses it and the benchmark
                            build compiles it.
                        -->
                        <configuration>
                            <release>${maven.compiler.release}</release>
                            <annotationProcessorPaths>
                                <path>
                                    <groupId>org.openjdk.jmh</groupId>
                                    <artifactId>jmh-generator-annprocess</artifactId>
                                    <version>${jmh.version}</version>
                                </path>
                            </annotationProcessorPaths>
                        </configuration>
                    </plugin>
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>
                        <artifactId>exec-maven-plugin</artifactId>
                        <executions>
                            <execution>
                                <id>run-benchmarks</id>
                                <phase>verify</phase>
                                <goals>
                                    <goal>exec</goal>
                                </goals>
                                <configuration>
                                    <skip>${benchmark.skip}</skip>
                                    <executable>java</executable>
                                    <classpathScope>test</classpathScope>
                                    <arguments>
                                        <argument>-XX:+UnlockExperimentalVMOptions</argument>
                                        <argument>${benchmark.jvm.gc}</argument>
                                        <argument>-Dbenchmark.jvmArgs=${benchmark.jvmArgs}</argument>
                                        <argument>--enable-native-access=ALL-UNNAMED</argument>
                                        <argument>-Djava.library.path=${java.library.path}${path.separator}${native.lib.dir}</argument>
                                        <argument>--add-opens</argument>
                                        <argument>java.base/sun.nio.ch=ALL-UNNAMED</argument>
                                        <argument>--add-opens</argument>
                                        <argument>java.base/java.io=ALL-UNNAMED</argument>
                                        <argument>-classpath</argument>
                                        <classpath/>
                                        <argument>org.openjdk.jmh.Main</argument>
                                        <argument>${benchmark.includes}</argument>
                                        <argument>-f</argument>
                                        <argument>${benchmark.forks}</argument>
                                        <argument>-wi</argument>
                                        <argument>${benchmark.warmup}</argument>
                                        <argument>-i</argument>
                                        <argument>${benchmark.iterations}</argument>
                                        <argument>-w</argument>
                                        <argument>${benchmark.warmuptime}</argument>
                                        <argument>-r</argument>
                                        <argument>${benchmark.iterationstime}</argument>
                                        <argument>-rf</argument>
                                        <argument>json</argument>
                                        <argument>-rff</argument>
                                        <argument>${benchmark.output}</argument>
                                        <argument>-jvmArgsAppend</argument>
                                        <argument>${benchmark.jvmArgsAppend}</argument>
                                    </arguments>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>