tiny-test-fw: fix misc bugs:

1. configs are not functional
    * decorator will be executed when search case, need to set default config before search case.
2. fix DUT encode/decode errors
    * python3 serial don't support write string/unicode, need to convert to bytes first.
    * python2 string could failed to encode/decode non-acsii chars
3. fix bug that log folder not created
4. fix bug that test suite name is not correctly passed:
    * the keyward arg should be `test_suite_name` not `test_name`
5. fix bug that test stopped on failed case
6. fix DUT `read` don't return all data cache
    * `_DataCache.get_data` should first copy all data from queue to data cache and then return to user.
7. fix bug that `expect_all` failed even all expected item passed
8. optimize error info for expect
    * print pattern for regular expression when match failed
9. fix bug that set default config doesn't work
This commit is contained in:
He Yin Ling
2018-01-16 22:16:03 +08:00
committed by bot
parent 98d1f05ab5
commit 2b068f3ceb
8 changed files with 62 additions and 29 deletions

View File

@@ -78,9 +78,12 @@ class BaseApp(object):
if not test_suite_name: if not test_suite_name:
test_suite_name = os.path.splitext(os.path.basename(sys.modules['__main__'].__file__))[0] test_suite_name = os.path.splitext(os.path.basename(sys.modules['__main__'].__file__))[0]
sdk_path = cls.get_sdk_path() sdk_path = cls.get_sdk_path()
return os.path.join(sdk_path, "TEST_LOGS", log_folder = os.path.join(sdk_path, "TEST_LOGS",
test_suite_name + test_suite_name +
time.strftime("_%m%d_%H_%M_%S", time.localtime(LOG_FOLDER_TIMESTAMP))) time.strftime("_%m%d_%H_%M_%S", time.localtime(LOG_FOLDER_TIMESTAMP)))
if not os.path.exists(log_folder):
os.makedirs(log_folder)
return log_folder
def process_app_info(self): def process_app_info(self):
""" """

View File

@@ -85,6 +85,14 @@ def _decode_data(data):
return data return data
def _pattern_to_string(pattern):
try:
ret = "RegEx: " + pattern.pattern
except AttributeError:
ret = pattern
return ret
class _DataCache(_queue.Queue): class _DataCache(_queue.Queue):
""" """
Data cache based on Queue. Allow users to process data cache based on bytes instead of Queue." Data cache based on Queue. Allow users to process data cache based on bytes instead of Queue."
@@ -94,6 +102,21 @@ class _DataCache(_queue.Queue):
_queue.Queue.__init__(self, maxsize=maxsize) _queue.Queue.__init__(self, maxsize=maxsize)
self.data_cache = str() self.data_cache = str()
def _move_from_queue_to_cache(self):
"""
move all of the available data in the queue to cache
:return: True if moved any item from queue to data cache, else False
"""
ret = False
while True:
try:
self.data_cache += _decode_data(self.get(0))
ret = True
except _queue.Empty:
break
return ret
def get_data(self, timeout=0): def get_data(self, timeout=0):
""" """
get a copy of data from cache. get a copy of data from cache.
@@ -105,12 +128,16 @@ class _DataCache(_queue.Queue):
if timeout < 0: if timeout < 0:
timeout = 0 timeout = 0
try: ret = self._move_from_queue_to_cache()
data = self.get(timeout=timeout)
self.data_cache += _decode_data(data) if not ret:
except _queue.Empty: # we only wait for new data if we can't provide a new data_cache
# don't do anything when on update for cache try:
pass data = self.get(timeout=timeout)
self.data_cache += _decode_data(data)
except _queue.Empty:
# don't do anything when on update for cache
pass
return copy.deepcopy(self.data_cache) return copy.deepcopy(self.data_cache)
def flush(self, index=0xFFFFFFFF): def flush(self, index=0xFFFFFFFF):
@@ -417,7 +444,7 @@ class BaseDUT(object):
data = self.data_cache.get_data(time.time() + timeout - start_time) data = self.data_cache.get_data(time.time() + timeout - start_time)
if ret is None: if ret is None:
raise ExpectTimeout(self.name + ": " + str(pattern)) raise ExpectTimeout(self.name + ": " + _pattern_to_string(pattern))
return ret return ret
def _expect_multi(self, expect_all, expect_item_list, timeout): def _expect_multi(self, expect_all, expect_item_list, timeout):
@@ -457,12 +484,11 @@ class BaseDUT(object):
if expect_item["ret"] is not None: if expect_item["ret"] is not None:
# match succeed for one item # match succeed for one item
matched_expect_items.append(expect_item) matched_expect_items.append(expect_item)
break
# if expect all, then all items need to be matched, # if expect all, then all items need to be matched,
# else only one item need to matched # else only one item need to matched
if expect_all: if expect_all:
match_succeed = (matched_expect_items == expect_items) match_succeed = len(matched_expect_items) == len(expect_items)
else: else:
match_succeed = True if matched_expect_items else False match_succeed = True if matched_expect_items else False
@@ -482,7 +508,7 @@ class BaseDUT(object):
# flush already matched data # flush already matched data
self.data_cache.flush(slice_index) self.data_cache.flush(slice_index)
else: else:
raise ExpectTimeout(self.name + ": " + str(expect_items)) raise ExpectTimeout(self.name + ": " + str([_pattern_to_string(x) for x in expect_items]))
@_expect_lock @_expect_lock
def expect_any(self, *expect_items, **timeout): def expect_any(self, *expect_items, **timeout):

