Skip to content

Commit 7aedc32

Browse files
authored
Merge pull request #31169 from pnicolucci/AddFATForTcpOptionsPortOpenRetries
Add tcpOptions portOpenRetries FAT
2 parents af5961e + b683745 commit 7aedc32

File tree

8 files changed

+299
-4
lines changed

8 files changed

+299
-4
lines changed

dev/fattest.simplicity/src/com/ibm/websphere/simplicity/config/TcpOptions.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class TcpOptions extends ConfigElement {
2525
private String hostNameIncludeList;
2626
private String hostNameExcludeList;
2727
private Integer maxOpenConnections;
28+
private Integer portOpenRetries;
2829

2930
public Boolean isSoReuseAddr() {
3031
return this.soReuseAddr;
@@ -50,6 +51,10 @@ public Integer getMaxOpenConnections() {
5051
return maxOpenConnections;
5152
}
5253

54+
public Integer getPortOpenRetries() {
55+
return portOpenRetries;
56+
}
57+
5358
@XmlAttribute
5459
public void setSoReuseAddr(Boolean soReuseAddr) {
5560
this.soReuseAddr = soReuseAddr;
@@ -80,6 +85,11 @@ public void setMaxOpenConnections(Integer maxOpenConnections) {
8085
this.maxOpenConnections = maxOpenConnections;
8186
}
8287

88+
@XmlAttribute
89+
public void setPortOpenRetries(Integer portOpenRetries) {
90+
this.portOpenRetries = portOpenRetries;
91+
}
92+
8393
@Override
8494
public String toString() {
8595
StringBuffer buf = new StringBuffer("TcpOptions{");
@@ -97,6 +107,9 @@ public String toString() {
97107
buf.append("hostNameExcludeList=\"" + hostNameExcludeList + "\" ");
98108
if (getMaxOpenConnections() != null)
99109
buf.append("maxOpenConnections=\"" + maxOpenConnections + "\" ");
110+
if (getPortOpenRetries() != null) {
111+
buf.append("portOpenRetries=\"" + portOpenRetries + "\" ");
112+
}
100113
buf.append("}");
101114
return buf.toString();
102115
}

dev/io.openliberty.netty.internal.impl/src/io/openliberty/netty/internal/tcp/TCPUtils.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2021, 2023 IBM Corporation and others.
2+
* Copyright (c) 2021, 2025 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -172,8 +172,8 @@ private static ChannelFuture open(NettyFrameworkImpl framework, AbstractBootstra
172172

173173
if (retryCount > 0) {
174174
if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
175-
Tr.debug(tc, "attempt to bind again after a wait of " + timeBetweenRetriesMsec + "ms; "
176-
+ retryCount + " attempts remaining" + " for " + config.getExternalName());
175+
// config.getPortOpenRetries() + 1 because the initial bind failed, now trying config.getPortOpenRetries() additional times.
176+
Tr.debug(tc, "attempt " + retryCount + " of " + (config.getPortOpenRetries() + 1) + " failed to open the port, will try again after wait interval");
177177
}
178178
// recurse until we either complete successfully or run out of retries;
179179
try {

dev/io.openliberty.transport.http_fat/fat/src/io/openliberty/transport/http_fat/FATSuite.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
@RunWith(Suite.class)
2424
@SuiteClasses({
2525
AccessListsTests.class,
26-
MaxOpenConnectionsTest.class
26+
MaxOpenConnectionsTest.class,
27+
PortOpenRetriesTests.class
2728
})
2829
public class FATSuite {
2930

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 IBM Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License 2.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*******************************************************************************/
10+
package io.openliberty.transport.http_fat;
11+
12+
import static org.junit.Assert.assertNotNull;
13+
14+
import java.util.logging.Logger;
15+
16+
import org.junit.After;
17+
import org.junit.AfterClass;
18+
import org.junit.Before;
19+
import org.junit.BeforeClass;
20+
import org.junit.Test;
21+
import org.junit.runner.RunWith;
22+
23+
import com.ibm.websphere.simplicity.config.HttpEndpoint;
24+
import com.ibm.websphere.simplicity.config.ServerConfiguration;
25+
26+
import componenttest.annotation.Server;
27+
import componenttest.custom.junit.runner.FATRunner;
28+
import componenttest.custom.junit.runner.Mode;
29+
import componenttest.custom.junit.runner.Mode.TestMode;
30+
import componenttest.topology.impl.LibertyServer;
31+
32+
/**
33+
* Test to ensure that the tcpOptions portOpenRetries works.
34+
*/
35+
@RunWith(FATRunner.class)
36+
public class PortOpenRetriesTests {
37+
38+
private static final String CLASS_NAME = PortOpenRetriesTests.class.getName();
39+
private static final Logger LOG = Logger.getLogger(CLASS_NAME);
40+
41+
@Server("PortOpenRetries1")
42+
public static LibertyServer server1;
43+
44+
@Server("PortOpenRetries2")
45+
public static LibertyServer server2;
46+
47+
@BeforeClass
48+
public static void setup() throws Exception {
49+
// Start server1 and use the class name so we can find logs easily.
50+
server1.startServer(PortOpenRetriesTests.class.getSimpleName() + ".log");
51+
}
52+
53+
@AfterClass
54+
public static void tearDown() throws Exception {
55+
// Stop server1.
56+
if (server1 != null && server1.isStarted()) {
57+
//CWWKG0011W: The configuration validation did not succeed. Value "-1" is out of range.
58+
// CWWKG0083W: A validation failure occurred while processing the [portOpenRetries] property, value = [-1]. Default value in use: [0].
59+
server1.stopServer("CWWKG0011W", "CWWKG0083W");
60+
}
61+
62+
// Server2 should already have been stopped but let's make sure!
63+
if (server2 != null && server2.isStarted()) {
64+
// CWWKO0221E: TCP Channel defaultHttpEndpoint initialization did not succeed.
65+
// The socket bind did not succeed for host * and port 8010. The port might already be in use.
66+
// Exception Message: Address already in use: bind
67+
server2.stopServer("CWWKO0221E");
68+
}
69+
}
70+
71+
/**
72+
* Save the server configuration before each test, this should be the default server
73+
* configuration.
74+
*
75+
* @throws Exception
76+
*/
77+
@Before
78+
public void beforeTest() throws Exception {
79+
server1.saveServerConfiguration();
80+
81+
ServerConfiguration configuration = server1.getServerConfiguration();
82+
LOG.info("Server configuration that was saved: " + configuration);
83+
}
84+
85+
/**
86+
* Restore the server configuration to the default state after each test.
87+
*
88+
* @throws Exception
89+
*/
90+
@After
91+
public void afterTest() throws Exception {
92+
// Restore the servers to their default state.
93+
server1.setMarkToEndOfLog();
94+
server1.setTraceMarkToEndOfDefaultTrace();
95+
server1.restoreServerConfiguration();
96+
server1.waitForConfigUpdateInLogUsingMark(null);
97+
}
98+
99+
/**
100+
* The test will check the default value of portOpenRetries by searching the trace file.
101+
*
102+
* The default value is 0.
103+
*/
104+
@Test
105+
public void testPortOpenRetries_default() throws Exception {
106+
// Validate that portOpenRetries default is 0.
107+
assertNotNull("The default value of portOpenRetries was not: 0!", server1.waitForStringInTrace("portOpenRetries: 0"));
108+
}
109+
110+
/**
111+
* The test will set portOpenRetries to a value of 60 and validate in the trace file that
112+
* the correct value is being used.
113+
*
114+
* The below configuration will be used to set portOpenRetries to 60:
115+
* <tcpOptions portOpenRetries="60"/>
116+
*
117+
* @throws Exception
118+
*/
119+
@Test
120+
@Mode(TestMode.FULL)
121+
public void testPortOpenRetries_nonDefault() throws Exception {
122+
ServerConfiguration configuration = server1.getServerConfiguration();
123+
LOG.info("Server configuration that the test started with: " + configuration);
124+
125+
HttpEndpoint httpEndpoint = configuration.getHttpEndpoints().getById("defaultHttpEndpoint");
126+
httpEndpoint.getTcpOptions().setPortOpenRetries(60);
127+
128+
server1.setMarkToEndOfLog();
129+
server1.setTraceMarkToEndOfDefaultTrace();
130+
server1.updateServerConfiguration(configuration);
131+
server1.waitForConfigUpdateInLogUsingMark(null);
132+
133+
// Validate that portOpenRetries is set to 60.
134+
assertNotNull("The configured value of portOpenRetries was not 60!", server1.waitForStringInTraceUsingMark("portOpenRetries: 60"));
135+
}
136+
137+
/**
138+
* The test will set portOpenRetries to a value of -1 and validate that is an incorrect configuration.
139+
*
140+
* The below configuration will be used to set portOpenRetries to -1:
141+
* <tcpOptions portOpenRetries="-1"/>
142+
*
143+
* @throws Exception
144+
*/
145+
@Test
146+
@Mode(TestMode.FULL)
147+
public void testPortOpenRetries_invalid() throws Exception {
148+
ServerConfiguration configuration = server1.getServerConfiguration();
149+
LOG.info("Server configuration that the test started with: " + configuration);
150+
151+
HttpEndpoint httpEndpoint = configuration.getHttpEndpoints().getById("defaultHttpEndpoint");
152+
httpEndpoint.getTcpOptions().setPortOpenRetries(-1);
153+
154+
server1.setMarkToEndOfLog();
155+
server1.setTraceMarkToEndOfDefaultTrace();
156+
server1.updateServerConfiguration(configuration);
157+
server1.waitForConfigUpdateInLogUsingMark(null);
158+
159+
//CWWKG0011W: The configuration validation did not succeed. Value "-1" is out of range.
160+
assertNotNull("The CWWKG0011W was not found in the logs!", server1.waitForStringInLogUsingMark("CWWKG0011W"));
161+
162+
// CWWKG0083W: A validation failure occurred while processing the [portOpenRetries] property, value = [-1]. Default value in use: [0].
163+
assertNotNull("The CWWKG0083W was not found in the logs!", server1.waitForStringInLogUsingMark("CWWKG0083W"));
164+
}
165+
166+
/**
167+
* The test uses server2 which defines the following configuration:
168+
* <tcpOptions portOpenRetries="5"/>
169+
*
170+
* The test will start server2 which has not been started yet. Both server1 and server2
171+
* define the same ports to bind to. The test will then verify that server2 tries to bind to
172+
* the port that is already in use 5 times and ensure that the server eventually fails to bind
173+
* to the port and the following message is logged:
174+
*
175+
* CWWKO0221E: TCP Channel defaultHttpEndpoint initialization did not succeed.
176+
* The socket bind did not succeed for host * and port 8010. The port might already be in use.
177+
* Exception Message: Address already in use: bind
178+
*
179+
* @throws Exception
180+
*/
181+
@Test
182+
@Mode(TestMode.FULL)
183+
public void testPortOpenRetries() throws Exception {
184+
// Start server2 and use the class name so we can find logs easily.
185+
server2.startServer(PortOpenRetriesTests.class.getSimpleName() + ".log");
186+
187+
// Validate that portOpenRetries is set to 5.
188+
assertNotNull("The configured value of portOpenRetries was not 5!", server2.waitForStringInTrace("portOpenRetries: 5"));
189+
190+
// Validate that the port binding was tried 5 times.
191+
assertNotNull("Attempt 1 to bind did not fail and should have!", server2.waitForStringInTrace("attempt 1 of 6 failed to open the port"));
192+
assertNotNull("Attempt 2 to bind did not fail and should have!", server2.waitForStringInTrace("attempt 2 of 6 failed to open the port"));
193+
assertNotNull("Attempt 3 to bind did not fail and should have!", server2.waitForStringInTrace("attempt 3 of 6 failed to open the port"));
194+
assertNotNull("Attempt 4 to bind did not fail and should have!", server2.waitForStringInTrace("attempt 4 of 6 failed to open the port"));
195+
assertNotNull("Attempt 5 to bind did not fail and should have!", server2.waitForStringInTrace("attempt 5 of 6 failed to open the port"));
196+
197+
// Validate that CWWKO0221E was logged.
198+
assertNotNull("The PortOpenRetries2 server was able to bind successfully should not have been able to!!", server2.waitForStringInLog("CWWKO0221E"));
199+
200+
if (server2 != null && server2.isStarted()) {
201+
server2.stopServer("CWWKO0221E");
202+
}
203+
}
204+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
###############################################################################
2+
# Copyright (c) 2025 IBM Corporation and others.
3+
# All rights reserved. This program and the accompanying materials
4+
# are made available under the terms of the Eclipse Public License 2.0
5+
# which accompanies this distribution, and is available at
6+
# http://www.eclipse.org/legal/epl-2.0/
7+
#
8+
# SPDX-License-Identifier: EPL-2.0
9+
###############################################################################
10+
bootstrap.include=../testports.properties
11+
com.ibm.ws.logging.trace.specification=*=info:TCPChannel=all
12+
com.ibm.ws.logging.max.file.size=100
13+
com.ibm.ws.logging.max.files=10
14+
com.ibm.ws.logging.trace.format=BASIC
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!--
2+
Copyright (c) 2025 IBM Corporation and others.
3+
All rights reserved. This program and the accompanying materials
4+
are made available under the terms of the Eclipse Public License 2.0
5+
which accompanies this distribution, and is available at
6+
http://www.eclipse.org/legal/epl-2.0/
7+
8+
SPDX-License-Identifier: EPL-2.0
9+
-->
10+
<server description="Test tcpOptions portOpenRetries configuration.">
11+
12+
<include location="../fatTestCommon.xml"/>
13+
14+
<httpEndpoint id="defaultHttpEndpoint"
15+
host="*"
16+
httpPort="${bvt.prop.HTTP_default}"
17+
httpsPort="${bvt.prop.HTTP_default.secure}">
18+
</httpEndpoint>
19+
20+
<featureManager>
21+
<feature>servlet-3.1</feature>
22+
</featureManager>
23+
24+
</server>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
###############################################################################
2+
# Copyright (c) 2025 IBM Corporation and others.
3+
# All rights reserved. This program and the accompanying materials
4+
# are made available under the terms of the Eclipse Public License 2.0
5+
# which accompanies this distribution, and is available at
6+
# http://www.eclipse.org/legal/epl-2.0/
7+
#
8+
# SPDX-License-Identifier: EPL-2.0
9+
###############################################################################
10+
bootstrap.include=../testports.properties
11+
com.ibm.ws.logging.trace.specification=*=info:TCPChannel=all
12+
com.ibm.ws.logging.max.file.size=100
13+
com.ibm.ws.logging.max.files=10
14+
com.ibm.ws.logging.trace.format=BASIC
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!--
2+
Copyright (c) 2025 IBM Corporation and others.
3+
All rights reserved. This program and the accompanying materials
4+
are made available under the terms of the Eclipse Public License 2.0
5+
which accompanies this distribution, and is available at
6+
http://www.eclipse.org/legal/epl-2.0/
7+
8+
SPDX-License-Identifier: EPL-2.0
9+
-->
10+
<server description="Test tcpOptions portOpenRetries configuration.">
11+
12+
<include location="../fatTestCommon.xml"/>
13+
14+
<httpEndpoint id="defaultHttpEndpoint"
15+
host="*"
16+
httpPort="${bvt.prop.HTTP_default}"
17+
httpsPort="${bvt.prop.HTTP_default.secure}">
18+
<tcpOptions portOpenRetries="5"/>
19+
</httpEndpoint>
20+
21+
<featureManager>
22+
<feature>servlet-3.1</feature>
23+
</featureManager>
24+
25+
</server>

0 commit comments

Comments
 (0)