From 8f1101df131a4d3e03b377738507d88b745831c0 Mon Sep 17 00:00:00 2001 From: "Yiting.Li" Date: Tue, 22 Dec 2015 17:11:12 -0800 Subject: Upload the contribution of vstf as bottleneck network framework. End to End Performance test JIRA:BOTTLENECK-29 Change-Id: Ib2c553c8b60d6cda9e7a7b52b737c9139f706ebd Signed-off-by: Yiting.Li --- .../controller/reporters/report/pdf/__init__.py | 14 + .../controller/reporters/report/pdf/element.py | 781 +++++++++++++++++++++ .../controller/reporters/report/pdf/pdfcreator.py | 446 ++++++++++++ .../controller/reporters/report/pdf/pdftemplate.py | 107 +++ vstf/vstf/controller/reporters/report/pdf/story.py | 191 +++++ .../vstf/controller/reporters/report/pdf/styles.py | 198 ++++++ 6 files changed, 1737 insertions(+) create mode 100755 vstf/vstf/controller/reporters/report/pdf/__init__.py create mode 100755 vstf/vstf/controller/reporters/report/pdf/element.py create mode 100755 vstf/vstf/controller/reporters/report/pdf/pdfcreator.py create mode 100755 vstf/vstf/controller/reporters/report/pdf/pdftemplate.py create mode 100755 vstf/vstf/controller/reporters/report/pdf/story.py create mode 100755 vstf/vstf/controller/reporters/report/pdf/styles.py (limited to 'vstf/vstf/controller/reporters/report/pdf') diff --git a/vstf/vstf/controller/reporters/report/pdf/__init__.py b/vstf/vstf/controller/reporters/report/pdf/__init__.py new file mode 100755 index 00000000..89dcd4e2 --- /dev/null +++ b/vstf/vstf/controller/reporters/report/pdf/__init__.py @@ -0,0 +1,14 @@ +# Copyright Huawei Technologies Co., Ltd. 1998-2015. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an AS IS BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. diff --git a/vstf/vstf/controller/reporters/report/pdf/element.py b/vstf/vstf/controller/reporters/report/pdf/element.py new file mode 100755 index 00000000..2528f2c5 --- /dev/null +++ b/vstf/vstf/controller/reporters/report/pdf/element.py @@ -0,0 +1,781 @@ +#!/usr/bin/python +# -*- coding: utf8 -*- +# author: wly +# date: 2015-05-04 +# see license for license details +__version__ = ''' ''' +__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 = "" + dstr + "
" + dstr = dstr + "
" + else: + dstr = dstr + "
" + result += dstr + return result + + def create(self): + self._para = Paragraph(self._data, self._pstyle) + + @property + def para(self): + return self._para diff --git a/vstf/vstf/controller/reporters/report/pdf/pdfcreator.py b/vstf/vstf/controller/reporters/report/pdf/pdfcreator.py new file mode 100755 index 00000000..50b3bc65 --- /dev/null +++ b/vstf/vstf/controller/reporters/report/pdf/pdfcreator.py @@ -0,0 +1,446 @@ +#!/usr/bin/python +# -*- coding: utf8 -*- +# author: wly +# date: 2015-05-29 +# see license for license details +__version__ = ''' ''' + +import os + +from vstf.controller.reporters.report.pdf.styles import TemplateStyle +from vstf.controller.reporters.report.pdf.pdftemplate import PdfVswitch +from vstf.controller.reporters.report.pdf.story import TitleStory, SpaceStory, ImageStory, LineChartStory, \ + LinePlotStory, uTableStory, Story, TableOfContentsStory, PageBreakStory, ParagraphStory, BarChartStory, cTableStory +from vstf.controller.reporters.report.data_factory import CommonData, ScenarioData, HistoryData +from vstf.controller.database.dbinterface import DbManage +import vstf.controller + + +class LetterOrder(object): + def __init__(self): + self.lettertable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + self._cur = 0 + self._len = len(self.lettertable) + + def get(self): + return self.lettertable[self._cur] + + def pre(self): + self._cur = (self._cur + self._len - 1) % self._len + + def next(self): + self._cur = (self._cur + 1) % self._len + + +class PdfBase(object): + def __init__(self): + self._case = '' + self._ofile = '' + self._title = [] + self._story = [] + self._rootdir = os.path.dirname(vstf.controller.__file__) + '/' + self._pdf = None + + def create_pdf(self): + style = TemplateStyle(name='default') + title = self._title + logo = [self._rootdir + "res/logo.jpg"] + header = [''] + footer = [""] + note = ['', ''] + output = [self._ofile] + self._pdf = PdfFrameLoss(style, title, logo, header, footer, output, note) + + def save_pdf(self): + self._pdf.generate(self._story) + + def add_coverpage(self): + story = Story() + story = PageBreakStory(story) + self._story += story.storylist + + def create_story(self): + raise NotImplementedError("abstract PdfBase") + + def create(self): + self.create_pdf() + self.create_story() + self.save_pdf() + + +class PdfvSwitchCreator(PdfBase): + def __init__(self, ofile, common_data, scenario_data, history_data): + PdfBase.__init__(self) + self._common = common_data + self._result = scenario_data + self._history = history_data + self._ofile = ofile + self._chapterid = 0 + self._appendixid = LetterOrder() + + def create_pdf(self): + style = TemplateStyle(name='default') + title = self._result.get_covertitle() + logo = [self._rootdir + "res/logo.jpg"] + header = [''] + footer = [""] + note = ['', ''] + output = [self._ofile] + self._pdf = PdfVswitch(style, title, logo, header, footer, output, note) + + def get_chapterid(self): + self._chapterid = self._chapterid + 1 + return self._chapterid + + def create_story(self): + self.add_coverpage() + self.add_table_of_contents() + # self.add_contact() + # self.add_overview() + self.add_scenario() + # self.add_info() + # self.add_appendix() + self.add_historys() + + def add_info(self): + self.add_systeminfo() + self.add_gitinfo() + self.add_profile_parameters() + self.add_testing_options() + + def add_contact(self): + story = Story() + story = SpaceStory(story) + title = ["", "", "", "Reporter"] + body = self._common.get_contact() + story = TitleStory(story, data=title, style=7) + story = ParagraphStory(story, data=body) + self._story += story.storylist + + def add_table_of_contents(self): + story = Story() + story = TableOfContentsStory(story) + self._story += story.storylist + + def add_overview(self): + story = Story() + story = PageBreakStory(story) + + chapterid = self.get_chapterid() + title = ["%d.Overview" % (chapterid)] + body = [""] + story = TitleStory(story, data=title, style=1) + story = ParagraphStory(story, data=body) + + sectionid = 1 + title = ["%d.%d Components under Test" % (chapterid, sectionid)] + body = self._common.get_components() + story = TitleStory(story, data=title, style=2) + story = ParagraphStory(story, data=body) + + sectionid = sectionid + 1 + title = ["%d.%d Test" % (chapterid, sectionid)] + body = self._result.get_test() + story = TitleStory(story, data=title, style=2) + story = ParagraphStory(story, data=body) + + sectionid = sectionid + 1 + title = ["%d.%d Configuration" % (chapterid, sectionid)] + story = TitleStory(story, data=title, style=2) + + title = ["Software"] + body = self._common.get_software() + story = TitleStory(story, data=title, style=6) + story = ParagraphStory(story, data=body) + + title = ["Hardware"] + body = self._common.get_hardware() + story = TitleStory(story, data=title, style=6) + story = ParagraphStory(story, data=body) + self._story += story.storylist + + def add_scenario(self): + case_list = self._result.get_caselist() + for case in case_list: + self.add_case(case) + + def add_case(self, case): + story = Story() + chapterid = self.get_chapterid() + + title = ["%d. Case : %s (%s)" % (chapterid, case, self._common.get_casename(case))] + + tools = self._result.get_test_tools(case) + pic = self._common.get_casefigure(case, tools) + print pic + + story = TitleStory(story, data=title, style=1) + story = SpaceStory(story) + story = ImageStory(story, data=[self._rootdir + pic]) + story = SpaceStory(story) + + sectionid = 1 + story = self.add_summary(story, chapterid, sectionid, case) + story = SpaceStory(story) + + if self._result.is_throughput_start(case): + sectionid = sectionid + 1 + story = self.add_throughput_result(story, chapterid, sectionid, case) + + if self._result.is_frameloss_start(case): + sectionid = sectionid + 1 + story = self.add_frameloss_result(story, chapterid, sectionid, case) + + if self._result.is_latency_start(case): + sectionid = sectionid + 1 + story = self.add_latency_result(story, chapterid, sectionid, case) + + story = SpaceStory(story) + story = SpaceStory(story) + self._story += story.storylist + + def add_summary(self, story, chapterid, sectionid, case): + title = ["%d.%d Summary" % (chapterid, sectionid)] + story = TitleStory(story, data=title, style=2) + provider_list = ["fastlink", "rdp", "l2switch"] + provider_dict = {"fastlink": "Fast Link", "l2switch": "L2Switch", "rdp": "Kernel RDP"} + unitid = 1 + case_name = self._common.get_casename(case) + for provider in provider_list: + if self._result.is_provider_start(case, provider): + title = ["%d.%d.%d %s (%s_%s)" % ( + chapterid, sectionid, unitid, provider_dict[provider], case_name, provider)] + unitid = unitid + 1 + story = TitleStory(story, data=title, style=6) + test_types = ["throughput", "frameloss"] + for test_type in test_types: + if self._result.is_type_provider_start(case, provider, test_type): + story = self.add_summary_type(story, case, provider, test_type) + return story + + def add_summary_type(self, story, case, provider, test_type): + bar_list = [test_type, "latency"] + for item in bar_list: + bar_data = self._result.get_bardata(case, provider, item) + story = SpaceStory(story) + story = BarChartStory(story, data=bar_data) + + table_content = self._result.get_summary_tabledata(case, provider, test_type) + story = SpaceStory(story) + story = cTableStory(story, data=table_content, style=3) + story = SpaceStory(story) + return story + + def add_throughput_result(self, story, chapterid, sectionid, case): + title = ["%d.%d Throughput " % (chapterid, sectionid)] + story = TitleStory(story, data=title, style=2) + unitid = 1 + title = ["%d.%d.%d Summary" % (chapterid, sectionid, unitid)] + story = TitleStory(story, data=title, style=6) + + test_type = "throughput" + unit = 'RX Frame Rate' + chart_data = self._result.get_frameloss_chartdata(case, test_type) + table_data = self._result.get_frameloss_tabledata(case, test_type) + title = [unit + ' (%)'] + story = TitleStory(story, data=title, style=6) + # story = SpaceStory(story) + # story = LinePlotStory(story, data=chart_data) + story = SpaceStory(story) + story = uTableStory(story, data=table_data) + story = SpaceStory(story) + + unit = 'Frame Loss Rate' + title = [unit + ' (Mpps)'] + + chart_data = self._result.get_framerate_chartdata(case, test_type) + table_data = self._result.get_framerate_tabledata(case, test_type) + story = TitleStory(story, data=title, style=6) + story = SpaceStory(story) + story = LinePlotStory(story, data=chart_data) + story = SpaceStory(story) + story = uTableStory(story, data=table_data) + story = SpaceStory(story) + return story + + def add_frameloss_result(self, story, chapterid, sectionid, case): + title = ["%d.%d Frame Loss Rate " % (chapterid, sectionid)] + story = TitleStory(story, data=title, style=2) + unitid = 1 + title = ["%d.%d.%d Summary" % (chapterid, sectionid, unitid)] + story = TitleStory(story, data=title, style=6) + + test_type = "frameloss" + unit = 'RX Frame Rate' + chart_data = self._result.get_frameloss_chartdata(case, test_type) + table_data = self._result.get_frameloss_tabledata(case, test_type) + title = [unit + ' (%)'] + story = TitleStory(story, data=title, style=6) + # story = SpaceStory(story) + # story = LineChartStory(story, data=chart_data) + story = SpaceStory(story) + story = uTableStory(story, data=table_data) + story = SpaceStory(story) + + unit = 'Frame Loss Rate' + title = [unit + ' (Mpps)'] + + chart_data = self._result.get_framerate_chartdata(case, test_type) + table_data = self._result.get_framerate_tabledata(case, test_type) + story = TitleStory(story, data=title, style=6) + story = SpaceStory(story) + story = LineChartStory(story, data=chart_data) + story = SpaceStory(story) + story = uTableStory(story, data=table_data) + story = SpaceStory(story) + return story + + def add_latency_result(self, story, chapterid, sectionid, case): + title = ["%d.%d Latency " % (chapterid, sectionid)] + story = TitleStory(story, data=title, style=2) + unitid = 1 + title = ["%d.%d.%d Summary" % (chapterid, sectionid, unitid)] + story = TitleStory(story, data=title, style=6) + + unit = 'Average Latency' + title = [unit + ' (uSec)'] + # chart_data = self._result.get_latency_chartdata(case) + bar_data = self._result.get_latency_bardata(case) + table_data = self._result.get_latency_tabledata(case) + story = TitleStory(story, data=title, style=6) + story = SpaceStory(story) + # story = LineChartStory(story, data=chart_data) + story = BarChartStory(story, data=bar_data) + + story = SpaceStory(story) + story = uTableStory(story, data=table_data) + story = SpaceStory(story) + return story + + def add_systeminfo(self): + story = Story() + chapterid = self.get_chapterid() + story = SpaceStory(story) + title = ["%d. System Information " % (chapterid)] + story = PageBreakStory(story) + story = TitleStory(story, data=title, style=1) + table_content = self._common.get_systeminfo_tabledata() + story = SpaceStory(story) + story = cTableStory(story, data=table_content, style=0) + story = SpaceStory(story) + self._story += story.storylist + + def add_gitinfo(self): + story = Story() + chapterid = self.get_chapterid() + title = ["%d. Git Repository Information " % (chapterid)] + story = TitleStory(story, data=title, style=1) + + table_content = self._common.get_gitinfo_tabledata() + if table_content: + story = SpaceStory(story) + story = cTableStory(story, data=table_content, style=5) + story = SpaceStory(story) + self._story += story.storylist + + def add_testing_options(self): + story = Story() + chapterid = self.get_chapterid() + story = SpaceStory(story) + title = ["%d. Testing Options" % (chapterid)] + + story = TitleStory(story, data=title, style=1) + table_content = self._common.get_testingoptions_tabledata() + story = SpaceStory(story) + story = cTableStory(story, data=table_content, style=1) + story = SpaceStory(story) + self._story += story.storylist + + def add_profile_parameters(self): + story = Story() + chapterid = self.get_chapterid() + story = PageBreakStory(story) + title = ["%d. " % (chapterid)] + story = TitleStory(story, data=title, style=1) + table_content = self._common.get_profileparameters_tabledData() + story = SpaceStory(story) + story = cTableStory(story, data=table_content, style=2) + story = SpaceStory(story) + self._story += story.storylist + + def add_appendix(self): + story = Story() + story = PageBreakStory(story) + + title = ["Appendix %s: vSwitching Testing Methodology" % (self._appendixid.get())] + self._appendixid.next() + story = TitleStory(story, data=title, style=1) + filename = "res/Traffic-types.jpg" + story = SpaceStory(story) + story = ImageStory(story, data=[self._rootdir + filename]) + # story = SpaceStory(story) + + title = ["Traffic Patterns: "] + story = TitleStory(story, data=title, style=6) + + body = [ + "Ti - South North Traffic", + "Tu - East Eest Traffic", + "Tn - Physical host or VM loop back", + "Tnv - Virtual Machine loop back", + ] + story = ParagraphStory(story, data=body) + + title = ["Performance Testing Coverage (version 0.1):"] + story = TitleStory(story, data=title, style=6) + + table_content = self._common.get_introduct_tabledata() + story = SpaceStory(story) + story = cTableStory(story, data=table_content, style=4) + self._story += story.storylist + + def add_historys(self): + case_list = self._result.get_caselist() + for case in case_list: + history = self._history.get_history_info(case) + if history: + self.add_history(case, history) + + def add_history(self, case, history): + story = Story() + story = PageBreakStory(story) + + title = ["Appendix %s : %s History Records" % (self._appendixid.get(), case)] + story = TitleStory(story, data=title, style=1) + + for i in range(len(history)): + title = ["%s.%s %s" % (self._appendixid.get(), i, history[i]["title"])] + story = TitleStory(story, data=title, style=2) + + section = history[i]["data"] + for unit in section: + title = [unit['title']] + story = TitleStory(story, data=title, style=6) + content = unit['data'] + story = uTableStory(story, data=content) + + self._appendixid.next() + self._story += story.storylist + + +def main(): + dbase = DbManage() + taskid = dbase.get_last_taskid() + common_data = CommonData(taskid, dbase) + scenario_list = common_data.get_scenariolist() + history_data = HistoryData(taskid, dbase) + for scenario in scenario_list: + out_file = "vstf_report_%s.pdf" % (scenario) + scenario_data = ScenarioData(taskid, dbase, scenario) + reporter = PdfvSwitchCreator(out_file, common_data, scenario_data, history_data) + if reporter: + reporter.create() + + +if __name__ == '__main__': + main() diff --git a/vstf/vstf/controller/reporters/report/pdf/pdftemplate.py b/vstf/vstf/controller/reporters/report/pdf/pdftemplate.py new file mode 100755 index 00000000..819a5c57 --- /dev/null +++ b/vstf/vstf/controller/reporters/report/pdf/pdftemplate.py @@ -0,0 +1,107 @@ +#!/usr/bin/python +# -*- coding: utf8 -*- +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 + + +class MyDocTemplate(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: + def __init__(self, style, title, logo, header, footer, output, note=None): + self._style = style + self._title = title + self._logo = logo[0] + self._header = header[0] + self._footer = footer + self._output = output[0] + self._note = note + info = " Generated on %s " % time.strftime('%Y/%m/%d %H:%M:%S', time.localtime()) + self._note[0] += info + + def myFirstPage(self, canvas, doc): + raise NotImplementedError("abstract StoryDecorator") + + def myLaterPages(self, canvas, doc): + raise NotImplementedError("abstract StoryDecorator") + + def generate(self, story): + sizes = (self._style.page_wight, self._style.page_height) + doc = MyDocTemplate(self._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/vstf/vstf/controller/reporters/report/pdf/story.py b/vstf/vstf/controller/reporters/report/pdf/story.py new file mode 100755 index 00000000..3e56e185 --- /dev/null +++ b/vstf/vstf/controller/reporters/report/pdf/story.py @@ -0,0 +1,191 @@ +#!/usr/bin/python +# -*- coding: utf8 -*- +__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 uTableStory(StoryDecorator): + def new_story(self): + print "utable story" + style = ts_left + if not self._data: + print "data error " + return + self._story.storylist.append(eCommonTable(self._data, style).table) + + +class TableStory(StoryDecorator): + def new_story(self): + print "table story" + style = ts_default + self._story.storylist.append(eDataTable(self._data, style).table) + + +class SpaceStory(StoryDecorator): + def new_story(self): + style = ps_space + self._story.storylist.append(eParagraph([" ", " "], style).para) + + +class cTableStory(StoryDecorator): + def new_story(self): + print "table story" + style = ts_default + if self._style == 0: + self._story.storylist.append(eConfigTable(self._data, style).table) + elif self._style == 1: + self._story.storylist.append(eOptionsTable(self._data, style).table) + elif self._style == 2: + self._story.storylist.append(eProfileTable(self._data, style).table) + elif self._style == 3: + self._story.storylist.append(eSummaryTable(self._data, style).table) + elif self._style == 4: + self._story.storylist.append(eScenarioTable(self._data, style).table) + elif self._style == 5: + 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/vstf/vstf/controller/reporters/report/pdf/styles.py b/vstf/vstf/controller/reporters/report/pdf/styles.py new file mode 100755 index 00000000..d54ee8ab --- /dev/null +++ b/vstf/vstf/controller/reporters/report/pdf/styles.py @@ -0,0 +1,198 @@ +#!/usr/bin/python +# -*- coding: utf8 -*- +from reportlab.lib.styles import PropertySet +from reportlab.lib.pagesizes import A4 +from reportlab.lib import colors +from reportlab.lib.styles import ParagraphStyle +from reportlab.lib.enums import TA_LEFT + + +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'), + }, + background=colors.lightgrey, + labelsfont=6, + ) + + +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 +) + +is_default = ImageStyle(name='default') +is_traffic = ImageStyle(name='traffic', + image_height=150, + image_width=360, + image_hAlign='CENTRE') + +ts_default = TableStyle(name='default') +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=TA_LEFT, # TA_CENTRE, + 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) -- cgit 1.2.3-korg