+ generated = input_data.metadata(job, build).\
+ get(u"generated", u"")
+ if not generated:
+ continue
+ then = dt.strptime(generated, u"%Y%m%d %H:%M")
+ if (now - then) <= timeperiod:
+ tbl_dict[tst_name][u"data"][build] = (
+ tst_data[u"status"],
+ generated,
+ input_data.metadata(job, build).get(u"version",
+ u""),
+ build
+ )
+ except (TypeError, KeyError) as err:
+ logging.warning(f"tst_name: {tst_name} - err: {repr(err)}")
+
+ max_fails = 0
+ tbl_lst = list()
+ for tst_data in tbl_dict.values():
+ fails_nr = 0
+ fails_last_date = u""
+ fails_last_vpp = u""
+ fails_last_csit = u""
+ for val in tst_data[u"data"].values():
+ if val[0] == u"FAIL":
+ fails_nr += 1
+ fails_last_date = val[1]
+ fails_last_vpp = val[2]
+ fails_last_csit = val[3]
+ if fails_nr:
+ max_fails = fails_nr if fails_nr > max_fails else max_fails
+ tbl_lst.append([
+ tst_data[u"name"],
+ fails_nr,
+ fails_last_date,
+ fails_last_vpp,
+ f"{u'mrr-daily' if test_type == u'MRR' else u'ndrpdr-weekly'}"
+ f"-build-{fails_last_csit}"
+ ])
+
+ tbl_lst.sort(key=lambda rel: rel[2], reverse=True)
+ tbl_sorted = list()
+ for nrf in range(max_fails, -1, -1):
+ tbl_fails = [item for item in tbl_lst if item[1] == nrf]
+ tbl_sorted.extend(tbl_fails)
+
+ file_name = f"{table[u'output-file']}{table[u'output-file-ext']}"
+ logging.info(f" Writing file: {file_name}")
+ with open(file_name, u"wt") as file_handler:
+ file_handler.write(u",".join(header) + u"\n")
+ for test in tbl_sorted:
+ file_handler.write(u",".join([str(item) for item in test]) + u'\n')
+
+ logging.info(f" Writing file: {table[u'output-file']}.txt")
+ convert_csv_to_pretty_txt(file_name, f"{table[u'output-file']}.txt")
+
+
+def table_failed_tests_html(table, input_data):
+ """Generate the table(s) with algorithm: table_failed_tests_html
+ specified in the specification file.
+
+ :param table: Table to generate.
+ :param input_data: Data to process.
+ :type table: pandas.Series
+ :type input_data: InputData
+ """
+
+ _ = input_data
+
+ if not table.get(u"testbed", None):
+ logging.error(
+ f"The testbed is not defined for the table "
+ f"{table.get(u'title', u'')}. Skipping."
+ )
+ return
+
+ test_type = table.get(u"test-type", u"MRR")
+ if test_type not in (u"MRR", u"NDR", u"PDR", u"NDRPDR"):
+ logging.error(
+ f"Test type {table.get(u'test-type', u'MRR')} is not defined. "
+ f"Skipping."
+ )
+ return
+
+ if test_type in (u"NDRPDR", u"NDR", u"PDR"):
+ lnk_dir = u"../ndrpdr_trending/"
+ lnk_sufix = u"-pdr"
+ else:
+ lnk_dir = u"../trending/"
+ lnk_sufix = u""
+
+ logging.info(f" Generating the table {table.get(u'title', u'')} ...")
+
+ try:
+ with open(table[u"input-file"], u'rt') as csv_file:
+ csv_lst = list(csv.reader(csv_file, delimiter=u',', quotechar=u'"'))
+ except KeyError:
+ logging.warning(u"The input file is not defined.")
+ return
+ except csv.Error as err:
+ logging.warning(
+ f"Not possible to process the file {table[u'input-file']}.\n"
+ f"{repr(err)}"
+ )
+ return
+
+ # Table:
+ failed_tests = ET.Element(u"table", attrib=dict(width=u"100%", border=u'0'))
+
+ # Table header:
+ trow = ET.SubElement(failed_tests, u"tr", attrib=dict(bgcolor=u"#7eade7"))
+ for idx, item in enumerate(csv_lst[0]):
+ alignment = u"left" if idx == 0 else u"center"
+ thead = ET.SubElement(trow, u"th", attrib=dict(align=alignment))
+ thead.text = item
+
+ # Rows:
+ colors = (u"#e9f1fb", u"#d4e4f7")
+ for r_idx, row in enumerate(csv_lst[1:]):
+ background = colors[r_idx % 2]
+ trow = ET.SubElement(
+ failed_tests, u"tr", attrib=dict(bgcolor=background)
+ )
+
+ # Columns:
+ for c_idx, item in enumerate(row):
+ tdata = ET.SubElement(
+ trow,
+ u"td",
+ attrib=dict(align=u"left" if c_idx == 0 else u"center")
+ )
+ # Name:
+ if c_idx == 0 and table.get(u"add-links", True):
+ ref = ET.SubElement(
+ tdata,
+ u"a",
+ attrib=dict(
+ href=f"{lnk_dir}"
+ f"{_generate_url(table.get(u'testbed', ''), item)}"
+ f"{lnk_sufix}"
+ )
+ )
+ ref.text = item
+ else:
+ tdata.text = item
+ try:
+ with open(table[u"output-file"], u'w') as html_file:
+ logging.info(f" Writing file: {table[u'output-file']}")
+ html_file.write(u".. raw:: html\n\n\t")
+ html_file.write(str(ET.tostring(failed_tests, encoding=u"unicode")))
+ html_file.write(u"\n\t<p><br><br></p>\n")
+ except KeyError:
+ logging.warning(u"The output file is not defined.")
+ return
+
+
+def table_comparison(table, input_data):
+ """Generate the table(s) with algorithm: table_comparison
+ specified in the specification file.
+
+ :param table: Table to generate.
+ :param input_data: Data to process.
+ :type table: pandas.Series
+ :type input_data: InputData
+ """
+ logging.info(f" Generating the table {table.get(u'title', u'')} ...")
+
+ # Transform the data
+ logging.info(
+ f" Creating the data set for the {table.get(u'type', u'')} "
+ f"{table.get(u'title', u'')}."
+ )
+
+ columns = table.get(u"columns", None)
+ if not columns:
+ logging.error(
+ f"No columns specified for {table.get(u'title', u'')}. Skipping."
+ )
+ return
+
+ cols = list()
+ for idx, col in enumerate(columns):
+ if col.get(u"data-set", None) is None:
+ logging.warning(f"No data for column {col.get(u'title', u'')}")
+ continue
+ tag = col.get(u"tag", None)
+ data = input_data.filter_data(
+ table,
+ params=[u"throughput", u"result", u"name", u"parent", u"tags"],
+ data=col[u"data-set"],
+ continue_on_error=True
+ )
+ col_data = {
+ u"title": col.get(u"title", f"Column{idx}"),
+ u"data": dict()
+ }
+ for builds in data.values:
+ for build in builds:
+ for tst_name, tst_data in build.items():
+ if tag and tag not in tst_data[u"tags"]:
+ continue
+ tst_name_mod = \
+ _tpc_modify_test_name(tst_name, ignore_nic=True).\
+ replace(u"2n1l-", u"")
+ if col_data[u"data"].get(tst_name_mod, None) is None:
+ name = tst_data[u'name'].rsplit(u'-', 1)[0]
+ if u"across testbeds" in table[u"title"].lower() or \
+ u"across topologies" in table[u"title"].lower():
+ name = _tpc_modify_displayed_test_name(name)
+ col_data[u"data"][tst_name_mod] = {
+ u"name": name,
+ u"replace": True,
+ u"data": list(),
+ u"mean": None,
+ u"stdev": None
+ }
+ _tpc_insert_data(
+ target=col_data[u"data"][tst_name_mod],
+ src=tst_data,
+ include_tests=table[u"include-tests"]
+ )
+
+ replacement = col.get(u"data-replacement", None)
+ if replacement:
+ rpl_data = input_data.filter_data(
+ table,
+ params=[u"throughput", u"result", u"name", u"parent", u"tags"],
+ data=replacement,
+ continue_on_error=True
+ )
+ for builds in rpl_data.values:
+ for build in builds:
+ for tst_name, tst_data in build.items():
+ if tag and tag not in tst_data[u"tags"]:
+ continue
+ tst_name_mod = \
+ _tpc_modify_test_name(tst_name, ignore_nic=True).\
+ replace(u"2n1l-", u"")
+ if col_data[u"data"].get(tst_name_mod, None) is None:
+ name = tst_data[u'name'].rsplit(u'-', 1)[0]
+ if u"across testbeds" in table[u"title"].lower() \
+ or u"across topologies" in \
+ table[u"title"].lower():
+ name = _tpc_modify_displayed_test_name(name)
+ col_data[u"data"][tst_name_mod] = {
+ u"name": name,
+ u"replace": False,
+ u"data": list(),
+ u"mean": None,
+ u"stdev": None
+ }
+ if col_data[u"data"][tst_name_mod][u"replace"]:
+ col_data[u"data"][tst_name_mod][u"replace"] = False
+ col_data[u"data"][tst_name_mod][u"data"] = list()
+ _tpc_insert_data(
+ target=col_data[u"data"][tst_name_mod],
+ src=tst_data,
+ include_tests=table[u"include-tests"]
+ )
+
+ if table[u"include-tests"] in (u"NDR", u"PDR"):
+ for tst_name, tst_data in col_data[u"data"].items():
+ if tst_data[u"data"]:
+ tst_data[u"mean"] = mean(tst_data[u"data"])
+ tst_data[u"stdev"] = stdev(tst_data[u"data"])
+
+ cols.append(col_data)
+
+ tbl_dict = dict()
+ for col in cols:
+ for tst_name, tst_data in col[u"data"].items():
+ if tbl_dict.get(tst_name, None) is None:
+ tbl_dict[tst_name] = {
+ "name": tst_data[u"name"]
+ }
+ tbl_dict[tst_name][col[u"title"]] = {
+ u"mean": tst_data[u"mean"],
+ u"stdev": tst_data[u"stdev"]
+ }
+
+ if not tbl_dict:
+ logging.warning(f"No data for table {table.get(u'title', u'')}!")
+ return