Skip to content
Select theme

JUnit: FEGA

E2E_SUITE=java with E2E_TESTS_INTEGRATION=FEGA runs no.elixir.e2eTests.FEGAIntegrationTest, nine @Order-ed tests covering the same ground as e2e-fega in the same sequence: the fallback the coexistence period exists for.

  1. Start with the JUnit runner

    Terminal window
    E2E_SUITE=java E2E_TESTS_INTEGRATION=FEGA ./dev.sh start

    FEGA is the default test class, so E2E_TESTS_INTEGRATION can be dropped, and env.sh supplies every other variable.

  2. Read the verdict

    The result is the e2e-tests container’s exit code, which ./dev.sh start does not wait for. See the boot chain for how to follow the run.

why is there more than one selector?

E2E_SUITE picks the runner: go or java. E2E_TESTS_INTEGRATION picks the JUnit test class; the Go runner uses its own E2E_ENV instead and ignores E2E_TESTS_INTEGRATION. Choosing the environment is choosing the program (a test class here, a binary for Go), and the entrypoint refuses an unknown value with a non-zero exit rather than falling back to a default.

which nine tests does it run?

The same sequence as e2e-fega: the C1 forged-JWT check, upload via lega-commander, ingest, accession, finalize, mapping, inbox cleanup, release, download.

why does it need keytool?

Before running anything the entrypoint imports the root CA into the JDK truststore with keytool -importcert -file /storage/certs/rootCA.pem -cacerts -alias fega-root-ca, and logs an info line and continues if the file is absent. The Go runner has no such step: it reads the same PEM directly and builds its pools in process.

why do ingest and release die with a NullPointerException?

E2E_TESTS_TRUSTSTORE_PASSWORD is unset. It is load-bearing here and dead for Go: CertificateUtils calls .toCharArray() on it when building the AMQPS context, so ingest, accession, mapping and release all fail with a null-pointer dereference without it. env.sh keeps it in a clearly marked JUnit-only block for exactly this reason, to be deleted with the module (#851).

what command runs inside the container?

The suite is packaged as a fat jar and launched through the JUnit console: java -jar e2eTests.jar execute --select-class no.elixir.e2eTests.FEGAIntegrationTest.

E2E_TESTS_RUNTIME=local runs the suite outside the container: from IntelliJ IDEA’s green play button on the test class, or by executing the jar on the host, while the stack itself stays in docker. Usually the point is a debugger on localega-tsd-proxy or tsd-api-mock rather than on the test, and the stack ships with JDWP already open on both, but the run works the same without one.

  1. Bring the stack up, and wait for it

    Terminal window
    ./dev.sh start
    docker compose -f e2e/docker-compose.yml ps

    dev.sh start is docker compose up --build -d, so it returns while proxy and doa are still health: starting. Starting the tests before both report healthy produces connection errors that look like the trust or endpoint problems below. Note this also runs the Go suite in the e2e-tests container, since E2E_SUITE defaults to go; that is a separate run and does not interfere.

  2. Build and install lega-commander

    Terminal window
    (cd cli/lega-commander && go build -o /tmp/lega-commander .)
    sudo install /tmp/lega-commander /usr/local/bin/lega-commander

    UploadViaLegaCMDTest shells out to the absolute path /usr/local/bin/lega-commander, so putting the binary anywhere else on PATH does not work. Without it the upload fails instantly with Cannot run program, and FinalizeTest then fails too because nothing was ever uploaded.

  3. Trust the stack’s root CA

    dev.sh does this for you. Run it with no arguments and pick 14) Replace RootCA:

    Terminal window
    ./dev.sh

    That copies rootCA.pem out of the file-orchestrator container and imports it into your JDK’s cacerts under the alias fega, finding the keystore from JAVA_HOME or falling back to the usual Linux and macOS locations. It deletes the alias first, so running it again after a stack rebuild is safe. It uses sudo, because the system keystore is root-owned.

    The stack serves mkcert certificates, so until the host JVM trusts that CA every HTTPS call the suite makes fails PKIX validation.

    Without root, copy the truststore instead of editing it and point the JVM at the copy. In IntelliJ the same two -D flags go in the run configuration’s VM options:

    Terminal window
    docker cp file-orchestrator:/storage/certs/rootCA.pem /tmp/rootCA.pem
    JDK_HOME=$(dirname "$(dirname "$(readlink -f "$(command -v keytool)")")")
    cp "$JDK_HOME/lib/security/cacerts" /tmp/fega-cacerts && chmod u+w /tmp/fega-cacerts
    keytool -importcert -noprompt -alias fega-root-ca \
    -file /tmp/rootCA.pem -keystore /tmp/fega-cacerts -storepass changeit
    export JAVA_TOOL_OPTIONS="-Djavax.net.ssl.trustStore=/tmp/fega-cacerts -Djavax.net.ssl.trustStorePassword=changeit"
  4. Export the environment, in this order

    Terminal window
    export E2E_TESTS_RUNTIME=local
    source e2e/env.sh

    The order is load-bearing. env.sh reads E2E_TESTS_RUNTIME to decide whether to rewrite the endpoints, so exporting it after sourcing leaves every host on its in-network name and the run fails on connection errors. Launch IntelliJ from that shell, or copy the values into the run configuration’s environment.

  5. Run the test class

    The green play button on FEGAIntegrationTest, or from the same shell:

    Terminal window
    ./gradlew :e2eTests:test --tests no.elixir.e2eTests.FEGAIntegrationTest --rerun

    --tests is not optional: :e2eTests:test has no filter of its own, so without it Gradle also runs EgaDevIntegrationTest, which fails on the E2E_TESTS_EGA_DEV_* variables env.sh ships commented out, plus the vacuous GDIIntegrationTest. --rerun matters from the second run on: environment variables are not task inputs, so Gradle otherwise reports UP-TO-DATE without running anything, which reads as a pass.

  6. Attach a debugger, if that is why you are here

    A Remote JVM Debug configuration pointed at localhost and the port of the service you are chasing: proxy 5005, tsd-api-mock 5006, DOA 8088.

    If you have not set one up before, Debugging a running Java app in Docker walks through it screen by screen, with the same flags and the same port. It starts its container with plain docker run, which is the only part that differs: here the compose stack already carries the agent and publishes the port.

