Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 64 additions & 8 deletions ecosystem/testcontainers-example/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Sample Project for Testcontainers

This is a sample application generated by the Payara Starter.
It aims to be tested using Testcontainers.
It aims to be tested using WeldInitiator, Arquillian and Testcontainer.

## Getting Started

### Prerequisites

- [Java SE 11+](https://adoptium.net/temurin/releases?version=11&os=any&arch=any )
- [Java SE 21+](https://www.azul.com/downloads/?version=java-21-lts#zulu )
- [Maven](https://maven.apache.org/download.cgi )

## Running the Application
Expand All @@ -34,12 +34,68 @@ To run the tests for the application locally, follow these steps:

2. Make sure you have the appropriate Java version installed.

3. Execute the following command:

```
./mvn clean verify
```

3. Make sure [Docker](https://www.docker.com/products/docker-desktop/) is installed and running. The integration
tests (`*IT.java`) use [Testcontainers](https://testcontainers.com/) to start a real Payara Micro instance with
the application deployed, so Docker needs to be reachable from the JVM running the tests. If you hit
`Could not find a valid Docker environment` on Windows even though `docker` works fine from the shell, see
[Testcontainers' Windows troubleshooting guide](https://java.testcontainers.org/supported_docker_environment/windows/).

4. The first time you run the tests (or any time after `mvn clean`), install the local test tooling and run
everything in one go:

```
./mvn clean verify -Pinstall-deps
```

This installs the Playwright Chromium browser binary (for the `*UiIT` tests) and the Payara Micro jar the
Arquillian test launches directly (see `BookServiceArquillianIT` below). Both are behind the opt-in
`install-deps` Maven profile rather than running automatically, since Playwright's browser install can
prompt for (or require) `sudo` to install missing system libraries on some machines/OSes — not something
this build should force on you every time, especially if you don't have or don't want to grant those
permissions.

5. On later runs, once those are in place, the plain command works and reuses what's already installed:

```
./mvn verify
```

`mvn test` (just the `*Test` unit tests) never needs `-Pinstall-deps` at all — it doesn't touch Docker,
Playwright, or Payara Micro. Skipping `-Pinstall-deps` on a `verify` after a `clean` will fail the `*UiIT`
and `BookServiceArquillianIT` tests specifically (no browser binary / no Payara Micro jar to launch), while
the `*ServiceIT` REST tests are unaffected either way.

### What gets tested

- `*Test` (`fish.payara.examples.service`) — CDI unit tests using [`weld-junit5`](https://github.com/weld/weld-junit)'s
`WeldInitiator`. Boots a real (but minimal) Weld container for a single service bean with a mocked
`EntityManager` — no Docker, no app server, runs in milliseconds as part of `mvn test`.
- `*ServiceIT` (`fish.payara.examples.service`) — REST API tests hitting the deployed application directly with a
JAX-RS client.
- `*UiIT` (`fish.payara.examples.ui`) — browser tests driving the JSF pages (Book, Patron, Librarian, Loan) end to
end with [Playwright](https://playwright.dev/java/). The Playwright Chromium browser binary is installed by the
`exec-maven-plugin` execution in the `install-deps` profile (see above) — run with `-Pinstall-deps` at least
once (or again after `mvn clean`).
- `BookServiceArquillianIT` (`fish.payara.examples.arquillian`) — an [Arquillian](https://arquillian.org/) in-container
test using the Payara Micro Managed connector (`fish.payara.arquillian:arquillian-payara-micro-managed`). Unlike
the black-box `*ServiceIT`/`*UiIT` tests, this one gets `BookService` `@Inject`ed straight into the test class,
running inside a real, separately-launched Payara Micro instance. It covers `AbstractService#count()`,
`#findRange(int, int)`, and the named-query lookups (`#findByNamedQuery`/`#findSingleByNamedQuery`) — the one
corner of the codebase nothing else exercises, since no REST endpoint exposes pagination/counting/named queries
and the `*Test` classes mock the `EntityManager` away entirely. See the class Javadoc for the full comparison
with the other two testing approaches.

**This one needs more than Docker.** The Payara Micro Managed adapter launches Payara Micro as a plain OS
process rather than a Docker container, so it needs an actual runnable Payara Micro jar on disk — the
`maven-dependency-plugin` execution in the `install-deps` profile (see above) resolves one to
`target/payara-micro-${payara.version}.jar` before the integration-test phase runs. Also note the
`arquillian-payara-micro-managed` version pinned in `pom.xml` could not be verified against Maven Central from
the environment this was drafted in (no network access) — double-check it resolves before relying on this in CI.

Both sets of Testcontainers-based IT tests (`*ServiceIT`, `*UiIT`) share a single Payara Micro Testcontainer for
the whole test run (see `fish.payara.examples.testcontainers.AbstractContainerIT`), so it's started once instead
of once per test class. `BookServiceArquillianIT` is separate: it launches its own Payara Micro instance, scoped
to just that one test class.



152 changes: 129 additions & 23 deletions ecosystem/testcontainers-example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,18 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>11</maven.compiler.release>
<jakartaee-api.version>10.0.0</jakartaee-api.version>
<payara.version>6.2025.11</payara.version>
<payara.version>7.2026.6</payara.version>
<arquillian.version>1.10.1.Final</arquillian.version>
<arquillian-payara-micro-managed.version>4.0.alpha4</arquillian-payara-micro-managed.version>
<!-- payara-bom does NOT manage org.glassfish.jersey.* (confirmed via
`mvn dependency:tree -Dincludes="org.glassfish.jersey"` returning
empty once these were left unpinned - they simply dropped off the
classpath rather than following the BOM). Pin explicitly instead,
matching whatever Jersey Payara itself bundles for the current
payara.version - 4.0.2 is what Payara 7.2026.6 ships (its Jakarta
REST 4.0 / Jakarta EE 11 stack). Update this alongside
payara.version in the future. -->
<jersey.version>4.0.2</jersey.version>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -61,14 +72,14 @@
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.21.1</version>
<version>1.21.4</version>
<scope>test</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-junit5</artifactId>
<version>4.0.5.Final</version>
<version>5.0.3.Final</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -81,13 +92,19 @@
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>3.1.11.payara-p2</version>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>3.1.11.payara-p2</version>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -97,10 +114,39 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<groupId>org.jboss.arquillian.junit5</groupId>
<artifactId>arquillian-junit5-container</artifactId>
<version>${arquillian.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>fish.payara.arquillian</groupId>
<artifactId>arquillian-payara-micro-managed</artifactId>
<version>${arquillian-payara-micro-managed.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.jboss.weld</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>org.jboss.weld.se</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>fish.payara.extras</groupId>
<artifactId>payara-micro</artifactId>
<version>${payara.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
Expand All @@ -118,11 +164,10 @@
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<!-- Execute 'mvn clean package payara-micro:dev' to run the application. -->
<plugin>
<groupId>fish.payara.maven.plugins</groupId>
<artifactId>payara-micro-maven-plugin</artifactId>
<version>2.5.2</version>
<version>2.6.0</version>
<configuration>
<payaraMicroVersion>${payara.version}</payaraMicroVersion>
<deployWar>true</deployWar>
Expand All @@ -146,10 +191,12 @@
<goal>wget</goal>
</goals>
<configuration>
<skipCache>true</skipCache>
<skipCache>false</skipCache>
<url>https://github.com/swagger-api/swagger-ui/archive/master.tar.gz</url>
<unpack>true</unpack>
<outputDirectory>${project.build.directory}</outputDirectory>
<readTimeOut>60000</readTimeOut>
<retries>5</retries>
</configuration>
</execution>
</executions>
Expand Down Expand Up @@ -201,6 +248,8 @@
</includes>
<systemPropertyVariables>
<payara.microJar>${project.build.directory}/payara-micro-${payara.version}.jar</payara.microJar>
<payara.version>${payara.version}</payara.version>
<war.path>${project.build.directory}/${project.build.finalName}.war</war.path>
</systemPropertyVariables>
</configuration>
</execution>
Expand All @@ -209,19 +258,76 @@
</plugins>
</build>

<repositories>
<repository>
<id>payara-nexus-artifacts</id>
<url>https://nexus.dev.payara.fish/repository/payara-artifacts</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

<profiles>
<profile>
<id>install-deps</id>
<build>
<plugins>
<!-- Installs the Playwright browser binaries (used by the *UiIT tests) before the
integration-test phase runs. Uses exec:exec (a real child process) rather than
exec:java, because com.microsoft.playwright.CLI calls System.exit() internally,
which would otherwise kill the whole Maven JVM. -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.6.3</version>
<executions>
<execution>
<id>install-playwright-browsers</id>
<phase>generate-test-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>java</executable>
<classpathScope>test</classpathScope>
<arguments>
<argument>-classpath</argument>
<classpath/>
<argument>com.microsoft.playwright.CLI</argument>
<argument>install</argument>
<argument>chromium</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<!-- Copies the payara-micro test dependency's jar to
target/payara-micro-${payara.version}.jar - the exact path the
failsafe systemPropertyVariables below already advertise as
`payara.microJar` (that property existed before this plugin
execution did, but nothing produced the file it pointed at).
This is what the Payara Micro Managed Arquillian adapter used
by BookServiceArquillianIT launches as a plain OS process -
unlike PayaraMicroContainer, which pulls the same Payara Micro
version as a Docker image instead. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.7.1</version>
<executions>
<execution>
<id>copy-payara-micro-jar</id>
<phase>generate-test-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>fish.payara.extras</groupId>
<artifactId>payara-micro</artifactId>
<version>${payara.version}</version>
<destFileName>payara-micro-${payara.version}.jar</destFileName>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -1,3 +1,42 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2026 Payara Foundation and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://github.com/payara/Payara/blob/master/LICENSE.txt
* See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* The Payara Foundation designates this particular file as subject to the "Classpath"
* exception as provided by the Payara Foundation in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package fish.payara.examples.converter;

import jakarta.faces.component.UIComponent;
Expand Down
Loading