report generation added for dynamic data

pick 0429552 conflicts resolved in lf_graph changes
This commit is contained in:
anil-tegala
2021-07-13 19:18:28 +05:30
parent d50ed322f5
commit bcbaff86e6
5 changed files with 378 additions and 450 deletions

View File

@@ -9,7 +9,7 @@ SETUP:
/lanforge/html-reports directory needs to be present or output generated in local file
EXAMPLE:
see: /py-scritps/lf_csv_test.py for example
see: /py-scritps/lf_report_test.py for example
COPYWRITE
Copyright 2021 Candela Technologies Inc
@@ -41,7 +41,7 @@ class LfCSV:
df[self.columns[i]] = self.rows[i]
csv_df = pd.DataFrame(df)
print(csv_df)
csv_df.to_csv(self.filename, encoding='utf-8', na_rep='NA', float_format='%.2f')
csv_df.to_csv(self.filename, index=False, encoding='utf-8', na_rep='NA', float_format='%.2f')
if __name__ == "__main__":

View File

@@ -52,7 +52,7 @@ class lf_bar_graph():
_xticks_font = None,
_grp_title = "",
_dpi=96,
_enable_csv=True):
_enable_csv=False):
self.data_set = _data_set
self.xaxis_name = _xaxis_name
@@ -304,11 +304,11 @@ class lf_horizontal_stacked_graph():
plt.savefig("%s.png" % self.graph_image_name, dpi=96)
plt.close()
print("{}.png".format(self.graph_image_name))
# if self.enable_csv:
# self.lf_csv.columns = self.label
# self.lf_csv.rows = self.data_set
# self.lf_csv.filename = f"{self.graph_image_name}.csv"
# self.lf_csv.generate_csv()
if self.enable_csv:
self.lf_csv.columns = self.label
self.lf_csv.rows = self.data_set
self.lf_csv.filename = f"{self.graph_image_name}.csv"
self.lf_csv.generate_csv()
return "%s.png" % self.graph_image_name

View File

@@ -81,6 +81,7 @@ class lf_report():
self.footer_html = ""
self.graph_titles=""
self.graph_image=""
self.csv_file_name=""
self.html = ""
self.custom_html = ""
self.objective = _obj
@@ -146,8 +147,13 @@ class lf_report():
print("graph_src_file: {}".format(graph_src_file))
print("graph_dst_file: {}".format(graph_dst_file))
shutil.move(graph_src_file, graph_dst_file)
def move_csv_file(self):
csv_src_file = str(self.fil)
csv_src_file = str(self.csv_file_name)
csv_dst_file = str(self.path_date_time)+'/'+str(self.csv_file_name)
print("csv_src_file: {}".format(csv_src_file))
print("csv_dst_file: {}".format(csv_dst_file))
shutil.move(csv_src_file, csv_dst_file)
def set_path(self,_path):
self.path = _path
@@ -187,6 +193,11 @@ class lf_report():
def set_graph_title(self,_graph_title):
self.graph_title = _graph_title
# sets the csv file name as graph title
def set_csv_filename(self, _graph_title):
fname, ext = os.path.splitext(_graph_title)
self.csv_file_name = fname + ".csv"
# The _date is set when class is enstanciated / created so this set_date should be used with caution, used to synchronize results
def set_date(self,_date):
self.date = _date
@@ -275,7 +286,6 @@ class lf_report():
self.write_output_pdf = "{}/{}-{}".format(self.path_date_time,self.date,self.output_pdf)
pdfkit.from_file(self.write_output_html, self.write_output_pdf, options=options)
def generate_report(self):
self.write_html()
self.write_pdf()
@@ -351,7 +361,7 @@ class lf_report():
os.mkdir(self.path_date_time)
def build_table(self):
self.dataframe_html = self.dataframe.to_html(index=False, justify='left') # have the index be able to be passed in.
self.dataframe_html = self.dataframe.to_html(index=False, justify='center') # have the index be able to be passed in.
self.html += self.dataframe_html
def test_setup_table(self,test_setup_data, value):

View File

@@ -36,7 +36,7 @@ if __name__ == "__main__":
'radios': [1, 1, 2, 2, 6, 9, 3],
'MIMO': ['N', 'N', 'N', 'Y', 'Y', 'Y', 'Y'],
'stations': [200, 64, 200, 128, 384, 72, 192],
'mbps': [300, 300, 300, 10000, 10000, 10000, 10000]
'1 mbps': [300, 300, 300, 10000, 10000, 10000, 10000]
})
print(dataframe)

View File