which ports do I attach to?
Service JDWP port
proxy (localega-tsd-proxy) 5005
tsd-api-mock 5006
doa 8088

All three are published by the compose stack and carry -agentlib:jdwp=transport=dt_socket,server=y,suspend=n in the container command.

do I have to enable JDWP first?

No. The agents are in the container commands and the ports are published; nothing needs switching on. suspend=n means each service boots normally without waiting for a debugger, so you attach and detach whenever you like and never have to race the stack coming up.

why does the suite fail as soon as it starts on my host?

E2E_TESTS_RUNTIME is still at its default, container, which uses the in-network service names, so the suite resolves proxy and doa as hostnames and fails immediately outside the docker network. local rewrites four endpoints onto localhost and the stack’s published ports:

Variable Value under local
E2E_TESTS_PROXY_HOST / _PORT localhost / 10443
E2E_TESTS_SDA_DOA_HOST / _PORT localhost / 80
E2E_TESTS_SDA_DB_HOST localhost
E2E_TESTS_CEGAMQ_CONN_STR amqps://…@localhost:5673/…

The last two are easy to overlook and carry the most: the database host is what FinalizeTest asserts against, and the broker string is what every ingest, accession, mapping and release message publishes to. Only the JUnit runner reads E2E_TESTS_RUNTIME, and it is not an egadev switch.

why did four tests pass when nothing was uploaded?

Because four of the nine only publish a message to the CEGA broker and assert that the publish succeeded. IngestTest, AccessionTest, MappingTest and ReleaseTest will all go green against a stack that never received a file. Only FinalizeTest, InboxCleanupTest and DownloadTest assert pipeline state, and UploadViaLegaCMDTest and C1JwtSignatureVerificationTest talk to the proxy. So “4 passed, 5 failed” is not the suite half working: it is the suite failing with four tests that cannot tell.

can I skip the CA import because the suite disables TLS verification?

No, and the code makes it look as though you could. BaseE2ETest.setupTestEnvironment does:

try (UnirestInstance instance = Unirest.primaryInstance()) {
instance.config().verifySsl(false)...;
}

Try-with-resources closes the primary instance immediately, so verifySsl(false) never applies to any later request. In the container this is invisible, because the entrypoint’s keytool import makes the CA trusted anyway. On a host it is exactly what surfaces as PKIX failures. The bug is in the retiring module and is recorded on #851 rather than fixed.

doesn’t ./dev.sh start already run the suite in the container?

Yes, and there is no supported way to avoid it. e2e-tests is a service in the stack, dev.sh brings the stack up with a bare docker compose up --build -d, and the compose file declares no profiles, so nothing selects a subset. Your IDE run is therefore a second run alongside the container one. That is harmless: each run namespaces itself by a UUID fixture name and random accession and dataset ids, so the two do not collide. It is still wasted time and log noise on every start, tracked in known gaps.

can I run the jar instead of gradle?

Yes, and it needs the same steps 1 to 4. ./gradlew :e2eTests:jar builds e2eTests/build/libs/e2eTests.jar with the JUnit ConsoleLauncher as its main class, so from the same shell: java -jar e2eTests/build/libs/e2eTests.jar execute --select-class no.elixir.e2eTests.FEGAIntegrationTest. It selects the class directly, so no --tests filter and no --rerun are involved. One difference worth knowing: the 10 MiB fixture and its .enc are written to the working directory you launch from, whereas Gradle’s test worker writes them under e2eTests/. Neither is gitignored, and they are only cleaned up if the run finishes.

Built from f91944d