Skip to content

Add tcpOptions inactivityTimeout FAT #31159

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

Draft
wants to merge 3 commits into
base: integration
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class TcpOptions extends ConfigElement {
private String addressExcludeList;
private String hostNameIncludeList;
private String hostNameExcludeList;
private String inactivityTimeout;
private Integer maxOpenConnections;

public Boolean isSoReuseAddr() {
Expand All @@ -46,6 +47,10 @@ public String getHostNameExcludeList() {
return hostNameExcludeList;
}

public String getInactivityTimeout() {
return inactivityTimeout;
}

public Integer getMaxOpenConnections() {
return maxOpenConnections;
}
Expand Down Expand Up @@ -75,6 +80,11 @@ public void setHostNameExcludeList(String hostNameExcludeList) {
this.hostNameExcludeList = hostNameExcludeList;
}

@XmlAttribute
public void setInactivityTimeout(String inactivityTimeout) {
this.inactivityTimeout = inactivityTimeout;
}

@XmlAttribute
public void setMaxOpenConnections(Integer maxOpenConnections) {
this.maxOpenConnections = maxOpenConnections;
Expand All @@ -95,6 +105,8 @@ public String toString() {
buf.append("hostNameIncludeList=\"" + hostNameIncludeList + "\" ");
if (getHostNameExcludeList() != null)
buf.append("hostNameExcludeList=\"" + hostNameExcludeList + "\" ");
if (getInactivityTimeout() != null)
buf.append("inactivityTimeout=\"" + inactivityTimeout + "\" ");
if (getMaxOpenConnections() != null)
buf.append("maxOpenConnections=\"" + maxOpenConnections + "\" ");
buf.append("}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
@RunWith(Suite.class)
@SuiteClasses({
AccessListsTests.class,
MaxOpenConnectionsTest.class
MaxOpenConnectionsTest.class,
InactivityTimeoutTests.class
})
public class FATSuite {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
/*******************************************************************************
* Copyright (c) 2025 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package io.openliberty.transport.http_fat;

import static org.junit.Assert.assertNotNull;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.logging.Logger;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.ibm.websphere.simplicity.config.HttpEndpoint;
import com.ibm.websphere.simplicity.config.ServerConfiguration;

import componenttest.annotation.ExpectedFFDC;
import componenttest.annotation.Server;
import componenttest.custom.junit.runner.FATRunner;
import componenttest.custom.junit.runner.Mode;
import componenttest.custom.junit.runner.Mode.TestMode;
import componenttest.topology.impl.LibertyServer;

/**
* Test to ensure that the tcpOptions inactivityTimeout works.
*/
@RunWith(FATRunner.class)
@Mode(TestMode.FULL)
public class InactivityTimeoutTests {

static final Logger LOG = Logger.getLogger(InactivityTimeoutTests.class.getName());

@Server("InactivityTimeout")
public static LibertyServer server;

@BeforeClass
public static void setup() throws Exception {
// Start the server and use the class name so we can find logs easily.
server.startServer(InactivityTimeoutTests.class.getSimpleName() + ".log");
}

/**
* Save the server configuration before each test, this should be the default server
* configuration.
*
* @throws Exception
*/
@Before
public void beforeTest() throws Exception {
server.saveServerConfiguration();
}

@AfterClass
public static void tearDown() throws Exception {
// Stop the server
if (server != null && server.isStarted()) {
//CWWKO0211E: TCP Channel defaultHttpEndpoint has been constructed with an incorrect configuration property value. Name: inactivityTimeout Value: -1 Valid Range: Minimum 0, Maximum 3600000 <br>[4/8/25, 21:04:00:557 EDT] 0000004c com.ibm.ws.channelfw.internal.ChannelFrameworkImpl
//CWWKO0029E: An exception was generated when initializing chain CHAIN-defaultHttpEndpoint because of exception com.ibm.wsspi.channelfw.exception.ChannelException: A TCP Channel has been constructed with incorrect configuration property value, Channel Name: defaultHttpEndpoint name: inactivityTimeout value: -1 minimum Value: 0 maximum Value: 3600000
server.stopServer("CWWKO0211E", "CWWKO0029E");
}
}

/**
* Restore the server configuration to the default state after each test.
*
* @throws Exception
*/
@After
public void afterTest() throws Exception {
// Restore the server to the default state.
server.setMarkToEndOfLog();
server.setTraceMarkToEndOfDefaultTrace();
server.restoreServerConfiguration();
server.waitForConfigUpdateInLogUsingMark(null);
}

/**
* The test will check the default value of inactivityTimeout by searching the trace file.
*
* The default value is 60 seconds will be logged as 60000 miliseconds.
*/
@Test
public void testInactivityTimeout_default() throws Exception {
// Validate that inActivityTimeout default is 60s.
assertNotNull("The default value of inactivityTimeout was not: 60000!", server.waitForStringInTraceUsingMark("inactivityTimeout: 60000"));
}

/**
* The test will set inactivityTimeout to a value of 120s and validate in the trace file that
* the correct value is being used.
*
* The below configuration will be used to set inactivityTimeout to 120s:
* <tcpOptions inactivityTimeout="120s"/>
*
* @throws Exception
*/
@Test
public void testInactivityTimeout_nonDefault() throws Exception {
ServerConfiguration configuration = server.getServerConfiguration();
LOG.info("Server configuration that the test started with: " + configuration);

HttpEndpoint httpEndpoint = configuration.getHttpEndpoints().getById("defaultHttpEndpoint");
httpEndpoint.getTcpOptions().setInactivityTimeout("120s");

server.setMarkToEndOfLog();
server.setTraceMarkToEndOfDefaultTrace();
server.updateServerConfiguration(configuration);
server.waitForConfigUpdateInLogUsingMark(null);

// Validate that inactivityTimeout is set to 120000 (120s).
assertNotNull("The configured value of inactivityTimeout was not 120000!", server.waitForStringInTraceUsingMark("inactivityTimeout: 120000"));
}

/**
* The test will set inactivityTimeout to a value of -1s and validate that an error occurs.
*
* The below configuration will be used to set inactivityTimeout to 120s:
* <tcpOptions inactivityTimeout="-1"/>
*
* ExpectedFFDC:
* >------Start of DE processing------ = [4/8/25, 19:35:17:901 EDT]
* >Exception = com.ibm.wsspi.channelfw.exception.ChannelException
* >Source = com.ibm.ws.tcpchannel.internal.TCPChannelConfiguration
* >probeid = 102
* >Stack Dump = com.ibm.wsspi.channelfw.exception.ChannelException: A TCP Channel has been constructed with incorrect configuration property value, Channel Name:
* defaultHttpEndpoint name: inactivityTimeout value: -1 minimum Value: 0 maximum Value: 3600000
* > at com.ibm.ws.tcpchannel.internal.TCPChannelConfiguration.setValues(TCPChannelConfiguration.java:553)
*
* @throws Exception
*/
@Test
@ExpectedFFDC("com.ibm.wsspi.channelfw.exception.ChannelException")
public void testInactivityTimeout_negative() throws Exception {
ServerConfiguration configuration = server.getServerConfiguration();
LOG.info("Server configuration that the test started with: " + configuration);

HttpEndpoint httpEndpoint = configuration.getHttpEndpoints().getById("defaultHttpEndpoint");
httpEndpoint.getTcpOptions().setInactivityTimeout("-1");

server.setMarkToEndOfLog();
server.setTraceMarkToEndOfDefaultTrace();
server.updateServerConfiguration(configuration);
server.waitForConfigUpdateInLogUsingMark(null);

// Validate error messages due to invalid config.
assertNotNull("CWWKO0211E was not found and should have been!", server.waitForStringInTraceUsingMark("CWWKO0211E"));
assertNotNull("CWWKO0029E was not found and should have been!", server.waitForStringInTraceUsingMark("CWWKO0029E"));
}

/**
* The test will set the inactivitiyTimeout to a value of 10s.
*
* A socket will be opened.
*
* The test will sleep for 15s which is greater then the inactivityTimeout.
*
* The test will then send a request and validate that the response is null since the
* request should fail because the remote side of the Socket has closed due to the
* inactivityTimeout.
*
* @throws Exception
*/
//@Test
public void testInactivityTimeout() throws Exception {
String expectedResponse = "HTTP/1.1 408 Request Timeout";

String address = server.getHostname() + ":" + server.getHttpDefaultPort();

String request = "GET /" + " HTTP/1.1\r\n" +
"Host: " + address + "\r\n" +
"\r\n";

// Set the inactivityTimeout to 10 seconds to make testing quicker than the default 60 second timeout.
ServerConfiguration configuration = server.getServerConfiguration();
LOG.info("Server configuration that the test started with: " + configuration);

HttpEndpoint httpEndpoint = configuration.getHttpEndpoints().getById("defaultHttpEndpoint");
httpEndpoint.getTcpOptions().setInactivityTimeout("10s");

server.setMarkToEndOfLog();
server.setTraceMarkToEndOfDefaultTrace();
server.updateServerConfiguration(configuration);
server.waitForConfigUpdateInLogUsingMark(null);

// Validate that inactivityTimeout is set to 10000 (10s).
assertNotNull("The configured value of inactivityTimeout was not 10000!", server.waitForStringInTraceUsingMark("inactivityTimeout: 10000"));

// Ensure the TCP Channel has started.
// CWWKO0219I: TCP Channel defaultHttpEndpoint has been started and is now listening for requests on host * (IPv4) port 8010.
assertNotNull("The TCP Channel was not started!", server.waitForStringInLogUsingMark("CWWKO0219I"));

LOG.info("Creating a Socket connection.");
try (Socket socket = new Socket(server.getHostname(), server.getHttpDefaultPort())) {

// Sleep for more than the inactivityTimeout.
//Thread.sleep(15000);
// Even without this we get a inactivitiyTimeout

String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
OutputStream os = socket.getOutputStream();

// LOG.info("Read from the Socket.");
// boolean expectedResponseFound = false;
// while ((line = reader.readLine()) != null) {
// LOG.info(line);
// if (line.equals(expectedResponse)) {
// expectedResponseFound = true;
// }
// }

// Maybe sleep here???

//assertTrue("The expected response: " + expectedResponse + " was not found!", expectedResponseFound);

// Sending the request and reading the response should not work since the remote side of the Socket should have closed due to an inactivitiyTimeout!
LOG.info("Sending a request.");
os.write(request.getBytes());

Thread.sleep(15000);

LOG.info("Read the response.");
while ((line = reader.readLine()) != null) {
LOG.info(line);
//if (line.equals(expectedResponse)) {
// expectedResponseFound = true;
// }
}
//assertTrue("There should be no response data since the Socket was closed on the remote side due to an inactivityTimeout: " + response, response == null);

}
}

// TODO: Review the tracing of the above test and validate what is happening.
// Does the test above pass without any wait on the initial socket creation?

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
###############################################################################
# Copyright (c) 2025 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
###############################################################################
bootstrap.include=../testports.properties
com.ibm.ws.logging.trace.specification=*=info:TCPChannel=all
com.ibm.ws.logging.max.file.size=100
com.ibm.ws.logging.max.files=10
com.ibm.ws.logging.trace.format=BASIC
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!--
Copyright (c) 2025 IBM Corporation and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-2.0/

SPDX-License-Identifier: EPL-2.0
-->
<server description="Test tcpOptions inactivityTimeout configuration.">

<include location="../fatTestCommon.xml"/>

<httpEndpoint id="defaultHttpEndpoint"
host="*"
httpPort="${bvt.prop.HTTP_default}"
httpsPort="${bvt.prop.HTTP_default.secure}">
<tcpOptions portOpenRetries="60"/>
</httpEndpoint>

<featureManager>
<feature>servlet-3.1</feature>
</featureManager>

</server>