-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
test_logger.py
163 lines (140 loc) · 5.88 KB
/
test_logger.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"""
test_logger.py:
A wrapper on the openpyxl library that provides the ability to log messages in an excel sheet. Used
by the test API to log events, asserts, test cases and user messages. The documentation for openpyxl
can be found here:
https://openpyxl.readthedocs.io/en/stable/index.html
This class uses a write-only optimization that should allow for creating large log files without
hogging too much memory. Write-only optimization can be found here:
https://openpyxl.readthedocs.io/en/stable/optimized.html#write-only-mode
:author: koran
"""
import os
import time
import datetime
import threading
from openpyxl import Workbook
from openpyxl.styles import PatternFill, Font, Alignment
from openpyxl.cell import WriteOnlyCell
from openpyxl.utils.exceptions import WorkbookAlreadySaved
class TestLogger:
"""
User-accessible colors. Can be used for the color arguments
"""
BROWN = "E6CCB3"
RED = "FF9999"
ORANGE = "FFCC99"
YELLOW = "FFFF99"
GREEN = "ADEBAD"
BLUE = "99CCFF"
PURPLE = "CC99FF"
GRAY = "D9D9D9"
WHITE = "FFFFFF"
"""
User-accessible styles. Must be used for the style arguments
"""
BOLD = "BOLD"
ITALICS = "ITALICS"
UNDERLINED = "UNDERLINED"
__align = Alignment(vertical='top', wrap_text=True)
__font_name = 'calibri'
__time_fmt = "%H:%M:%S.%f"
def __init__(self, output_path, time_format=None, font_name=None):
"""
Constructs a TestLogger
Args:
output_path: a path where log files will
time_format: an optional string to specify the timestamp format. See datetime.strftime
font_name: an optional string to specify the font
"""
if not isinstance(output_path, str):
raise TypeError(
"Test Logger requires a filename where the output can be saved."
)
self.start_time = time.time()
date_string = datetime.datetime.fromtimestamp(self.start_time).strftime("%Y-%m-%dT%H:%M:%S")
self.filename = os.path.join(output_path, "TestLog_{}.xlsx".format(date_string))
self.workbook = Workbook(write_only=True)
self.worksheet = self.workbook.create_sheet()
self.ws_saved = False
if time_format is None:
self.time_format = self.__time_fmt
else:
self.time_format = time_format
if font_name is None:
self.font_name = self.__font_name
else:
self.font_name = font_name
timestring = datetime.datetime.fromtimestamp(self.start_time).strftime(self.time_format)
self.worksheet.column_dimensions['A'].width = len(timestring) + 1
self.worksheet.column_dimensions['D'].width = 120
top = []
date_string = datetime.datetime.fromtimestamp(self.start_time).strftime("%H:%M:%S.%f on %m/%d/%Y")
top.append(self.__get_cell("Test began at " + date_string))
self.worksheet.append(top)
labels = ["Log Time", "Case ID", "Sender", "Message"]
header = self.__get_ws_row(labels, style=self.BOLD)
self.worksheet.append(header)
self.case_id = "NA"
self.lock = threading.Lock()
def log_message(self, message, sender="NA", color=None, style=None, case_id=None):
"""
Logs a message to the TestLog. Each message will include a timestamp beforehand.
Note: Once specified, the test case's case_id will persist in the logs until it is
specified again.
Args:
message: a message to log (str).
sender: a short string describing who created the log message
color: a string object containing a color hex code "######"
style: a string choosing 1 of 3 formatting options (ITALICS, BOLD, UNDERLINED)
case_id: a short identifier to denote which test case the log message belongs to
"""
ts = time.time()
timestring = datetime.datetime.fromtimestamp(ts).strftime(self.time_format)
if case_id is not None:
if not isinstance(case_id, str):
case_id = str(case_id)
self.case_id = case_id
strings = [timestring, self.case_id, sender, message]
self.lock.acquire()
try:
print("{} [{}] {}".format(timestring, sender, message))
if not self.ws_saved:
row = self.__get_ws_row(strings, color, style)
self.worksheet.append(row)
except WorkbookAlreadySaved:
self.ws_saved = True
print("{} [{}] {}".format(timestring, "TestLogger", "Workbook has already been saved."))
finally:
self.lock.release()
def close_log(self):
"""
Saves the write-only workbook. Should be called only once when the log is completed.
"""
self.workbook.save(filename=self.filename)
self.ws_saved = True
def __get_cell(self, string, color=None, style=None):
"""
Helper method for log message. This method takes a string as well as color and style
arguments to create a write-only cell.
Args:
string: a string object to be written to the cell's value field.
color: a string object containing a color hex code "######"
style: a string choosing 1 of 3 formatting options (ITALICS, BOLD, UNDERLINED)
"""
cell = WriteOnlyCell(self.worksheet, value=string)
if color is not None:
cell.fill = PatternFill("solid", fgColor=color)
cell.font = Font(
name=self.font_name,
bold=(style == self.BOLD),
italic=(style == self.ITALICS),
underline=("single" if style == self.UNDERLINED else "none"),
)
cell.alignment = self.__align
return cell
def __get_ws_row(self, strings, color=None, style=None):
row = []
for string in strings:
row.append(self.__get_cell(string, color, style))
return row