Skip to content

Commit

Permalink
Add TCP multi-connection test
Browse files Browse the repository at this point in the history
  • Loading branch information
rickwu666666 committed Nov 30, 2023
1 parent c28e2f2 commit 4f76a0a
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 34 deletions.
89 changes: 55 additions & 34 deletions checkbox-provider-ce-oem/bin/tcp_multi_connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def server(start_port, end_port):
- start_port (int): Starting port for the server.
- end_port (int): Ending port for the server.
"""
for port in range(start_port, end_port):
for port in range(start_port, end_port+1):
threading.Thread(target=handle_port, args=(port,)).start()


Expand Down Expand Up @@ -69,7 +69,7 @@ def handle_client(conn, addr):
conn.sendall(received_data)


def client(host, start_port, end_port, payload, done_event, run_time):
def client(host, start_port, end_port, payload, done_event, start_time):
"""
Start the client to connect to a range of server ports.
Expand All @@ -79,12 +79,12 @@ def client(host, start_port, end_port, payload, done_event, run_time):
- end_port (int): Ending port for the client.
- payload (str): Payload to send to the server.
- done_event (threading.Event): Event to signal when the client is done.
- run_time (datetime): Time until which the client should run.
- start_time (datetime): Time until which the client should run.
"""
threads = []
for port in range(start_port, end_port+5):
for port in range(start_port, end_port+1):
thread = threading.Thread(target=send_payload,
args=(host, port, payload, run_time))
args=(host, port, payload, start_time))
threads.append(thread)
thread.start()

Expand All @@ -95,27 +95,35 @@ def client(host, start_port, end_port, payload, done_event, run_time):
done_event.set()


def send_payload(host, port, payload, run_time):
def send_payload(host, port, payload, start_time):
"""
Send a payload to the specified port and handle the server response.
Args:
- host (str): Server host.
- port (int): Port to connect to.
- payload (str): Payload to send to the server.
- run_time (datetime): Time until which the client should run.
- start_time (datetime): Time until which the client should run.
"""
try:
with socket.create_connection(
(host, port), timeout=120) as client_socket:
logging.info("Connect to port {}".format(port))
while datetime.now() < run_time:
while datetime.now() < start_time:
time.sleep(1)
for i in range(10):
logging.info("Sending payload to port {}.".format(port))
logging.info("Sending payload to port {}.".format(port))
# Sending payload for 30 sec after start sending.
count = 0
while datetime.now() < start_time + timedelta(seconds=30):
client_socket.sendall(payload.encode())
# Introduce a random interval between 0.1 and 0.5 seconds
interval_time = random.uniform(0.1, 0.5)
'''
Introduce a random interval between 1 and 3 seconds.
We try to control each port will send 64K payload
at least 10 times in 30 sec, but not more than 15 times
since too much traffic may take too long to test.
'''
interval_time = random.uniform(2, 3)
count = count+1
time.sleep(interval_time)
client_socket.shutdown(socket.SHUT_WR)
received_data = b''
Expand All @@ -125,16 +133,16 @@ def send_payload(host, port, payload, run_time):
break
received_data += data
logging.info("Server response from port {}.".format(port))
if received_data == payload.encode()*10:
if received_data == payload.encode()*count:
results.append("{}:PASS".format(port))
else:
results.append("{}:FAIL".format(port))
except socket.error as e:
logging.info("Error connecting to port {}: {}".format(port, e))
logging.error("{} on port {}".format(e, port))
results.append("{}:ERROR".format(port))
except Exception as e:
logging.info("An unexpected error occurred for port {}: {}"
.format(port, e))
logging.error("{}: An unexpected error occurred for port {}"
.format(e, port))
results.append("{}:ERROR".format(port))


Expand All @@ -148,21 +156,21 @@ def send_payload(host, port, payload, run_time):
these ports to send a payload and receive a response from the server.
Usage:
- To run as a server: ./script.py server
- To run as a server: ./script.py server -p <star_port> -e <end_port>
- To run as a client: ./script.py client -H <server_host> -p <start_port>
-e <end_port> -P <payload_size>
Arguments:
- mode (str): Specify whether to run as a server or client.
- host (str): Server host (client mode). Default is "localhost".
- host (str): Server host IP (client mode). This is mandatory arg.
- port (int): Starting port for the server or server port for the client.
Default is 1024.
- payload (int): Payload size in KB for the client. Default is 64.
- end_port (int): Ending port for the server. Default is 1224.
- end_port (int): Ending port for the server. Default is 1223.
Server Mode:
- The server listens on a range of ports concurrently, handling
incoming connections and logging received data.
incoming connections and send the received data back to client.
Client Mode:
- The client connects to a range of server ports,
Expand All @@ -172,30 +180,43 @@ def send_payload(host, port, payload, run_time):

parser = argparse.ArgumentParser(
description="Client-server with payload check on multiple ports")
parser.add_argument("mode", choices=["server", "client"],
help="Run as server or client")
parser.add_argument("-H", "--host", default="localhost",
help="Server host (client mode)")
parser.add_argument("-p", "--port", type=int, default=1024,
help="Starting port for server or server "
"port (client mode)")
parser.add_argument("-P", "--payload", type=int, default=64,
help="Payload size in KB (client mode)")
parser.add_argument("-e", "--end-port", type=int, default=1224,
help="Ending port for server (client mode)")

subparsers = parser.add_subparsers(dest="mode",
help="Run as server or client")

# Subparser for the server command
server_parser = subparsers.add_parser("server", help="Run as server")
server_parser.add_argument("-p", "--port",
type=int, default=1024,
help="Starting port for the server")
server_parser.add_argument("-e", "--end-port", type=int, default=1223,
help="Ending port for the server")

# Subparser for the client command
client_parser = subparsers.add_parser("client", help="Run as client")
client_parser.add_argument("-H", "--host", required=True,
help="Server host (client mode)")
client_parser.add_argument("-p", "--port", type=int, default=1024,
help="Starting port for the client")
client_parser.add_argument("-P", "--payload", type=int, default=64,
help="Payload size in KB (client mode)")
client_parser.add_argument("-e", "--end-port", type=int, default=1223,
help="Ending port for the client")
args = parser.parse_args()

done_event = threading.Event()
results = []
payload = 'A' * (args.payload * 1024)

# Ramp up time to wait until all ports are connected before
# starting to send the payload.
run_time = datetime.now() + timedelta(seconds=30)
start_time = datetime.now() + timedelta(seconds=30)

if args.mode == "server":
server(args.port, args.end_port)
elif args.mode == "client":
payload = 'A' * (args.payload * 1024)
client(args.host, args.port, args.end_port,
payload, done_event, run_time)
payload, done_event, start_time)

# Wait for all threads to finish
done_event.wait()
Expand Down
22 changes: 22 additions & 0 deletions checkbox-provider-ce-oem/units/ethernet/jobs.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,26 @@ _description:
environ: TCP_ECHO_SERVER_IP TCP_ECHO_SERVER_PORT TCP_ECHO_LOOP_ITERATIONS
estimated_duration: 10h
flags: also-after-suspend
requires: manifest.has_tcp_echo_stress_server == 'True'
imports: from com.canonical.plainbox import manifest
command: tcpecho_stress.sh -s {{ interface }} -i "$TCP_ECHO_SERVER_IP" -p "$TCP_ECHO_SERVER_PORT" -l "$TCP_ECHO_LOOP_ITERATIONS" -o "${PLAINBOX_SESSION_SHARE}"/tcp_echo.log

id: ce-oem-ethernet/tcp-multi-connections
plugin: shell
user: root
category_id: com.canonical.plainbox::ethernet
_summary: Check if the system can handle multiple connections on TCP without error.
_description:
This job will connect to server listened ports(200 ports in total),
and send the payload(64KB) for 10 times of each port. This job will
send the payload after all ports connection is established.
Need a server to run the following command before running the test.
e.g. Run a server to listen on port range from 1024 to 1223.
$ tcp_multi_connections.py server -p 1024 -e 1223
environ: TCP_MULTI_CONNECTIONS_SERVER_IP TCP_MULTI_CONNECTIONS_START_PORT TCP_MULTI_CONNECTIONS_END_PORT TCP_MULTI_CONNECTIONS_PAYLOAD_SIZE
estimated_duration: 300
flags: also-after-suspend
requires: manifest.has_tcp_multi_connection_server == 'True'
imports: from com.canonical.plainbox import manifest
command:
tcp_multi_connections.py client -H "$TCP_MULTI_CONNECTIONS_SERVER_IP" -p "$TCP_MULTI_CONNECTIONS_START_PORT" -e "$TCP_MULTI_CONNECTIONS_END_PORT" -P "$TCP_MULTI_CONNECTIONS_PAYLOAD_SIZE"
9 changes: 9 additions & 0 deletions checkbox-provider-ce-oem/units/ethernet/manifest.pxu
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
unit: manifest entry
id: has_tcp_multi_connection_server
_name: Has the TCP multi-connection server been set up?
value-type: bool

unit: manifest entry
id: has_tcp_echo_stress_server
_name: Has the TCP echo stress server been set up?
value-type: bool
25 changes: 25 additions & 0 deletions checkbox-provider-ce-oem/units/ethernet/test-plan.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,28 @@ bootstrap_include:
com.canonical.certification::device
include:
ce-oem-ethernet/tcp-echo-stress-.*

id: ce-oem-tcp-full
unit: test plan
_name: TCP connection tests
_description: TCP connection test of the device
include:
nested_part:
ce-oem-ethernet-tcp-automated
after-suspend-ce-oem-ethernet-tcp-automated

id: ce-oem-ethernet-tcp-automated
unit: test plan
_name: TCP connection test plan
_description: TCP connection test
estimated_duration: 300
include:
ce-oem-ethernet/tcp-multi-connections

id: after-suspend-ce-oem-ethernet-tcp-automated
unit: test plan
_name: TCP connection test plan
_description: TCP connection test
estimated_duration: 300
include:
after-suspend-ce-oem-ethernet/tcp-multi-connections
2 changes: 2 additions & 0 deletions checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ nested_part:
ce-oem-crypto-automated
ce-oem-optee-automated
ce-oem-socketcan-stress-automated
ce-oem-ethernet-tcp-automated
com.canonical.certification::eeprom-automated
com.canonical.certification::rtc-automated

Expand Down Expand Up @@ -130,6 +131,7 @@ nested_part:
after-suspend-ce-oem-crypto-automated
after-suspend-ce-oem-optee-automated
after-suspend-ce-oem-socketcan-stress-automated
after-suspend-ce-oem-ethernet-tcp-automated
com.canonical.certification::after-suspend-eeprom-automated
com.canonical.certification::after-suspend-rtc-automated

Expand Down

0 comments on commit 4f76a0a

Please sign in to comment.