1717package org .springframework .boot .web .embedded .netty ;
1818
1919import java .net .ConnectException ;
20+ import java .net .SocketAddress ;
2021import java .time .Duration ;
2122import java .util .Arrays ;
2223
24+ import io .netty .channel .Channel ;
2325import org .awaitility .Awaitility ;
2426import org .junit .jupiter .api .Test ;
2527import org .mockito .InOrder ;
28+ import reactor .core .CoreSubscriber ;
29+ import reactor .core .Disposable ;
2630import reactor .core .publisher .Mono ;
31+ import reactor .netty .DisposableChannel ;
32+ import reactor .netty .DisposableServer ;
2733import reactor .netty .http .server .HttpServer ;
2834import reactor .test .StepVerifier ;
2935
3440import org .springframework .boot .web .server .Ssl ;
3541import org .springframework .http .MediaType ;
3642import org .springframework .http .client .reactive .ReactorClientHttpConnector ;
43+ import org .springframework .http .server .reactive .ReactorHttpHandlerAdapter ;
3744import org .springframework .web .reactive .function .BodyInserters ;
3845import org .springframework .web .reactive .function .client .WebClient ;
3946
5259 */
5360class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactoryTests {
5461
55- @ Override
56- protected NettyReactiveWebServerFactory getFactory () {
57- return new NettyReactiveWebServerFactory (0 );
58- }
59-
6062 @ Test
6163 void exceptionIsThrownWhenPortIsAlreadyInUse () {
6264 AbstractReactiveWebServerFactory factory = getFactory ();
@@ -68,6 +70,14 @@ void exceptionIsThrownWhenPortIsAlreadyInUse() {
6870 .satisfies (this ::portMatchesRequirement ).withCauseInstanceOf (Throwable .class );
6971 }
7072
73+ @ Test
74+ void getPortWhenDisposableServerPortOperationIsUnsupportedReturnsMinusOne () {
75+ NettyReactiveWebServerFactory factory = new NoPortNettyReactiveWebServerFactory (0 );
76+ this .webServer = factory .getWebServer (new EchoHandler ());
77+ this .webServer .start ();
78+ assertThat (this .webServer .getPort ()).isEqualTo (-1 );
79+ }
80+
7181 private void portMatchesRequirement (PortInUseException exception ) {
7282 assertThat (exception .getPort ()).isEqualTo (this .webServer .getPort ());
7383 }
@@ -143,4 +153,102 @@ protected Mono<String> testSslWithAlias(String alias) {
143153 .retrieve ().bodyToMono (String .class );
144154 }
145155
156+ @ Override
157+ protected NettyReactiveWebServerFactory getFactory () {
158+ return new NettyReactiveWebServerFactory (0 );
159+ }
160+
161+ static class NoPortNettyReactiveWebServerFactory extends NettyReactiveWebServerFactory {
162+
163+ NoPortNettyReactiveWebServerFactory (int port ) {
164+ super (port );
165+ }
166+
167+ @ Override
168+ NettyWebServer createNettyWebServer (HttpServer httpServer , ReactorHttpHandlerAdapter handlerAdapter ,
169+ Duration lifecycleTimeout , Shutdown shutdown ) {
170+ return new NoPortNettyWebServer (httpServer , handlerAdapter , lifecycleTimeout , shutdown );
171+ }
172+
173+ }
174+
175+ static class NoPortNettyWebServer extends NettyWebServer {
176+
177+ NoPortNettyWebServer (HttpServer httpServer , ReactorHttpHandlerAdapter handlerAdapter , Duration lifecycleTimeout ,
178+ Shutdown shutdown ) {
179+ super (httpServer , handlerAdapter , lifecycleTimeout , shutdown );
180+ }
181+
182+ @ Override
183+ DisposableServer startHttpServer () {
184+ return new NoPortDisposableServer (super .startHttpServer ());
185+ }
186+
187+ }
188+
189+ static class NoPortDisposableServer implements DisposableServer {
190+
191+ private final DisposableServer delegate ;
192+
193+ NoPortDisposableServer (DisposableServer delegate ) {
194+ this .delegate = delegate ;
195+ }
196+
197+ @ Override
198+ public SocketAddress address () {
199+ return this .delegate .address ();
200+ }
201+
202+ @ Override
203+ public String host () {
204+ return this .delegate .host ();
205+ }
206+
207+ @ Override
208+ public String path () {
209+ return this .delegate .path ();
210+ }
211+
212+ @ Override
213+ public Channel channel () {
214+ return this .delegate .channel ();
215+ }
216+
217+ @ Override
218+ public void dispose () {
219+ this .delegate .dispose ();
220+ }
221+
222+ @ Override
223+ public void disposeNow () {
224+ this .delegate .disposeNow ();
225+ }
226+
227+ @ Override
228+ public void disposeNow (Duration timeout ) {
229+ this .delegate .disposeNow (timeout );
230+ }
231+
232+ @ Override
233+ public CoreSubscriber <Void > disposeSubscriber () {
234+ return this .delegate .disposeSubscriber ();
235+ }
236+
237+ @ Override
238+ public boolean isDisposed () {
239+ return this .delegate .isDisposed ();
240+ }
241+
242+ @ Override
243+ public Mono <Void > onDispose () {
244+ return this .delegate .onDispose ();
245+ }
246+
247+ @ Override
248+ public DisposableChannel onDispose (Disposable onDispose ) {
249+ return this .delegate .onDispose (onDispose );
250+ }
251+
252+ }
253+
146254}
0 commit comments