@@ -57,7 +57,8 @@ class ThroughputQOS(Realm):
create_sta=True,
name_prefix=None,
upstream=None,
radio="wiphy0",
radio_2g="wiphy0",
radio_5g="wiphy1",
host="localhost",
port=8080,
mode=0,
@@ -69,7 +70,6 @@ class ThroughputQOS(Realm):
number_template="00000",
test_duration="2m",
bands="2.4G, 5G, BOTH",
radios="",
test_case={},
use_ht160=False,
_debug_on=False,
@@ -89,7 +89,8 @@ class ThroughputQOS(Realm):
self.ssid_5g = ssid_5g
self.security_5g = security_5g
self.password_5g = password_5g
self.radio = radio.split(",")
self.radio_2g = radio_2g
self.radio_5g = radio_5g
self.sta_list = sta_list
self.create_sta = create_sta
self.mode = mode
@@ -98,7 +99,6 @@ class ThroughputQOS(Realm):
self.traffic_type = traffic_type
self.tos = tos.split(",")
self.bands = bands.split(",")
self.radios = radios
self.test_case = test_case
self.number_template = number_template
self.debug = _debug_on
@@ -115,7 +115,7 @@ class ThroughputQOS(Realm):
self.station_profile.use_ht160 = use_ht160
if self.station_profile.use_ht160:
self.station_profile.mode = 9
self.station_profile.mode = mode
# self.station_profile.mode = mode
if self.ap is not None:
self.station_profile.set_command_param("add_sta", "ap", self.ap)
self.cx_profile.host = self.host
@@ -127,15 +127,6 @@ class ThroughputQOS(Realm):
self.cx_profile.side_b_max_bps = side_b_max_rate
def start(self, print_pass=False, print_fail=False):
if self.create_sta:
self.station_profile.admin_up()
# check here if upstream port got IP
temp_stations = self.station_profile.station_names.copy()
if self.wait_for_ip(temp_stations):
self._pass("All stations got IPs")
else:
self._fail("Stations failed to get IPs")
self.exit_fail()
self.cx_profile.start_cx()
def stop(self):
@@ -159,78 +150,62 @@ class ThroughputQOS(Realm):
for key in self.bands:
if self.create_sta:
if key == "2.4G" or key == "2.4g":
self.station_profile.mode = 11
if self.ssid is None:
self.station_profile.use_security(self.security_2g, self.ssid_2g, self.password_2g)
else:
self.station_profile.use_security(self.security, self.ssid, self.password)
if key == "5G" or key == "5g":
if self.ssid is None:
self.station_profile.use_security(self.security_5g, self.ssid_5g, self.password_5g)
else:
self.station_profile.use_security(self.security, self.ssid, self.password)
self.station_profile.set_number_template(self.number_template)
print("Creating stations")
self.station_profile.set_command_flag("add_sta", "create_admin_down", 1)
self.station_profile.set_command_param("set_port", "report_timer", 1500)
self.station_profile.set_command_flag("set_port", "rpt_timer", 1)
self.station_profile.create(radio=self.radio_2g, sta_names_=self.sta_list, debug=self.debug)
if key == "5G" or key == "5g":
self.station_profile.mode = 9
if self.ssid is None:
self.station_profile.use_security(self.security_5g, self.ssid_5g, self.password_5g)
else:
self.station_profile.use_security(self.security, self.ssid, self.password)
self.station_profile.set_number_template(self.number_template)
print("Creating stations")
self.station_profile.set_command_flag("add_sta", "create_admin_down", 1)
self.station_profile.set_command_param("set_port", "report_timer", 1500)
self.station_profile.set_command_flag("set_port", "rpt_timer", 1)
self.station_profile.create(radio=self.radio_5g, sta_names_=self.sta_list, debug=self.debug)
if key == "BOTH" or key == "both":
keys = list(self.test_case.keys())
if "BOTH" in self.test_case:
self.radios = self.test_case["BOTH"].split(",")
elif "both" in self.test_case:
self.radios = self.test_case["both"].split(",")
split = len(self.sta_list) // 2
if keys[0] == "2.4G" or keys[0] == "2.4g":
if self.ssid is None:
self.station_profile.use_security(self.security_2g, self.ssid_2g, self.password_2g)
else:
self.station_profile.use_security(self.security, self.ssid, self.password)
self.station_profile.mode = 11
self.station_profile.create(radio=self.radios[0], sta_names_=self.sta_list[:split],
self.station_profile.set_number_template(self.number_template)
print("Creating stations")
self.station_profile.set_command_flag("add_sta", "create_admin_down", 1)
self.station_profile.set_command_param("set_port", "report_timer", 1500)
self.station_profile.set_command_flag("set_port", "rpt_timer", 1)
self.station_profile.create(radio=self.radio_2g, sta_names_=self.sta_list[:split],
debug=self.debug)
if self.ssid is None:
self.station_profile.use_security(self.security_5g, self.ssid_5g, self.password_5g)
else:
self.station_profile.use_security(self.security, self.ssid, self.password)
self.station_profile.mode = 9
self.station_profile.create(radio=self.radios[1], sta_names_=self.sta_list[split:],
self.station_profile.set_number_template(self.number_template)
self.station_profile.set_command_flag("add_sta", "create_admin_down", 1)
self.station_profile.set_command_param("set_port", "report_timer", 1500)
self.station_profile.set_command_flag("set_port", "rpt_timer", 1)
self.station_profile.create(radio=self.radio_5g, sta_names_=self.sta_list[split:],
debug=self.debug)
elif keys[0] == "5G" or keys[0] == "5g":
if self.ssid is None:
self.station_profile.use_security(self.security_5g, self.ssid_5g, self.password_5g)
self.station_profile.admin_up()
# check here if upstream port got IP
temp_stations = self.station_profile.station_names.copy()
if self.wait_for_ip(temp_stations):
self._pass("All stations got IPs")
else:
self.station_profile.use_security(self.security, self.ssid, self.password)
self.station_profile.mode = 9
self.station_profile.create(radio=self.radios[0], sta_names_=self.sta_list[:split],
debug=self.debug)
if self.ssid is None:
self.station_profile.use_security(self.security_2g, self.ssid_2g, self.password_2g)
else:
self.station_profile.use_security(self.security, self.ssid, self.password)
self.station_profile.mode = 11
self.station_profile.create(radio=self.radios[1], sta_names_=self.sta_list[split:],
debug=self.debug)
else:
if self.ssid is None:
self.station_profile.use_security(self.security_2g, self.ssid_2g, self.password_2g)
else:
self.station_profile.use_security(self.security, self.ssid, self.password)
self.station_profile.mode = 11
self.station_profile.create(radio=self.radios[0], sta_names_=self.sta_list[:split],
debug=self.debug)
if self.ssid is None:
self.station_profile.use_security(self.security_5g, self.ssid_5g, self.password_5g)
else:
self.station_profile.use_security(self.security, self.ssid, self.password)
self.station_profile.mode = 9
self.station_profile.create(radio=self.radios[1], sta_names_=self.sta_list[split:],
debug=self.debug)
else:
self.station_profile.create(radio=self.radio[0], sta_names_=self.sta_list, debug=self.debug)
self._fail("Stations failed to get IPs")
self.exit_fail()
self._pass("PASS: Station build finished")
self.create_cx()
print("cx build finished")
@@ -248,11 +223,12 @@ class ThroughputQOS(Realm):
sleep_time=0, tos=ip_tos)
print("cross connections with TOS type created.")
def evaluate_throughput(self):
global case
def evaluate_qos(self):
case = ""
tos_download = {'video': [], 'voice': [], 'bk': [], 'be': []}
tx_b = {'bk': [], 'be': [], 'video': [], 'voice': []}
rx_a = {'bk': [], 'be': [], 'video': [], 'voice': []}
delay = {'bk': [], 'be': [], 'video': [], 'voice': []}
pkt_loss = {}
tx_endps = {}
rx_endps = {}
@@ -261,10 +237,9 @@ class ThroughputQOS(Realm):
elif int(self.cx_profile.side_a_min_bps) != 0:
case = str(int(self.cx_profile.side_a_min_bps) // 1000000)
if len(self.cx_profile.created_cx.keys()) > 0:
endp_data = self.json_get('endp/all?fields=name,tx+pkts+ll,rx+pkts+ll')
endp_data = self.json_get('endp/all?fields=name,tx+pkts+ll,rx+pkts+ll,delay')
endp_data.pop("handler")
endp_data.pop("uri")
print(endp_data)
endps = endp_data['endpoint']
for i in range(len(endps)):
if i < len(endps) // 2:
@@ -279,44 +254,56 @@ class ThroughputQOS(Realm):
f"{list((self.json_get('/cx/%s?fields=bps+rx+a' % sta)).values())[2]['bps rx a'] / 1000000:.2f}"))
tx_b['bk'].append(int(f"{tx_endps['%s-B' % sta]['tx pkts ll']}"))
rx_a['bk'].append(int(f"{rx_endps['%s-A' % sta]['rx pkts ll']}"))
delay['bk'].append(int(f"{rx_endps['%s-A' % sta]['delay']}"))
else:
tos_download['bk'].append(float(0))
tx_b['bk'].append(int(0))
rx_a['bk'].append(int(0))
delay['bk'].append(int(0))
elif temp % 4 == 1:
if int(self.cx_profile.side_b_min_bps) != 0:
tos_download['be'].append(float(
f"{list((self.json_get('/cx/%s?fields=bps+rx+a' % sta)).values())[2]['bps rx a'] / 1000000:.2f}"))
tx_b['be'].append(int(f"{tx_endps['%s-B' % sta]['tx pkts ll']}"))
rx_a['be'].append(int(f"{rx_endps['%s-A' % sta]['rx pkts ll']}"))
delay['be'].append(int(f"{rx_endps['%s-A' % sta]['delay']}"))
else:
tos_download['be'].append(float(0))
tx_b['be'].append(int(0))
rx_a['be'].append(int(0))
delay['be'].append(int(0))
elif temp % 4 == 2:
if int(self.cx_profile.side_b_min_bps) != 0:
tos_download['voice'].append(float(
f"{list((self.json_get('/cx/%s?fields=bps+rx+a' % sta)).values())[2]['bps rx a'] / 1000000:.2f}"))
tx_b['voice'].append(int(f"{tx_endps['%s-B' % sta]['tx pkts ll']}"))
rx_a['voice'].append(int(f"{rx_endps['%s-A' % sta]['rx pkts ll']}"))
delay['voice'].append(int(f"{rx_endps['%s-A' % sta]['delay']}"))
else:
tos_download['voice'].append(float(0))
tx_b['voice'].append(int(0))
rx_a['voice'].append(int(0))
delay['voice'].append(int(0))
elif temp % 4 == 3:
if int(self.cx_profile.side_b_min_bps) != 0:
tos_download['video'].append(float(
f"{list((self.json_get('/cx/%s?fields=bps+rx+a' % sta)).values())[2]['bps rx a'] / 1000000:.2f}"))
tx_b['video'].append(int(f"{tx_endps['%s-B' % sta]['tx pkts ll']}"))
rx_a['video'].append(int(f"{rx_endps['%s-A' % sta]['rx pkts ll']}"))
delay['video'].append(int(f"{rx_endps['%s-A' % sta]['delay']}"))
else:
tos_download['video'].append(float(0))
tx_b['video'].append(int(0))
rx_a['video'].append(int(0))
delay['video'].append(int(0))
tos_download.update({"bkQOS": float(f"{sum(tos_download['bk']):.2f}")})
tos_download.update({"beQOS": float(f"{sum(tos_download['be']):.2f}")})
tos_download.update({"videoQOS": float(f"{sum(tos_download['video']):.2f}")})
tos_download.update({"voiceQOS": float(f"{sum(tos_download['voice']):.2f}")})
tos_download.update({"bkDELAY": float(f"{sum(delay['bk']) / 1000:.2f}")})
tos_download.update({"beDELAY": float(f"{sum(delay['be']) / 1000:.2f}")})
tos_download.update({"videoDELAY": float(f"{sum(delay['video']) / 1000:.2f}")})
tos_download.update({"voiceDELAY": float(f"{sum(delay['voice']) / 1000:.2f}")})
if sum(tx_b['bk']) != 0 or sum(tx_b['be']) != 0 or sum(tx_b['video']) != 0 or sum(tx_b['voice']) != 0:
tos_download.update(
{"bkLOSS": float(f"{((sum(tx_b['bk']) - sum(rx_a['bk'])) / sum(tx_b['bk'])) * 100:.2f}")})
@@ -328,21 +315,66 @@ class ThroughputQOS(Realm):
f"{((sum(tx_b['voice']) - sum(rx_a['voice'])) / sum(tx_b['voice'])) * 100:.2f}")})
tos_download.update({'tx_b': tx_b})
tos_download.update({'rx_a': rx_a})
tos_download.update({'delay': delay})
else:
print("no RX values available to evaluate QOS")
key = case + " " + "Mbps"
print(tos_download)
return {key: tos_download}
def generate_report(self, data, test_setup_info, input_setup_info):
def set_report_data(self, data):
print(data)
res = {}
if data is not None:
for i in range(len(data)):
res.update(data[i])
res.update({self.test_case[i]: data[i]})
else:
print("No Data found to generate report!")
exit(1)
if self.test_case is not None:
table_df = {}
num_stations = []
throughput = []
graph_df = {}
for case in self.test_case:
throughput_df = [[], [], [], []]
pkt_loss_df = [[], [], [], []]
latency_df = [[], [], [], []]
if case == "2.4g" or case == "2.4G":
num_stations.append("{} - bgn-AC".format(str(len(self.sta_list))))
elif case == "5g" or case == "5G":
num_stations.append("{} - an-AC".format(str(len(self.sta_list))))
elif case == "both" or case == "BOTH":
num_stations.append(
"{} - bgn-AC + {} - an-AC ".format(str(len(self.sta_list) // 2), str(len(self.sta_list) // 2)))
for key in res[case]:
throughput.append(
"BK : {}, BE : {}, VI: {}, VO: {}".format(res[case][key]["bkQOS"],
res[case][key]["beQOS"],
res[case][key][
"videoQOS"],
res[case][key][
"voiceQOS"]))
throughput_df[0].append(res[case][key]['bkQOS'])
throughput_df[1].append(res[case][key]['beQOS'])
throughput_df[2].append(res[case][key]['videoQOS'])
throughput_df[3].append(res[case][key]['voiceQOS'])
pkt_loss_df[0].append(res[case][key]['bkLOSS'])
pkt_loss_df[1].append(res[case][key]['beLOSS'])
pkt_loss_df[2].append(res[case][key]['videoLOSS'])
pkt_loss_df[3].append(res[case][key]['voiceLOSS'])
latency_df[0].append(res[case][key]['bkDELAY'])
latency_df[1].append(res[case][key]['beDELAY'])
latency_df[2].append(res[case][key]['videoDELAY'])
latency_df[3].append(res[case][key]['voiceDELAY'])
table_df.update({"No of Stations": num_stations})
table_df.update({"Throughput for Load {}".format(key): throughput})
graph_df.update({case: [throughput_df, pkt_loss_df, latency_df]})
res.update({"throughput_table_df": table_df})
res.update({"graph_df": graph_df})
return res
def generate_report(self, data, test_setup_info, input_setup_info):
res = self.set_report_data(data)
report = lf_report(_output_pdf="throughput_qos.pdf", _output_html="throughput_qos.html")
report_path = report.get_path()
report_path_date_time = report.get_path_date_time()
@@ -355,271 +387,202 @@ class ThroughputQOS(Realm):
_obj="Through this test we can evaluate the throughput for given number of clients which"
" runs the traffic with a particular Type of Service i.e BK,BE,VI,VO")
report.build_objective()
report.set_custom_html(_custom_html=self.test_setup_information(test_setup_data=test_setup_info,
colmn="Device Under Test"))
report.build_custom()
report.test_setup_table(test_setup_data=test_setup_info, value="Device Under Test")
report.set_table_title(
"Overall download Throughput for all TOS i.e BK | BE | Video (VI) | Voice (VO) in 2.4Ghz")
"Overall download Throughput for all TOS i.e BK | BE | Video (VI) | Voice (VO)")
report.build_table_title()
table_df = [[], [], [], [], []]
pkt_loss = [[], [], [], [], []]
for key in res:
if key == '1 Mbps':
table_df[0].append(res[key]['bkQOS'])
table_df[0].append(res[key]['beQOS'])
table_df[0].append(res[key]['videoQOS'])
table_df[0].append(res[key]['voiceQOS'])
pkt_loss[0].append(res[key]['bkLOSS'])
pkt_loss[0].append(res[key]['beLOSS'])
pkt_loss[0].append(res[key]['videoLOSS'])
pkt_loss[0].append(res[key]['voiceLOSS'])
if key == '2 Mbps':
table_df[1].append(res[key]['bkQOS'])
table_df[1].append(res[key]['beQOS'])
table_df[1].append(res[key]['videoQOS'])
table_df[1].append(res[key]['voiceQOS'])
pkt_loss[1].append(res[key]['bkLOSS'])
pkt_loss[1].append(res[key]['beLOSS'])
pkt_loss[1].append(res[key]['videoLOSS'])
pkt_loss[1].append(res[key]['voiceLOSS'])
if key == '3 Mbps':
table_df[2].append(res[key]['bkQOS'])
table_df[2].append(res[key]['beQOS'])
table_df[2].append(res[key]['videoQOS'])
table_df[2].append(res[key]['voiceQOS'])
pkt_loss[2].append(res[key]['bkLOSS'])
pkt_loss[2].append(res[key]['beLOSS'])
pkt_loss[2].append(res[key]['videoLOSS'])
pkt_loss[2].append(res[key]['voiceLOSS'])
if key == '4 Mbps':
table_df[3].append(res[key]['bkQOS'])
table_df[3].append(res[key]['beQOS'])
table_df[3].append(res[key]['videoQOS'])
table_df[3].append(res[key]['voiceQOS'])
pkt_loss[3].append(res[key]['bkLOSS'])
pkt_loss[3].append(res[key]['beLOSS'])
pkt_loss[3].append(res[key]['videoLOSS'])
pkt_loss[3].append(res[key]['voiceLOSS'])
if key == '5 Mbps':
table_df[4].append(res[key]['bkQOS'])
table_df[4].append(res[key]['beQOS'])
table_df[4].append(res[key]['videoQOS'])
table_df[4].append(res[key]['voiceQOS'])
pkt_loss[4].append(res[key]['bkLOSS'])
pkt_loss[4].append(res[key]['beLOSS'])
pkt_loss[4].append(res[key]['videoLOSS'])
pkt_loss[4].append(res[key]['voiceLOSS'])
table_df2 = []
for i in range(len(table_df)):
table_df2.append(
f'BK: {table_df[i][0]} | BE: {table_df[i][1]} | VI: {table_df[i][2]} | VO: {table_df[i][3]}')
df_throughput = pd.DataFrame({
'Mode': ['bgn-AC'], "No.of.clients": [len(self.sta_list)],
'Throughput for Load (1 Mbps)': [table_df2[0]],
'Throughput for Load (2 Mbps)': [table_df2[1]],
'Throughput for Load (3 Mbps)': [table_df2[2]],
'Throughput for Load (4 Mbps)': [table_df2[3]],
'Throughput for Load (5 Mbps)': [table_df2[4]],
})
df_throughput = pd.DataFrame(res["throughput_table_df"])
report.set_table_dataframe(df_throughput)
report.build_table()
graph_df = [[], [], [], []]
pkt_loss_df = [[], [], [], []]
for key in res:
if key == '1 Mbps':
graph_df[0].append(res[key]['bkQOS'])
graph_df[1].append(res[key]['beQOS'])
graph_df[2].append(res[key]['videoQOS'])
graph_df[3].append(res[key]['voiceQOS'])
pkt_loss_df[0].append(res[key]['bkLOSS'])
pkt_loss_df[1].append(res[key]['beLOSS'])
pkt_loss_df[2].append(res[key]['videoLOSS'])
pkt_loss_df[3].append(res[key]['voiceLOSS'])
if key == '2 Mbps':
graph_df[0].append(res[key]['bkQOS'])
graph_df[1].append(res[key]['beQOS'])
graph_df[2].append(res[key]['videoQOS'])
graph_df[3].append(res[key]['voiceQOS'])
pkt_loss_df[0].append(res[key]['bkLOSS'])
pkt_loss_df[1].append(res[key]['beLOSS'])
pkt_loss_df[2].append(res[key]['videoLOSS'])
pkt_loss_df[3].append(res[key]['voiceLOSS'])
if key == '3 Mbps':
graph_df[0].append(res[key]['bkQOS'])
graph_df[1].append(res[key]['beQOS'])
graph_df[2].append(res[key]['videoQOS'])
graph_df[3].append(res[key]['voiceQOS'])
pkt_loss_df[0].append(res[key]['bkLOSS'])
pkt_loss_df[1].append(res[key]['beLOSS'])
pkt_loss_df[2].append(res[key]['videoLOSS'])
pkt_loss_df[3].append(res[key]['voiceLOSS'])
if key == '4 Mbps':
graph_df[0].append(res[key]['bkQOS'])
graph_df[1].append(res[key]['beQOS'])
graph_df[2].append(res[key]['videoQOS'])
graph_df[3].append(res[key]['voiceQOS'])
pkt_loss_df[0].append(res[key]['bkLOSS'])
pkt_loss_df[1].append(res[key]['beLOSS'])
pkt_loss_df[2].append(res[key]['videoLOSS'])
pkt_loss_df[3].append(res[key]['voiceLOSS'])
if key == '5 Mbps':
graph_df[0].append(res[key]['bkQOS'])
graph_df[1].append(res[key]['beQOS'])
graph_df[2].append(res[key]['videoQOS'])
graph_df[3].append(res[key]['voiceQOS'])
pkt_loss_df[0].append(res[key]['bkLOSS'])
pkt_loss_df[1].append(res[key]['beLOSS'])
pkt_loss_df[2].append(res[key]['videoLOSS'])
pkt_loss_df[3].append(res[key]['voiceLOSS'])
report.set_graph_title(f"Overall Download throughput for all {self.bands[0]} clients with different TOS.")
for key in res["graph_df"]:
report.set_graph_title(f"Overall Download throughput for {len(self.sta_list)} - {key} clients with different TOS.")
report.set_obj_html(_obj_title="", _obj="The below graph represents overall download throughput for all "
"connected stations running BK, BE, VO, VI traffic with different "
"intended loads per station 1 Mbps, 2 Mbps, 3 Mbps, 4 Mbps, 5 Mbps.")
"intended loads per station {}".format(res["graph_df"][key].keys()))
report.build_graph_title()
report.build_objective()
graph = lf_bar_graph(_data_set=graph_df,
graph = lf_bar_graph(_data_set=res["graph_df"][key][0],
_xaxis_name="Load per Type of Service",
_yaxis_name="Throughput (Mbps)",
_xaxis_categories=[1, 2, 3, 4, 5, 6],
_xaxis_categories=[1],
_xaxis_label=['1 Mbps', '2 Mbps', '3 Mbps', '4 Mbps', '5 Mbps'],
_graph_image_name=f"tos_download_{self.bands[0]}Hz",
_graph_image_name=f"tos_download_{key}Hz",
_label=["BK", "BE", "VI", "VO"],
_step_size=1,
_xaxis_step=1,
_graph_title="Overall download throughput BK,BE,VO,VI traffic streams",
_title_size=16,
_color=['orangered', 'greenyellow', 'steelblue', 'blueviolet'],
_color_edge='black',
_bar_width=0.15,
_dpi=96,
_enable_csv=True,
_color_name=['orangered', 'greenyellow', 'steelblue', 'blueviolet'])
graph_png = graph.build_bar_graph()
print("graph name {}".format(graph_png))
report.set_graph_image(graph_png)
# need to move the graph image to the results
# need to move the graph image to the results directory
report.move_graph_image()
report.set_csv_filename(graph_png)
report.move_csv_file()
report.build_graph()
report.set_graph_title(f"Overall Packet loss for all {self.bands[0]} clients with different TOS.")
report.set_obj_html(_obj_title="", _obj="This graph shows the overall packet loss for the connected stations "
"for BK,BE,VO,VI traffic with intended load per station 1 Mbps, "
"2 Mbps, 3 Mbps, 4 Mbps, 5 Mbps")
report.set_graph_title(f"Overall Packet loss for {len(self.sta_list)} - {key} clients with different TOS.")
report.set_obj_html(_obj_title="",
_obj="This graph shows the overall packet loss for the connected stations "
"for BK,BE,VO,VI traffic with intended load per station {}".format(res["graph_df"][key].keys()))
report.build_graph_title()
report.build_objective()
graph = lf_bar_graph(_data_set=pkt_loss_df,
graph = lf_bar_graph(_data_set=res["graph_df"][key][1],
_xaxis_name="Load per Type of Service",
_yaxis_name="Packet Loss (%)",
_xaxis_categories=[1, 2, 3, 4, 5, 6],
_xaxis_categories=[1],
_xaxis_label=['1 Mbps', '2 Mbps', '3 Mbps', '4 Mbps', '5 Mbps'],
_graph_image_name=f"pkt_loss_{self.bands[0]}Hz",
_graph_image_name=f"pkt_loss_{key}Hz",
_label=["BK", "BE", "VI", "VO"],
_step_size=1,
_xaxis_step=1,
_graph_title="Load vs Packet Loss",
_title_size=16,
_color=['orangered', 'greenyellow', 'steelblue', 'blueviolet'],
_color_edge='black',
_bar_width=0.15,
_dpi=96,
_enable_csv=True,
_color_name=['orangered', 'greenyellow', 'steelblue', 'blueviolet'])
graph_png = graph.build_bar_graph()
print("graph name {}".format(graph_png))
report.set_graph_image(graph_png)
# need to move the graph image to the results
# need to move the graph image to the results directory
report.move_graph_image()
report.set_csv_filename(graph_png)
report.move_csv_file()
report.build_graph()
self.generate_individual_graph(data, report)
report.set_custom_html(_custom_html=self.test_setup_information(test_setup_data=input_setup_info, colmn="Information"))
report.set_obj_html(
_obj_title=f"Overall Latency for {len(self.sta_list)} - {key} clients with different TOS.",
_obj="This graph shows the overall Latency for the connected stations "
"for BK,BE,VO,VI traffic with intended load per station {}".format(res["graph_df"][key].keys()))
report.build_objective()
graph = lf_bar_graph(_data_set=res["graph_df"][key][2],
_xaxis_name="Load per Type of Service",
_yaxis_name="Average Latency (in seconds)",
_xaxis_categories=[1],
_xaxis_label=['1 Mbps', '2 Mbps', '3 Mbps', '4 Mbps', '5 Mbps'],
_graph_image_name=f"latency_{key}Hz",
_label=["BK", "BE", "VI", "VO"],
_xaxis_step=1,
_graph_title="Overall Download Latency BK,BE,VO,VI traffic streams",
_title_size=16,
_show_bar_value=True,
_color=['orangered', 'yellowgreen', 'steelblue', 'blueviolet'],
_color_edge='black',
_bar_width=0.15,
_dpi=96,
_enable_csv=True,
_color_name=['orangered', 'yellowgreen', 'steelblue', 'blueviolet'])
graph_png = graph.build_bar_graph()
print("graph name {}".format(graph_png))
report.set_graph_image(graph_png)
# need to move the graph image to the results directory
report.move_graph_image()
report.set_csv_filename(graph_png)
report.move_csv_file()
report.build_graph()
self.generate_individual_graph(res, report)
report.test_setup_table(test_setup_data=input_setup_info, value="Information")
report.build_custom()
report.write_html()
report.write_pdf()
def generate_individual_graph(self, data, report):
if data is not None:
res = {}
for i in range(len(data)):
res.update(data[i])
def generate_individual_graph(self, res, report):
if len(res.keys()) > 0:
count = 1
if "throughput_table_df" in res:
res.pop("throughput_table_df")
if "graph_df" in res:
res.pop("graph_df")
for key in res:
report.set_graph_title(
_graph_title=f"Individual download throughput with intended load {key}/station for traffic BK(WiFi).")
report.set_obj_html(_obj_title="",
for load in res[key]:
report.set_obj_html(
_obj_title=f"Individual download throughput with intended load {load}/station for traffic BK(WiFi).",
_obj=f"The below graph represents individual throughput for {len(self.sta_list)} clients running BK "
f"(WiFi) traffic. X- axis shows “number of clients” and Y-axis shows “"
f"Throughput in Mbps”.")
report.build_graph_title()
report.build_objective()
graph = lf_bar_graph(_data_set=[res[key]['bk']], _xaxis_name="Clients running - BK",
graph = lf_bar_graph(_data_set=[res[key][load]['bk']], _xaxis_name="Clients running - BK",
_yaxis_name="Throughput in Mbps",
_xaxis_categories=[i+1 for i in range(len(self.sta_list))],
_xaxis_label=[i+1 for i in range(len(self.sta_list))],
_xaxis_categories=[i + 1 for i in range(len(self.sta_list))],
_xaxis_label=[i + 1 for i in range(len(self.sta_list))],
_label=["BK"],
_step_size=1,
_xaxis_step=1,
_xticks_font=8,
_graph_title="Individual download throughput for BK(WIFI) traffic - {} clients".format(self.bands[0]),
_graph_title="Individual download throughput for BK(WIFI) traffic - {} clients".format(
key),
_title_size=16,
_bar_width=0.15, _color_name=['orangered'],
_graph_image_name="{}_bk_{}".format(self.bands[0], count), _color_edge=['black'],
_enable_csv=True,
_graph_image_name="{}_bk_{}".format(key, load), _color_edge=['black'],
_color=['orangered'])
graph_png = graph.build_bar_graph()
print("graph name {}".format(graph_png))
report.set_graph_image(graph_png)
# need to move the graph image to the results
report.move_graph_image()
report.set_csv_filename(graph_png)
report.move_csv_file()
report.build_graph()
report.set_graph_title(
_graph_title=f"Individual download throughput with intended load {key}/station for traffic BE(WiFi).")
report.set_obj_html(_obj_title="",
report.set_obj_html(
_obj_title=f"Individual download throughput with intended load {load}/station for traffic BE(WiFi).",
_obj=f"The below graph represents individual throughput for {len(self.sta_list)} clients running BE "
f"(WiFi) traffic. X- axis shows “number of clients” and Y-axis shows "
f"“Throughput in Mbps”.")
report.build_graph_title()
report.build_objective()
graph = lf_bar_graph(_data_set=[res[key]['be']], _xaxis_name="Clients running - BE",
graph = lf_bar_graph(_data_set=[res[key][load]['be']], _xaxis_name="Clients running - BE",
_yaxis_name="Throughput in Mbps",
_xaxis_categories=[i+1 for i in range(len(self.sta_list))],
_xaxis_label=[i+1 for i in range(len(self.sta_list))],
_xaxis_categories=[i + 1 for i in range(len(self.sta_list))],
_xaxis_label=[i + 1 for i in range(len(self.sta_list))],
_label=["BE"],
_step_size=1,
_xaxis_step=1,
_xticks_font=8,
_graph_title="Individual download throughput for BE(WIFI) traffic - {} clients".format(self.bands[0]),
_graph_title="Individual download throughput for BE(WIFI) traffic - {} clients".format(
key),
_title_size=16,
_bar_width=0.15, _color_name=['greenyellow'],
_graph_image_name="{}_be_{}".format(self.bands[0], count), _color_edge=['black'],
_color=['greenyellow'])
_bar_width=0.15, _color_name=['yellowgreen'],
_enable_csv=True,
_graph_image_name="{}_be_{}".format(key, load), _color_edge=['black'],
_color=['yellowgreen'])
graph_png = graph.build_bar_graph()
print("graph name {}".format(graph_png))
report.set_graph_image(graph_png)
# need to move the graph image to the results
report.move_graph_image()
report.set_csv_filename(graph_png)
report.move_csv_file()
report.build_graph()
report.set_graph_title(
_graph_title=f"Individual download throughput with intended load {key}/station for traffic VI(WiFi).")
report.set_obj_html(_obj_title="",
report.set_obj_html(
_obj_title=f"Individual download throughput with intended load {load}/station for traffic VI(WiFi).",
_obj=f"The below graph represents individual throughput for {len(self.sta_list)} clients running VI "
f"(WiFi) traffic. X- axis shows “number of clients” and Y-axis shows "
f"“Throughput in Mbps”.")
report.build_graph_title()
report.build_objective()
graph = lf_bar_graph(_data_set=[res[key]['video']], _xaxis_name="Clients running - VI",
graph = lf_bar_graph(_data_set=[res[key][load]['video']], _xaxis_name="Clients running - VI",
_yaxis_name="Throughput in Mbps",
_xaxis_categories=[i+1 for i in range(len(self.sta_list))],
_xaxis_label=[i+1 for i in range(len(self.sta_list))],
_xaxis_categories=[i + 1 for i in range(len(self.sta_list))],
_xaxis_label=[i + 1 for i in range(len(self.sta_list))],
_label=["Video"],
_step_size=1,
_xaxis_step=1,
_xticks_font=8,
_graph_title="Individual download throughput for VI(WIFI) traffic - {} clients".format(self.bands[0]),
_graph_title="Individual download throughput for VI(WIFI) traffic - {} clients".format(
key),
_title_size=16,
_bar_width=0.15, _color_name=['steelblue'],
_graph_image_name="{}_video_{}".format(self.bands[0], count),
_enable_csv=True,
_graph_image_name="{}_video_{}".format(key, load),
_color_edge=['black'],
_color=['steelblue'])
graph_png = graph.build_bar_graph()
@@ -627,26 +590,28 @@ class ThroughputQOS(Realm):
report.set_graph_image(graph_png)
# need to move the graph image to the results
report.move_graph_image()
report.set_csv_filename(graph_png)
report.move_csv_file()
report.build_graph()
report.set_graph_title(
_graph_title=f"Individual download throughput with intended load {key}/station for traffic VO(WiFi).")
report.set_obj_html(_obj_title="",
report.set_obj_html(
_obj_title=f"Individual download throughput with intended load {load}/station for traffic VO(WiFi).",
_obj=f"The below graph represents individual throughput for {len(self.sta_list)} clients running VO "
f"(WiFi) traffic. X- axis shows “number of clients” and Y-axis shows "
f"“Throughput in Mbps”.")
report.build_graph_title()
report.build_objective()
graph = lf_bar_graph(_data_set=[res[key]['voice']], _xaxis_name="Clients running - VO",
graph = lf_bar_graph(_data_set=[res[key][load]['voice']], _xaxis_name="Clients running - VO",
_yaxis_name="Throughput in Mbps",
_xaxis_categories=[i+1 for i in range(len(self.sta_list))],
_xaxis_label=[i+1 for i in range(len(self.sta_list))],
_xaxis_categories=[i + 1 for i in range(len(self.sta_list))],
_xaxis_label=[i + 1 for i in range(len(self.sta_list))],
_label=['Voice'],
_step_size=1,
_xaxis_step=1,
_xticks_font=8,
_graph_title="Individual download throughput for VO(WIFI) traffic - {} clients".format(self.bands[0]),
_graph_title="Individual download throughput for VO(WIFI) traffic - {} clients".format(
key),
_title_size=16,
_bar_width=0.15, _color_name=['blueviolet'],
_graph_image_name="{}_voice_{}".format(self.bands[0], count),
_enable_csv=True,
_graph_image_name="{}_voice_{}".format(key, load),
_color_edge=['black'],
_color=['blueviolet'])
graph_png = graph.build_bar_graph()
@@ -654,38 +619,12 @@ class ThroughputQOS(Realm):
report.set_graph_image(graph_png)
# need to move the graph image to the results
report.move_graph_image()
report.set_csv_filename(graph_png)
report.move_csv_file()
report.build_graph()
count += 1
else:
print("No individual graph to generate.")
def test_setup_information(self, test_setup_data=None, colmn="Setup Information"):
# custom table for test-setup/input-setup information
if test_setup_data is None:
return None
else:
var = ""
for i in test_setup_data:
var = var + "<tr><td>" + i + "</td><td colspan='3'>" + str(test_setup_data[i]) + "</td></tr>"
setup_information = """
<!-- Test Setup Information -->
<br><br>
<table width='700px' border='1' cellpadding='2' cellspacing='0' style='border-top-color: gray; border-top-style: solid; border-top-width: 1px; border-right-color: gray; border-right-style: solid; border-right-width: 1px; border-bottom-color: gray; border-bottom-style: solid; border-bottom-width: 1px; border-left-color: gray; border-left-style: solid; border-left-width: 1px'>
<tr>
<th colspan='2'> Test Setup Information </th>
</tr>
<tr>
<td>""" + colmn + """</td>
<td>
<table width='100%' border='0' cellpadding='2' cellspacing='0' style='border-top-color: gray; border-top-style: solid; border-top-width: 1px; border-right-color: gray; border-right-style: solid; border-right-width: 1px; border-bottom-color: gray; border-bottom-style: solid; border-bottom-width: 1px; border-left-color: gray; border-left-style: solid; border-left-width: 1px'>
""" + str(var) + """
</table>
</td>
</tr>
</table>
<br><br>
"""
return str(setup_information)
def main():
@@ -702,7 +641,7 @@ Generic command layout:
python3 ./throughput_QOS.py
--upstream_port eth1
--radio wiphy0
--radio_2g wiphy0
--num_stations 32
--security {open|wep|wpa|wpa2|wpa3}
--mode 1
@@ -722,8 +661,6 @@ python3 ./throughput_QOS.py
"bgnAX" : "13"}
--ssid netgear
--password admin123
--test_duration 2m (default)
--monitor_interval_ms
--a_min 3000
--b_min 1000
--ap "00:0e:8e:78:e1:76"
@@ -733,9 +670,8 @@ python3 ./throughput_QOS.py
--traffic_type lf_udp (traffic type, lf_udp | lf_tcp)
--test_duration 5m (duration to run traffic 5m --> 5 Minutes)
--create_sta False (False, means it will not create stations and use the sta_names specified below)
--sta_names sta000,sta001,sta002 (used if --create_sta False, comma separated names of stations)
--sta_names sta000,sta001,sta002 (used if --create_sta is False, comma separated names of stations)
''')
parser.add_argument('--mode', help='Used to force mode of stations', default="0")
parser.add_argument('--ap', help='Used to force a connection to a particular AP')
parser.add_argument('--traffic_type', help='Select the Traffic Type [lf_udp, lf_tcp]', required=True)
@@ -748,22 +684,23 @@ python3 ./throughput_QOS.py
default="Best Effort")
parser.add_argument('--ap_name', help="AP Model Name", default="Test-AP")
parser.add_argument('--bands', help='used to run on multiple radio bands,can be used with multiple stations',
default="2,4G, 5G, BOTH", required=True)
default="2.4G, 5G, BOTH", required=True)
parser.add_argument('--ssid_2g', help="ssid for 2.4Ghz band")
parser.add_argument('--security_2g', help="security type for 2.4Ghz band")
parser.add_argument('--passwd_2g', help="password for 2.4Ghz band")
parser.add_argument('--ssid_5g', help="ssid for 5Ghz band")
parser.add_argument('--security_5g', help="security type for 5Ghz band")
parser.add_argument('--passwd_5g', help="password for 5Ghz band")
parser.add_argument('--radio_2g', help="radio which supports 2.4G bandwidth", default="wiphy0")
parser.add_argument('--radio_5g', help="radio which supports 5G bandwidth", default="wiphy1")
args = parser.parse_args()
print("--------------------------------------------")
print(args)
print("--------------------------------------------")
args.test_case = {}
args.test_case = args.bands.split(',')
test_results = []
loads = {}
bands = []
radios = []
station_list = []
if (args.a_min is not None) and (args.b_min is not None):
@@ -779,11 +716,6 @@ python3 ./throughput_QOS.py
if args.bands is not None:
bands = args.bands.split(',')
if args.radio is not None:
radios = args.radio.split(',')
if len(radios) < 2:
radios.extend(radios[0])
if args.test_duration is not None:
args.test_duration = args.test_duration.strip('m')
@@ -793,59 +725,44 @@ python3 ./throughput_QOS.py
for i in range(len(bands)):
if bands[i] == "2.4G" or bands[i] == "2.4g":
args.bands = bands[i]
if args.mode is not None:
args.mode = 11
if i == 0:
args.radio = radios[0]
args.test_case.update({bands[i]: radios[0]})
else:
args.radio = radios[1]
args.test_case.update({bands[i]: radios[1]})
if args.create_sta:
station_list = LFUtils.portNameSeries(prefix_="sta", start_id_=0, end_id_=int(args.num_stations) - 1,
padding_number_=10000, radio=args.radio)
padding_number_=10000, radio=args.radio_2g)
else:
station_list = args.sta_names.split(",")
elif bands[i] == "5G" or bands[i] == "5g":
args.bands = bands[i]
args.mode = 9
if i == 0:
args.radio = radios[0]
args.test_case.update({bands[i]: radios[0]})
else:
args.radio = radios[1]
args.test_case.update({bands[i]: radios[1]})
if args.create_sta:
station_list = LFUtils.portNameSeries(prefix_="sta", start_id_=0, end_id_=int(args.num_stations) - 1,
padding_number_=10000,
radio=args.radio)
radio=args.radio_5g)
else:
station_list = args.sta_names.split(",")
elif bands[i] == "BOTH" or bands[i] == "both":
args.bands = bands[i]
args.radio = str(radios[0] + "," + radios[1])
args.test_case.update({bands[i]: radios[0] + "," + radios[1]})
args.mode = 0
if (int(args.num_stations) % 2) != 0:
print("Number of stations for Both Band should be even in number.")
exit(1)
mid = int(args.num_stations) // 2
if args.create_sta:
station_list = LFUtils.portNameSeries(prefix_="sta", start_id_=0, end_id_=mid - 1,
padding_number_=10000,
radio=radios[0])
radio=args.radio_2g)
station_list.extend(LFUtils.portNameSeries(prefix_="sta", start_id_=mid,
end_id_=int(args.num_stations) - 1,
padding_number_=10000,
radio=radios[1]))
radio=args.radio_5g))
else:
station_list = args.sta_names.split(",")
else:
print("Band " + bands[i] + " Not Exist")
exit(1)
print("-----------------")
# print(bands[i])
print(args.radio)
# print(args.mode)
# print(station_list)
print(args.test_case)
print("-----------------")
print("------------------------")
print(args.bands)
print("------------------------")
# ---------------------------------------#
for index in range(len(loads["b_min"])):
throughput_qos = ThroughputQOS(host=args.mgr,
@@ -865,11 +782,12 @@ python3 ./throughput_QOS.py
ssid_5g=args.ssid_5g,
password_5g=args.passwd_5g,
security_5g=args.security_5g,
radio=args.radio,
radio_2g=args.radio_2g,
radio_5g=args.radio_5g,
test_duration=args.test_duration,
use_ht160=False,
side_a_min_rate=loads['a_min'][index],
side_b_min_rate=loads['b_min'][index],
side_a_min_rate=int(loads['a_min'][index]),
side_b_min_rate=int(loads['b_min'][index]),
mode=args.mode,
bands=args.bands,
ap=args.ap,
@@ -888,11 +806,10 @@ python3 ./throughput_QOS.py
layer3connections = ','.join([[*x.keys()][0] for x in throughput_qos.json_get('endp')['endpoint']])
except:
raise ValueError('Try setting the upstream port flag if your device does not have an eth1 port')
throughput_qos.start(False, False)
time.sleep(int(args.test_duration) * 60)
throughput_qos.stop()
test_results.append(throughput_qos.evaluate_throughput())
test_results.append(throughput_qos.evaluate_qos())
if args.create_sta:
if not throughput_qos.passes():
print(throughput_qos.get_fail_message())
@@ -909,7 +826,8 @@ python3 ./throughput_QOS.py
"SSID": throughput_qos.ssid,
"SSID - 2.4 Ghz": throughput_qos.ssid_2g,
"SSID - 5 Ghz": throughput_qos.ssid_5g,
"Test Duration": datetime.datetime.strptime(test_end_time, "%b %d %H:%M:%S") - datetime.datetime.strptime(test_start_time, "%b %d %H:%M:%S")
"Test Duration": datetime.datetime.strptime(test_end_time, "%b %d %H:%M:%S") - datetime.datetime.strptime(
test_start_time, "%b %d %H:%M:%S")
}
if throughput_qos.ssid is None:
test_setup_info.pop("SSID")