OVMS3-idf/components/test/TestCaseScript/TCPStress/TCPConnStressTC.py
Yinling 90e57cdf8f add auto generated test folder to components:
1. add test cases and related scripts
2. add CI config files
read README.md for detail
2016-10-11 17:19:40 +11:00

363 lines
15 KiB
Python
Executable file

import random
import re
import sys
import threading
import time
import TCPConnUtility
from NativeLog import NativeLog
from TCAction import TCActionBase
reload(sys)
sys.setdefaultencoding('iso-8859-1') # # use encoding that with 1 Byte length and contain 256 chars
DEFAULT_MAX_CONN_ALLOWED = 5
# complicated design because I want to make this script applied for all TCP connect/close test scenarios
# basic flow: try to create max connections, send/recv data if possible, close all connections
# connect:
# 1. find available (target_link_id, socket_id) list,
# notice that target_link_id maybe not correct if PC is client
# (during that time, some link may timeout and got disconnected from FIN_WAIT or other state)
# 2. choose one method from method set, try to connect
# 3. update state table: a)check result and destination state, b)find real target_link_id, c)update
# send/recv data:
# 1. find channels that are possible to send data on all connections
# 2. send data on possible channels
# disconnect:
# 1. find available connections
# 2. choose one method from disconnect set, try to disconnect
# 3. update state table (phase 1)
# async process:
# listen on AT UART port, record all "x,CONNECT" and "x,CLOSE" command
# for "x,CONNECT", append them to self.target_link_id_list, used when need to find real target_link_id
# for "x,CLOSE", update state table (phase 2), if matching connection is pending on wait state,
# close them and remove from state table
class TCPConnStressTC(TCActionBase.CommonTCActionBase):
def __init__(self, name, test_env, cmd_set, timeout=30, log_path=TCActionBase.LOG_PATH):
TCActionBase.CommonTCActionBase.__init__(self, name, test_env, cmd_set=cmd_set,
timeout=timeout, log_path=log_path)
self.__at1_buff = ""
self.max_conn_allowed = test_env.get_variable_by_name("max_conn")
self.enable_log = True
# load param from excel
for i in range(1, len(cmd_set)):
if cmd_set[i][0] != "dummy":
cmd_string = "self." + cmd_set[i][0]
exec cmd_string
# connection_state_dict: {target_link_id: [socket_id, target_state, socket_state, is_closed]}
# is_closed: found "x,CLOSE" in AT UART port
self.connection_state_dict = dict(zip(range(self.max_conn_allowed), [None] * self.max_conn_allowed))
self.created_link_id_list = []
self.__available_soc_id = range(2, 2+self.max_conn_allowed)
self.__available_link_id = range(self.max_conn_allowed)
self.result_cntx = TCActionBase.ResultCheckContext(self, test_env, self.tc_name)
self.utility = TCPConnUtility.TCPConnUtility(self)
self.state_lock = threading.Lock()
self.link_id_lock = threading.Lock()
self.available_id_lock = threading.Lock()
pass
def __add_log(self, log_str):
if self.enable_log is True:
NativeLog.add_trace_info(log_str)
def __get_created_target_link_id(self):
self.link_id_lock.acquire()
try:
link_id = self.created_link_id_list[-1]
self.created_link_id_list = []
finally:
self.link_id_lock.release()
return link_id
pass
def __set_created_target_link_id(self, link_id):
self.link_id_lock.acquire()
try:
self.created_link_id_list.append(link_id)
finally:
self.link_id_lock.release()
pass
def __find_channel_list(self):
channel_list = [] # # [(socket_id, able_to_send, link_id, able_to_send), ]
self.state_lock.acquire()
try:
for link_id in self.connection_state_dict:
state = self.connection_state_dict[link_id]
if state is not None:
channel_list.append([state[0], self.utility.is_able_to_send_data(state[2]),
link_id, self.utility.is_able_to_send_data(state[1])])
finally:
self.state_lock.release()
return channel_list
pass
def __established_connection_list(self):
conn_list = [] # # [(socket_id, link_id), ]
self.state_lock.acquire()
try:
for link_id in self.connection_state_dict:
state = self.connection_state_dict[link_id]
if state is not None:
if self.utility.is_established_connection([state[1], state[2]]) is True:
conn_list.append([state[0], link_id])
finally:
self.state_lock.release()
return conn_list
pass
# find free socket_id, target_link_id pair
def __get_available_id_list(self):
self.available_id_lock.acquire()
try:
id_list = zip(self.__available_soc_id, self.__available_link_id)
finally:
self.available_id_lock.release()
return id_list
pass
def __update_available_id_list(self, soc_id, link_id, action="ADD"):
self.available_id_lock.acquire()
try:
if action == "ADD":
self.__available_link_id.append(link_id)
self.__available_soc_id.append(soc_id)
self.__add_log("[AVAILABLE ID]soc %d link %d is available" % (soc_id, link_id))
elif action == "REMOVE":
self.__available_link_id.remove(link_id)
self.__available_soc_id.remove(soc_id)
self.__add_log("[AVAILABLE ID]soc %d link %d is used" % (soc_id, link_id))
finally:
self.available_id_lock.release()
def __update_connection_state_item(self, target_link_id, socket_id=None,
target_state=None, socket_state=None, is_closed=None):
self.state_lock.acquire()
try:
state = self.connection_state_dict[target_link_id]
if state is None:
state = [None] * 4
if socket_id is not None:
state[0] = socket_id
if target_state is not None:
state[1] = target_state
if socket_state is not None:
state[2] = socket_state
if is_closed is not None:
state[3] = is_closed
# remove closed connections
closed = self.utility.is_closed_state(state[1]) and (state[3] is True)
if closed is True:
self.__update_available_id_list(state[0], target_link_id)
state = None
# if new connection created
if self.connection_state_dict[target_link_id] is None:
created = self.utility.is_created_state(state[1])
if created is True:
self.__update_available_id_list(state[0], target_link_id, "REMOVE")
else:
# connection did not created, do not add them to connection state table
state = None
# set new connection_state
self.connection_state_dict[target_link_id] = state
self.__add_log("[STATE] link id is %d, state is %s" % (target_link_id, state))
except StandardError, e:
pass
finally:
self.state_lock.release()
pass
# update state table: if result is false, return, if result is true:
# for connect, find real link id, update table according to destination state
# for disconnect, if target in SOC_CLOSE_STATE && catch "x,CLOSE" from AT, remove the item
def update_connection_state_table(self, conn_id, destination_state=None):
if isinstance(conn_id, list) is True or isinstance(conn_id, tuple) is True:
socket_id = conn_id[0]
try:
target_link_id = self.__get_created_target_link_id()
except IndexError:
target_link_id = conn_id[1]
self.__add_log("[STATE]fail to get link id, state is %s, %s"
% (destination_state[0], destination_state[1]))
self.__update_connection_state_item(target_link_id, socket_id,
destination_state[0], destination_state[1])
pass
else: # # called when recv CLOSED
target_link_id = conn_id
self.__update_connection_state_item(target_link_id, is_closed=True)
pass
pass
def process_at_data(self, data):
pos1 = 0
pos2 = 0
connect = re.compile("\d,CONNECT\r\n")
close = re.compile("\d,CLOSED\r\n")
connect_match = connect.findall(data)
close_match = close.findall(data)
close = re.compile("\d,CONNECT FAIL\r\n")
close_match += close.findall(data)
if len(connect_match) != 0:
pos1 = data.find(connect_match[-1]) + 9
# append last connected link id
self.__set_created_target_link_id(int(connect_match[-1][:1]))
pass
if len(close_match) != 0:
pos2 = data.find(close_match[-1]) + 7
# update for all closed links
for close_str in close_match:
self.update_connection_state_table(int(close_str[:1]))
pass
pos = pos1 if pos1 > pos2 else pos2
return data[pos:]
def execute(self):
TCActionBase.TCActionBase.execute(self)
self.result_cntx.start()
# configurable params
# mandatory params
try:
connect_method_set = self.connect_method_set
test_count = self.test_count
except StandardError, e:
NativeLog.add_trace_critical("Error configuration for TCPConnSingleMode script, error is %s" % e)
raise StandardError("Error configuration")
# optional params
try:
disconn_method_set = self.disconn_method_set
except StandardError:
disconn_method_set = ["D_05"]
pass
try:
delay = self.delay
except StandardError:
delay = 0
pass
try:
check_data_len = self.check_data_len
except StandardError:
check_data_len = [0, 0]
pass
if isinstance(check_data_len, list) is False:
check_data_len = [check_data_len] * 2
# configurable params
# step1 use <test_tcp_port1> to create server on both PC and target side
checker_stings = ["SOCP SOC_COM L OK", "ATP AT1 L OK"]
test_action_string = ["SOC SOC1 LISTEN <test_tcp_port1>", "ATC AT1 CIPSERVER 1 <test_tcp_port1>"]
fail_string = "Fail, Fail on create server"
if self.load_and_exe_one_step(checker_stings, test_action_string, fail_string) is False:
return
for tested_count in xrange(test_count):
# step2 do connect
available_id_list = self.__get_available_id_list()
for conn_id in available_id_list:
connect_method = random.choice(connect_method_set)
# ret, destination_state = self.utility.execute_tcp_method(connect_method, conn_id)
try:
self.__add_log("[ACTION]connect method is %s, connect id is %s"
% (connect_method, conn_id))
ret, destination_state = self.utility.execute_tcp_method(connect_method, conn_id)
except StandardError, e:
NativeLog.add_trace_critical("Error in connect, error is %s" % e)
raise StandardError("Exception happen when connect")
if ret is False:
# connect fail, should terminate TC and mark as fail
return
else:
# succeed, append to table
self.update_connection_state_table(conn_id, destination_state)
if delay != 0:
time.sleep(delay)
# step 3 send/recv test data
# # [(socket_id, able_to_send, link_id, able_to_send)]
self.__add_log("[ACTION]SEND/RECV data")
channel_list = self.__find_channel_list()
for channel in channel_list:
_check_data_len = [0, 0]
if channel[1] is True:
_check_data_len[0] = check_data_len[0]
if channel[3] is True:
_check_data_len[1] = check_data_len[1]
ret = self.utility.send_test_data(channel[0],
channel[2],
_check_data_len)
if ret is False:
# send/recv fail, should terminate TC and mark as fail
return
if delay != 0:
time.sleep(delay)
# step 4 close all established connections
# (socket_id, link_id)
conn_list = self.__established_connection_list()
for conn_id in conn_list:
disconn_method = random.choice(disconn_method_set)
try:
self.__add_log("[ACTION]disconnect method is %s, connect id is %s"
% (disconn_method, conn_id))
ret, destination_state = self.utility.execute_tcp_method(disconn_method, conn_id)
except StandardError, e:
NativeLog.add_trace_critical("Error in disconnect, error is %s" % e)
raise StandardError("Exception happen when disconnect")
if ret is False:
# connect fail, should terminate TC and mark as fail
return
else:
# succeed, append to table
self.update_connection_state_table(conn_id, destination_state)
if delay != 0:
time.sleep(delay)
# finally, execute done
self.result_cntx.set_result("Succeed")
def result_check(self, port_name, data):
TCActionBase.CommonTCActionBase.result_check(self, port_name, data)
self.result_cntx.append_data(port_name, data)
# find "x,CONNECT" and "x,CLOSE"
if port_name.find("AT") != -1:
self.__at1_buff += data
self.__at1_buff = self.process_at_data(self.__at1_buff)
def main():
at1_buff = ""
pos1 = 0
pos2 = 0
data = "dafgajglajdfg0,CLOSEjdalghalksdg1,CONNECT\r\n\r\n3,CONNECT4,CLOSEadfaasdf"
at1_buff += data
connect = re.compile("\d,CONNECT")
close = re.compile("\d,CLOSE")
connect_match = connect.findall(at1_buff)
close_match = close.findall(at1_buff)
if len(connect_match) != 0:
pos1 = at1_buff.find(connect_match[-1]) + 9
pass
if len(close_match) != 0:
pos2 = at1_buff.find(close_match[-1]) + 7
pass
pos = pos1 if pos1 > pos2 else pos2
at1_buff = at1_buff[pos:]
pass
if __name__ == '__main__':
main()