summaryrefslogtreecommitdiffstats
path: root/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report
diff options
context:
space:
mode:
Diffstat (limited to 'testsuites/vstf/vstf_scripts/vstf/controller/reporters/report')
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/__init__.py10
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/candy_generator.py138
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/data_factory.py441
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/__init__.py9
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/html_base.py43
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/htmlcreator.py84
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/__init__.py9
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/element.py785
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/pdfcreator.py127
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/pdftemplate.py114
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/story.py186
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/styles.py206
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/__init__.py8
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/html_provider.py45
-rw-r--r--testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/pdf_provider.py49
15 files changed, 2254 insertions, 0 deletions
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/__init__.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/__init__.py
new file mode 100644
index 00000000..547db686
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/__init__.py
@@ -0,0 +1,10 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/candy_generator.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/candy_generator.py
new file mode 100644
index 00000000..ea296550
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/candy_generator.py
@@ -0,0 +1,138 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+from vstf.controller.settings.template_settings import TemplateSettings
+from vstf.controller.reporters.report.data_factory import TaskData
+from vstf.controller.database.dbinterface import DbManage
+import vstf.common.candy_text as candy
+import logging
+LOG = logging.getLogger(__name__)
+
+
+class CandyGenerator(object):
+ def __init__(self, task):
+ self._task = task
+
+ def create(self, scenario):
+ context = {}
+
+ sn = 1
+ chapterid = 1
+ name = candy.tuple2text(sn, candy.chapter, chapterid)
+ context[name] = self.create_env()
+
+ sn += 1
+ chapterid += 1
+ name = candy.tuple2text(sn, candy.chapter, chapterid)
+ context[name] = self.create_scenario(scenario)
+
+ template = TemplateSettings()
+ template.set_context(context)
+ LOG.info(template.settings)
+
+ def create_all(self):
+ context = {}
+
+ sn = 1
+ chapterid = 1
+ name = candy.tuple2text(sn, candy.chapter, chapterid)
+ context[name] = self.create_env()
+
+ scenarios = self._task.common.get_scenariolist()
+ for scenario in scenarios:
+ sn += 1
+ chapterid += 1
+ name = candy.tuple2text(sn, candy.chapter, chapterid)
+ context[name] = self.create_scenario(scenario)
+
+ template = TemplateSettings()
+ template.set_context(context)
+ LOG.info(template.settings)
+
+ def create_env(self):
+ env = {
+ "01##title#1": ["System Environment"],
+ "02##table#2": self._task.common.get_systeminfo()
+ }
+ return env
+
+ def create_scenario(self, scenario):
+ scenario_chapter = {
+ "01##title#1": ["Scenario Result"]
+ }
+ scenario_data = getattr(self._task, scenario)
+ test_list = scenario_data.get_testlist()
+ sectionid = 0
+ sn = 1
+ for test in test_list:
+ sn += 1
+ sectionid += 1
+ name = candy.tuple2text(sn, candy.section, sectionid)
+ testid = test.TestID
+ case = test.CaseTag.decode()
+ ttype = test.Type.decode()
+
+ params_info = [
+ " Case: " + case,
+ " Test tool: " + test.Tools.decode(),
+ " vSwitch: " + test.Switch.decode(),
+ " Protocol: " + test.Protocol.decode(),
+ " Type: " + ttype
+ ]
+ if ttype in ["frameloss", "throughput"]:
+ draw = {
+ "style": 1,
+ "node": candy.plot,
+ "data": scenario_data.get_framerate_chartdata(case, ttype)
+ }
+ table = scenario_data.get_ratedata(testid, ttype)
+ else:
+ draw = {
+ "style": 1,
+ "node": candy.chart,
+ "data": scenario_data.get_latency_bardata(case)
+ }
+ table = scenario_data.get_latency_tabledata(case)
+ test_section = self.create_test(sectionid, params_info, table, draw)
+ scenario_chapter[name] = test_section
+
+ return scenario_chapter
+
+ def create_test(self, section, info, table, draw):
+ """
+
+ :rtype : dict
+ """
+ sn = 7
+ draw_name = candy.tuple2text(sn, draw["node"], draw["style"])
+ case_section = {
+ "01##title#2": ["Test ID: %s" % section],
+ "02##paragraph#2": ["Parameter"],
+ "03##paragraph#3": info,
+ "04##paragraph#2": ["Result"],
+ "05##table#2": table,
+ "06##space#2": 2,
+ draw_name: draw["data"]
+ }
+ return case_section
+
+
+def main():
+ from vstf.common.log import setup_logging
+ setup_logging(level=logging.DEBUG, log_file="/var/log/vstf/vstf-candy.log", clevel=logging.INFO)
+
+ dbase = DbManage()
+ taskid = dbase.get_last_taskid()
+ task = TaskData(taskid, dbase)
+ creator = CandyGenerator(task)
+
+ creator.create("Tn")
+if __name__ == '__main__':
+ main()
+
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/data_factory.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/data_factory.py
new file mode 100644
index 00000000..f9fc69d9
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/data_factory.py
@@ -0,0 +1,441 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+from vstf.controller.database.dbinterface import DbManage
+import vstf.common.constants as cst
+
+
+class DataProvider(object):
+ def __init__(self, taskid, dbase):
+ self._dbase = dbase
+ self._taskid = taskid
+
+
+class CommonData(DataProvider):
+ def get_taskname(self):
+ return self._dbase.query_taskname(self._taskid)
+
+ def get_systeminfo(self):
+ systable = [
+ ['Host', 'Server', 'CPU', 'MEM', 'NIC', 'OS'],
+ ]
+ query = self._dbase.query_task_host_list(self._taskid)
+ query = map(lambda x: list(x), query)
+ # rows = len(query)
+ # cols = len(zip(*query))
+ # for i in range(rows):
+ # for j in range(cols):
+ # query[i][j] = query[i][j].replace('\",','\"\n')
+ systable += query
+ systable = map(lambda x: list(x), zip(*systable))
+ return systable
+
+ def get_introduct_tabledata(self):
+ result = [
+ ["Type", "Case", "Name", "Direction", "Configure"]
+ ]
+ query = self._dbase.query_caseinfo()
+ result += map(lambda x: list(x), query)
+ return result
+
+ def get_scenariolist(self):
+ query = self._dbase.query_scenariolist(self._taskid)
+ result = map(lambda x: list(x), zip(*query))
+ if result:
+ return result[0]
+ else:
+ return result
+
+ def is_scenario_start(self):
+ scenarioList = self.get_scenariolist()
+ print "scenarioList: ", scenarioList
+ if scenarioList:
+ return True
+ return False
+
+ def get_casename(self, case):
+ return self._dbase.query_casename(case)
+
+ def get_casefigure(self, case, tools):
+ return self._dbase.query_casefigure(case, tools)
+
+
+class ScenarioData(DataProvider):
+ def __init__(self, taskid, dbase, scenario):
+ print "ScenarioData in"
+ DataProvider.__init__(self, taskid, dbase)
+ self._scenario = scenario
+
+ def get_test_tools(self, case):
+ query = self._dbase.query_casetools(self._taskid, case)
+ result = map(lambda x: list(x), query)
+ if result:
+ return result[0][0]
+ else:
+ return result
+
+ def get_caselist(self):
+ query = self._dbase.query_caselist(self._taskid, self._scenario)
+ result = map(lambda x: list(x), zip(*query))
+ if result:
+ return result[0]
+ else:
+ return result
+
+ def get_testlist(self):
+ query = self._dbase.query_testlist(self._taskid, self._scenario)
+ result = []
+ for item in query:
+ result.append(item.__dict__)
+ return query
+
+ def is_provider_start(self, case, provider):
+ count = self._dbase.query_case_provider_count(self._taskid, case, provider)
+ if count:
+ return True
+ return False
+
+ def is_type_provider_start(self, case, provider, ptype):
+ count = self._dbase.query_case_type_provider_count(self._taskid, case, provider, ptype)
+ if count:
+ return True
+ return False
+
+ def is_type_start(self, case, ptype):
+ count = self._dbase.query_case_type_count(self._taskid, case, ptype)
+ if count:
+ return True
+ return False
+
+ def is_throughput_start(self, case):
+ test_type = "throughput"
+ return self.is_type_start(case, test_type)
+
+ def is_frameloss_start(self, case):
+ test_type = "frameloss"
+ return self.is_type_start(case, test_type)
+
+ def is_latency_start(self, case):
+ test_type = "latency"
+ return self.is_type_start(case, test_type)
+
+ def get_summary_throughput_data(self, case, provider):
+ test_type = "throughput"
+ return self.get_summary_tabledata(case, provider, test_type)
+
+ def get_summary_frameLoss_data(self, case, provider):
+ test_type = "frameloss"
+ return self.get_summary_tabledata(case, provider, test_type)
+
+ def get_summary_tabledata(self, case, provider, test_type, table_type='pdf'):
+ table_head = []
+ table_body = []
+ type_title = {
+ "frameloss": "Load",
+ "throughput": "Load"
+ }
+ tools = self.get_test_tools(case)
+ if "spirent" in tools:
+ table_body = self._dbase.query_summary_table(self._taskid, case, provider, test_type)
+ if 'pdf' == table_type:
+ table_head = [
+ ["FrameSize (byte)", test_type, "", "", "", "Latency(uSec)", "", ""],
+ ["", " Mpps ", " " + type_title[test_type] + " (%) ", "CPU Used (%)", " Mpps/Ghz ",
+ " Min ", " Max ", " Avg "]
+ ]
+ else:
+ table_head = [
+ ["FrameSize (byte)", " Mpps ", " " + type_title[test_type] + " (%) ", "CPU Used (%)",
+ " Mpps/Ghz ", "MinLatency(uSec)", "MaxLatency(uSec)", "AvgLatency(uSec)"],
+ ]
+ else:
+ table_body = self._dbase.query_summary_simpletable(self._taskid, case, provider, test_type)
+ if 'pdf' == table_type:
+ table_head = [
+ ["FrameSize (byte)", test_type, "", "", "", "Latency(uSec)"],
+ ["", " Mpps ", " " + type_title[test_type] + " (%)", "CPU Used (%)", " Mpps/Ghz ",
+ " Avg "]
+ ]
+ else:
+ table_head = [
+ ["FrameSize (byte)", " Mpps ", " " + type_title[test_type] + " (%) ", "CPU Used (%)",
+ " Mpps/Ghz ", "AvgLatency(uSec)"],
+ ]
+ return table_head + table_body
+
+ def get_ratedata(self, testid, test_type):
+ table_head = [
+ ["FrameSize (bytes)", "Bandwidth(Mpps)", "Load (%)", "CPU Usage(%)", "Mpps/Ghz", "AvgLatency(uSec)"],
+ ]
+ query = self._dbase.query_testdata(testid, test_type)
+ table_body = []
+ for item in query:
+ table_body.append([item.AvgFrameSize, item.Bandwidth, item.OfferedLoad, item.CPU, item.MppspGhz,
+ item.AverageLatency])
+ result = []
+ if table_body:
+ result = table_head + table_body
+ return result
+
+ def get_tabledata(self, case, test_type, item):
+ type_dict = {
+ "FrameSize": "FrameSize (byte)",
+ "fastlink": "fastlink",
+ "l2switch": "l2switch",
+ "rdp": "kernel rdp",
+ None: "ovs",
+ "line": "line speed"
+ }
+ item_dict = {
+ "Percent": " ",
+ "Mpps": " ",
+ "Avg": " ",
+ }
+ table = []
+ line_speed = 20.0 if case in ["Tn-2v", "Tn-2"] else 10.0
+
+ for provider in cst.PROVIDERS:
+ if self.is_provider_start(case, provider):
+ if item == 'Percent':
+ query = self._dbase.query_load(self._taskid, case, provider, test_type)
+ elif item == 'Mpps':
+ query = self._dbase.query_bandwidth(self._taskid, case, provider, test_type)
+ else:
+ query = self._dbase.query_avglatency(self._taskid, case, provider, test_type)
+ query = map(lambda x: list(x), zip(*query))
+ if query:
+ table_head = [[type_dict["FrameSize"]] + map(lambda x: " %4d " % (x), query[0])]
+ if item == "Avg":
+ data = map(lambda x: item_dict[item] + "%.1f" % x + item_dict[item], query[1])
+ else:
+ data = map(lambda x: item_dict[item] + "%.2f" % x + item_dict[item], query[1])
+ if item == "Mpps":
+ line_table = map(lambda x: "%.2f" % (line_speed * 1000 / (8 * (x + 20))), query[0])
+ table.append([type_dict[provider]] + data)
+ if table:
+ if item == "Mpps":
+ table.append([type_dict["line"]] + line_table)
+ table = table_head + table
+ return table
+
+ def get_frameloss_tabledata(self, case, test_type):
+ item = "Percent"
+ table = self.get_tabledata(case, test_type, item)
+ return table
+
+ def get_frameloss_chartdata(self, case, test_type):
+ result = self.get_frameloss_tabledata(case, test_type)
+ result = map(list, zip(*result))
+ return result
+
+ def get_framerate_tabledata(self, case, test_type):
+ item = "Mpps"
+ table = self.get_tabledata(case, test_type, item)
+ return table
+
+ def get_framerate_chartdata(self, case, test_type):
+ result = self.get_framerate_tabledata(case, test_type)
+ result = map(list, zip(*result))
+ return result
+
+ def get_latency_tabledata(self, case):
+ test_type = "latency"
+ item = "Avg"
+ table = self.get_tabledata(case, test_type, item)
+ return table
+
+ def get_latency_chartdata(self, case):
+ result = self.get_latency_tabledata(case)
+ result = map(list, zip(*result))
+ return result
+
+ def get_latency_bardata(self, case):
+ table_data = self.get_latency_tabledata(case)
+ result = []
+ if table_data:
+ ytitle = "Average Latency (uSec)"
+ category_names = map(lambda x: "FS:%4d" % int(float(x)) + "LOAD:50", table_data[0][1:])
+ bar_ = map(lambda x: x[0], table_data[1:])
+ data = map(lambda x: x[1:], table_data[1:])
+ result = [ytitle, category_names, bar_, data]
+ return result
+
+ def get_bardata(self, case, provider, test_type):
+ if test_type == "latency":
+ query = self._dbase.query_avglatency(self._taskid, case, provider, test_type)
+ item = "Avg"
+ else:
+ query = self._dbase.query_load(self._taskid, case, provider, test_type)
+ item = "Percent"
+
+ title_dict = {
+ "Avg": "Latency (uSec)",
+ "Percent": test_type + " (%)"
+ }
+ name_dict = {
+ "Avg": " LOAD:50",
+ "Percent": " OF:100 "
+ }
+ color_dict = {
+ "Avg": "latency",
+ "Percent": "loss"
+ }
+ ytitle = title_dict[item]
+ query = map(lambda x: list(x), zip(*query))
+ result = []
+ if query:
+ category_names = map(lambda x: "FS:%4d" % x + name_dict[item], query[0])
+ data = query[1:]
+ bar_ = [color_dict[item]]
+ result = [ytitle, category_names, bar_, data]
+ return result
+
+
+class TaskData(object):
+ def __init__(self, taskid, dbase):
+ self.__common = CommonData(taskid, dbase)
+ scenario_list = self.__common.get_scenariolist()
+ scenario_dic = {}
+ for scenario in scenario_list:
+ scenario_dic[scenario] = ScenarioData(taskid, dbase, scenario)
+ self.__dict__.update(scenario_dic)
+
+ @property
+ def common(self):
+ return self.__common
+
+
+class HistoryData(DataProvider):
+ def get_data(self, task_list, case, provider, ttype, item):
+ """
+ @provider in ["fastlink", "rdp", "l2switch", ""]
+ @ttype in ["throughput", "frameloss", "latency"]
+ @item in ["avg", "ratep", "load"]
+ """
+ table = []
+ table_head = []
+ datas = []
+ sizes = []
+ for taskid in task_list:
+ if item == 'ratep':
+ query = self._dbase.query_bandwidth(taskid, case, provider, ttype)
+ else:
+ query = self._dbase.query_avglatency(taskid, case, provider, ttype)
+
+ if query:
+ data = {}
+ for size, value in query:
+ data[size] = value
+ sizes.extend(data.keys())
+ sizes = {}.fromkeys(sizes).keys()
+ sizes.sort()
+ datas.append({taskid: data})
+
+ result = []
+ for data in datas:
+ print data
+ taskid = data.keys()[0]
+ data_th = self._dbase.query_taskdate(taskid)
+ testdata = data[taskid]
+ item = [data_th]
+ for size in sizes:
+ item.append(str(testdata.get(size, '')))
+ result.append(item)
+
+ if result:
+ head_th = "FrameSize (byte)"
+ table_head = [[head_th] + map(lambda x: " %4d " % (x), sizes)]
+ table = table_head + result
+
+ return table
+
+ def get_tasklist(self, count=5):
+ task_list = []
+ query = self._dbase.query_tasklist()
+ if query:
+ for item in query:
+ if item.TaskID <= self._taskid:
+ task_list.append(item.TaskID)
+
+ task_list = task_list[-count:]
+ return task_list
+
+ def get_history_info(self, case):
+ provider_dict = {"fastlink": "Fast Link ", "l2switch": "L2Switch ", "rdp": "Kernel RDP "}
+ ttype_dict = {
+ "throughput": "Throughput Testing ",
+ "frameloss": "Frame Loss Testing ",
+ "latency": "Latency Testing "
+ }
+
+ items_dict = {
+ "ratep": "RX Frame Rate(Mpps) ",
+ "avg": "Average Latency (uSec) "
+ }
+
+ task_list = self.get_tasklist()
+ result = []
+
+ for ttype in cst.TTYPES:
+ content = {}
+ if ttype == "latency":
+ item = "avg"
+ else:
+ item = "ratep"
+
+ for provider in cst.PROVIDERS:
+ table_data = self.get_data(task_list, case, provider, ttype, item)
+ if table_data:
+ data = {
+ "title": provider_dict[provider] + items_dict[item],
+ "data": table_data
+ }
+ content["title"] = ttype_dict[ttype]
+ content.setdefault("data", [])
+ content["data"].append(data)
+ if content:
+ result.append(content)
+ print result
+ return result
+
+
+def unit_test():
+ dbase = DbManage()
+ taskid = dbase.get_last_taskid()
+ hdata = HistoryData(taskid, dbase)
+ task_list = hdata.get_tasklist()
+
+ cdata = CommonData(taskid, dbase)
+ scenario_list = cdata.get_scenariolist()
+ print scenario_list
+
+ scenario = "Tn"
+ sdata = ScenarioData(taskid, dbase, scenario)
+
+ case_list = sdata.get_caselist()
+ print case_list
+
+ case = "Tn-1"
+
+ ttypes = ["throughput", "frameloss"]
+ items = ["ratep", "load"]
+
+ for provider in cst.PROVIDERS:
+ for ttype in ttypes:
+ for item in items:
+ print provider
+ print ttype
+ print item
+ print hdata.get_data(task_list, case, provider, ttype, item)
+
+ hdata.get_history_info(case)
+
+
+if __name__ == '__main__':
+ unit_test()
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/__init__.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/__init__.py
new file mode 100644
index 00000000..df7d24d0
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/__init__.py
@@ -0,0 +1,9 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/html_base.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/html_base.py
new file mode 100644
index 00000000..5769da79
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/html_base.py
@@ -0,0 +1,43 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+
+import os
+import vstf.common.pyhtml as pyhtm
+
+
+class HtmlBase(object):
+ def __init__(self, provider):
+ self._page = pyhtm.PyHtml('Html Text')
+ self._provider = provider
+
+ def save(self, ofile):
+ if ofile:
+ os.system('rm -rf %s' % ofile)
+ self._page.output(ofile)
+
+ def as_string(self):
+ return self._page.as_string()
+
+ def add_table(self, data):
+ if data and zip(*data):
+ self._page.add_table(data)
+
+ def add_style(self):
+ style = self._provider.get_style
+ self._page.add_style(style)
+
+ def create(self, ofile='text.html'):
+ self.add_style()
+ self.create_story()
+ self.save(ofile)
+ return self.as_string()
+
+ def create_story(self):
+ raise NotImplementedError("abstract HtmlBase")
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/htmlcreator.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/htmlcreator.py
new file mode 100644
index 00000000..695ea37f
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/html/htmlcreator.py
@@ -0,0 +1,84 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+
+import logging
+
+import vstf.common.candy_text as candy
+from vstf.controller.reporters.report.provider.html_provider import HtmlProvider
+from vstf.controller.settings.template_settings import TemplateSettings
+from vstf.controller.settings.html_settings import HtmlSettings
+from vstf.controller.reporters.report.html.html_base import HtmlBase, pyhtm
+
+LOG = logging.getLogger(__name__)
+
+
+class HtmlCreator(HtmlBase):
+ def create_story(self):
+ self.add_context()
+
+ def add_context(self):
+ context = self._provider.get_context
+ self._raw_context(context)
+
+ def _raw_context(self, context, ci=0, si=0, ui=0, level=-1):
+ _story = []
+ for key, value in sorted(context.items()):
+ LOG.info(key)
+ LOG.info(value)
+ _sn, _node, _style = candy.text2tuple(key)
+ if _node in candy.dom:
+ if _node == candy.chapter:
+ ci = _style
+ elif _node == candy.section:
+ si = _style
+ else:
+ ui = _style
+ self._raw_context(value, ci, si, ui, level + 1)
+
+ else:
+ LOG.info("node: %s %s" % (_node, candy.title))
+ if _node == candy.title:
+ assert value
+ if level in range(len(candy.dom)):
+ if level == 0:
+ value[0] = "Chapter %s %s" % (ci, value[0])
+ for title in value:
+ self._page << pyhtm.H2(title)
+ elif level == 1:
+ value[0] = "%s.%s %s" % (ci, si, value[0])
+ for title in value:
+ self._page << pyhtm.H3(title)
+ else:
+ value[0] = "%s.%s.%s %s" % (ci, si, ui, value[0])
+ for title in value:
+ self._page << pyhtm.H3(title)
+
+ elif _node == candy.table:
+ self.add_table(value)
+ elif _node == candy.paragraph:
+ for para in value:
+ para = pyhtm.space(2) + para
+ self._page << pyhtm.P(para)
+
+
+def unit_test():
+ from vstf.common.log import setup_logging
+ setup_logging(level=logging.DEBUG, log_file="/var/log/html-creator.log", clevel=logging.INFO)
+
+ out_file = "vstf_report.html"
+
+ info = TemplateSettings()
+ html_settings = HtmlSettings()
+ provider = HtmlProvider(info.settings, html_settings.settings)
+ reporter = HtmlCreator(provider)
+ reporter.create(out_file)
+
+if __name__ == '__main__':
+ unit_test()
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/__init__.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/__init__.py
new file mode 100644
index 00000000..df7d24d0
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/__init__.py
@@ -0,0 +1,9 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/element.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/element.py
new file mode 100644
index 00000000..ef8b54df
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/element.py
@@ -0,0 +1,785 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+
+__doc__ = """
+it contains the base element for pdf
+eImage is used to draw picture on the pdf document
+eDataTable is used to draw table on the pdf document
+eGraphicsTable is used to draw plot on the pdf document
+eParagraph is used to draw text on the pdf document
+"""
+from reportlab.platypus import Image, Table
+from reportlab.graphics.shapes import Drawing
+from reportlab.graphics.charts.lineplots import LinePlot
+from reportlab.graphics.charts.linecharts import HorizontalLineChart
+from reportlab.platypus.paragraph import Paragraph
+from reportlab.graphics.widgets.markers import makeMarker
+from reportlab.graphics.charts.legends import Legend
+from reportlab.graphics.charts.textlabels import Label
+from reportlab.graphics.charts.axes import XValueAxis
+from reportlab.graphics.shapes import Group
+from reportlab.graphics.charts.barcharts import VerticalBarChart
+from vstf.controller.reporters.report.pdf.styles import *
+
+
+class eImage(Image):
+ """ an image(digital picture)which contains the function of auto zoom picture """
+
+ def __init__(self, filename, width=None, height=None, kind='direct', mask="auto", lazy=1, hAlign='CENTRE',
+ vAlign='BOTTOM'):
+ Image.__init__(self, filename, None, None, kind, mask, lazy)
+ print height, width
+ print self.drawHeight, self.drawWidth
+ if self.drawWidth * height > self.drawHeight * width:
+ self.drawHeight = width * self.drawHeight / self.drawWidth
+ self.drawWidth = width
+ else:
+ self.drawWidth = height * self.drawWidth / self.drawHeight
+ self.drawHeight = height
+ self.hAlign = hAlign
+ self.vAlign = vAlign
+ print self.drawHeight, self.drawWidth
+
+
+class eTable(object):
+ """ an abstract table class, which is contains the base functions to create table """
+
+ def __init__(self, data, style=TableStyle(name="default")):
+ self._tablestyle = style
+ self._table = []
+ self._spin = False
+ self._colWidths = None
+ self._data = self.analysisData(data)
+ if self._data:
+ self.create()
+
+ def analysisData(self, data):
+ raise NotImplementedError("abstract eTable")
+
+ def create(self):
+ self._table = Table(self._data, style=self._style, splitByRow=1)
+ self._table.hAlign = self._tablestyle.table_hAlign
+ self._table.vAlign = self._tablestyle.table_vAlign
+ self._table.colWidths = self._tablestyle.table_colWidths
+ if self._spin or self._colWidths:
+ self._table.colWidths = self._colWidths
+ self._table.rowHeights = self._tablestyle.table_rowHeights
+
+ @property
+ def table(self):
+ return self._table
+
+
+class eCommonTable(eTable):
+ def analysisData(self, data):
+ self._style = [
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
+ ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
+ ('BOX', (0, 0), (-1, -1), 1.2, colors.black)
+ ]
+ return data
+
+
+class eConfigTable(eTable):
+ def analysisData(self, data):
+ self._style = [
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
+ ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
+ ('BOX', (0, 0), (-1, -1), 1, colors.black),
+ ('SPAN', (2, 0), (3, 0)),
+ ('SPAN', (2, 1), (3, 1)),
+ ('SPAN', (2, 8), (3, 8)),
+ ('SPAN', (2, 9), (3, 9)),
+ ('SPAN', (2, 10), (3, 10)),
+ ('SPAN', (0, 0), (0, 7)),
+ ('SPAN', (0, 8), (0, 10)),
+ ('SPAN', (0, 11), (0, 19)),
+ ('SPAN', (1, 2), (1, 6)),
+ ('SPAN', (1, 12), (1, 13)),
+ ('SPAN', (1, 14), (1, 16)),
+ ('SPAN', (1, 17), (1, 19)),
+ ('SPAN', (2, 3), (2, 6))
+ ]
+ return data
+
+
+class eSummaryTable(eTable):
+ def analysisData(self, data):
+ self._style = [
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
+ ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
+ ('BOX', (0, 0), (-1, -1), 1, colors.black),
+ ('SPAN', (0, 0), (0, 1)),
+ ('SPAN', (1, 0), (4, 0)),
+ ('SPAN', (5, 0), (-1, 0))
+ ]
+ return data
+
+
+class eGitInfoTable(eTable):
+ def analysisData(self, data):
+ self._style = [
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
+ ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
+ ('BOX', (0, 0), (-1, -1), 1, colors.black),
+ ('SPAN', (0, 0), (0, 2)),
+ ('SPAN', (0, 3), (0, 5)),
+ ('SPAN', (0, 6), (0, 8))
+ ]
+ return data
+
+
+class eScenarioTable(eTable):
+ def analysisData(self, data):
+ self._style = [
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
+ ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
+ ('BOX', (0, 0), (-1, -1), 1, colors.black),
+ ('ALIGN', (2, 1), (-1, -1), 'LEFT'),
+ ('SPAN', (0, 1), (0, 6)),
+ ('SPAN', (0, 7), (0, 12)),
+ ('SPAN', (0, 13), (0, 16)),
+ ('SPAN', (0, 17), (0, 20))
+ ]
+ return data
+
+
+class eOptionsTable(eTable):
+ def analysisData(self, data):
+ self._style = [
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
+ ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
+ ('BOX', (0, 0), (-1, -1), 1, colors.black),
+ ('SPAN', (2, 0), (4, 0)),
+ ('SPAN', (2, 1), (4, 1)),
+ ('SPAN', (0, 0), (0, -1)),
+ ('SPAN', (1, 2), (1, 16)),
+ ('SPAN', (1, 17), (1, 19)),
+ ('SPAN', (1, 20), (1, 22)),
+ ('SPAN', (1, 23), (1, 24)),
+ ('SPAN', (2, 2), (2, 4)),
+ ('SPAN', (2, 5), (2, 12)),
+ ('SPAN', (2, 13), (2, 16)),
+ ('SPAN', (2, 17), (2, 19)),
+ ('SPAN', (2, 20), (2, 22)),
+ ('SPAN', (2, 23), (2, 24))
+ ]
+ return data
+
+
+class eProfileTable(eTable):
+ def analysisData(self, data):
+ self._style = [
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
+ ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
+ ('BOX', (0, 0), (-1, -1), 1, colors.black),
+ ('SPAN', (0, 1), (0, -1)),
+ ('SPAN', (1, 0), (2, 0)),
+ ]
+ return data
+
+
+class eDataTable(eTable):
+ def analysisData(self, data):
+ result = data
+ self._style = [
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
+ ('LEADING', (0, 0), (-1, -1), 18),
+ ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
+ ('BOX', (0, 0), (-1, -1), 1, colors.black),
+ ('LINEBEFORE', (1, 0), (1, -1), 0.8, colors.black),
+ # ('LINEBEFORE', (3, 0), (3, -1), 1, colors.black),
+ # ('LINEBEFORE', (5, 0), (5, -1), 1, colors.black),
+ ('LINEBELOW', (0, 0), (-1, 0), 0.8, colors.black),
+ # ('SPAN', (0, 0), (0, 1)),
+ # ('SPAN', (1, 0), (2, 0)),
+ # ('SPAN', (3, 0), (4, 0))
+ ]
+ if self._spin is True:
+ print "start spin"
+ result = map(list, zip(*result))
+ style = []
+ for value in self._style:
+ value = list(value)
+ value[1] = (value[1][1], value[1][0])
+ value[2] = (value[2][1], value[2][0])
+ if value[0] == 'LINEBELOW':
+ value[0] = 'LINEAFTER'
+ elif value[0] == 'LINEBEFORE':
+ value[0] = 'LINEABOVE'
+ value = tuple(value)
+ style.append(value)
+ self._style = style
+ return result
+
+
+class eGraphicsTable(eTable):
+ def analysisData(self, data):
+ self._style = [
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE')
+ ]
+ return data
+
+
+class noScaleXValueAxis(XValueAxis):
+ def __init__(self):
+ XValueAxis.__init__(self)
+
+ def makeTickLabels(self):
+ g = Group()
+ if not self.visibleLabels: return g
+
+ f = self._labelTextFormat # perhaps someone already set it
+ if f is None:
+ f = self.labelTextFormat or (self._allIntTicks() and '%.0f' or str)
+ elif f is str and self._allIntTicks():
+ f = '%.0f'
+ elif hasattr(f, 'calcPlaces'):
+ f.calcPlaces(self._tickValues)
+ post = self.labelTextPostFormat
+ scl = self.labelTextScale
+ pos = [self._x, self._y]
+ d = self._dataIndex
+ pos[1 - d] = self._labelAxisPos()
+ labels = self.labels
+ if self.skipEndL != 'none':
+ if self.isXAxis:
+ sk = self._x
+ else:
+ sk = self._y
+ if self.skipEndL == 'start':
+ sk = [sk]
+ else:
+ sk = [sk, sk + self._length]
+ if self.skipEndL == 'end':
+ del sk[0]
+ else:
+ sk = []
+
+ nticks = len(self._tickValues)
+ nticks1 = nticks - 1
+ for i, tick in enumerate(self._tickValues):
+ label = i - nticks
+ if label in labels:
+ label = labels[label]
+ else:
+ label = labels[i]
+ if f and label.visible:
+ v = self.scale(i)
+ if sk:
+ for skv in sk:
+ if abs(skv - v) < 1e-6:
+ v = None
+ break
+ if v is not None:
+ if scl is not None:
+ t = tick * scl
+ else:
+ t = tick
+ if isinstance(f, str):
+ txt = f % t
+ elif isSeq(f):
+ # it's a list, use as many items as we get
+ if i < len(f):
+ txt = f[i]
+ else:
+ txt = ''
+ elif hasattr(f, '__call__'):
+ if isinstance(f, TickLabeller):
+ txt = f(self, t)
+ else:
+ txt = f(t)
+ else:
+ raise ValueError('Invalid labelTextFormat %s' % f)
+ if post: txt = post % txt
+ pos[d] = v
+ label.setOrigin(*pos)
+ label.setText(txt)
+
+ # special property to ensure a label doesn't project beyond the bounds of an x-axis
+ if self.keepTickLabelsInside:
+ if isinstance(self, XValueAxis): # not done yet for y axes
+ a_x = self._x
+ if not i: # first one
+ x0, y0, x1, y1 = label.getBounds()
+ if x0 < a_x:
+ label = label.clone(dx=label.dx + a_x - x0)
+ if i == nticks1: # final one
+ a_x1 = a_x + self._length
+ x0, y0, x1, y1 = label.getBounds()
+ if x1 > a_x1:
+ label = label.clone(dx=label.dx - x1 + a_x1)
+ g.add(label)
+
+ return g
+
+ def ___calcScaleFactor(self):
+ """Calculate the axis' scale factor.
+ This should be called only *after* the axis' range is set.
+ Returns a number.
+ """
+ self._scaleFactor = self._length / (len(self._tickValues) + 1)
+ return self._scaleFactor
+
+ def scale(self, value):
+ """Converts a numeric value to a plotarea position.
+ The chart first configures the axis, then asks it to
+ """
+ assert self._configured, "Axis cannot scale numbers before it is configured"
+ if value is None: value = 0
+ # this could be made more efficient by moving the definition of org and sf into the configuration
+ org = (self._x, self._y)[self._dataIndex]
+ sf = self._length / (len(self._tickValues) + 1)
+ if self.reverseDirection:
+ sf = -sf
+ org += self._length
+ return org + sf * (value + 1)
+
+
+class noScaleLinePlot(LinePlot):
+ def __init__(self):
+ LinePlot.__init__(self)
+ self.xValueAxis = noScaleXValueAxis()
+
+ def calcPositions(self):
+ """Works out where they go.
+
+ Sets an attribute _positions which is a list of
+ lists of (x, y) matching the data.
+ """
+ self._seriesCount = len(self.data)
+ self._rowLength = max(map(len, self.data))
+
+ self._positions = []
+ for rowNo in range(len(self.data)):
+ line = []
+ len_row = len(self.data[rowNo])
+ for colNo in range(len_row):
+ datum = self.data[rowNo][colNo] # x, y value
+ x = self.x + self.width / (len_row + 1) * (colNo + 1)
+ self.xValueAxis.labels[colNo].x = self.x + self.width / (len_row + 1) * (colNo + 1)
+ y = self.yValueAxis.scale(datum[1])
+ # print self.width, " ", x
+ line.append((x, y))
+ self._positions.append(line)
+
+
+# def _innerDrawLabel(self, rowNo, colNo, x, y):
+# return None
+class eLinePlot(object):
+ def __init__(self, data, style):
+ self._lpstyle = style
+ self._linename = data[0]
+ self._data = self.analysisData(data[1:])
+ if self._data:
+ self.create()
+
+ @property
+ def draw(self):
+ return self._draw
+
+ def analysisData(self, data):
+ columns = len(data)
+ # print data
+ data = map(list, zip(*data))
+ rows = len(data)
+
+ for i in range(rows):
+ for j in range(columns):
+ data[i][j] = float(data[i][j])
+ self._linename = self._linename[1:]
+ """
+ delcnt = 0
+ delrows = []
+ for i in range(columns):
+ delrows.append(0.0)
+ del_line = [self._linename[0]]
+ for i in range(rows):
+ for j in range(columns):
+ data[i][j] = float(data[i][j])
+ if data[i] == delrows:
+ delcnt += 1
+ del_line.append(self._linename[i])
+ for i in range(delcnt):
+ data.remove(delrows)
+ for name in del_line:
+ self._linename.remove(name)
+
+ rows = len(data)
+ """
+ # print rows
+ # print data
+ xvalueSteps = data[0]
+ xvalueMin = data[0][0]
+ xvalueMax = data[0][0]
+ yvalueMin = data[1][0]
+ yvalueMax = data[1][0]
+ yvalueSteps = []
+ result = []
+ for j in range(columns):
+ if xvalueMin > data[0][j]:
+ xvalueMin = data[0][j]
+ if xvalueMax < data[0][j]:
+ xvalueMax = data[0][j]
+
+ for i in range(rows - 1):
+ lst = []
+ for j in range(columns):
+ lst.append((data[0][j], data[i + 1][j]))
+ if yvalueMin > data[i + 1][j]:
+ yvalueMin = data[i + 1][j]
+ if yvalueMax < data[i + 1][j]:
+ yvalueMax = data[i + 1][j]
+ yvalueSteps.append(int(data[i + 1][j] * 2.5) / 2.5)
+ result.append(tuple(lst))
+ xvalueMin = int(xvalueMin) / 100 * 100
+ xvalueMax = int(xvalueMax) / 100 * 100 + 200
+ yvalueMin = int(yvalueMin) * 1.0 - 1
+ if yvalueMin < 0:
+ yvalueMin = 0.0
+ yvalueMax = int(yvalueMax) + 2.0
+ yvalueSteps.append(yvalueMin)
+ yvalueSteps.append(yvalueMax)
+ yvalueSteps = {}.fromkeys(yvalueSteps).keys()
+
+ self._xvalue = (xvalueMin, xvalueMax, xvalueSteps)
+ self._yvalue = (yvalueMin, yvalueMax, yvalueSteps)
+ print result
+ return result
+
+ def create(self):
+ lpw = self._lpstyle.width
+ lph = self._lpstyle.height
+ draw = Drawing(lpw, lph)
+ line_cnts = len(self._linename)
+ # lp = noScaleLinePlot()
+ lp = LinePlot()
+ lg_line = (line_cnts + 3) / 4
+ lp.x = self._lpstyle.left
+ lp.y = self._lpstyle.bottom
+
+ lp.height = lph - self._lpstyle.bottom * (lg_line + 1.5)
+ lp.width = lpw - lp.x * 2
+ lp.data = self._data
+ lp.joinedLines = 1
+ lp.strokeWidth = self._lpstyle.strokeWidth
+ line_cnts = len(self._data)
+ sytle_cnts = len(self._lpstyle.linestyle)
+ color_paris = []
+ for i in range(line_cnts):
+ styleIndex = i % sytle_cnts
+ lp.lines[i].strokeColor = self._lpstyle.linestyle[styleIndex][0]
+ lp.lines[i].symbol = makeMarker(self._lpstyle.linestyle[styleIndex][1])
+ lp.lines[i].strokeWidth = self._lpstyle.linestyle[styleIndex][2]
+ color_paris.append((self._lpstyle.linestyle[styleIndex][0], self._linename[i]))
+ # lp.lineLabels[i].strokeColor = self._lpstyle.linestyle[styleIndex][0]
+
+ lp.lineLabelFormat = self._lpstyle.format[0]
+
+ lp.strokeColor = self._lpstyle.strokeColor
+
+ lp.xValueAxis.valueMin, lp.xValueAxis.valueMax, lp.xValueAxis.valueSteps = self._xvalue
+ # valueMin, valueMax, xvalueSteps = self._xvalue
+ # lp.xValueAxis.valueStep = (lp.xValueAxis.valueMax - lp.xValueAxis.valueMin)/len(xvalueSteps)
+ # lp.xValueAxis.valueSteps = map(lambda x: str(x), xvalueSteps)
+
+ lp.yValueAxis.valueMin, lp.yValueAxis.valueMax, lp.yValueAxis.valueSteps = self._yvalue
+
+
+
+ # lp.xValueAxis.forceZero = 0
+ # lp.xValueAxis.avoidBoundFrac = 1
+ # lp.xValueAxis.tickDown = 3
+ # lp.xValueAxis.visibleGrid = 1
+ # lp.xValueAxis.categoryNames = '64 256 512 1400 1500 4096'.split(' ')
+
+ lp.xValueAxis.labelTextFormat = self._lpstyle.format[1]
+ lp.yValueAxis.labelTextFormat = self._lpstyle.format[2]
+
+ delsize = int(lp.xValueAxis.valueMax / 2000)
+ lp.xValueAxis.labels.fontSize = self._lpstyle.labelsfont
+ lp.xValueAxis.labels.angle = 25
+
+ lp.yValueAxis.labels.fontSize = self._lpstyle.labelsfont
+ lp.lineLabels.fontSize = self._lpstyle.labelsfont - delsize
+ draw.add(lp)
+
+ lg = Legend()
+ lg.colorNamePairs = color_paris
+ lg.fontName = 'Helvetica'
+ lg.fontSize = 7
+
+ lg.x = self._lpstyle.left * 3
+ lg.y = self._lpstyle.bottom * (1 + lg_line) + lp.height
+
+ lg.dxTextSpace = 5
+ lg.dy = 5
+ lg.dx = 20
+ lg.deltax = 60
+ lg.deltay = 0
+ lg.columnMaximum = 1
+ lg.alignment = 'right'
+ draw.add(lg)
+ self._draw = draw
+
+
+class eHorizontalLineChart(object):
+ def __init__(self, data, style):
+ self._lcstyle = style
+ if len(data) < 1:
+ return
+ self._linename = data[0]
+ self._data = self.analysisData(data[1:])
+ if self._data:
+ self.create()
+
+ @property
+ def draw(self):
+ return self._draw
+
+ def analysisData(self, data):
+ columns = len(data)
+ data = map(list, zip(*data))
+ self._catNames = data[0]
+ self._linename = self._linename[1:]
+ data = data[1:]
+ rows = len(data)
+
+ yvalueMin = float(data[0][0])
+ yvalueMax = float(data[0][0])
+ yvalueSteps = []
+ result = []
+
+ for rowNo in range(rows):
+ for columnNo in range(columns):
+ data[rowNo][columnNo] = float(data[rowNo][columnNo])
+ if yvalueMin > data[rowNo][columnNo]:
+ yvalueMin = data[rowNo][columnNo]
+ if yvalueMax < data[rowNo][columnNo]:
+ yvalueMax = data[rowNo][columnNo]
+ yvalueSteps.append(int(data[rowNo][columnNo] * 1.0) / 1.0)
+ result.append(tuple(data[rowNo]))
+
+ yvalueMin = int(yvalueMin) * 1.0 - 1
+ if yvalueMin < 0:
+ yvalueMin = 0.0
+ yvalueMax = int(yvalueMax) + 2.0
+ yvalueSteps.append(yvalueMin)
+ yvalueSteps.append(yvalueMax)
+ yvalueSteps = {}.fromkeys(yvalueSteps).keys()
+
+ self._value = (yvalueMin, yvalueMax, yvalueSteps)
+ print result
+ return result
+
+ def create(self):
+ dw = self._lcstyle.width
+ dh = self._lcstyle.height
+ draw = Drawing(dw, dh)
+
+ lc = HorizontalLineChart()
+ line_cnts = len(self._linename)
+
+ lg_line = (line_cnts + 3) / 4
+ lc.height = dh - self._lcstyle.bottom * (lg_line + 1.5)
+ lc.width = dw - lc.x * 2
+ lc.x = self._lcstyle.left
+ lc.y = self._lcstyle.bottom
+
+ lc.data = self._data
+
+ lc.strokeColor = self._lcstyle.strokeColor
+ lc.strokeWidth = self._lcstyle.strokeWidth
+ lc.useAbsolute = 1
+ lc.groupSpacing = lc.width * 2.0 / len(self._catNames)
+ lc.joinedLines = 1
+ lc.lineLabelFormat = self._lcstyle.format[0]
+
+ lc.valueAxis.valueMin, lc.valueAxis.valueMax, lc.valueAxis.valueSteps = self._value
+ lc.valueAxis.labelTextFormat = self._lcstyle.format[1]
+ lc.valueAxis.labels.fontSize = self._lcstyle.labelsfont
+
+ lc.categoryAxis.categoryNames = self._catNames
+ lc.categoryAxis.labels.boxAnchor = 'ne'
+ lc.categoryAxis.labels.dx = lc.width / 2.0 / len(self._catNames)
+ lc.categoryAxis.labels.dy = -6
+ lc.categoryAxis.labels.angle = 10
+ lc.categoryAxis.labels.fontSize = self._lcstyle.labelsfont
+ # lc.categoryAxis.visibleGrid = 1
+ # lc.categoryAxis.tickUp = 100
+ # lc.categoryAxis.tickDown = 50
+ # lc.categoryAxis.gridEnd = dh
+ sytle_cnts = len(self._lcstyle.linestyle)
+ color_paris = []
+ for i in range(line_cnts):
+ styleIndex = i % sytle_cnts
+ lc.lines[i].strokeColor = self._lcstyle.linestyle[styleIndex][0]
+ lc.lines[i].symbol = makeMarker(self._lcstyle.linestyle[styleIndex][1])
+ lc.lines[i].strokeWidth = self._lcstyle.linestyle[styleIndex][2]
+ color_paris.append((self._lcstyle.linestyle[styleIndex][0], self._linename[i]))
+
+ lc.lineLabels.fontSize = self._lcstyle.labelsfont - 2
+
+ draw.add(lc)
+
+ lg = Legend()
+ lg.colorNamePairs = color_paris
+ lg.fontName = 'Helvetica'
+ lg.fontSize = 7
+ # lg.x = dw /2
+ # lg.y = self._lcstyle.bottom *(1.5 + lg_line)
+
+ lg.x = self._lcstyle.left * 3
+ lg.y = self._lcstyle.bottom * (1 + lg_line) + lc.height
+
+ lg.dxTextSpace = 5
+ lg.dy = 5
+ lg.dx = 20
+ lg.deltax = 60
+ lg.deltay = 0
+ lg.columnMaximum = 1
+ lg.alignment = 'right'
+ draw.add(lg)
+ self._draw = draw
+
+
+class eBarChartColumn(object):
+ def __init__(self, data, style):
+ self._bcstyle = style
+ if len(data) < 4:
+ return
+ self._data = self.analysisData(data)
+ if self._data:
+ self.create()
+
+ @property
+ def draw(self):
+ return self._draw
+
+ def analysisData(self, data):
+ self._ytitle = data[0]
+ self._name = data[1]
+ self._bar = data[2]
+ bar_data = data[3]
+ result = []
+ for bar in bar_data:
+ bar = map(lambda x: float(x), bar)
+ result.append(tuple(bar))
+ return result
+
+ def create(self):
+ dw = self._bcstyle.width
+ dh = self._bcstyle.height
+ draw = Drawing(dw, dh)
+
+ bc = VerticalBarChart()
+ bar_cnt = len(self._bar)
+ lg_line = (bar_cnt + 3) / 4
+
+ bc.width = dw - self._bcstyle.left - self._bcstyle.right
+ bc.height = dh - self._bcstyle.top - self._bcstyle.bottom
+ if bar_cnt > 1:
+ bc.height -= lg_line * 15
+
+ bc.x = self._bcstyle.left
+ bc.y = self._bcstyle.bottom
+ color_paris = []
+ for i in range(bar_cnt):
+ bc.bars[i].fillColor = self._bcstyle.pillarstyle[self._bar[i]][0]
+ color_paris.append((self._bcstyle.pillarstyle[self._bar[i]][0], self._bar[i]))
+
+ bc.fillColor = self._bcstyle.background
+ bc.barLabels.fontName = 'Helvetica'
+ bc.barLabelFormat = self._bcstyle.pillarstyle[self._bar[0]][1]
+ bc.barLabels.fontSize = self._bcstyle.labelsfont
+ bc.barLabels.dy = self._bcstyle.labelsfont
+ bc.valueAxis.labels.fontName = 'Helvetica'
+ bc.valueAxis.labels.fontSize = self._bcstyle.labelsfont
+ bc.valueAxis.forceZero = 1
+ bc.valueAxis.valueMin = 0
+
+ bc.data = self._data
+ bc.barSpacing = self._bcstyle.barSpacing
+ bc.groupSpacing = self._bcstyle.groupSpacing / bar_cnt
+ bc.valueAxis.avoidBoundFrac = 1
+ bc.valueAxis.gridEnd = dw - self._bcstyle.right
+ bc.valueAxis.tickLeft = self._bcstyle.tick
+ bc.valueAxis.visibleGrid = 1
+ bc.categoryAxis.categoryNames = self._name
+ bc.categoryAxis.tickDown = self._bcstyle.tick
+ bc.categoryAxis.labels.fontName = 'Helvetica'
+ bc.categoryAxis.labels.fontSize = self._bcstyle.labelsfont
+ bc.categoryAxis.labels.dy = -27
+ bc.categoryAxis.labels.angle = -90
+ draw.add(bc)
+ lb = Label()
+ lb.fontName = 'Helvetica'
+ lb.fontSize = 7
+ lb.x = 12
+ lb.y = 80
+ lb.angle = 90
+ lb.textAnchor = 'middle'
+ lb.maxWidth = 100
+ lb.height = 20
+ lb._text = self._ytitle
+ draw.add(lb)
+ if bar_cnt > 1:
+ lg = Legend()
+ lg.colorNamePairs = color_paris
+ lg.fontName = 'Helvetica'
+ lg.fontSize = 7
+
+ lg.x = self._bcstyle.left + bc.width / (bar_cnt + 1)
+ lg.y = dh - self._bcstyle.top - lg_line * 5
+
+ lg.dxTextSpace = 5
+ lg.dy = 5
+ lg.dx = 25
+ lg.deltax = 80
+ lg.deltay = 0
+ lg.columnMaximum = 1
+ lg.alignment = 'right'
+ draw.add(lg)
+
+ self._draw = draw
+
+
+class eParagraph(object):
+ def __init__(self, data, style):
+ self._pstyle = style
+ self._data = self.analysisData(data)
+ self.create()
+
+ def analysisData(self, data):
+ result = ""
+ for dstr in data:
+ if self._pstyle.name == 'ps_body':
+ # dstr = "<i>" + dstr + "</i><br/>"
+ dstr = dstr + "<br/>"
+ else:
+ dstr = dstr + "<br/>"
+ result += dstr
+ return result
+
+ def create(self):
+ self._para = Paragraph(self._data, self._pstyle)
+
+ @property
+ def para(self):
+ return self._para
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/pdfcreator.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/pdfcreator.py
new file mode 100644
index 00000000..c33974ec
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/pdfcreator.py
@@ -0,0 +1,127 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+
+from vstf.controller.reporters.report.pdf.pdftemplate import PdfVswitch
+from vstf.controller.reporters.report.pdf.story import TitleStory, SpaceStory, ImageStory, TableStory, \
+ LinePlotStory, Story, TableOfContentsStory, PageBreakStory, ParagraphStory, BarChartStory
+import vstf.common.candy_text as candy
+from vstf.controller.reporters.report.provider.pdf_provider import PdfProvider
+from vstf.controller.settings.template_settings import TemplateSettings
+
+import os
+import logging
+
+LOG = logging.getLogger(__name__)
+
+
+class PdfCreator(object):
+ def __init__(self, provider):
+ self._provider = provider
+ self._story = []
+ self._pdf = None
+
+ def create_pdf(self):
+ theme = self._provider.get_theme
+ self._pdf = PdfVswitch(theme["title"],
+ theme["logo"],
+ theme["header"],
+ theme["footer"],
+ theme["note"],
+ theme["style"])
+
+ def save_pdf(self, ofile):
+ self._pdf.generate(self._story, ofile)
+
+ def add_coverpage(self):
+ story = Story()
+ story = PageBreakStory(story)
+ self._story += story.storylist
+
+ def add_contents(self):
+ if self._provider.ifcontents:
+ story = Story()
+ story = TableOfContentsStory(story)
+ self._story += story.storylist
+
+ def create_story(self):
+ self.add_coverpage()
+ self.add_contents()
+ self.add_context()
+
+ def create(self, ofile):
+ self.create_pdf()
+ self.create_story()
+ self.save_pdf(ofile)
+
+ def add_context(self):
+ context = self._provider.get_context
+ self._story += self._raw_context(context)
+
+ def _raw_context(self, context, ci=0, si=0, ui=0, level=-1):
+ _story = []
+ for key, value in sorted(context.items()):
+ LOG.info(key)
+ LOG.info(value)
+ _sn, _node, _style = candy.text2tuple(key)
+ if _node in candy.dom:
+ if _node == candy.chapter:
+ ci = _style
+ elif _node == candy.section:
+ si = _style
+ else:
+ ui = _style
+ _story += self._raw_context(value, ci, si, ui, level + 1)
+
+ else:
+ story = Story()
+ LOG.info("node: %s %s" % (_node, candy.title))
+ if _node == candy.title:
+ assert value
+ if level in range(len(candy.dom)):
+ if level == 0:
+ value[0] = "Chapter %s %s" % (ci, value[0])
+ story = PageBreakStory(story)
+ elif level == 1:
+ value[0] = "%s.%s %s" % (ci, si, value[0])
+ else:
+ value[0] = "%s.%s.%s %s" % (ci, si, ui, value[0])
+ LOG.info(value)
+ story = TitleStory(story, data=value, style=_style)
+ elif _node == candy.table:
+ story = TableStory(story, data=value, style=_style)
+ elif _node == candy.figure:
+ story = ImageStory(story, data=value, style=_style)
+ elif _node == candy.paragraph:
+ story = ParagraphStory(story, data=value, style=_style)
+ elif _node == candy.plot:
+ story = LinePlotStory(story, data=value, style=_style)
+ elif _node == candy.chart:
+ story = BarChartStory(story, data=value, style=_style)
+ elif _node == candy.space:
+ assert isinstance(value, int)
+ for i in range(value):
+ story = SpaceStory(story)
+ _story += story.storylist
+ return _story
+
+
+def main():
+ from vstf.common.log import setup_logging
+ setup_logging(level=logging.DEBUG, log_file="/var/log/pdf-creator.log", clevel=logging.INFO)
+
+ out_file = "vstf_report.pdf"
+
+ info = TemplateSettings()
+ provider = PdfProvider(info.settings)
+ reporter = PdfCreator(provider)
+ reporter.create(out_file)
+
+if __name__ == '__main__':
+ main()
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/pdftemplate.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/pdftemplate.py
new file mode 100644
index 00000000..69c65401
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/pdftemplate.py
@@ -0,0 +1,114 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import time
+
+from reportlab.platypus.doctemplate import SimpleDocTemplate
+from reportlab.platypus import PageBreak
+from vstf.controller.reporters.report.pdf.styles import TemplateStyle, ps_head_lv1, ps_head_lv2, ps_head_lv3
+import vstf.common.constants as cst
+
+
+class BaseDocTemplate(SimpleDocTemplate):
+ def __init__(self, filename, **kw):
+ self.allowSplitting = 0
+ SimpleDocTemplate.__init__(self, filename, **kw)
+
+ def afterFlowable(self, flowable):
+ """Registers TOC entries."""
+ if flowable.__class__.__name__ == 'Paragraph':
+ text = flowable.getPlainText()
+ style = flowable.style.name
+ if style == ps_head_lv1.name:
+ self.notify('TOCEntry', (0, text, self.page - 1))
+ elif style == ps_head_lv2.name:
+ self.notify('TOCEntry', (1, text, self.page - 1))
+ elif style == ps_head_lv3.name:
+ self.notify('TOCEntry', (2, text, self.page - 1))
+
+
+class PdfTemplate(object):
+ def __init__(self, title, logo, header, footer, note=[], style="default"):
+ self._style = TemplateStyle(name=style)
+ self._title = title
+ self._logo = logo[0]
+ #self._header = header[0]
+ self._footer = footer
+ self._note = note
+ info = " Generated on %s " % time.strftime(cst.TIME_FORMAT2, time.localtime())
+ self._note += [info]
+
+ def myFirstPage(self, canvas, doc):
+ raise NotImplementedError("abstract StoryDecorator")
+
+ def myLaterPages(self, canvas, doc):
+ raise NotImplementedError("abstract StoryDecorator")
+
+ def generate(self, story, output):
+ sizes = (self._style.page_wight, self._style.page_height)
+ doc = BaseDocTemplate(output, pagesize=sizes)
+ # doc.build(story, onFirstPage=self.myFirstPage, onLaterPages=self.myLaterPages)
+ doc.multiBuild(story, onFirstPage=self.myFirstPage, onLaterPages=self.myLaterPages)
+
+
+class PdfVswitch(PdfTemplate):
+ def myFirstPage(self, canvas, doc):
+ canvas.saveState()
+ title_lines = len(self._title)
+ line_size = [self._style.title_size] * title_lines
+ line_size.append(0)
+
+ canvas.drawImage(self._logo,
+ (self._style.page_wight - self._style.logo_width) / 2.0,
+ self._style.page_height / 2.0 + (1 + self._style.title_leading) * reduce(lambda x, y: x + y,
+ line_size),
+ self._style.logo_width,
+ self._style.logo_height
+ )
+ for i in range(title_lines):
+ canvas.setFont(self._style.title_font, line_size[i])
+ canvas.drawCentredString(self._style.page_wight / 2.0,
+ self._style.page_height / 2.0 + (1 + self._style.title_leading) * reduce(
+ lambda x, y: x + y, line_size[i + 1:]),
+ self._title[i]
+ )
+ size = self._style.body_size
+ canvas.setFont(self._style.body_font, size)
+ note_line = len(self._note)
+
+ for i in range(note_line):
+ print self._note[i]
+ canvas.drawCentredString(self._style.page_wight / 2.0,
+ self._style.page_height / 5.0 + (1 + self._style.body_leading) * size * (
+ note_line - i - 1),
+ self._note[i]
+ )
+ size = self._style.body_size - 2
+ canvas.setFont(self._style.body_font, size)
+ canvas.drawCentredString(self._style.page_wight / 2.0,
+ self._style.page_bottom / 2.0 + (1 + self._style.body_leading) * size,
+ self._footer[0])
+ canvas.restoreState()
+
+ def myLaterPages(self, canvas, doc):
+ canvas.saveState()
+ canvas.setLineWidth(self._style.line_width)
+ canvas.line(self._style.page_left,
+ self._style.page_height - self._style.page_top,
+ self._style.page_wight - self._style.page_right,
+ self._style.page_height - self._style.page_top
+ )
+ size = self._style.body_size - 2
+ canvas.setFont(self._style.body_font, size)
+ canvas.drawCentredString(self._style.page_wight / 2.0,
+ self._style.page_bottom - 24,
+ "%s%s Page %2d " % (self._footer[0], " " * 8, doc.page - 1)
+ )
+ canvas.restoreState()
+
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/story.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/story.py
new file mode 100644
index 00000000..940c20fb
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/story.py
@@ -0,0 +1,186 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+__doc__ = """
+Story Decorator contains ImageStory, HeaderStory, PageBreakStory,
+TableStory, LinePlotStory, TitleStory, ParagraphStory
+"""
+import sys
+import os
+from reportlab.platypus import PageBreak
+from reportlab.lib import colors
+from reportlab.platypus.tableofcontents import TableOfContents
+from styles import *
+from element import *
+
+
+class Story(object):
+ def __init__(self):
+ self._storylist = []
+
+ @property
+ def storylist(self):
+ return self._storylist
+
+
+class StoryDecorator(Story):
+ def __init__(self, story, data=None, style=None):
+ self._story = story
+ self._data = data
+ self._style = style
+ print self._data
+ self.new_story()
+
+ # print self._story.storylist
+ @property
+ def storylist(self):
+ return self._story.storylist
+
+ def new_story(self):
+ raise NotImplementedError("abstract StoryDecorator")
+
+
+class ImageStory(StoryDecorator):
+ def new_story(self):
+ print "Image Story"
+ for filename in self._data:
+ if os.path.exists(filename) == False:
+ print "not find %s" % filename
+ continue
+ if 'Traffic-types' in filename:
+ style = is_traffic
+ image_height = style.image_height
+ image_width = style.image_width
+ image_hAlign = style.image_hAlign
+ image_vAlign = style.image_vAlign
+ self._story.storylist.append(
+ eImage(filename, image_width, image_height, hAlign=image_hAlign, vAlign=image_vAlign))
+ else:
+ style = is_default
+ image_height = style.image_height
+ image_width = style.image_width
+ image_hAlign = style.image_hAlign
+ image_vAlign = style.image_vAlign
+ # self._story.storylist.append(eGraphicsTable([[' ' * 5, eImage(filename, image_width, image_height, hAlign=image_hAlign, vAlign=image_vAlign)]], ts_left).table)
+ self._story.storylist.append(
+ eImage(filename, image_width, image_height, hAlign=image_hAlign, vAlign=image_vAlign))
+
+
+class HeaderStory(StoryDecorator):
+ def new_story(self):
+ print "header story"
+ self._story.storylist.append(PageBreak())
+
+
+class PageBreakStory(StoryDecorator):
+ def new_story(self):
+ print "PageBreak story"
+ self._story.storylist.append(PageBreak())
+
+
+class TableOfContentsStory(StoryDecorator):
+ def new_story(self):
+ print "TableOfContents story"
+ self._data = [" ", " ", "Table Of Contents", ""]
+ style = ps_head_lv4
+ self._story.storylist.append(eParagraph(self._data, style).para)
+ toc = TableOfContents()
+ toc.levelStyles = [ps_head_lv7, ps_head_lv8, ps_head_lv9]
+ self._story.storylist.append(toc)
+
+
+class SpaceStory(StoryDecorator):
+ def new_story(self):
+ style = ps_space
+ self._story.storylist.append(eParagraph([" ", " "], style).para)
+
+
+class TableStory(StoryDecorator):
+ def new_story(self):
+ print "table story"
+ style = ts_default
+ if self._style == 1:
+ self._story.storylist.append(eDataTable(self._data, style).table)
+ elif self._style ==2:
+ style = ts_left
+ self._story.storylist.append(eCommonTable(self._data, style).table)
+ elif self._style == 3:
+ self._story.storylist.append(eConfigTable(self._data, style).table)
+ elif self._style == 4:
+ self._story.storylist.append(eOptionsTable(self._data, style).table)
+ elif self._style == 5:
+ self._story.storylist.append(eProfileTable(self._data, style).table)
+ elif self._style == 6:
+ self._story.storylist.append(eSummaryTable(self._data, style).table)
+ elif self._style == 7:
+ self._story.storylist.append(eScenarioTable(self._data, style).table)
+ elif self._style == 8:
+ self._story.storylist.append(eGitInfoTable(self._data, style).table)
+
+
+class LinePlotStory(StoryDecorator):
+ def new_story(self):
+ print "LinePlot"
+ style = lps_default
+ if not self._data:
+ print "data error "
+ return
+ data = eGraphicsTable([[eLinePlot(self._data, style).draw]]).table
+ if data:
+ self._story.storylist.append(data)
+
+
+class LineChartStory(StoryDecorator):
+ def new_story(self):
+ print "LineChartStory: "
+ style = lcs_default
+ if not self._data:
+ print "data error "
+ return
+ data = eGraphicsTable([[eHorizontalLineChart(self._data, style).draw]]).table
+ if data:
+ self._story.storylist.append(data)
+
+
+class BarChartStory(StoryDecorator):
+ def new_story(self):
+ print "BarChartStory: "
+ style = bcs_default
+ if not self._data:
+ print "data error "
+ return
+
+ data = eGraphicsTable([[eBarChartColumn(self._data, style).draw]]).table
+ if data:
+ self._story.storylist.append(data)
+
+
+class ParagraphStory(StoryDecorator):
+ def new_story(self):
+ print "Paragraph Story"
+ style = ps_body
+ if not self._data:
+ print "data error "
+ return
+ data = eParagraph(self._data, style).para
+ if data:
+ self._story.storylist.append(data)
+
+
+class TitleStory(StoryDecorator):
+ def new_story(self):
+ print "Paragraph Story"
+ if self._style - 1 in range(9):
+ style = eval("ps_head_lv" + "%d" % self._style)
+ else:
+ style = ps_body
+ # print style
+ # print self._data
+
+ self._story.storylist.append(eParagraph(self._data, style).para)
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/styles.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/styles.py
new file mode 100644
index 00000000..2860c245
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/pdf/styles.py
@@ -0,0 +1,206 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+from reportlab.lib.styles import PropertySet
+from reportlab.lib.pagesizes import A4
+from reportlab.lib import colors
+from reportlab.lib.styles import ParagraphStyle
+import reportlab.lib.enums as ens
+
+
+class TemplateStyle(PropertySet):
+ defaults = dict(
+ page_height=A4[1],
+ page_wight=A4[0],
+ page_left=78,
+ page_top=60,
+ page_bottom=70,
+ page_right=78,
+ title_size=16,
+ title_leading=1.25,
+ title_font='Courier-Bold',
+ body_size=10,
+ body_leading=0.8,
+ body_font='Courier',
+ line_width=1,
+ logo_width=131.2,
+ logo_height=127.7
+ )
+
+
+class ImageStyle(PropertySet):
+ defaults = dict(
+ image_height=165,
+ image_width=175,
+ image_hAlign='CENTRE', # LEFT,CENTRE or RIGHT
+ image_vAlign='MIDDLE' # BOTTOM,MIDDLE or TOP
+ )
+
+
+class TableStyle(PropertySet):
+ defaults = dict(
+ table_hAlign='CENTRE', # LEFT,CENTRE or RIGHT
+ table_vAlign='MIDDLE', # BOTTOM,MIDDLE or TOP
+ table_colWidths=None,
+ table_rowHeights=None
+ )
+
+
+class LinePlotStyle(PropertySet):
+ defaults = dict(
+ width=430,
+ height=400,
+ left=30,
+ bottom=20,
+ strokeColor=colors.black,
+ strokeWidth=1,
+ format=('%4.2f', '%4.0f', '%3.1f'),
+ labelsfont=7,
+ linestyle=[
+ (colors.red, 'Circle', 1.5),
+ (colors.blue, 'Diamond', 1.5),
+ (colors.gold, 'Square', 1.5),
+ (colors.green, 'Triangle', 1.5),
+ (colors.pink, 'FilledCircle', 1.5),
+ (colors.lightblue, 'FilledDiamond', 1.5),
+ (colors.lightgreen, 'FilledTriangle', 1.5)
+ ]
+ )
+
+
+class LineChartStyle(PropertySet):
+ defaults = dict(
+ width=430,
+ height=400,
+ left=30,
+ bottom=20,
+ strokeColor=colors.lightgrey,
+ strokeWidth=1,
+ format=('%4.2f', '%3.1f'),
+ labelsfont=8,
+ linestyle=[
+ (colors.red, 'Circle', 1.5),
+ (colors.blue, 'Diamond', 1.5),
+ (colors.gold, 'Square', 1.5),
+ (colors.green, 'Triangle', 1.5),
+ (colors.pink, 'FilledCircle', 1.5),
+ (colors.lightblue, 'FilledDiamond', 1.5),
+ (colors.lightgreen, 'FilledTriangle', 1.5)
+ ]
+ )
+
+
+class BarChartStyle(PropertySet):
+ defaults = dict(
+ width=430,
+ height=135,
+ left=30,
+ bottom=50,
+ top=0,
+ right=30,
+ groupSpacing=32,
+ barSpacing=4,
+ tick=3,
+ strokeColor=colors.lightgrey,
+ strokeWidth=1,
+ pillarstyle={
+ "loss": (colors.lightgreen, '%4.2f'),
+ "latency": (colors.indianred, '%4.1f'),
+ "fastlink": (colors.pink, '%4.1f'),
+ "l2switch": (colors.lightblue, '%4.1f'),
+ "kernel rdp": (colors.lightgreen, '%4.1f'),
+ "ovs": (colors.purple, '%4.1f')
+ },
+ background=colors.lightgrey,
+ labelsfont=6,
+ )
+
+
+tes_default = TemplateStyle(name='default')
+is_default = ImageStyle(name='default')
+is_traffic = ImageStyle(name='traffic',
+ image_height=150,
+ image_width=360,
+ image_hAlign='CENTRE')
+
+ts_default = TableStyle(name='default')
+ts_left = TableStyle(
+ name='left',
+ table_hAlign='LEFT', # LEFT,CENTRE or RIGHT
+ table_vAlign='BOTTOM', # BOTTOM,MIDDLE or TOP
+ table_colWidths=None,
+ table_rowHeights=None
+)
+lps_default = LinePlotStyle(name='default')
+lcs_default = LineChartStyle(name='default')
+bcs_default = BarChartStyle(name='default')
+ps_head_lv1 = ParagraphStyle(name='ps_head_lv1',
+ fontName='Courier-Bold',
+ alignment=ens.TA_CENTER, # TA_LEFT, TA_RIGHT
+ fontSize=13,
+ leading=22,
+ leftIndent=0)
+
+ps_head_lv2 = ParagraphStyle(name='ps_head_lv2',
+ fontName='Courier',
+ fontSize=12,
+ leading=20,
+ leftIndent=16)
+
+ps_head_lv3 = ParagraphStyle(name='ps_head_lv3',
+ fontSize=11,
+ fontName='Courier',
+ leading=20,
+ leftIndent=16)
+
+ps_head_lv4 = ParagraphStyle(name='ps_head_lv4',
+ fontSize=13,
+ fontName='Courier-Bold',
+ leading=22,
+ leftIndent=0)
+
+ps_head_lv5 = ParagraphStyle(name='ps_head_lv5',
+ fontSize=12,
+ fontName='Courier',
+ leading=20,
+ leftIndent=16)
+
+ps_head_lv6 = ParagraphStyle(name='ps_head_lv6',
+ fontSize=11,
+ fontName='Courier',
+ leading=20,
+ leftIndent=16)
+
+ps_head_lv7 = ParagraphStyle(name='ps_head_lv7',
+ fontSize=11,
+ fontName='Courier',
+ leading=18,
+ leftIndent=0)
+
+ps_head_lv8 = ParagraphStyle(name='ps_head_lv8',
+ fontSize=11,
+ fontName='Courier',
+ leading=18,
+ leftIndent=16)
+
+ps_head_lv9 = ParagraphStyle(name='ps_head_lv9',
+ fontSize=11,
+ fontName='Courier',
+ leading=18,
+ leftIndent=32)
+
+ps_body = ParagraphStyle(name='ps_body',
+ fontSize=11,
+ fontName='Courier',
+ leading=18,
+ leftIndent=32)
+
+ps_space = ParagraphStyle(name='ps_space',
+ fontSize=5,
+ leading=5)
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/__init__.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/__init__.py
new file mode 100644
index 00000000..83b8d15d
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/__init__.py
@@ -0,0 +1,8 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/html_provider.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/html_provider.py
new file mode 100644
index 00000000..74c4c593
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/html_provider.py
@@ -0,0 +1,45 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import logging
+
+LOG = logging.getLogger(__name__)
+from vstf.controller.settings.html_settings import HtmlSettings
+from vstf.controller.settings.template_settings import TemplateSettings
+
+
+class HtmlProvider(object):
+ def __init__(self, info, style):
+ self._info = info
+ self._style = style
+
+ @property
+ def get_style(self):
+ assert "style" in self._style
+ return self._style["style"]
+
+ @property
+ def get_context(self):
+ assert "context" in self._info
+ return self._info["context"]
+
+
+def main():
+ from vstf.common.log import setup_logging
+ setup_logging(level=logging.DEBUG, log_file="/var/log/html-provder.log", clevel=logging.INFO)
+
+ html_settings = HtmlSettings()
+ LOG.info(html_settings.settings)
+ info = TemplateSettings()
+ provider = HtmlProvider(info.settings, html_settings.settings)
+ LOG.info(provider.get_style)
+ LOG.info(provider.get_context)
+
+if __name__ == '__main__':
+ main() \ No newline at end of file
diff --git a/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/pdf_provider.py b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/pdf_provider.py
new file mode 100644
index 00000000..e1cb09ef
--- /dev/null
+++ b/testsuites/vstf/vstf_scripts/vstf/controller/reporters/report/provider/pdf_provider.py
@@ -0,0 +1,49 @@
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+
+import logging
+
+LOG = logging.getLogger(__name__)
+from vstf.controller.settings.template_settings import TemplateSettings
+
+
+class PdfProvider(object):
+ def __init__(self, info):
+ self._info = info
+
+ @property
+ def get_theme(self):
+ assert "theme" in self._info
+ return self._info["theme"]
+
+ @property
+ def ifcontents(self):
+ assert "contents" in self._info
+ assert "enable" in self._info["contents"]
+ return self._info["contents"]["enable"]
+
+ @property
+ def get_context(self):
+ assert "context" in self._info
+ return self._info["context"]
+
+
+def main():
+ from vstf.common.log import setup_logging
+ setup_logging(level=logging.DEBUG, log_file="/var/log/pdf-provider.log", clevel=logging.INFO)
+
+ info = TemplateSettings()
+ provider = PdfProvider(info.settings)
+ LOG.info(provider.get_theme)
+ LOG.info(provider.ifcontents)
+ LOG.info(provider.get_context)
+
+if __name__ == '__main__':
+ main() \ No newline at end of file