-
Notifications
You must be signed in to change notification settings - Fork 41.2k
SpringBootTest with MockMvc and WebSocketHandlers work with Tomcat and Undertow but not with Jetty #7487
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
There's no standardised API for performing a WebSocket upgrade so Spring Framework has a strategy interface, RequestUpgradeStrategy, and a number of container-specific implementations. The Jetty implementation requires Jetty to be running. I don't think there's anything we can do about that in Spring Boot as it's simply due to the way that Jetty's been implemented.
One final point to note is that this test will reproduce the problem without any involvement from Spring Boot: public class MockServletContextJettyWebSocketTests {
@Test
public void test() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setServletContext(new MockServletContext());
context.register(ExampleConfiguration.class);
context.refresh();
}
@Configuration
@EnableWebSocket
static class ExampleConfiguration implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler(), "/ws");
}
@Bean
public WebSocketHandler webSocketHandler() {
return new TextWebSocketHandler();
}
}
} If you'd like to pursue your current arrangement working with Jetty then please open a Spring Framework JIRA ticket. |
I have been struggling to get integration tests working with jetty and websockets and came across this issue. I checked out https://github.com/isopov/mockmvc-test-websocket and it does not work with jetty. It seems to be related to https://jira.spring.io/browse/SPR-16263 Within the init method of WebSocketServerFactory, this exception is thrown ContextHandler handler = ContextHandler.getContextHandler(context); if (handler == null) According to the jira, it appears this is because Spring's MockServletContext doesn't implement Jetty's ContextHandler.Context; i.e. ContextHandler.getContextHandler(context); returns null. is there anyway to get websocket integration tests (with or without spring boot) to work jetty? |
Yes, I believe you can integration test WebSockets with Jetty by starting Jetty rather than trying to use |
I have posted a question here: https://stackoverflow.com/questions/49446510/spring-integration-testing-with-jetty-and-websockets |
@jmc420 start a real jetty server for your websocket testing. It starts faster then the Spring MockMVC anyway. (in our testing we can start a real server, toss a dozen messages with echo at the websocket, and shutdown the server in under 150ms) As for ... ContextHandler handler = ContextHandler.getContextHandler(context);
if (handler == null)
{
throw new ServletException("Not running on Jetty, WebSocket support unavailable");
} That's from the WebSocketUpgradeFilter (Not the WebSocketServerFactory). In WebSocket on Jetty there are 2 such checks ... org/eclipse/jetty/websocket/server/WebSocketUpgradeFilter.java org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java The internal use of the Jetty ContextHandler and ServletContextHandler exist to manage the Jetty object LifeCycle and allow reuse of other expensive LifeCycle components (such as the ThreadPool, Executor, and HttpClient) I'd be open to making Jetty (perhaps Jetty 9.4.10, definitely Jetty 10.x) a bit more flexible here to allow MockMVC. What's the requirements from the MockMVC point of view? |
@joakime Thanks for the reply. I would see if you can get it working with the (unit) test in the example repo above: As I mentioned in the stackoverflow post, I am running a Jetty integration (rather than unit) test using these annotations:
When I run this without a WebSocket configuration picked up by component scanning, everything works fine, but when I introduce a WebSocket configuration it fails because of which is the exception (throw new ServletException("Not running on Jetty, WebSocket support unavailable");) I am running Jetty 9.3 which is why it appears for me in WebSocketServerFactory rather than WebSocketUpgradeFilter. |
Looking at this ... Why does Hmm, lots of strange decisions here. |
Those are interesting questions, but they're question for the Spring Framework team. The code in question is not part of Spring Boot. /cc @rstoyanchev |
I've made some minor changes to WebSocketServerFactory to allow MockMVC to function. Jetty Branch: https://github.com/eclipse/jetty.project/tree/jetty-9.4.x-issue-2376-ws-context-relaxation Let me know if this is sufficient (for now), or of anything else is needed? Aside: I think the Jetty implementation for upgrade at Spring Framework needs an overhaul to be more resilient. |
Note: I had to upgrade to version 2.0.0 in my fork.
The two key lines ...
If those concepts are not provided, or found in the context hierarchy, or found via the server reference, then they are created locally. |
@jmc420, judging from your comments here and on SO, I think there is a misunderstanding. Can you clarify which do you want? To test WebSocket endpoints with Spring MVC Test uses mock Servlet API objects and for such tests there is no running Servlet container. It exists mainly to help with testing controllers (for which plain unit tests are useless) taking into account annotations and Spring configuration. To test WebSockets you need a running server. Or if you're using annotated controllers with STOMP over WebSocket, you can see this here. The referenced sample test is actually targetting a regular controller method. It succeeds on Tomcat and Undertow because WebSocket initialization does not fail, not because WebSockets are used in the test. In SPR-16263 the goal is also not to test WebSockets but to load Spring configuration in a test environment, and that configuration includes WebSocket endpoints. I think the answer there would be to separate the WebSocket related configuration and avoid loading it during the test, or to use the Spring config profile feature to mark and exclude it in tests. @joakime the purpose of JSR-356 did not provide such a mechanism, even though we requested it (the spec JIRA is now gone so I can no longer link). That request was up-voted but as you know there were never any real spec updates beyond the initial release. Over time we did ask various servers to expose some API for this use case, and we got it from Tomcat, Undertow, and WebSphere. I don't recall any longer TBH if we did ask the Jetty team or not. It would be great to have such an API for performing a WebSocket upgrade at runtime explicitly supported in Jetty. Or perhaps there is an existing API I have misssed? |
@rstoyanchev the current location of the JSR-356 spec issues is https://github.com/eclipse-ee4j/websocket-api/issues btw. Your documentation has a link to https://java.net/jira/browse/WEBSOCKET_SPEC-211 |
Good to know about the new location, and I've updated the documentation to point to it. |
Linking back to jetty/jetty.project#2376 for historical/tracking reasons. |
judging from your comments here and on SO, I think there is a
misunderstanding. Can you clarify which do you want? To test WebSocket
endpoints with MockMvc, or to test regular HTTP endpoints with MockMvc but
can't load your Spring config because of failures related to WebSocket
initialization?
The latter is correct. I do not want to test websockets but there is
websocket configuration in the service I want to write tests for and the
test will not startup because of the initialisation errors. I tried
excluding the configuration in the component scan but could not fix the
problem that way.
James
…On 28 March 2018 at 21:25, Joakim Erdfelt ***@***.***> wrote:
Linking back to jetty/jetty.project#2376
<jetty/jetty.project#2376> for
historical/tracking reasons.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#7487 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ALLjCUy8FbYuZgJ7oGbxiwke_Z6hzfTVks5ti_G0gaJpZM4K8cCc>
.
|
Test projects may be found here: https://github.com/isopov/mockmvc-test-websocket
Basically it is simple "hello world" application with "do nothing" WebSocketHandler and MockMvc-based SpringBootTest to test "hello world" endpoint. This test passes successfully with Tomcat and Undertow in the classpath, but not with Jetty.
Full stacktrace is:
The text was updated successfully, but these errors were encountered: