lf_check.py : separating out the test_dut information from the test_rig

information
ct_us_001.json : removed the dut specific information
ct_AX88U_dut.json : json specific to the ASUS dut
lf_qa.py : added comment on future feature

Signed-off-by: Chuck SmileyRekiere <chuck.smileyrekiere@candelatech.com>
This commit is contained in:
Chuck SmileyRekiere
2021-09-07 17:40:44 -06:00
parent 5ba8a5bfcf
commit 3906d9e469
4 changed files with 187 additions and 84 deletions

View File

@@ -0,0 +1,26 @@
{
"ct_AX88U_dut":{
"Notes":[
"This json file is used as an input to the ./lf_check.py file",
"The variables that are all capitalized below are replaced with configuration",
"from the json file. so LF_MGR_IP in the test below is replaced by the json lf_mgr_ip",
"The replacement is loosely coupled so the upper and lower case convention is used",
"to identify replaced strings in the lf_check.py code.",
"The dut related configuration is contained in this file"
]
},
"test_dut":{
"dut_set_name": "DUT_NAME ASUSRT-AX88U",
"dut_name": "ASUSRT-AX88U",
"dut_bssid_2g": "3c:7c:3f:55:4d:60",
"dut_bssid_5g": "3c:7c:3f:55:4d:64",
"dut_sw": "3.0.0.4.386_44266",
"ssid_5g_used": "asus11ax-5",
"ssid_5g_pw_used": "hello123",
"security_5g_used": "wpa2",
"ssid_2g_used": "asus11ax-2",
"ssid_2g_pw_used": "hello123",
"security_2g_used": "wpa2"
}
}

View File

