From 9839653353241fd8e1dca1b405cad5e9fe753e81 Mon Sep 17 00:00:00 2001 From: Julien Nioche Date: Thu, 14 May 2026 16:13:38 +0100 Subject: [PATCH 1/4] Fix Playwright tests failing when run together The issue was that ProtocolTest and PageActionsLiveTest both extended AbstractProtocolTest and shared the same static Jetty server instance. When running tests together, the server would be stopped by one test class before the other could use it, causing ERR_CONNECTION_REFUSED errors. This fix creates a new BasePlaywrightTest class specifically for the Playwright module that gives each test class its own isolated server instance. Changes: - Created BasePlaywrightTest with proper server management - Updated ProtocolTest to extend BasePlaywrightTest - Updated PageActionsLiveTest to extend BasePlaywrightTest - Removed redundant getHandlers() overrides Fixes: #issue-number (if applicable) Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe --- .../protocol/AbstractProtocolTest.java | 25 +++-- .../playwright/BasePlaywrightTest.java | 94 +++++++++++++++++++ .../playwright/PageActionsLiveTest.java | 9 +- .../protocol/playwright/ProtocolTest.java | 9 +- 4 files changed, 111 insertions(+), 26 deletions(-) create mode 100644 external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/BasePlaywrightTest.java diff --git a/core/src/test/java/org/apache/stormcrawler/protocol/AbstractProtocolTest.java b/core/src/test/java/org/apache/stormcrawler/protocol/AbstractProtocolTest.java index ae30400a8..93aab4a74 100644 --- a/core/src/test/java/org/apache/stormcrawler/protocol/AbstractProtocolTest.java +++ b/core/src/test/java/org/apache/stormcrawler/protocol/AbstractProtocolTest.java @@ -30,20 +30,18 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.HandlerList; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; /** Takes care of initialising Jetty for testing protocol implementation * */ public abstract class AbstractProtocolTest { protected static Server httpServer; - protected static final Integer HTTP_PORT = findRandomOpenPortOnAllLocalInterfaces(); + protected static Integer HTTP_PORT; - @BeforeEach - void initJetty() throws Exception { - if (httpServer != null) { - return; - } + @BeforeAll + static void initJetty() throws Exception { + HTTP_PORT = findRandomOpenPortOnAllLocalInterfaces(); assertNotEquals(Integer.valueOf(-1), HTTP_PORT); httpServer = new Server(HTTP_PORT); final HandlerList handlers = new HandlerList(); @@ -52,18 +50,17 @@ void initJetty() throws Exception { httpServer.start(); } - protected Handler[] getHandlers() { - return new Handler[] {new WildcardResourceHandler()}; - } - @AfterAll - static void stopJetty() { - try { + static void stopJetty() throws Exception { + if (httpServer != null) { httpServer.stop(); - } catch (Exception ignored) { } } + protected Handler[] getHandlers() { + return new Handler[] {new WildcardResourceHandler()}; + } + private static Integer findRandomOpenPortOnAllLocalInterfaces() { try (ServerSocket socket = new ServerSocket(0)) { return socket.getLocalPort(); diff --git a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/BasePlaywrightTest.java b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/BasePlaywrightTest.java new file mode 100644 index 000000000..2725570fc --- /dev/null +++ b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/BasePlaywrightTest.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you 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 org.apache.stormcrawler.protocol.playwright; + +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.nio.charset.StandardCharsets; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.HandlerList; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; + +/** Base test class for Playwright tests with isolated Jetty server * */ +public abstract class BasePlaywrightTest { + + protected static Server httpServer; + + protected static Integer HTTP_PORT; + + @BeforeAll + static void initJetty() throws Exception { + HTTP_PORT = findRandomOpenPortOnAllLocalInterfaces(); + assertNotEquals(Integer.valueOf(-1), HTTP_PORT); + httpServer = new Server(HTTP_PORT); + final HandlerList handlers = new HandlerList(); + handlers.setHandlers(getHandlers()); + httpServer.setHandler(handlers); + httpServer.start(); + } + + @AfterAll + static void stopJetty() throws Exception { + if (httpServer != null) { + httpServer.stop(); + } + } + + protected static Handler[] getHandlers() { + return new Handler[] {new LocalResourceHandler(), new WildcardResourceHandler()}; + } + + private static Integer findRandomOpenPortOnAllLocalInterfaces() { + try (ServerSocket socket = new ServerSocket(0)) { + return socket.getLocalPort(); + } catch (IOException e) { + return -1; + } + } + + public static class WildcardResourceHandler extends AbstractHandler { + + @Override + public void handle( + String s, + Request baseRequest, + jakarta.servlet.http.HttpServletRequest httpServletRequest, + jakarta.servlet.http.HttpServletResponse response) + throws IOException { + if (response.isCommitted() || baseRequest.isHandled()) { + return; + } + baseRequest.setHandled(true); + final String content = "Success!"; + response.setStatus(HttpServletResponse.SC_OK); + response.setContentType("text/html"); + response.setContentLength(content.length()); + try (OutputStream out = response.getOutputStream()) { + out.write(content.getBytes(StandardCharsets.UTF_8)); + } + } + } +} diff --git a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java index 38d096884..60faebb42 100644 --- a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java +++ b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java @@ -30,7 +30,7 @@ import java.util.concurrent.TimeUnit; import org.apache.storm.Config; import org.apache.stormcrawler.Metadata; -import org.apache.stormcrawler.protocol.AbstractProtocolTest; +import org.apache.stormcrawler.protocol.playwright.BasePlaywrightTest; import org.apache.stormcrawler.protocol.ProtocolResponse; import org.apache.stormcrawler.protocol.playwright.actions.DismissOverlayAction; import org.apache.stormcrawler.protocol.playwright.actions.EvaluateAction; @@ -49,15 +49,12 @@ * implementations. Requires a working Playwright/Chrome install (or a {@code playwright.cdp.url}) * and is skipped when {@code CI_ENV=true}, mirroring the gate used by {@link ProtocolTest}. */ -class PageActionsLiveTest extends AbstractProtocolTest { +class PageActionsLiveTest extends BasePlaywrightTest { private static final String USER_AGENT = "StormCrawlerTest"; private static final String FIXTURE_PATH = "/page-actions-fixture.html"; - @Override - protected Handler[] getHandlers() { - return new Handler[] {new LocalResourceHandler(), new WildcardResourceHandler()}; - } + @BeforeEach void setup() { diff --git a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java index a52436cae..377e49061 100644 --- a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java +++ b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java @@ -27,7 +27,7 @@ import org.apache.storm.Config; import org.apache.storm.utils.MutableObject; import org.apache.stormcrawler.Metadata; -import org.apache.stormcrawler.protocol.AbstractProtocolTest; +import org.apache.stormcrawler.protocol.playwright.BasePlaywrightTest; import org.apache.stormcrawler.protocol.ProtocolResponse; import org.eclipse.jetty.server.Handler; import org.junit.jupiter.api.Assertions; @@ -39,14 +39,11 @@ * Tests for Playwright protocol implementation. Chrome should be running on localhost, whether is * has been launched manually or by Playwright. */ -class ProtocolTest extends AbstractProtocolTest { +class ProtocolTest extends BasePlaywrightTest { private static final String USER_AGENT = "StormCrawlerTest"; - @Override - protected Handler[] getHandlers() { - return new Handler[] {new LocalResourceHandler(), new WildcardResourceHandler()}; - } + public HttpProtocol getProtocol() { Config conf = new Config(); From cd5c4f57e217530d72fa2e54cbe5b5cc62a5725e Mon Sep 17 00:00:00 2001 From: Julien Nioche Date: Thu, 14 May 2026 16:45:24 +0100 Subject: [PATCH 2/4] Removed unecessary imports Signed-off-by: Julien Nioche --- .../stormcrawler/protocol/playwright/PageActionsLiveTest.java | 4 ---- .../apache/stormcrawler/protocol/playwright/ProtocolTest.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java index 60faebb42..55af76113 100644 --- a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java +++ b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java @@ -30,7 +30,6 @@ import java.util.concurrent.TimeUnit; import org.apache.storm.Config; import org.apache.stormcrawler.Metadata; -import org.apache.stormcrawler.protocol.playwright.BasePlaywrightTest; import org.apache.stormcrawler.protocol.ProtocolResponse; import org.apache.stormcrawler.protocol.playwright.actions.DismissOverlayAction; import org.apache.stormcrawler.protocol.playwright.actions.EvaluateAction; @@ -38,7 +37,6 @@ import org.apache.stormcrawler.protocol.playwright.actions.ScreenshotAction; import org.apache.stormcrawler.protocol.playwright.actions.ScrollToBottomAction; import org.apache.stormcrawler.protocol.playwright.actions.WaitForSelectorAction; -import org.eclipse.jetty.server.Handler; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -54,8 +52,6 @@ class PageActionsLiveTest extends BasePlaywrightTest { private static final String USER_AGENT = "StormCrawlerTest"; private static final String FIXTURE_PATH = "/page-actions-fixture.html"; - - @BeforeEach void setup() { assumeTrue("false".equals(System.getProperty("CI_ENV", "false"))); diff --git a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java index 377e49061..03914834c 100644 --- a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java +++ b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java @@ -27,9 +27,7 @@ import org.apache.storm.Config; import org.apache.storm.utils.MutableObject; import org.apache.stormcrawler.Metadata; -import org.apache.stormcrawler.protocol.playwright.BasePlaywrightTest; import org.apache.stormcrawler.protocol.ProtocolResponse; -import org.eclipse.jetty.server.Handler; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -43,8 +41,6 @@ class ProtocolTest extends BasePlaywrightTest { private static final String USER_AGENT = "StormCrawlerTest"; - - public HttpProtocol getProtocol() { Config conf = new Config(); conf.put("http.agent.name", USER_AGENT); From a15a8c6c23bcbbdecf868632041ed19661ecec0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Szigecs=C3=A1n?= Date: Fri, 15 May 2026 14:02:13 +0200 Subject: [PATCH 3/4] Fix Playwright tests failing when run together --- .../protocol/AbstractProtocolTest.java | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/core/src/test/java/org/apache/stormcrawler/protocol/AbstractProtocolTest.java b/core/src/test/java/org/apache/stormcrawler/protocol/AbstractProtocolTest.java index 93aab4a74..36f5a78d3 100644 --- a/core/src/test/java/org/apache/stormcrawler/protocol/AbstractProtocolTest.java +++ b/core/src/test/java/org/apache/stormcrawler/protocol/AbstractProtocolTest.java @@ -17,20 +17,19 @@ package org.apache.stormcrawler.protocol; -import static org.junit.jupiter.api.Assertions.assertNotEquals; - import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStream; -import java.net.ServerSocket; import java.nio.charset.StandardCharsets; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.HandlerList; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; /** Takes care of initialising Jetty for testing protocol implementation * */ public abstract class AbstractProtocolTest { @@ -39,21 +38,27 @@ public abstract class AbstractProtocolTest { protected static Integer HTTP_PORT; - @BeforeAll - static void initJetty() throws Exception { - HTTP_PORT = findRandomOpenPortOnAllLocalInterfaces(); - assertNotEquals(Integer.valueOf(-1), HTTP_PORT); - httpServer = new Server(HTTP_PORT); + @BeforeEach + void initJetty() throws Exception { + if (httpServer != null && httpServer.isRunning()) { + return; + } + + httpServer = new Server(0); final HandlerList handlers = new HandlerList(); handlers.setHandlers(getHandlers()); httpServer.setHandler(handlers); httpServer.start(); + + HTTP_PORT = ((ServerConnector) httpServer.getConnectors()[0]).getLocalPort(); + Assertions.assertNotNull(HTTP_PORT); } @AfterAll static void stopJetty() throws Exception { if (httpServer != null) { httpServer.stop(); + httpServer = null; } } @@ -61,14 +66,6 @@ protected Handler[] getHandlers() { return new Handler[] {new WildcardResourceHandler()}; } - private static Integer findRandomOpenPortOnAllLocalInterfaces() { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } catch (IOException e) { - return -1; - } - } - public static class WildcardResourceHandler extends AbstractHandler { @Override From 4258fbd3b645a67c01bcb81b0f88d51b5ce2f722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Szigecs=C3=A1n?= Date: Fri, 15 May 2026 14:12:33 +0200 Subject: [PATCH 4/4] Revert unneeded changes --- .../playwright/BasePlaywrightTest.java | 94 ------------------- .../playwright/PageActionsLiveTest.java | 9 +- .../protocol/playwright/ProtocolTest.java | 9 +- 3 files changed, 16 insertions(+), 96 deletions(-) delete mode 100644 external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/BasePlaywrightTest.java diff --git a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/BasePlaywrightTest.java b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/BasePlaywrightTest.java deleted file mode 100644 index 2725570fc..000000000 --- a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/BasePlaywrightTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you 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 org.apache.stormcrawler.protocol.playwright; - -import static org.junit.jupiter.api.Assertions.assertNotEquals; - -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.OutputStream; -import java.net.ServerSocket; -import java.nio.charset.StandardCharsets; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.server.handler.HandlerList; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -/** Base test class for Playwright tests with isolated Jetty server * */ -public abstract class BasePlaywrightTest { - - protected static Server httpServer; - - protected static Integer HTTP_PORT; - - @BeforeAll - static void initJetty() throws Exception { - HTTP_PORT = findRandomOpenPortOnAllLocalInterfaces(); - assertNotEquals(Integer.valueOf(-1), HTTP_PORT); - httpServer = new Server(HTTP_PORT); - final HandlerList handlers = new HandlerList(); - handlers.setHandlers(getHandlers()); - httpServer.setHandler(handlers); - httpServer.start(); - } - - @AfterAll - static void stopJetty() throws Exception { - if (httpServer != null) { - httpServer.stop(); - } - } - - protected static Handler[] getHandlers() { - return new Handler[] {new LocalResourceHandler(), new WildcardResourceHandler()}; - } - - private static Integer findRandomOpenPortOnAllLocalInterfaces() { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } catch (IOException e) { - return -1; - } - } - - public static class WildcardResourceHandler extends AbstractHandler { - - @Override - public void handle( - String s, - Request baseRequest, - jakarta.servlet.http.HttpServletRequest httpServletRequest, - jakarta.servlet.http.HttpServletResponse response) - throws IOException { - if (response.isCommitted() || baseRequest.isHandled()) { - return; - } - baseRequest.setHandled(true); - final String content = "Success!"; - response.setStatus(HttpServletResponse.SC_OK); - response.setContentType("text/html"); - response.setContentLength(content.length()); - try (OutputStream out = response.getOutputStream()) { - out.write(content.getBytes(StandardCharsets.UTF_8)); - } - } - } -} diff --git a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java index 55af76113..38d096884 100644 --- a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java +++ b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/PageActionsLiveTest.java @@ -30,6 +30,7 @@ import java.util.concurrent.TimeUnit; import org.apache.storm.Config; import org.apache.stormcrawler.Metadata; +import org.apache.stormcrawler.protocol.AbstractProtocolTest; import org.apache.stormcrawler.protocol.ProtocolResponse; import org.apache.stormcrawler.protocol.playwright.actions.DismissOverlayAction; import org.apache.stormcrawler.protocol.playwright.actions.EvaluateAction; @@ -37,6 +38,7 @@ import org.apache.stormcrawler.protocol.playwright.actions.ScreenshotAction; import org.apache.stormcrawler.protocol.playwright.actions.ScrollToBottomAction; import org.apache.stormcrawler.protocol.playwright.actions.WaitForSelectorAction; +import org.eclipse.jetty.server.Handler; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -47,11 +49,16 @@ * implementations. Requires a working Playwright/Chrome install (or a {@code playwright.cdp.url}) * and is skipped when {@code CI_ENV=true}, mirroring the gate used by {@link ProtocolTest}. */ -class PageActionsLiveTest extends BasePlaywrightTest { +class PageActionsLiveTest extends AbstractProtocolTest { private static final String USER_AGENT = "StormCrawlerTest"; private static final String FIXTURE_PATH = "/page-actions-fixture.html"; + @Override + protected Handler[] getHandlers() { + return new Handler[] {new LocalResourceHandler(), new WildcardResourceHandler()}; + } + @BeforeEach void setup() { assumeTrue("false".equals(System.getProperty("CI_ENV", "false"))); diff --git a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java index 03914834c..a52436cae 100644 --- a/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java +++ b/external/playwright/src/test/java/org/apache/stormcrawler/protocol/playwright/ProtocolTest.java @@ -27,7 +27,9 @@ import org.apache.storm.Config; import org.apache.storm.utils.MutableObject; import org.apache.stormcrawler.Metadata; +import org.apache.stormcrawler.protocol.AbstractProtocolTest; import org.apache.stormcrawler.protocol.ProtocolResponse; +import org.eclipse.jetty.server.Handler; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -37,10 +39,15 @@ * Tests for Playwright protocol implementation. Chrome should be running on localhost, whether is * has been launched manually or by Playwright. */ -class ProtocolTest extends BasePlaywrightTest { +class ProtocolTest extends AbstractProtocolTest { private static final String USER_AGENT = "StormCrawlerTest"; + @Override + protected Handler[] getHandlers() { + return new Handler[] {new LocalResourceHandler(), new WildcardResourceHandler()}; + } + public HttpProtocol getProtocol() { Config conf = new Config(); conf.put("http.agent.name", USER_AGENT);