Move test-framework to its own repository

Signed-off-by: Robert Baldyga <baldyga.r@gmail.com>
This commit is contained in:
Robert Baldyga
2023-05-01 18:55:34 +02:00
commit 40f08a369a
89 changed files with 9914 additions and 0 deletions

0
log/__init__.py Normal file
View File

78
log/base_log.py Normal file
View File

@@ -0,0 +1,78 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from enum import Enum
from re import sub
class BaseLogResult(Enum):
DEBUG = 10
PASSED = 11
WORKAROUND = 12
WARNING = 13
SKIPPED = 14
FAILED = 15
EXCEPTION = 16
BLOCKED = 17
CRITICAL = 18
def escape(msg):
return sub(u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+', '', msg)
class BaseLog():
def __init__(self, begin_message=None):
self.__begin_msg = begin_message
self.__result = BaseLogResult.PASSED
def __enter__(self):
if self.__begin_msg is not None:
self.begin(self.__begin_msg)
else:
self.begin("Start BaseLog ...")
def __exit__(self, *args):
self.end()
def __try_to_set_new_result(self, new_result):
if new_result.value > self.__result.value:
self.__result = new_result
def begin(self, message):
pass
def debug(self, message):
pass
def info(self, message):
pass
def workaround(self, message):
self.__try_to_set_new_result(BaseLogResult.WORKAROUND)
def warning(self, message):
self.__try_to_set_new_result(BaseLogResult.WARNING)
def skip(self, message):
self.__try_to_set_new_result(BaseLogResult.SKIPPED)
def error(self, message):
self.__try_to_set_new_result(BaseLogResult.FAILED)
def blocked(self, message):
self.__try_to_set_new_result(BaseLogResult.BLOCKED)
def exception(self, message):
self.__try_to_set_new_result(BaseLogResult.EXCEPTION)
def critical(self, message):
self.__try_to_set_new_result(BaseLogResult.CRITICAL)
def end(self):
return self.__result
def get_result(self):
return self.__result

0
log/group/__init__.py Normal file
View File

View File

@@ -0,0 +1,43 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from log.base_log import BaseLogResult, BaseLog
from log.group.html_group_log import HtmlGroupLog
from datetime import datetime
class HtmlChapterGroupLog(HtmlGroupLog):
SET_RESULT = {
BaseLogResult.PASSED: BaseLog.info,
BaseLogResult.WORKAROUND: BaseLog.workaround,
BaseLogResult.WARNING: BaseLog.warning,
BaseLogResult.SKIPPED: BaseLog.skip,
BaseLogResult.FAILED: BaseLog.error,
BaseLogResult.BLOCKED: BaseLog.blocked,
BaseLogResult.EXCEPTION: BaseLog.exception,
BaseLogResult.CRITICAL: BaseLog.critical}
def __init__(self, html_base, cfg, begin_msg=None, id='ch0'):
super().__init__(HtmlChapterGroupLog._factory, html_base, cfg, begin_msg, id)
@staticmethod
def _factory(html_base, cfg, begin_msg, id):
return HtmlChapterGroupLog(html_base, cfg, begin_msg, id)
def end_dir_group(self, ref_group):
group = super().end_group()
ref_container_id = ref_group._container.get('id')
group._header.set('ondblclick', f"chapterClick('{ref_container_id}')")
def set_result(self, result):
if self._successor is not None:
self._successor.set_result(result)
HtmlChapterGroupLog.SET_RESULT[result](self, "set result")
def end(self):
result = super().end()
exe_time = (datetime.now() - self._start_time).seconds
self._cfg.group_chapter_end(exe_time, self._header, self._container, result)
return result

139
log/group/html_group_log.py Normal file
View File

@@ -0,0 +1,139 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from datetime import datetime
from log.base_log import BaseLog, BaseLogResult
class HtmlGroupLog(BaseLog):
def __init__(self, constructor, html_base_element, cfg, begin_message, id_):
super().__init__(begin_message)
self._successor = None
self.__factory = constructor
self.__log_main_store = html_base_element
self._id = id_
self._container = None
self._header = None
self.__msg_idx = 0
self._start_time = datetime.now()
self._cfg = cfg
self._header_msg_type = type(begin_message)
def begin(self, message):
policy = self._cfg.get_policy(type(message))
self._header, self._container = policy.group_begin(self._id, message, self.__log_main_store)
super().begin(message)
def get_step_id(self):
if self._successor is not None:
return self._successor.get_step_id()
else:
return f'step.{self._id}.{self.__msg_idx}'
def __add_test_step(self, message, result=BaseLogResult.PASSED):
policy = self._cfg.get_policy(type(message))
policy.standard(self.get_step_id(), message, result, self._container)
self.__msg_idx += 1
def get_main_log_store(self):
return self.__log_main_store
def start_group(self, message):
self._header_msg_type = type(message)
if self._successor is not None:
result = self._successor.start_group(message)
else:
new_id = f"{self._id}.{self.__msg_idx}"
self.__msg_idx += 1
self._successor = self.__factory(self._container, self._cfg, message, new_id)
self._successor.begin(message)
result = self._successor
return result
def end_group(self):
if self._successor is not None:
if self._successor._successor is None:
self._successor.end()
result = self._successor
self._successor = None
else:
result = self._successor.end_group()
else:
self.end()
result = self
return result
def debug(self, message):
if self._successor is not None:
self._successor.debug(message)
else:
self.__add_test_step(message, BaseLogResult.DEBUG)
return super().debug(message)
def info(self, message):
if self._successor is not None:
self._successor.info(message)
else:
self.__add_test_step(message)
super().info(message)
def workaround(self, message):
if self._successor is not None:
self._successor.workaround(message)
else:
self.__add_test_step(message, BaseLogResult.WORKAROUND)
super().workaround(message)
def warning(self, message):
if self._successor is not None:
self._successor.warning(message)
else:
self.__add_test_step(message, BaseLogResult.WARNING)
super().warning(message)
def skip(self, message):
if self._successor is not None:
self._successor.skip(message)
else:
self.__add_test_step(message, BaseLogResult.SKIPPED)
super().skip(message)
def error(self, message):
if self._successor is not None:
self._successor.error(message)
else:
self.__add_test_step(message, BaseLogResult.FAILED)
super().error(message)
def blocked(self, message):
if self._successor is not None:
self._successor.blocked(message)
else:
self.__add_test_step(message, BaseLogResult.BLOCKED)
super().blocked(message)
def critical(self, message):
if self._successor is not None:
self._successor.critical(message)
else:
self.__add_test_step(message, BaseLogResult.CRITICAL)
super().critical(message)
def exception(self, message):
if self._successor is not None:
self._successor.exception(message)
else:
self.__add_test_step(message, BaseLogResult.EXCEPTION)
super().exception(message)
def end(self):
return super().end()
def get_current_group(self):
if self._successor is not None:
result = self._successor.get_current_group()
else:
result = self
return result

View File

@@ -0,0 +1,20 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from log.group.html_group_log import HtmlGroupLog
class HtmlIterationGroupLog(HtmlGroupLog):
def __init__(self, html_base, cfg, begin_msg, id='itg0'):
super().__init__(HtmlIterationGroupLog._factory, html_base, cfg, begin_msg, id)
@staticmethod
def _factory(html_base, cfg, begin_msg, id):
return HtmlIterationGroupLog(html_base, cfg, begin_msg, id)
def end(self):
result = super().end()
self._cfg.group_end(self._id, self._header, self._container, result)
return result

102
log/html_file_item_log.py Normal file
View File

@@ -0,0 +1,102 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from log.html_file_log import HtmlFileLog
from log.group.html_chapter_group_log import HtmlChapterGroupLog
from log.group.html_iteration_group_log import HtmlIterationGroupLog
from datetime import datetime
from lxml.etree import Element
class HtmlFileItemLog(HtmlFileLog):
def __init__(self, html_file_path, test_title, cfg, iteration_title="Test summary"):
super().__init__(html_file_path, test_title)
root = self.get_root()
self._log_items_store = root.xpath('/html/body')[0]
self._idx = 0
self._log_chapters_store = root.xpath('/html/body/section[@id="iteration-chapters"]')[0]
self._chapter_group = HtmlChapterGroupLog(self._log_chapters_store, cfg, test_title)
self._main_group = HtmlIterationGroupLog(self._log_items_store, cfg, test_title)
self._start_time = datetime.now()
iteration_title_node = root.xpath('/html/body/a/h1')[0]
iteration_title_node.text = iteration_title
self._config = cfg
self._fail_container = root.xpath('/html/body/div/select[@id="error-list-selector"]')[0]
def __add_error(self, msg_idx, msg, error_class):
fail_element = Element('option', value=msg_idx)
fail_element.set('class', error_class)
fail_element.text = msg
self._fail_container.append(fail_element)
def start_iteration(self, message):
super().begin(message)
def get_result(self):
return self._main_group.get_result()
def begin(self, message):
self._chapter_group.begin(message)
self._main_group.begin(message)
def debug(self, message):
self._main_group.debug(message)
def info(self, message):
self._main_group.info(message)
def workaround(self, message):
self._main_group.workaround(message)
def warning(self, message):
self._main_group.warning(message)
def skip(self, message):
self._main_group.skip(message)
def error(self, message):
msg_idx = self._main_group.get_step_id()
self.__add_error(msg_idx, message, "fail")
self._main_group.error(message)
def blocked(self, message):
msg_idx = self._main_group.get_step_id()
self.__add_error(msg_idx, message, "blocked")
self._main_group.blocked(message)
def exception(self, message):
msg_idx = self._main_group.get_step_id()
self.__add_error(msg_idx, message, "exception")
self._main_group.exception(message)
def critical(self, message):
msg_idx = self._main_group.get_step_id()
self.__add_error(msg_idx, message, "critical")
self._main_group.critical(message)
def start_group(self, message):
self._chapter_group.start_group(message)
self._main_group.start_group(message)
def end_group(self):
ref_group = self._main_group.get_current_group()
self._chapter_group.set_result(ref_group.get_result())
self._main_group.end_group()
self._chapter_group.end_dir_group(ref_group)
def end_all_groups(self):
while self._main_group._successor is not None:
self.end_group()
def end(self):
while self._main_group._successor is not None:
self.end_group()
self.end_group()
time_result = datetime.now() - self._start_time
time_node = self.get_root().xpath('/html/body/div[@class="iteration-execution-time"]')[0]
status_node = self.get_root().xpath('/html/body/div[@class="iteration-status"]')[0]
self._config.end_iteration_func(
time_node, status_node, time_result.total_seconds(), self.get_result())
super().end()

29
log/html_file_log.py Normal file
View File

@@ -0,0 +1,29 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from log.base_log import BaseLog
from lxml.html import fromstring
from lxml.html import tostring
class HtmlFileLog(BaseLog):
def __init__(self, file_path, title):
super().__init__(title)
self.__path = file_path
with open(file_path) as file_stream:
self.__root = fromstring(file_stream.read())
node_list = self.__root.xpath('/html/head/title')
node_list[0].text = title
def get_path(self):
return self.__path
def get_root(self):
return self.__root
def end(self):
with open(self.__path, "wb") as file:
x = tostring(self.__root)
file.write(x)

13
log/html_iteration_log.py Normal file
View File

@@ -0,0 +1,13 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from log.html_file_item_log import HtmlFileItemLog
class HtmlIterationLog(HtmlFileItemLog):
def __init__(self, test_title, iteration_title, config):
self.iteration_closed: bool = False
html_file = config.create_iteration_file()
super().__init__(html_file, test_title, config, iteration_title)

204
log/html_log_config.py Normal file
View File

@@ -0,0 +1,204 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
import os
from os import path, environ, makedirs
from datetime import datetime
from shutil import copyfile
from lxml.etree import Element
from log.base_log import BaseLogResult
from log.presentation_policy import null_policy
def convert_seconds_to_str(time_in_sec):
h = str(int(time_in_sec / 3600) % 24).zfill(2)
m = str(int(time_in_sec / 60) % 60).zfill(2)
s = str(int(time_in_sec % 60)).zfill(2)
time_msg = f"{h}:{m}:{s} [s]"
if time_in_sec > 86400:
time_msg = f"{int(time_in_sec // (3600 * 24))}d {time_msg}"
return time_msg
class HtmlLogConfig:
STYLE = {
BaseLogResult.DEBUG: 'debug',
BaseLogResult.PASSED: '',
BaseLogResult.WORKAROUND: 'workaround',
BaseLogResult.WARNING: 'warning',
BaseLogResult.SKIPPED: 'skip',
BaseLogResult.FAILED: 'fail',
BaseLogResult.BLOCKED: 'blocked',
BaseLogResult.CRITICAL: 'critical',
BaseLogResult.EXCEPTION: 'exception'}
__MAIN = 'main'
__SETUP = 'setup'
__T_ITERATION = 'iteration'
__FRAMEWORK_T_FOLDER = 'template'
MAIN = __MAIN + '.html'
CSS = __MAIN + '.css'
JS = __MAIN + '.js'
ITERATION_FOLDER = 'iterations'
SETUP = __SETUP + ".html"
def iteration(self):
return f'{HtmlLogConfig.__T_ITERATION}_{str(self._iteration_id).zfill(3)}.html'
def __init__(self, base_dir=None, presentation_policy=null_policy):
self._log_base_dir = base_dir
if base_dir is None:
if os.name == 'nt':
self._log_base_dir = 'c:\\History'
else:
if environ["USER"] == 'root':
self._log_base_dir = '/root/history'
else:
self._log_base_dir = f'/home/{environ["USER"]}'
self._log_dir = None
self._presentation_policy = {}
self.register_presentation_policy(str, presentation_policy)
self._iteration_id = 0
def get_iteration_id(self):
return self._iteration_id
def get_policy(self, type):
return self._presentation_policy[type]
def get_policy_collection(self):
for type, policy in self._presentation_policy.items():
yield policy
def register_presentation_policy(self, type, presentation_policy):
self._presentation_policy[type] = presentation_policy
def __find_template_file(self, name, relative_path=None):
base_dir = path.dirname(path.abspath(__file__))
file_path = path.join(base_dir, HtmlLogConfig.__FRAMEWORK_T_FOLDER)
if relative_path is not None:
file_path = path.join(file_path, relative_path)
file_path = path.join(file_path, name)
if path.isfile(file_path):
return file_path
else:
raise Exception(
f"Unable to find file: {name} in location: {os.path.dirname(file_path)}")
def __get_main_template_file_path(self):
return self.__find_template_file(HtmlLogConfig.MAIN)
def _get_setup_template_file_path(self):
return self.__find_template_file(HtmlLogConfig.SETUP, HtmlLogConfig.ITERATION_FOLDER)
def __get_iteration_template_path(self):
return self.__find_template_file(HtmlLogConfig.__T_ITERATION + '.html',
HtmlLogConfig.ITERATION_FOLDER)
def create_html_test_log(self, test_title):
now = datetime.now()
time_stamp = f"{now.year}_{str(now.month).zfill(2)}_{str(now.day).zfill(2)}_" \
f"{str(now.hour).zfill(2)}_{str(now.minute).zfill(2)}_{str(now.second).zfill(2)}"
self._log_dir = path.join(self._log_base_dir, test_title, time_stamp)
makedirs(self._log_dir)
additional_location = path.join(self._log_dir, HtmlLogConfig.ITERATION_FOLDER)
makedirs(additional_location)
dut_info_folder = path.join(self._log_dir, 'dut_info')
makedirs(dut_info_folder)
main_html = self.__get_main_template_file_path()
main_css = main_html.replace('html', 'css')
main_js = main_html.replace('html', 'js')
copyfile(main_html, path.join(self._log_dir, HtmlLogConfig.MAIN))
copyfile(main_css, path.join(self._log_dir, HtmlLogConfig.CSS))
copyfile(main_js, path.join(self._log_dir, HtmlLogConfig.JS))
copyfile(self._get_setup_template_file_path(), path.join(additional_location,
HtmlLogConfig.SETUP))
return self._log_dir
def get_main_file_path(self):
return path.join(self._log_dir, HtmlLogConfig.MAIN)
def get_setup_file_path(self):
return path.join(self._log_dir, HtmlLogConfig.ITERATION_FOLDER, HtmlLogConfig.SETUP)
def create_iteration_file(self):
self._iteration_id += 1
template_file = self.__get_iteration_template_path()
new_file_name = self.iteration()
result = path.join(self._log_dir, HtmlLogConfig.ITERATION_FOLDER, new_file_name)
copyfile(template_file, result)
return result
def end_iteration(self,
iteration_selector_div,
iteration_selector_select,
iteration_id,
iteration_result):
style = "iteration-selector"
if iteration_result != BaseLogResult.PASSED:
style = f'{style} {HtmlLogConfig.STYLE[iteration_result]}'
if iteration_id and iteration_id % 8 == 0:
new_element = Element("br")
iteration_selector_div[0].append(new_element)
new_element = Element("a")
new_element.set('class', style)
new_element.set('onclick', f"selectIteration('{iteration_id}')")
new_element.text = str(iteration_id)
iteration_selector_div[0].append(new_element)
new_element = Element('option', value=f"{iteration_id}")
new_element.text = 'iteration_' + str(iteration_id).zfill(3)
if iteration_result != BaseLogResult.PASSED:
new_element.set('class', HtmlLogConfig.STYLE[iteration_result])
iteration_selector_select.append(new_element)
def end_setup_iteration(self, iteration_selector_div, iteration_selector_select, log_result):
if log_result != BaseLogResult.PASSED:
a_element = iteration_selector_div[0]
select_element = iteration_selector_select[0]
a_element.set('class', f'iteration-selector {HtmlLogConfig.STYLE[log_result]}')
select_element.set('class', HtmlLogConfig.STYLE[log_result])
def end_iteration_func(self, time_node, status_node, time_in_sec, log_result):
time_node.text = f"Execution time: {convert_seconds_to_str(time_in_sec)}"
status_node.text = f"Iteration status: {log_result.name}"
if log_result != BaseLogResult.PASSED:
status_node.set('class', f'iteration-status {HtmlLogConfig.STYLE[log_result]}')
def end_main_log(self, test_status_div, log_result):
if log_result != BaseLogResult.PASSED:
test_status_div[0].set('class',
f"sidebar-test-status {HtmlLogConfig.STYLE[log_result]}")
test_status_div[0].text = f"Test status: {log_result.name}"
def group_end(self, msg_id, html_header, html_container, log_result):
html_header.set('onclick', f"showHide('ul_{msg_id}')")
sub_element = Element('a', href="#top")
sub_element.text = "[TOP]"
sub_element.set('class', "top-time-marker")
html_header.append(sub_element)
div_style = 'test-group-step'
ul_style = 'iteration-content'
if log_result == BaseLogResult.PASSED:
html_container.set('style', "display: none;")
else:
div_style = f"{div_style} {HtmlLogConfig.STYLE[log_result]}"
ul_style = f"{ul_style} {HtmlLogConfig.STYLE[log_result]}"
html_header.set('class', div_style)
html_container.set('class', ul_style)
def group_chapter_end(self, time_in_sec, html_header, html_container, log_result):
sub_element = Element('a')
sub_element.text = convert_seconds_to_str(time_in_sec)
sub_element.set('class', 'top-marker')
html_header.append(sub_element)
div_style = 'test-group-step'
ul_style = 'iteration-content'
if log_result != BaseLogResult.PASSED:
div_style = f"{div_style} {HtmlLogConfig.STYLE[log_result]}"
ul_style = f"{ul_style} {HtmlLogConfig.STYLE[log_result]}"
html_header.set('class', div_style)
html_container.set('class', ul_style)

126
log/html_log_manager.py Normal file
View File

@@ -0,0 +1,126 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from log.base_log import BaseLog, escape
from log.html_iteration_log import HtmlIterationLog
from log.html_log_config import HtmlLogConfig
from log.html_main_log import HtmlMainLog
from log.html_setup_log import HtmlSetupLog
class HtmlLogManager(BaseLog):
def __init__(self, begin_message=None, log_config=None):
super().__init__(begin_message)
self._config = HtmlLogConfig() if log_config is None else log_config
self._main = None
self._log_setup = None
self._log_iterations = []
self._current_log = None
self._files_path = None
def __add(self, msg):
pass
def begin(self, message):
self._files_path = self._config.create_html_test_log(message)
self._main = HtmlMainLog(message, self._config)
self._log_setup = HtmlSetupLog(message, config=self._config)
self._current_log = self._log_setup
self._main.begin(message)
self._current_log.begin(message)
self.__add("begin: " + message)
@property
def base_dir(self):
return self._files_path
def get_result(self):
log_result = self._log_setup.get_result()
for iteration in self._log_iterations:
if log_result.value < iteration.get_result().value:
log_result = iteration.get_result()
return log_result
def end(self):
self._log_setup.end()
self._main.end_setup_iteration(self._log_setup.get_result())
log_result = self.get_result()
self._main.end(log_result)
self.__add("end")
def add_build_info(self, message):
self._main.add_build_info(escape(message))
def start_iteration(self, message):
message = escape(message)
self._log_iterations.append(HtmlIterationLog(message, message, self._config))
self._main.start_iteration(self._config.get_iteration_id())
self._current_log = self._log_iterations[-1]
self._current_log.begin(message)
self._log_setup.start_iteration(message)
self.__add("start_iteration: " + message)
def end_iteration(self):
self._current_log.end()
self._main.end_iteration(self._current_log.get_result())
self._log_setup.end_iteration(self._current_log.get_result())
self._current_log.iteration_closed = True
self._current_log = self._log_setup
self.__add("end_iteration: ")
return self._current_log
def debug(self, message):
self._current_log.debug(escape(message))
self.__add("debug: " + message)
def info(self, message):
self._current_log.info(escape(message))
self.__add("info: " + message)
def workaround(self, message):
self._current_log.workaround(escape(message))
self.__add(": " + message)
def warning(self, message):
self._current_log.warning(escape(message))
self.__add(": " + message)
def skip(self, message):
self._current_log.skip(escape(message))
self.__add("warning: " + message)
def error(self, message):
self._current_log.error(escape(message))
self.__add("error: " + message)
def blocked(self, message):
self._current_log.blocked(escape(message))
self.__add(f'blocked: {message}')
self.end_all_groups()
def exception(self, message):
self._current_log.exception(escape(message))
self.__add("exception: " + message)
self.end_all_groups()
def critical(self, message):
self._current_log.critical(escape(message))
self.__add("critical: " + message)
self.end_all_groups()
def start_group(self, message):
self._current_log.start_group(escape(message))
self.__add("start_group: " + message)
def end_group(self):
self._current_log.end_group()
self.__add("end_group")
def end_all_groups(self):
for iteration in reversed(self._log_iterations):
if not iteration.iteration_closed:
self.end_iteration()
self._current_log.end_all_groups()

53
log/html_main_log.py Normal file
View File

@@ -0,0 +1,53 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from log.html_file_log import HtmlFileLog
from lxml.etree import Element
class HtmlMainLog(HtmlFileLog):
def __init__(self, title, config):
super().__init__(config.get_main_file_path(), title)
self._config = config
self.__current_iteration_id = None
root = self.get_root()
test_title_div = root.xpath('/html/body/div/div/div/div[@class="sidebar-test-title"]')[0]
test_title_div.text = title
self.__build_information_set = root.xpath(
'/html/body/div/div/div/div[@id="sidebar-tested-build"]')[0]
def add_build_info(self, message):
build_info = Element("div")
build_info.text = message
self.__build_information_set.append(build_info)
def start_iteration(self, iteration_id):
self.__current_iteration_id = iteration_id
def end_iteration(self):
pass
def end_iteration(self, iteration_result):
root = self.get_root()
iteration_selector_div = root.xpath('/html/body/div/div/div[@id="iteration-selector"]')
iteration_selector_select = root.xpath(
'/html/body/div/div/select[@id="sidebar-iteration-list"]')[0]
self._config.end_iteration(iteration_selector_div,
iteration_selector_select,
self.__current_iteration_id,
iteration_result)
def end_setup_iteration(self, result):
root = self.get_root()
iteration_selector_div = root.xpath('/html/body/div/div/div[@id="iteration-selector"]')[0]
iteration_selector_select = root.xpath(
'/html/body/div/div/select[@id="sidebar-iteration-list"]')[0]
self._config.end_setup_iteration(iteration_selector_div, iteration_selector_select, result)
def end(self, result):
root = self.get_root()
test_status_div = root.xpath('/html/body/div/div/div/div[@class="sidebar-test-status"]')
self._config.end_main_log(test_status_div, result)
super().end()

View File

@@ -0,0 +1,45 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from log.base_log import BaseLogResult
from lxml.etree import Element
from datetime import datetime
from log.presentation_policy import PresentationPolicy
from log.html_log_config import HtmlLogConfig
def std_log_entry(msg_id, msg, log_result, html_node):
test_step = Element('li')
style = 'test-step'
if log_result != BaseLogResult.PASSED:
style = f"{style} {HtmlLogConfig.STYLE[log_result]}"
test_step.set('class', style)
test_time = Element('div')
test_time.set('class', 'ts-time')
test_time_txt = Element('a', name=msg_id)
time = datetime.now()
test_time_txt.text = f"{str(time.hour).zfill(2)}:" \
f"{str(time.minute).zfill(2)}:{str(time.second).zfill(2)}"
test_time.append(test_time_txt)
test_step.append(test_time)
test_msg = Element('div')
test_msg.set('class', 'ts-msg')
test_msg.text = msg
test_step.append(test_msg)
html_node.append(test_step)
def group_log_begin(msg_id, msg, html_node):
element = Element("div")
sub_element = Element('a', name=msg_id)
sub_element.text = msg
element.append(sub_element)
html_node.append(element)
ul_set = Element('ul', id=f'ul_{msg_id}')
html_node.append(ul_set)
return element, ul_set
html_policy = PresentationPolicy(std_log_entry, group_log_begin)

34
log/html_setup_log.py Normal file
View File

@@ -0,0 +1,34 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
from log.html_file_item_log import HtmlFileItemLog
from log.base_log import BaseLogResult
class HtmlSetupLog(HtmlFileItemLog):
LOG_RESULT = {
BaseLogResult.PASSED: HtmlFileItemLog.info,
BaseLogResult.WORKAROUND: HtmlFileItemLog.workaround,
BaseLogResult.WARNING: HtmlFileItemLog.warning,
BaseLogResult.SKIPPED: HtmlFileItemLog.skip,
BaseLogResult.FAILED: HtmlFileItemLog.error,
BaseLogResult.BLOCKED: HtmlFileItemLog.blocked,
BaseLogResult.EXCEPTION: HtmlFileItemLog.exception,
BaseLogResult.CRITICAL: HtmlFileItemLog.critical}
def __init__(self, test_title, config, iteration_title="Test summary"):
html_file_path = config.get_setup_file_path()
super().__init__(html_file_path, test_title, config, iteration_title)
self._last_iteration_title = ''
def start_iteration(self, message):
self._last_iteration_title = message
def end_iteration(self, iteration_result):
HtmlSetupLog.LOG_RESULT[iteration_result](self, self._last_iteration_title)
def end(self):
super().end()

220
log/logger.py Normal file
View File

@@ -0,0 +1,220 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
import logging
import os
import sys
from contextlib import contextmanager
from datetime import datetime
from threading import Lock
import portalocker
from log.html_log_config import HtmlLogConfig
from log.html_log_manager import HtmlLogManager
from log.html_presentation_policy import html_policy
from test_utils.output import Output
from test_utils.singleton import Singleton
def create_log(log_base_path, test_module, additional_args=None):
Log.setup()
log_cfg = HtmlLogConfig(base_dir=log_base_path,
presentation_policy=html_policy)
log = Log(log_config=log_cfg)
test_name = 'TestNameError'
error_msg = None
try:
test_name = test_module
if additional_args:
test_name += f"__{'_'.join(additional_args)}"
except Exception as ex:
error_msg = f'Detected some problems during calculating test name: {ex}'
finally:
log.begin(test_name)
print(f"\n<LogFile>{os.path.join(log.base_dir, 'main.html')}</LogFile>")
if error_msg:
log.exception(error_msg)
return log
class Log(HtmlLogManager, metaclass=Singleton):
logger = None
LOG_FORMAT = '%(asctime)s %(levelname)s:\t%(message)s'
DATE_FORMAT = "%Y/%m/%d %H:%M:%S"
command_id = 0
lock = Lock()
@classmethod
def destroy(cls):
del cls._instances[cls]
@classmethod
def setup(cls):
# Get handle to root logger.
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# Set paramiko log level to warning
logging.getLogger('paramiko').setLevel(logging.WARNING)
# Create Handlers.
stdout_handler = logging.StreamHandler(sys.stdout)
# Set logging level on handlers.
stdout_handler.setLevel(logging.DEBUG)
# Set log formatting on each handler.
formatter = logging.Formatter(Log.LOG_FORMAT, Log.DATE_FORMAT)
stdout_handler.setFormatter(formatter)
# Attach handlers to root logger.
logger.handlers = []
logger.addHandler(stdout_handler)
cls.logger = logger
logger.info("Logger successfully initialized.")
@contextmanager
def step(self, message):
self.step_info(message)
super(Log, self).start_group(message)
if Log.logger:
Log.logger.info(message)
yield
super(Log, self).end_group()
@contextmanager
def group(self, message):
self.start_group(message)
yield
self.end_group()
def add_build_info(self, msg):
super(Log, self).add_build_info(msg)
if Log.logger:
Log.logger.info(msg)
def info(self, msg):
super(Log, self).info(msg)
if Log.logger:
Log.logger.info(msg)
def debug(self, msg):
super(Log, self).debug(msg)
if Log.logger:
Log.logger.debug(msg)
def error(self, msg):
super(Log, self).error(msg)
if Log.logger:
Log.logger.error(msg)
def blocked(self, msg):
super(Log, self).blocked(msg)
if Log.logger:
Log.logger.fatal(msg)
def exception(self, msg):
super(Log, self).exception(msg)
if Log.logger:
Log.logger.exception(msg)
def critical(self, msg):
super(Log, self).critical(msg)
if Log.logger:
Log.logger.fatal(msg)
def workaround(self, msg):
super(Log, self).workaround(msg)
if Log.logger:
Log.logger.warning(msg)
def warning(self, msg):
super(Log, self).warning(msg)
if Log.logger:
Log.logger.warning(msg)
def get_new_command_id(self):
self.lock.acquire()
command_id = self.command_id
self.command_id += 1
self.lock.release()
return command_id
def write_to_command_log(self, message):
super(Log, self).debug(message)
command_log_path = os.path.join(self.base_dir, "dut_info", 'commands.log')
timestamp = datetime.now().strftime('%Y-%m-%d_%H:%M:%S:%f')
with portalocker.Lock(command_log_path, "ab+") as command_log:
line_to_write = f"[{timestamp}] {message}\n"
command_log.write(line_to_write.encode())
def write_command_to_command_log(self, command, command_id, info=None):
added_info = "" if info is None else f"[{info}] "
self.write_to_command_log(f"{added_info}Command id: {command_id}\n{command}")
def write_output_to_command_log(self, output: Output, command_id):
if output is not None:
line_to_write = f"Command id: {command_id}\n\texit code: {output.exit_code}\n" \
f"\tstdout: {output.stdout}\n" \
f"\tstderr: {output.stderr}\n\n\n"
self.write_to_command_log(line_to_write)
else:
self.write_to_command_log(f"Command id: {command_id}\n\tNone output.")
def step_info(self, step_name):
from core.test_run import TestRun
decorator = "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //\n\n"
message = f"\n\n\n{decorator}{step_name}\n\n{decorator}\n"
try:
serial_monitor = TestRun.plugin_manager.get_plugin("serial_monitor")
serial_monitor.send_to_serial(message)
except (KeyError, AttributeError):
pass
self.write_to_command_log(message)
def get_additional_logs(self):
from core.test_run import TestRun
from test_tools.fs_utils import check_if_file_exists
messages_log = "/var/log/messages"
if not check_if_file_exists(messages_log):
messages_log = "/var/log/syslog"
log_files = {"messages.log": messages_log,
"dmesg.log": "/tmp/dmesg"}
extra_logs = TestRun.config.get("extra_logs", {})
log_files.update(extra_logs)
TestRun.executor.run(f"dmesg > {log_files['dmesg.log']}")
for log_name, log_source_path in log_files.items():
try:
log_destination_path = os.path.join(
self.base_dir, f"dut_info", TestRun.dut.ip, log_name
)
TestRun.executor.rsync_from(log_source_path, log_destination_path)
except Exception as e:
TestRun.LOGGER.warning(
f"There was a problem during gathering {log_name} log.\n{str(e)}"
)
def generate_summary(self, item, meta):
import json
summary_path = os.path.join(self.base_dir, 'info.json')
with open(summary_path, "w+") as summary:
data = {
'module': os.path.relpath(item.fspath, os.getcwd()),
'function': item.name,
'meta': meta,
'status': self.get_result().name,
'path': os.path.normpath(self.base_dir),
'stage_status': {
'setup': getattr(item, "rep_setup", {}),
'call': getattr(item, "rep_call", {}),
'teardown': getattr(item, "rep_teardown", {})
}
}
json.dump(data, summary)

View File

@@ -0,0 +1,21 @@
#
# Copyright(c) 2019-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
class PresentationPolicy:
def __init__(self, standard_log, group_begin_func):
self.standard = standard_log
self.group_begin = group_begin_func
def std_log_entry(msg_id, msg, log_result, html_node):
pass
def group_log_begin(msg_id, msg, html_node):
return html_node, html_node
null_policy = PresentationPolicy(std_log_entry, group_log_begin)

View File

@@ -0,0 +1,35 @@
<!--
Copyright(c) 2019-2021 Intel Corporation
SPDX-License-Identifier: BSD-3-Clause
-->
<html>
<head>
<title>[title]</title>
<link rel="stylesheet" type="text/css" href="../main.css"/>
<script src="../main.js"></script>
<meta charset="UTF-8"/>
</head>
<body onload="onLoadDocument();">
<div class="floating">
<b>View: </b>
<select id="mode-selector" onchange="selectMode();">
<option style="background-color: white; color: black;" value="info">Info</option>
<option style="background-color: white; color: black" value="debug">Debug</option>
</select>
<b>Errors: </b>
<button onclick="previousError()"><</button>
<select id="error-list-selector" onchange="errorSelected('error-list-selector')">
<option value="top" class="empty">-empty-</option>
</select>
<button onclick="nextError()">></button>
</div>
<br/>
<a name="top"><h1 class="iteration-title" style="border-bottom: 4px solid rgba(255, 0, 0, 1)">[title]</h1></a>
<div class="iteration-status">Iteration status: [status]</div>
<div class="iteration-execution-time">Execution time: [time] [s]</div>
<section class="iteration-chapters" id="iteration-chapters">
<h2>Groups:</h2>
</section>
</body>
</html>

View File

@@ -0,0 +1,37 @@
<!--
Copyright(c) 2019-2021 Intel Corporation
SPDX-License-Identifier: BSD-3-Clause
-->
<html>
<head>
<title>Setup</title>
<link rel="stylesheet" type="text/css" href="../main.css"/>
<meta charset="UTF-8"/>
<script src="../main.js"></script>
</head>
<body onload="onLoadDocument();">
<div class="floating">
<b>View: </b>
<select id="mode-selector" onchange="selectMode();">
<option style="background-color: white; color: black;" value="info">Info</option>
<option style="background-color: white; color: black" value="debug">Debug</option>
</select>
<b>Errors: </b>
<button onclick="previousError()"><</button>
<select id="error-list-selector" onchange="errorSelected('error-list-selector')">
<option value="top">-empty-</option>
</select>
<button onclick="nextError()">></button>
</div>
<br/>
<a name="top">
<h1 class="iteration-title" style="border-bottom: 4px solid rgba(255, 0, 0, 1)">Test summary</h1>
</a>
<div class="iteration-status">Iteration status: [STATUS]</div>
<div class="iteration-execution-time">Execution time: [time] [s]</div>
<section class="iteration-chapters" id="iteration-chapters">
<h2>Groups:</h2>
</section>
</body>
</html>

383
log/template/main.css Normal file
View File

@@ -0,0 +1,383 @@
/*
Copyright(c) 2019-2021 Intel Corporation
SPDX-License-Identifier: BSD-3-Clause
*/
html, body {
margin: 0;
padding: 0;
background-color: #F0F0F0;
font-family: Calibri;
color: black;
}
div { display: block; }
h2 { margin: 0; padding: 0; }
h4 { margin: 0; padding: 0; }
div.meta-container {
margin-left: 502px;
min-width: 500px;
height: 100vh;
}
div.main-layaut {
float: right;
width: 100%;
background-color: #FDFDFD;
height: 100vh;
overflow-y: scroll;
overflow-x: hidden;
}
div.sidebar {
float: left;
width: 500px;
height: 100vh;
margin-left: -502px;
border: 4px;
background-color: #F0F0F0;
overflow-x: hidden;
overflow-y: auto;
text-align: center;
color: white;
overflow-x: hidden;
overflow-y: hidden;
}
div.sidebar-hide {
padding: 3px;
height: 20px;
margin: 5px auto;
font-family: Consolas;
font-weight: normal;
font-size: 15px;
color: white;
text-shadow: 1px 1px 3px black;
background-color: rgb(40,80,180);
cursor: default;
border: 2px solid silver;
border-radius: 25px;
}
div.sidebar-show { color: balck; height: 50%; }
div.sidebar-test { overflow-x: hidden; overflow-y: hidden;}
div.sidebar-test-title {
padding: 10px;
height: 40px;
margin: 5px auto;
background-color: rgb(40,80,180);
font-size: 100%;
border: 2px solid silver;
border-radius: 25px;
}
div.sidebar-test-status {
padding: 3px;
height: 20px;
background-color: green;
border: 2px solid silver;
border-radius: 25px;
}
div.sidebar-tested-build {
color: black;
border-radius: 25px;
width: 80%;
margin: 5px auto;
padding: 25px;
background-color: #F7F7F7;
border: 1px solid silver;
word-wrap: break-word;
word-break: break-all;
overflow: hidden;
text-align: left;
}
div.sidebar-test-iteration {
padding: 3px;
height: 20px;
margin: 5px auto;
font-family: Consolas;
font-weight: normal;
font-size: 15px;
color: white;
text-shadow: 1px 1px 3px black;
background-color: rgb(40,80,180);
cursor: default;
border: 2px solid silver;
border-radius: 25px;
}
.debug { display: none; }
select.sidebar-iteration-list {
margin: 5px auto;
background-color: white;
color: black;
width: 90%;
}
select.warning { background-color: #ff0; color: black; }
select.workaround { background-color: #fff8dc; color: black; }
select.skip { background-color: silver; color: black; }
select.fail { background-color: red; color: white; }
select.blocked { background-color: #7030a0; color: white; }
select.exception { background-color: #e29517; color: white; }
select.critical { background-color: #002060; color: white; }
option {
background-color: green;
color: white;
margin: 2px;
}
option.warning { background-color: #ff0; color: black; }
option.workaround { background-color: #fff8dc; color: black; }
option.skip { background-color: silver; color: black; }
option.error { background-color: red; color: white; }
option.blocked { background-color: #7030a0; color: white; }
option.exception { background-color: #e29517; color: white; }
select.critical { background-color: #002060; color: white; }
a.iteration-selector {
border: 2px solid silver;
border-radius: 40px;
width: 36px;
height: 36px;
margin: 0;
padding: 0;
vertical-align: middle;
display: table-cell;
color: white;
background-color: green;
text-shadow: 0 0 3px black;
font-size: 20px;
font-weight: bold;
line-height: 1em;
text-align: center;
cursor: pointer;
}
a.warning { background-color: #ff0; }
a.workaround { background-color: #fff8dc; }
a.skip { background-color: silver; }
a.fail { background-color: red; }
a.exception { background-color: #e29517; }
a.blocked { background-color: #7030a0; }
a.critical { background-color: #002060; }
a.selected { border: 2px solid black; }
select.error-list-selector { background-color: silver; }
div.test-chapter-step {
margin: 4px auto;
border-style: solid;
border-color: #8CB9AE;
border-radius: 10px;
padding-left: 10px;
padding-right: 10px;
cursor: pointer;
}
div.sidebar-copyright {
position: absolute;
background-color: #DDD;
text-align: center;
padding: 4px;
color: #888;
bottom: 0;
font-size: 12px;
font-family: Consolas;
}
div.floating {
right: 0;
border: 3px solid silver;
width: 40%;
text-align: center;
vertical-align: top;
position: fixed;
background-color : #F0F0F0;
border-bottom: 1px solid #999;
z-index: 999;
color: #333;
box-shadow: 0 0px 6px gray;
}
h1 {
display: block;
font-size: 2em;
font-weight: bold;
}
div.iteration-selector {
margin: 5px auto;
}
div.iteration-status {
padding: 3px;
height: 20px;
background-color: green;
border: 2px solid silver;
border-radius: 25px;
color: white;
text-align: center;
}
h1.iteration-title { text-align: center; }
div.iteration-execution-time { text-align: center; }
section.iteration-chapters {
border-radius: 25px;
width: 80%;
margin: 10px auto;
padding: 25px;
background-color: #F7F7F7;
border: 1px solid silver;
word-wrap: break-word;
word-break: break-all;
overflow: hidden;
}
ul.iteration-content {
list-style-type: none;
border-left-color: green;
border-left-style: solid;
margin: 0px;
}
ul.warning { border-left-color: #ff0; }
ul.workaround { border-left-color: #fff8dc; }
ul.skip { border-left-color: silver; }
ul.fail { border-left-color: red; }
ul.blocked { border-left-color: #7030a0; }
ul.critical { border-left-color: #002060; }
ul.exception { border-left-color: #e29517; }
li.iteration-content {
border-color: rgba(192, 192, 192, 1);
background-color: rgba(238, 238, 238, 1);
display: block;
margin: 2px auto;
border: 1px solid #C0C0C0;
padding: 3px 6px;
font-family: Calibri;
font-size: 16px;
line-height: 1.15em;
word-wrap: break-word;
word-break: break-all;
overflow: hidden;
border-left-color: green;
border-left-style: solid;
word-break: break-all;
}
div.test-group-step {
color: black;
background-color: #8CB9AE;
border: 1px solid #5C8880;
font-size: 18px;
letter-spacing: 2px;
cursor: pointer;
margin: 4px;
border-radius: 10px;
padding-left: 10px;
padding-right: 10px;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-all;
}
div.warning { background-color: #ff0; color: black; }
div.workaround { background-color: #fff8dc; color: black; }
div.skip { background-color: silver; color: black; }
div.fail { background-color: red; color: white; }
div.blocked { background-color: #7030a0; color: white; }
div.critical { background-color: #002060; color: white; }
div.exception { background-color: #e29517; color: white; }
a.top-marker { cursor: pointer; float: right; }
a.top-time-marker {
word-wrap: break-word;
float: right;
}
li.test-step {
color: black;
border-color: rgba(192, 192, 192, 1);
background-color: rgba(238, 238, 238, 1);
display: block;
margin: 4px auto;
border: 1px solid #C0C0C0;
padding: 3px 6px;
font-family: Calibri;
font-size: 16px;
line-height: 1.15em;
word-wrap: break-word;
word-break: break-all;
overflow: hidden;
border-left-color: green;
border-left-style: solid;
border-radius: 10px;
padding-left: 10px;
padding-right: 10px
}
li.warning { background-color: #ff0; border-left-color: #ff0; }
li.workaround { background-color: #fff8dc; border-left-color: #fff8dc; }
li.skip { background-color: silver; border-left-color: silver; }
li.fail {
background-color: red;
border-left-color: red;
color: white;
}
li.blocked {
background-color: #7030a0;
border-left-color: #7030a0;
color: white;
}
li.exception {
background-color: #e29517;
border-left-color: #e29517;
color: white;
}
li.critical {
background-color: #002060;
border-left-color: #002060;
color: white;
}
div.ts-iteration {
float: left;
margin: 2px auto;
border: 1px solid silver;
padding: 3px 3px;
text-align: center;
}
div.ts-total-time {
margin: 2px auto;
border: 1px solid silver;
padding: 3px 3px;
text-align: right;
}
div.ts-time {
float: left;
font-size: 12px;
margin: 2px auto;
border: 1px solid #A7A7A7;
padding: 3px 3px;
}
div.ts-msg {
font-size: 16px;
font-family: Courier;
margin: 2px auto;
border: 1px solid #A7A7A7;
padding: 3px 3px;
white-space: pre-wrap;
word-break: break-all;
}

44
log/template/main.html Normal file
View File

@@ -0,0 +1,44 @@
<!--
Copyright(c) 2019-2021 Intel Corporation
SPDX-License-Identifier: BSD-3-Clause
-->
<html>
<head>
<title>[test title]</title>
<link rel="stylesheet" type="text/css" href="main.css">
<meta charset="UTF-8"/>
</head>
<body>
<div class="meta-container">
<div class="sidebar">
<div class="sidebar-test" id="sidebar-test">
<div class="sidebar-show" style="display:none" onclick="sidebarCtrl('sidebar-hide', 'sidebar-show')">&gt;&gt;</div>
<div class="sidebar-test-title">Test title: </div>
<div class="sidebar-test-status">Test status: </div>
<div class="sidebar-tested-build" id="sidebar-tested-build">
<h2>Build:</h2>
</div>
<div class="sidebar-hide" id=sidebar-hide" onclick="sidebarCtrl('sidebar-hide', 'sidebar-show')">&lt;&lt;</div>
<div class="sidebar-show" style="display:none" onclick="sidebarCtrl('sidebar-hide', 'sidebar-show')">&gt;&gt;</div>
</div>
<div class="sidebar-test-iteration">Executed iterations:</div>
<select id="sidebar-iteration-list" class="sidebar-iteration-list" onchange="selectIterationFromSelect()" onclick="clickSelectIteration()">
<option value="M">Setup</option>
</select>
<div id="iteration-selector">
<a class="iteration-selector" onclick="selectIteration('M')">M</a>
</div>
<div class="sidebar-copyright" id="sidebar-copyright">
SPDX-License-Identifier: BSD-3-Clause
<br>
Copyright &#xa9 2015-2021 Intel Corporation
</div>
</div>
<div class="main-layaut">
<iframe id="main-view" src="iterations/setup.html" width="100%" height="99%"></iframe>
</div>
</div>
<script src="main.js"></script>
</body>
</html>

223
log/template/main.js Normal file
View File

@@ -0,0 +1,223 @@
/*
Copyright(c) 2019-2021 Intel Corporation
SPDX-License-Identifier: BSD-3-Clause
*/
function onLoadDocument() {
hideDebug();
}
function selectMode() {
var selector = document.getElementById('mode-selector');
if (selector.value.includes('info')) {
hideDebug();
} else {
showDebug();
}
}
function hideDebug() {
var debugTestStepArray = document.getElementsByTagName('li');
for (i = 0; i < debugTestStepArray.length; i ++) {
if(debugTestStepArray[i].className.includes('debug')) {
debugTestStepArray[i].style.display = 'none';
}
}
}
function showDebug() {
var debugTestStepArray = document.getElementsByTagName('li');
for (i = 0; i < debugTestStepArray.length; i ++) {
if(debugTestStepArray[i].className.includes('debug')) {
debugTestStepArray[i].style.display = '';
}
}
}
function sidebarCtrl(ctrlHideId, ctrlShowClass) {
var metaContainer = document.getElementsByClassName("meta-container")[0];
var sidebar = document.getElementsByClassName('sidebar')[0];
var sidebarTest = document.getElementById('sidebar-test');
var ctrlHide = document.getElementById(ctrlHideId);
var ctrlShowSet = document.getElementsByClassName(ctrlShowClass);
if(sidebar.style.width.includes('15px')) {
showSidebar(metaContainer, sidebar, ctrlHide, ctrlShowSet, sidebarTest);
} else {
hideSidebar(metaContainer, sidebar, ctrlHide, ctrlShowSet, sidebarTest);
}
}
function showSidebar(mContainer, sidebar, ctrlHide, ctrlShowSet, sidebarTest) {
sidebar.style.cursor = 'default';
mContainer.style.marginLeft = '';
sidebarTest.style.width = '';
sidebarTest.style.height = '';
sidebar.style.height = '';
sidebar.style.marginLeft = '';
sidebar.style.width = '';
var i;
for (i = 0; i < sidebarTest.children.length; i++) {
sidebarTest.children[i].style.display = '';
}
document.getElementById('iteration-selector').style.display = '';
document.getElementById('sidebar-iteration-list').style.display = '';
document.getElementById('sidebar-copyright').style.display = '';
for(i = 0; i < ctrlShowSet.length; i ++) {
ctrlShowSet[i].style.display = 'none';
}
}
function hideSidebar(mContainer, sidebar, ctrlHide, ctrlShowSet, sidebarTest) {
document.getElementById('iteration-selector').style.display = 'none';
document.getElementById('sidebar-iteration-list').style.display = 'none';
document.getElementById('sidebar-copyright').style.display = 'none';
var i;
for (i = 0; i < sidebarTest.children.length; i++) {
sidebarTest.children[i].style.display = 'none';
}
sidebarTest.style.display = '';
for(i = 0; i < ctrlShowSet.length; i ++) {
ctrlShowSet[i].style.display = '';
ctrlShowSet[i].style.color = 'black';
}
sidebar.style.width = '15px';
sidebar.style.marginLeft = '-15px';
sidebar.style.height = '100%';
sidebarTest.style.height = '100%';
sidebarTest.style.width = '100%';
mContainer.style.marginLeft = '16px';
sidebar.style.cursor = 'pointer';
}
function previousError() {
var errorSelector = document.getElementById("error-list-selector");
if (errorSelector.length > 1) {
var id = errorSelector.selectedIndex;
if (id - 1 > 0) {
errorSelector.selectedIndex = (id - 1);
} else {
errorSelector.selectedIndex = (errorSelector.length - 1);
}
errorSelected('error-list-selector');
}
}
function nextError() {
var errorSelector = document.getElementById("error-list-selector");
if (errorSelector.length > 1) {
var id = errorSelector.selectedIndex;
if (id + 1 < errorSelector.length) {
errorSelector.selectedIndex = (id + 1);
} else {
errorSelector.selectedIndex = 1;
}
errorSelected('error-list-selector');
}
}
function selectIterationFromSelect() {
var element = document.getElementById("sidebar-iteration-list");
loadDocument(element.value);
updateIterationSelector(element);
}
function clickSelectIteration() {
var element = document.getElementById("sidebar-iteration-list");
for (i = 0; i < element.length; i ++) {
option = element[i];
var cls = option.getAttribute('class');
switch(cls) {
case "warning":
option.style.backgroundColor = "yellow";
option.style.color = "black";
break;
case "skip":
option.style.backgroundColor = "silver";
option.style.color = "black";
break;
case "fail":
option.style.backgroundColor = "red";
option.style.color = "white";
break;
case "exception":
option.style.backgroundColor = "blueviolet";
option.style.color = "white";
break;
default:
option.style.backgroundColor = "white";
option.style.color = "black";
break;
}
};
}
function selectIteration(iteration) {
var selectElement = document.getElementById("sidebar-iteration-list");
var docId = loadDocument(iteration);
selectElement.selectedIndex = docId;
updateIterationSelector(selectElement);
}
function loadDocument(fileId) {
var result = 0;
if(fileId == 'M') {
document.getElementById("main-view").src = "iterations/setup.html";
} else {
var id = pad(fileId, 3);
document.getElementById("main-view").src = "iterations/iteration_" + id + ".html";
result = parseInt(fileId);
}
return result;
}
function updateIterationSelector(element) {
var index = element.selectedIndex
var option_class = element[index].getAttribute('class')
if (option_class != null) {
element.setAttribute('class', "sidebar-iteration-list " + option_class);
} else {
element.setAttribute('class', "sidebar-iteration-list");
}
}
function errorSelected(selectorId) {
var newLocation = document.getElementById(selectorId).value;
window.location.hash = newLocation;
}
function pad(strNumber, padding) {
while((strNumber.length + 1) <= padding) {
strNumber = "0" + strNumber;
}
return strNumber;
}
function showHide(id) {
var ulElement = document.getElementById(id);
if(ulElement.style.display == 'none') {
ulElement.style.display = '';
} else {
ulElement.style.display = 'none';
}
}
function chapterClick(id) {
var id_array = id.split('.');
var node_id = "";
var i = 0;
var destinationElement = document.getElementById(id);
if (destinationElement.style.display == 'none') {
do {
node_id += id_array[i];
var ele = document.getElementById(node_id);
ele.style.display = '';
node_id += '.';
i += 1;
} while (i < id_array.length);
window.location = '#' + id;
} else {
destinationElement.style.display = 'none';
}
}