@@ -12,14 +12,10 @@
"test_parameters":{ "test_parameters":{
"test_bed": "CT-US-001", "test_bed": "CT-US-001",
"test_rig": "CT-US-001", "test_rig": "CT-US-001",
"database_sqlite": "./tools/qa_001_test_db",
"database_tag": "testbed CT-US-001", "database_tag": "testbed CT-US-001",
"lf_mgr_ip": "192.168.100.116", "lf_mgr_ip": "192.168.100.116",
"lf_mgr_port": "8080", "lf_mgr_port": "8080",
"dut_set_name": "DUT_NAME ASUSRT-AX88U",
"dut_name": "ASUSRT-AX88U",
"dut_bssid_2g": "3c:7c:3f:55:4d:60",
"dut_bssid_5g": "3c:7c:3f:55:4d:64",
"dut_sw": "3.0.0.4.386_44266",
"test_timeout": 600, "test_timeout": 600,
"load_blank_db": false, "load_blank_db": false,
"load_factory_default_db": true, "load_factory_default_db": true,
@@ -39,9 +35,6 @@
}, },
"test_generic":{ "test_generic":{
"radio_used": "wiphy1", "radio_used": "wiphy1",
"ssid_used": "asus11ax-5",
"ssid_pw_used": "hello123",
"security_used": "wpa2",
"num_sta": 1, "num_sta": 1,
"col_names": "name,tx_byptes,rx_bytes,dropped", "col_names": "name,tx_byptes,rx_bytes,dropped",
"upstream_port": "eth2" "upstream_port": "eth2"

View File

@@ -141,6 +141,8 @@ class lf_check():
# meta.txt # meta.txt
self.meta_data_path = "" self.meta_data_path = ""
# lanforge configuration # lanforge configuration
self.lf_mgr_ip = "192.168.0.102" self.lf_mgr_ip = "192.168.0.102"
self.lf_mgr_port = "8080" self.lf_mgr_port = "8080"
@@ -148,6 +150,7 @@ class lf_check():
self.lf_mgr_pass = "lanforge" self.lf_mgr_pass = "lanforge"
# results # results
self.database_sqlite = ""
self.test_start_time = "" self.test_start_time = ""
self.test_end_time = "" self.test_end_time = ""
self.duration = "" self.duration = ""
@@ -156,11 +159,34 @@ class lf_check():
self.ftp_test_ip = "" self.ftp_test_ip = ""
self.test_ip = "" self.test_ip = ""
# section DUT
# dut selection
self.dut_set_name = 'DUT_NAME ASUSRT-AX88U' # note the name will be set as --set DUT_NAME ASUSRT-AX88U, this is not dut_name (see above)
# dut configuration
self.dut_name = "DUT_NAME_NA" # "ASUSRT-AX88U" note this is not dut_set_name
self.dut_hw = "DUT_HW_NA"
self.dut_sw = "DUT_SW_NA"
self.dut_model = "DUT_MODEL_NA"
self.dut_serial = "DUT_SERIAL_NA"
self.dut_bssid_2g = "BSSID_2G_NA" # "3c:7c:3f:55:4d:64" - this is the mac for the 2.4G radio this may be seen with a scan
self.dut_bssid_5g = "BSSID_5G_NA" # "3c:7c:3f:55:4d:64" - this is the mac for the 5G radio this may be seen with a scan
self.dut_bssid_6g = "BSSID_6G_NA" # "3c:7c:3f:55:4d:64" - this is the mac for the 6G radio this may be seen with a scan
self.ssid_2g = ""
self.ssid_2g_pw = ""
self.security_2g = ""
self.ssid_5g = ""
self.ssid_5g_pw = ""
self.security_5g = ""
self.ssid_6g = ""
self.ssid_6g_pw = ""
self.security_6g = ""
# section TEST_GENERIC # section TEST_GENERIC
self.radio_lf = "" self.radio_lf = ""
self.ssdi = ""
self.ssid_pw = ""
self.security = ""
self.num_sta = "" self.num_sta = ""
self.col_names = "" self.col_names = ""
self.upstream_port = "" self.upstream_port = ""
@@ -183,18 +209,6 @@ class lf_check():
self.email_title_txt = "" self.email_title_txt = ""
self.email_txt = "" self.email_txt = ""
# dut selection
self.dut_set_name = 'DUT_NAME ASUSRT-AX88U' # note the name will be set as --set DUT_NAME ASUSRT-AX88U, this is not dut_name (see above)
# dut configuration
self.dut_name = "DUT_NAME_NA" # "ASUSRT-AX88U" note this is not dut_set_name
self.dut_hw = "DUT_HW_NA"
self.dut_sw = "DUT_SW_NA"
self.dut_model = "DUT_MODEL_NA"
self.dut_serial = "DUT_SERIAL_NA"
self.dut_bssid_2g = "BSSID_2G_NA" # "3c:7c:3f:55:4d:64" - this is the mac for the 2.4G radio this may be seen with a scan
self.dut_bssid_5g = "BSSID_5G_NA" # "3c:7c:3f:55:4d:64" - this is the mac for the 5G radio this may be seen with a scan
self.dut_bssid_6g = "BSSID_6G_NA" # "3c:7c:3f:55:4d:64" - this is the mac for the 6G radio this may be seen with a scan
# NOTE: My influx token is unlucky and starts with a '-', but using the syntax below # with '=' right after the argument keyword works as hoped. # NOTE: My influx token is unlucky and starts with a '-', but using the syntax below # with '=' right after the argument keyword works as hoped.
# --influx_token= # --influx_token=
@@ -490,6 +504,16 @@ http://{blog}:2368""".format(blog=self.blog_host)
else: else:
self.logger.info("EXITING radio_dict not in json {}".format(self.json_rig)) self.logger.info("EXITING radio_dict not in json {}".format(self.json_rig))
exit(1) exit(1)
# read dut configuration
def read_json_dut(self):
if "test_dut" in self.json_dut:
self.logger.info("json: read test_dut")
self.read_test_dut()
else:
self.logger.info("EXITING test_dut not in json {}".format(self.json_dut))
exit(1)
# Top Level for reading the tests to run # Top Level for reading the tests to run
def read_json_test(self): def read_json_test(self):
if "test_suites" in self.json_test: if "test_suites" in self.json_test:
@@ -536,6 +560,10 @@ http://{blog}:2368""".format(blog=self.blog_host)
self.test_rig = self.json_rig["test_parameters"]["test_rig"] self.test_rig = self.json_rig["test_parameters"]["test_rig"]
else: else:
self.logger.info("test_rig not in test_parameters json") self.logger.info("test_rig not in test_parameters json")
if "database_sqlite" in self.json_rig["test_parameters"]:
self.database_sqlite = self.json_rig["test_parameters"]["database_sqlite"]
else:
self.logger.info("database_sqlite not in test_parameters json")
if "test_timeout" in self.json_rig["test_parameters"]: if "test_timeout" in self.json_rig["test_parameters"]:
self.test_timeout = self.json_rig["test_parameters"]["test_timeout"] self.test_timeout = self.json_rig["test_parameters"]["test_timeout"]
self.test_timeout_default = self.test_timeout self.test_timeout_default = self.test_timeout
@@ -599,45 +627,99 @@ http://{blog}:2368""".format(blog=self.blog_host)
self.lf_mgr_port = self.json_rig["test_parameters"]["lf_mgr_port"] self.lf_mgr_port = self.json_rig["test_parameters"]["lf_mgr_port"]
else: else:
self.logger.info("lf_mgr_port not in test_parameters json") self.logger.info("lf_mgr_port not in test_parameters json")
# dut_set_name selectes the DUT to test against , it is different then dut_name # dut_set_name selectes the DUT to test against , it is different then dut_name
# this value gets set in the test # this value gets set in the test
if "dut_set_name" in self.json_rig["test_parameters"]: def read_dut_parameters(self):
self.dut_set_name = self.json_rig["test_parameters"]["dut_set_name"] if "dut_set_name" in self.json_dut["test_dut"]:
self.dut_set_name = self.json_dut["test_dut"]["dut_set_name"]
else: else:
self.logger.info("dut_set_name not in test_database json") self.logger.info("dut_set_name not in test_dut json")
# dut name will set a chamberview scenerio for a DUT which can be selected with dut_set_name # dut name will set a chamberview scenerio for a DUT which can be selected with dut_set_name
if "dut_name" in self.json_rig["test_parameters"]: if "dut_name" in self.json_dut["test_dut"]:
self.dut_name = self.json_rig["test_parameters"]["dut_name"] self.dut_name = self.json_dut["test_dut"]["dut_name"]
else: else:
self.logger.info("dut_name not in test_parameters json") self.logger.info("dut_name not in test_dut json")
if "dut_hw" in self.json_rig["test_parameters"]:
self.dut_hw = self.json_rig["test_parameters"]["dut_hw"] if "dut_hw" in self.json_dut["test_dut"]:
self.dut_hw = self.json_dut["test_dut"]["dut_hw"]
else: else:
self.logger.info("dut_hw not in test_parameters json") self.logger.info("dut_hw not in test_dut json")
if "dut_sw" in self.json_rig["test_parameters"]:
self.dut_sw = self.json_rig["test_parameters"]["dut_sw"] if "dut_sw" in self.json_dut["test_dut"]:
self.dut_sw = self.json_dut["test_dut"]["dut_sw"]
else: else:
self.logger.info("dut_sw not in test_parameters json") self.logger.info("dut_sw not in test_parameters json")
if "dut_model" in self.json_rig["test_parameters"]:
self.dut_model = self.json_rig["test_parameters"]["dut_model"] if "dut_model" in self.json_dut["test_dut"]:
self.dut_model = self.json_dut["test_dut"]["dut_model"]
else: else:
self.logger.info("dut_model not in test_parameters json") self.logger.info("dut_model not in test_dut json")
if "dut_serial" in self.json_rig["test_parameters"]:
self.dut_serial = self.json_rig["test_parameters"]["dut_serial"] if "dut_serial" in self.json_dut["test_dut"]:
self.dut_serial = self.json_dut["test_dut"]["dut_serial"]
else: else:
self.logger.info("dut_serial not in test_parameters json") self.logger.info("dut_serial not in test_dut json")
if "dut_bssid_2g" in self.json_rig["test_parameters"]:
self.dut_bssid_2g = self.json_rig["test_parameters"]["dut_bssid_2g"] if "dut_bssid_2g" in self.json_dut["test_dut"]:
self.dut_bssid_2g = self.json_dut["test_dut"]["dut_bssid_2g"]
else: else:
self.logger.info("dut_bssid_2G not in test_parameters json") self.logger.info("dut_bssid_2G not in test_dut json")
if "dut_bssid_5g" in self.json_rig["test_parameters"]:
self.dut_bssid_5g = self.json_rig["test_parameters"]["dut_bssid_5g"] if "dut_bssid_5g" in self.json_dut["test_dut"]:
self.dut_bssid_5g = self.json_dut["test_dut"]["dut_bssid_5g"]
else: else:
self.logger.info("dut_bssid_5g not in test_parameters json") self.logger.info("dut_bssid_5g not in test_dut json")
if "dut_bssid_6g" in self.json_rig["test_parameters"]:
self.dut_bssid_6g = self.json_rig["test_parameters"]["dut_bssid_6g"] if "dut_bssid_6g" in self.json_dut["test_dut"]:
self.dut_bssid_6g = self.json_dut["test_dut"]["dut_bssid_6g"]
else: else:
self.logger.info("dut_bssid_6g not in test_parameters json") self.logger.info("dut_bssid_6g not in test_dut json")
if "ssid_6g_used" in self.json_dut["test_dut"]:
self.ssid_6g = self.json_dut["test_dut"]["ssid_5g_used"]
else:
self.logger.info("ssid_6g_used not in test_dut json")
if "ssid_6g_pw_used" in self.json_dut["test_dut"]:
self.ssid_6g_pw = self.json_dut["test_dut"]["ssid_6g_pw_used"]
else:
self.logger.info("ssid_6g_pw_used not in test_dut json")
if "security_6g_used" in self.json_dut["test_dut"]:
self.security_6g = self.json_rig["test_dut"]["security_6g_used"]
else:
self.logger.info("security_6g_used not in test_dut json")
if "ssid_5g_used" in self.json_dut["test_dut"]:
self.ssid_5g = self.json_dut["test_dut"]["ssid_5g_used"]
else:
self.logger.info("ssid_5g_used not in test_dut json")
if "ssid_5g_pw_used" in self.json_dut["test_dut"]:
self.ssid_5g_pw = self.json_dut["test_dut"]["ssid_5g_pw_used"]
else:
self.logger.info("ssid_5g_pw_used not in test_dut json")
if "security_5g_used" in self.json_dut["test_dut"]:
self.security_5g = self.json_rig["test_dut"]["security_5g_used"]
else:
self.logger.info("security_5g_used not in test_dut json")
if "ssid_2g_used" in self.json_dut["test_dut"]:
self.ssid_2g = self.json_dut["test_dut"]["ssid_2g_used"]
else:
self.logger.info("ssid_2g_used not in test_dut json")
if "ssid_2g_pw_used" in self.json_dut["test_dut"]:
self.ssid_2g_pw = self.json_dut["test_dut"]["ssid_2g_pw_used"]
else:
self.logger.info("ssid_2g_pw_used not in test_dut json")
if "security_2g_used" in self.json_dut["test_dut"]:
self.security_2g = self.json_rig["test_dut"]["security_2g_used"]
else:
self.logger.info("security_2g_used not in test_dut json")
def read_test_network(self): def read_test_network(self):
if "http_test_ip" in self.json_rig["test_network"]: if "http_test_ip" in self.json_rig["test_network"]:
@@ -662,21 +744,6 @@ http://{blog}:2368""".format(blog=self.blog_host)
else: else:
self.logger.info("radio_used not in test_generic json") self.logger.info("radio_used not in test_generic json")
exit(1) exit(1)
if "ssid_used" in self.json_rig["test_generic"]:
self.ssid = self.json_rig["test_generic"]["ssid_used"]
else:
self.logger.info("ssid_used not in test_generic json")
exit(1)
if "ssid_pw_used" in self.json_rig["test_generic"]:
self.ssid_pw = self.json_rig["test_generic"]["ssid_pw_used"]
else:
self.logger.info("ssid_pw_used not in test_generic json")
exit(1)
if "security_used" in self.json_rig["test_generic"]:
self.security = self.json_rig["test_generic"]["security_used"]
else:
self.logger.info("security_used not in test_generic json")
exit(1)
if "num_sta" in self.json_rig["test_generic"]: if "num_sta" in self.json_rig["test_generic"]:
self.num_sta = self.json_rig["test_generic"]["num_sta"] self.num_sta = self.json_rig["test_generic"]["num_sta"]
else: else:
@@ -876,9 +943,10 @@ http://{blog}:2368""".format(blog=self.blog_host)
self.radio_dict[radio]['PASSWD'], self.radio_dict[radio]['SECURITY'], self.radio_dict[radio]['PASSWD'], self.radio_dict[radio]['SECURITY'],
self.radio_dict[radio]['STATIONS'])) self.radio_dict[radio]['STATIONS']))
if 'DATABASE_SQLITE' in self.test_dict[test]['args']:
self.text_dict[test]['args'] = self.test_dict[test]['args'].replace('DATABASE_SQLITE', self.database_sqlite)
if 'HTTP_TEST_IP' in self.test_dict[test]['args']: if 'HTTP_TEST_IP' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('HTTP_TEST_IP', self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('HTTP_TEST_IP', self.http_test_ip)
self.http_test_ip)
if 'FTP_TEST_IP' in self.test_dict[test]['args']: if 'FTP_TEST_IP' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('FTP_TEST_IP', self.ftp_test_ip) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('FTP_TEST_IP', self.ftp_test_ip)
if 'TEST_IP' in self.test_dict[test]['args']: if 'TEST_IP' in self.test_dict[test]['args']:
@@ -889,6 +957,10 @@ http://{blog}:2368""".format(blog=self.blog_host)
if 'LF_MGR_PORT' in self.test_dict[test]['args']: if 'LF_MGR_PORT' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('LF_MGR_PORT', self.lf_mgr_port) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('LF_MGR_PORT', self.lf_mgr_port)
if 'RADIO_USED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('RADIO_USED', self.radio_lf)
# DUT Configuration
if 'DUT_NAME' in self.test_dict[test]['args']: if 'DUT_NAME' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_NAME', self.dut_name) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_NAME', self.dut_name)
if 'DUT_HW' in self.test_dict[test]['args']: if 'DUT_HW' in self.test_dict[test]['args']:
@@ -899,24 +971,35 @@ http://{blog}:2368""".format(blog=self.blog_host)
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_MODEL', self.dut_model) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_MODEL', self.dut_model)
if 'DUT_SERIAL' in self.test_dict[test]['args']: if 'DUT_SERIAL' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_SERIAL', self.dut_serial) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_SERIAL', self.dut_serial)
if 'DUT_BSSID_2G' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_BSSID_2G',
self.dut_bssid_2g)
if 'DUT_BSSID_5G' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_BSSID_5G',
self.dut_bssid_5g)
if 'DUT_BSSID_6G' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_BSSID_6G',
self.dut_bssid_6g)
if 'RADIO_USED' in self.test_dict[test]['args']: if 'DUT_BSSID_2G' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('RADIO_USED', self.radio_lf) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_BSSID_2G', self.dut_bssid_2g)
if 'SSID_USED' in self.test_dict[test]['args']: if 'SSID_2G_USED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SSID_USED', self.ssid) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SSID_2G_USED', self.ssid_2g)
if 'SSID_PW_USED' in self.test_dict[test]['args']: if 'SSID_2G_PW_USED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SSID_PW_USED', self.ssid_pw) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SSID_2G_PW_USED', self.ssid_2g_pw)
if 'SECURITY_USED' in self.test_dict[test]['args']: if 'SECURITY_2G_USED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SECURITY_USED', self.security) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SECURITY_2G_USED', self.security_2g)
if 'DUT_BSSID_5G' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_BSSID_5G', self.dut_bssid_5g)
if 'SSID_5G_USED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SSID_5G_USED', self.ssid_5g)
if 'SSID_5G_PW_USED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SSID_5G_PW_USED', self.ssid_5g_pw)
if 'SECURITY_5G_USED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SECURITY_5G_USED', self.security_5g)
if 'DUT_BSSID_6G' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DUT_BSSID_6G', self.dut_bssid_6g)
if 'SSID_6G_USED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SSID_6G_USED', self.ssid_6g)
if 'SSID_6G_PW_USED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SSID_6G_PW_USED', self.ssid_6g_pw)
if 'SECURITY_6G_USED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('SECURITY_6G_USED', self.security_6g)
if 'NUM_STA' in self.test_dict[test]['args']: if 'NUM_STA' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('NUM_STA', self.num_sta) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('NUM_STA', self.num_sta)
if 'COL_NAMES' in self.test_dict[test]['args']: if 'COL_NAMES' in self.test_dict[test]['args']:
@@ -934,7 +1017,7 @@ http://{blog}:2368""".format(blog=self.blog_host)
if 'TEST_BED' in self.test_dict[test]['args']: if 'TEST_BED' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('TEST_BED', self.database_tag) self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('TEST_BED', self.database_tag)
# database configuration # Influx database configuration
if 'DATABASE_HOST' in self.test_dict[test]['args']: if 'DATABASE_HOST' in self.test_dict[test]['args']:
self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DATABASE_HOST', self.test_dict[test]['args'] = self.test_dict[test]['args'].replace('DATABASE_HOST',
self.database_host) self.database_host)

View File

@@ -464,6 +464,7 @@ class csv_sqlite_dash():
# host = '0.0.0.0' allows for remote access, local debug host = '127.0.0.1' # host = '0.0.0.0' allows for remote access, local debug host = '127.0.0.1'
# app.run_server(host= '0.0.0.0', debug=True) # app.run_server(host= '0.0.0.0', debug=True)
# Feature, Sum up the subtests passed/failed from the kpi files for each run, poke those into the database, and generate a kpi graph for them.
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(