Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testing With Eclipse GlassFish

Testing With Eclipse GlassFish

* History of GlassFish tests and testing applications using GlassFish as a platform.
* Options for testing Jakarta EE based applications
* Example: Using TestContainers with Eclipse GlassFish to test a simple web application.

OmniFish Presentations

October 23, 2024
Tweet

More Decks by OmniFish Presentations

Other Decks in Programming

Transcript

  1. 1 Testing with Eclipse GlassFish David Matějček Owner & Angry

    QA & Developer OmniFish Eclipse GlassFish Lead
  2. 2 Good Old Times … …? 2005 Sun Java Application

    Server 8 Java EE was born, standardization. Extremely buggy version Unfinished prototyping 2009 Sun GlassFish Enterprise Server 2.1.1.2 Production ready again 1997 Netscape iPlanet 2003 SunOne 7 Quite reliable, WebArchive (war), Single UI manages several instances. Enterprise solution, commercial Java version required. 2011 Oracle GlassFish 3.1 Java EE 6 Users started losing patience 2017 Oracle GlassFish 5.0 Java EE 8 Very buggy
  3. 3 Rescue of Java EE Platform: Eclipse Foundation 2020 Eclipse

    GlassFish 6 Jakarta EE train gains speed Remaining community evaluates 2022 Eclipse GlassFish 7 Production ready again Jakarta EE 10 Java 11-23 supported (17 rec.) Stable development Bugfixes Improvements Refactoring Commercial support Community is slowly growing 2017 Oracle donated GlassFish Why? To be able to validate JEE Specifications 2019 Eclipse GlassFish 5.1 Same as Oracle GlassFish 5.0, but under Eclipse Foundation 2025 Eclipse GlassFish 8 Jakarta EE 11 Java 21+ supported Already releasing milestones To Be Continued …
  4. Testing Java EE Applications 2005 • We had a Java

    EE Platform making things easier … but without any support for automated tests … making things pretty uneasy • Ejb3Unit (died too soon, supported just simple features) • EasyMock, Mockito (but mocks were so complicated!) • Integration Tests (but the server was always still running!) • GlassFish used around 65000 integration tests: usually small war application testing single scenario ◦ How long could it run in 2005???
  5. EasyMock vs. HttpServletRequest import static org.easymock .EasyMock .createNiceMock; import static

    org.easymock .EasyMock .expect; import static org.easymock .EasyMock .isA; import static org.easymock .EasyMock .replay; import static org.junit.jupiter.api.Assertions .assertEquals; public class EasyMockTest { @Test public void getParameter() throws Exception { HttpServletRequest request = createNiceMock(HttpServletRequest .class); expect(request.getParameter(isA(String.class))).andStubReturn("anything"); expect(request.getMethod()).andStubReturn("GET"); replay(request); assertEquals("anything", request.getParameter("parameterName")); } } 5
  6. Testing Jakarta EE Applications 2024 • We still have a

    Jakarta EE Platform making things easier • We have much better support many people don’t know • JUnit5, EasyMock, Mockito, Weld-Junit, HK2 based tests, TestContainers, GlassFish Test Utilities, JMH, Selenium, Embedded GlassFish … and their combinations!!! • Integration Tests ◦ GlassFish still uses around 65000 integration tests ◦ Execution take some 8 hours ◦ Can run them locally
  7. Testing with JUnit5 7 Junit5 Extension Deploy - Undeploy Configure

    - reset Defines actions for test classes and methods Uses environment Can be combined 3 Global Environment System dependencies, file system, ports, network interfaces, cpu, memory, … resources. 4 Test Method Send Input to the application, verify results @BeforeEach, @AfterEach, 1 Test Class Defines some unit @BeforeAll, @AfterAll 2
  8. Weld-Junit or HK2? • Partially support injections • You can

    customize - ie. to fake Jakarta Transactions support or mock SQL database • Weld directly targets unit tests • HK2 is partial CDI implementation
  9. Weld-Junit or HK2? @ExtendWith(WeldJunit5Extension.class) class SimpleTest { @WeldSetup public WeldInitiator

    weld = WeldInitiator.of(Foo.class); @Test public void testFoo() { // Note that Weld container is started automatically // WeldInitiator can be used to perform programmatic lookup of beans assertEquals("baz", weld.select(Foo.class).get().getBaz()); // WeldInitiator can be used to fire a CDI event weld.event().select(Baz.class).fire(new Baz()); } } 9
  10. TestContainers: GlassFish • https://github.com/eclipse-ee4j/glassfish.docker/pkgs/container/glassfish or search for the Eclipse GlassFish

    Docker Image • Supported platforms: amd64 and arm64 • Id: ghcr.io/eclipse-ee4j/glassfish:7.0.18 • We are still waiting for the merge of the PR for DockerHub
  11. TestContainers: GlassFish @Testcontainers public class AsadminTest { @Container private final

    GenericContainer server = new GenericContainer <>(”ghcr.io/eclipse-ee4j/glassfish:7.0.18” ) .withCommand("asadmin start-domain" ).withExposedPorts (8080) .withLogConsumer (o -> System.err.print("GF: " + o.getUtf8String())); @Test void getRoot() throws Exception { URL url = URI.create("http://localhost:" + server.getMappedPort(8080) + "/").toURL(); HttpURLConnection connection = (HttpURLConnection ) url.openConnection (); String content; try { connection.setRequestMethod ("GET"); assertEquals(200, connection.getResponseCode (), "Response code" ); try (InputStream in = connection.getInputStream ()) { content = new String(in.readAllBytes(), StandardCharsets .UTF_8); } } finally { connection.disconnect(); } assertThat(content, stringContainsInOrder("Eclipse GlassFish" , "index.html", "production-quality" )); } } 11
  12. TestContainers: GlassFish + Web Application @ApplicationPath("") public class SimpleApplication extends

    Application { @Override public Set<Class<?>> getClasses() { return Set.of(SimpleResource .class); } } @Path("/") public class SimpleResource { @GET public Response getResponse() { return Response.ok("Hello TestCon!" ).build(); } } 12
  13. TestContainers: GlassFish + Web Application public class AsadminTest { private

    static final Logger LOG = System.getLogger(AsadminTest.class.getName()); private static final String APP_NAME = "application"; private static final String APP_FILENAME = APP_NAME + ".war"; @TempDir private static Path tempDir; private static Path applicationPath; private static GenericContainer<?> server; @BeforeAll public static void init() { WebArchive webArchive = ShrinkWrap.create(WebArchive.class).addClass(SimpleResource.class) .addClass(SimpleApplication.class).addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); LOG.log(INFO, webArchive.toString(true)); applicationPath = tempDir.resolve(APP_FILENAME); webArchive.as(ZipExporter.class).exportTo(applicationPath.toFile(), true); server = new GenericContainer<>("ghcr.io/eclipse-ee4j/glassfish:7.0.18").withCommand("startserv") .withExposedPorts(8080).withLogConsumer(o -> System.err.print("GF: " + o.getUtf8String())) .withCopyFileToContainer(MountableFile.forHostPath(applicationPath), "/opt/glassfish7/glassfish/domains/domain1/autodeploy/" + APP_FILENAME) .waitingFor( Wait.forLogMessage(".*Successfully autodeployed.*", 1).withStartupTimeout(Duration.ofSeconds(10L))) ; server.start(); } 13
  14. TestContainers: GlassFish + Web Application @Test void getRoot() throws Exception

    { String content = get(""); assertThat(content, stringContainsInOrder("Eclipse GlassFish", "index.html", "production-quality")); } @Test void getApplication() throws Exception { assertThat(get(APP_NAME), stringContainsInOrder("Hello TestCon!")); } private String get(String endpointRelativePath) throws IOException { URL url = URI.create("http://localhost:" + server.getMappedPort(8080) + "/" + endpointRelativePath).toURL(); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); String content; try { connection.setConnectTimeout(10); connection.setReadTimeout(1000); connection.setRequestMethod("GET"); assertEquals(200, connection.getResponseCode(), "Response code"); try (InputStream in = connection.getInputStream()) { content = new String(in.readAllBytes(), StandardCharsets.UTF_8); } } finally { connection.disconnect(); } return content; } 14
  15. TestContainers: GlassFish + Web Application [INFO] Tests run: 2, Failures:

    0, Errors: 0, Skipped: 0, Time elapsed: 8.920 s -- in org.omnifish.testcon.tc. AsadminTest 15
  16. TestContainers: Embedded GlassFish @Testcontainers public class EmbeddedTest { @Container private

    final GenericContainer server = new GenericContainer <>("ghcr.io/eclipse-ee4j/glassfish:7.0.18" ) .withCommand("runembedded").withExposedPorts (8080).withLogConsumer (output -> { // FIXME: If we don't use the interactive terminal, spams STDOUT. To be fixed in 7.0.19+. if (output.getType() == OutputType.STDERR) { System.err.print("GF: " + output.getUtf8String()); } }); @Test void getRoot() throws Exception { URL url = URI.create("http://localhost:" + server.getMappedPort(8080) + "/").toURL(); HttpURLConnection connection = (HttpURLConnection ) url.openConnection (); try { connection.setRequestMethod ("GET"); assertEquals(404, connection.getResponseCode (), "Response code" ); } finally { connection.disconnect(); } } } 16
  17. Fake Production Database • When you want to reproduce something

    from production • Randomized data, thin ice • Usually a temporary solution • Corrupted data sooner or later
  18. TestContainers: Database + GlassFish • When you plan to do

    awful things to your data • Postgress container, MySql, etc. • The database is destroyed after the test • Similar way you can create containers for anything just as if you would build a virtual network
  19. TestContainers: Fake Production Database When you want to test integration

    of your Java code with JPA, JTA, JDBC, and real SQL database. When you want to check compatibility with several versions of the database. Idea: 1. Implement tool able to copy consistent data from some source and use it for selective dumps. 2. Maintain such source using the application. 3. Dump those data from time to time and add them to GIT (csv, json, unl, …) 4. Use @Container and your own impl loading dump before the test. 5. Run some test sequence whenever you want.
  20. GlassFish Test Utilities • When you don’t like TestContainers •

    Ensures proper start+stop of the domain/cluster/… • Able to test whatever admin would do with the domain • GlassFishTestEnvironment class