View File

@@ -49,12 +49,12 @@ class Env(object):
dut=None, dut=None,
env_tag=None, env_tag=None,
env_config_file=None, env_config_file=None,
test_name=None, test_suite_name=None,
**kwargs): **kwargs):
self.app_cls = app self.app_cls = app
self.default_dut_cls = dut self.default_dut_cls = dut
self.config = EnvConfig.Config(env_config_file, env_tag) self.config = EnvConfig.Config(env_config_file, env_tag)
self.log_path = self.app_cls.get_log_folder(test_name) self.log_path = self.app_cls.get_log_folder(test_suite_name)
if not os.path.exists(self.log_path): if not os.path.exists(self.log_path):
os.makedirs(self.log_path) os.makedirs(self.log_path)

View File

@@ -53,7 +53,7 @@ class Config(object):
try: try:
with open(config_file) as f: with open(config_file) as f:
configs = yaml.load(f)[env_name] configs = yaml.load(f)[env_name]
except (OSError, TypeError): except (OSError, TypeError, IOError):
configs = dict() configs = dict()
return configs return configs

View File

@@ -40,18 +40,22 @@ class Runner(threading.Thread):
def __init__(self, test_case, case_config, env_config_file=None): def __init__(self, test_case, case_config, env_config_file=None):
super(Runner, self).__init__() super(Runner, self).__init__()
self.setDaemon(True) self.setDaemon(True)
test_methods = SearchCases.Search.search_test_cases(test_case)
self.test_cases = CaseConfig.Parser.apply_config(test_methods, case_config)
self.test_result = True
if case_config: if case_config:
test_suite_name = os.path.splitext(os.path.basename(case_config))[0] test_suite_name = os.path.splitext(os.path.basename(case_config))[0]
else: else:
test_suite_name = "TestRunner" test_suite_name = "TestRunner"
TinyFW.set_default_config(env_config_file=env_config_file, test_suite_name=test_suite_name) TinyFW.set_default_config(env_config_file=env_config_file, test_suite_name=test_suite_name)
test_methods = SearchCases.Search.search_test_cases(test_case)
self.test_cases = CaseConfig.Parser.apply_config(test_methods, case_config)
self.test_result = []
def run(self): def run(self):
for case in self.test_cases: for case in self.test_cases:
self.test_result = self.test_result and case.run() result = case.run()
self.test_result.append(result)
def get_test_result(self):
return self.test_result and all(self.test_result)
if __name__ == '__main__': if __name__ == '__main__':
@@ -76,5 +80,5 @@ if __name__ == '__main__':
except KeyboardInterrupt: except KeyboardInterrupt:
print("exit by Ctrl-C") print("exit by Ctrl-C")
break break
if not runner.test_result: if not runner.get_test_result():
sys.exit(1) sys.exit(1)

View File

@@ -132,12 +132,6 @@ def test_method(**kwargs):
case_info["name"] = test_func.__name__ case_info["name"] = test_func.__name__
case_info.update(kwargs) case_info.update(kwargs)
# create env instance
env_config = DefaultEnvConfig.get_default_config()
for key in kwargs:
if key in env_config:
env_config[key] = kwargs[key]
@functools.wraps(test_func) @functools.wraps(test_func)
def handle_test(extra_data=None, **overwrite): def handle_test(extra_data=None, **overwrite):
""" """
@@ -147,6 +141,12 @@ def test_method(**kwargs):
:param overwrite: args that runner or main want to overwrite :param overwrite: args that runner or main want to overwrite
:return: None :return: None
""" """
# create env instance
env_config = DefaultEnvConfig.get_default_config()
for key in kwargs:
if key in env_config:
env_config[key] = kwargs[key]
env_config.update(overwrite) env_config.update(overwrite)
env_inst = Env.Env(**env_config) env_inst = Env.Env(**env_config)
# prepare for xunit test results # prepare for xunit test results

View File

@@ -69,7 +69,7 @@ Let's first check a simple simple::
if __name__ == '__main__': if __name__ == '__main__':
TinyFW.set_default_config(config_file="EnvConfigTemplate.yml") TinyFW.set_default_config(env_config_file="EnvConfigTemplate.yml")
test_examples_protocol_https_request() test_examples_protocol_https_request()

View File

@@ -47,5 +47,5 @@ def test_examples_protocol_https_request(env, extra_data):
if __name__ == '__main__': if __name__ == '__main__':
TinyFW.set_default_config(config_file="EnvConfigTemplate.yml", dut=IDF.IDFDUT) TinyFW.set_default_config(env_config_file="EnvConfigTemplate.yml", dut=IDF.IDFDUT)
test_examples_protocol_https_request() test_examples_protocol_https_request()