[libvirt] [test-API PATCH 0/4]Add feature to check case file before running

The set of patches add a new feature to examine testcase config file before running it. The framework will do the job on behalf of testcase, so test writer will release from the work. Usage: In testcase, it only needs to define two global tuple variables required_params are the mandatory options to the testcase optional_params are the optional options ... required_params = ('networkname', 'autostart') optional_params = ('optparams1', 'optparas2') def testcase(params): ... Checking results: on success, it will run these testcases defined in testcase config file on error-detected, error as follows Unknown parameter 'whoami' the No.2 : domain:testb Parameter autostart is required the No.5 : domain:testa The idea and part of code in patches is from Osier:)

activityfilter.py --- activityfilter.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 74 insertions(+), 0 deletions(-) create mode 100644 activityfilter.py diff --git a/activityfilter.py b/activityfilter.py new file mode 100644 index 0000000..d99d690 --- /dev/null +++ b/activityfilter.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# +# libvirt-test-API is copyright 2010, 2012 Red Hat, Inc. +# +# libvirt-test-API is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. This program is distributed in +# the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranties of TITLE, NON-INFRINGEMENT, +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# The GPL text is available in the file COPYING that accompanies this +# distribution and at <http://www.gnu.org/licenses>. +# + + +class Filter(object): + """filter activity list to form various data list""" + def __init__(self, activities_list): + self.testcase_keys = [] + for activity in activities_list: + for testcase in activity: + testcases_key = testcase.keys() + self.testcase_keys += testcases_key + + def unique_testcase_cleansuffix(self): + """get a list of module:testcase from activities_list + eliminate duplicate items, with 'module:testcase_clean' + """ + keylist_clean = self._keylist_cleanappended_without_sleep() + return list(set(keylist_clean)) + + def unique_testcases(self): + """ get a list of module:testcase from activities_list + eliminate duplicate items + """ + keylist = self._keylist_without_sleep_clean() + return list(set(keylist)) + + def _keylist_without_sleep_clean(self): + """ filter out 'clean' and 'sleep' flag + to generate a list of testcases + """ + keylist = [] + for key in self.testcase_keys: + key = key.lower() + if key == 'clean' or key == 'sleep': + continue + + keylist.append(key) + + return keylist + + def _keylist_cleanappended_without_sleep(self): + """ remove 'sleep' flag, and append ':_clean' to + the previous testcase to form a new element + """ + keylist_clean = [] + prev_casename = '' + + for key in self.testcase_keys: + key = key.lower() + if key == 'sleep': + continue + + if key == 'clean': + keylist_clean.append(prev_casename + ":_clean") + continue + + prev_casename = key + keylist_clean.append(prev_casename) + + return keylist_clean -- 1.7.7.5

On 04/11/2012 04:04 PM, Guannan Ren wrote:
activityfilter.py --- activityfilter.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 74 insertions(+), 0 deletions(-) create mode 100644 activityfilter.py
diff --git a/activityfilter.py b/activityfilter.py new file mode 100644 index 0000000..d99d690 --- /dev/null +++ b/activityfilter.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# +# libvirt-test-API is copyright 2010, 2012 Red Hat, Inc. +# +# libvirt-test-API is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. This program is distributed in +# the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranties of TITLE, NON-INFRINGEMENT, +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# The GPL text is available in the file COPYING that accompanies this +# distribution and at <http://www.gnu.org/licenses>. +# + + +class Filter(object): + """filter activity list to form various data list""" + def __init__(self, activities_list): + self.testcase_keys = [] + for activity in activities_list: + for testcase in activity: + testcases_key = testcase.keys() + self.testcase_keys += testcases_key + + def unique_testcase_cleansuffix(self): + """get a list of module:testcase from activities_list + eliminate duplicate items, with 'module:testcase_clean' + """ + keylist_clean = self._keylist_cleanappended_without_sleep() + return list(set(keylist_clean)) + + def unique_testcases(self): + """ get a list of module:testcase from activities_list + eliminate duplicate items + """ + keylist = self._keylist_without_sleep_clean() + return list(set(keylist)) + + def _keylist_without_sleep_clean(self): + """ filter out 'clean' and 'sleep' flag + to generate a list of testcases + """ + keylist = [] + for key in self.testcase_keys: + key = key.lower() + if key == 'clean' or key == 'sleep': + continue + + keylist.append(key) + + return keylist + + def _keylist_cleanappended_without_sleep(self): + """ remove 'sleep' flag, and append ':_clean' to + the previous testcase to form a new element + """ + keylist_clean = [] + prev_casename = '' + + for key in self.testcase_keys: + key = key.lower() + if key == 'sleep': + continue + + if key == 'clean': + keylist_clean.append(prev_casename + ":_clean") + continue + + prev_casename = key + keylist_clean.append(prev_casename) + + return keylist_clean
This looks ok, ACK. I'm looking at the rest now. Martin

casecfgcheck.py --- casecfgcheck.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 66 insertions(+), 0 deletions(-) create mode 100644 casecfgcheck.py diff --git a/casecfgcheck.py b/casecfgcheck.py new file mode 100644 index 0000000..3c4696d --- /dev/null +++ b/casecfgcheck.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# +# libvirt-test-API is copyright 2010, 2012 Red Hat, Inc. +# +# libvirt-test-API is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. This program is distributed in +# the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranties of TITLE, NON-INFRINGEMENT, +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# The GPL text is available in the file COPYING that accompanies this +# distribution and at <http://www.gnu.org/licenses>. +# + +import proxy + +class CaseCfgCheck(object): + """validate the options in testcase config file""" + def __init__(self, unique_testcases, activities_list): + self.unique_testcases = unique_testcases + + # XXX to check the first testcase list in activities_list + self.activitie = activities_list[0] + + proxy_obj = proxy.Proxy(self.unique_testcases) + self.case_params = proxy_obj.get_params_variables() + + def check(self): + """check options to each testcase in case config file""" + case_number = 0 + error_flag = 0 + passed_testcase = [] + for testcase in self.activitie: + case_number += 1 + if testcase in passed_testcase: + continue + + testcase_name = testcase.keys()[0] + actual_params = testcase.values()[0] + + required_params, optional_params = self.case_params[testcase_name] + ret = self._check_params(required_params, optional_params, actual_params) + if ret: + error_flag = 1 + print "the No.%s : %s\n" % (case_number, testcase_name) + + passed_testcase.append(testcase) + + if error_flag: + return 1 + return 0 + + def _check_params(self, required_params, optional_params, actual_params): + for p in required_params: + if p not in actual_params.keys(): + print "Parameter %s is required" % p + return 1 + + for p in actual_params.keys(): + if p not in required_params and p not in optional_params: + print "Unknown parameter '%s'" % p + return 1 + + return 0 -- 1.7.7.5

On 04/11/2012 04:04 PM, Guannan Ren wrote:
casecfgcheck.py --- casecfgcheck.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 66 insertions(+), 0 deletions(-) create mode 100644 casecfgcheck.py
diff --git a/casecfgcheck.py b/casecfgcheck.py new file mode 100644 index 0000000..3c4696d --- /dev/null +++ b/casecfgcheck.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# +# libvirt-test-API is copyright 2010, 2012 Red Hat, Inc. +# +# libvirt-test-API is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. This program is distributed in +# the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranties of TITLE, NON-INFRINGEMENT, +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# The GPL text is available in the file COPYING that accompanies this +# distribution and at <http://www.gnu.org/licenses>. +# + +import proxy + +class CaseCfgCheck(object): + """validate the options in testcase config file""" + def __init__(self, unique_testcases, activities_list): + self.unique_testcases = unique_testcases + + # XXX to check the first testcase list in activities_list + self.activitie = activities_list[0] + + proxy_obj = proxy.Proxy(self.unique_testcases) + self.case_params = proxy_obj.get_params_variables()
typo: s/activitie/activity/ plus I'm not sure if we can be sure that all the activities are the same in this call (if it's just a multiplication of one array)? On other places (like 'libvirt-test-api.py') we check for all members in the array.
+ + def check(self): + """check options to each testcase in case config file""" + case_number = 0 + error_flag = 0 + passed_testcase = [] + for testcase in self.activitie:
second typo or copy paste error :) s/activitie/activity/
+ case_number += 1 + if testcase in passed_testcase: + continue + + testcase_name = testcase.keys()[0] + actual_params = testcase.values()[0]
I don't quite understand what are you trying to achieve here. The order of keys and values in python dict cannot be guaranteed if I'm not wrong. And even if yes, that would mean you are checking just for the first testcase, I guess. Or maybe I just don't get this right.
+ + required_params, optional_params = self.case_params[testcase_name] + ret = self._check_params(required_params, optional_params, actual_params) + if ret: + error_flag = 1 + print "the No.%s : %s\n" % (case_number, testcase_name) + + passed_testcase.append(testcase) + + if error_flag: + return 1 + return 0 + + def _check_params(self, required_params, optional_params, actual_params): + for p in required_params: + if p not in actual_params.keys(): + print "Parameter %s is required" % p + return 1 + + for p in actual_params.keys(): + if p not in required_params and p not in optional_params: + print "Unknown parameter '%s'" % p + return 1 + + return 0
Martin

On 04/12/2012 07:38 PM, Martin Kletzander wrote:
On 04/11/2012 04:04 PM, Guannan Ren wrote:
casecfgcheck.py --- casecfgcheck.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 66 insertions(+), 0 deletions(-) create mode 100644 casecfgcheck.py
diff --git a/casecfgcheck.py b/casecfgcheck.py new file mode 100644 index 0000000..3c4696d --- /dev/null +++ b/casecfgcheck.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# +# libvirt-test-API is copyright 2010, 2012 Red Hat, Inc. +# +# libvirt-test-API is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. This program is distributed in +# the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranties of TITLE, NON-INFRINGEMENT, +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# The GPL text is available in the file COPYING that accompanies this +# distribution and at<http://www.gnu.org/licenses>. +# + +import proxy + +class CaseCfgCheck(object): + """validate the options in testcase config file""" + def __init__(self, unique_testcases, activities_list): + self.unique_testcases = unique_testcases + + # XXX to check the first testcase list in activities_list + self.activitie = activities_list[0] + + proxy_obj = proxy.Proxy(self.unique_testcases) + self.case_params = proxy_obj.get_params_variables()
typo: s/activitie/activity/
plus I'm not sure if we can be sure that all the activities are the same in this call (if it's just a multiplication of one array)? On other places (like 'libvirt-test-api.py') we check for all members in the array.
+ + def check(self): + """check options to each testcase in case config file""" + case_number = 0 + error_flag = 0 + passed_testcase = [] + for testcase in self.activitie: second typo or copy paste error :) s/activitie/activity/
Thanks, it is fixed and pushed.
+ case_number += 1 + if testcase in passed_testcase: + continue + + testcase_name = testcase.keys()[0] + actual_params = testcase.values()[0] I don't quite understand what are you trying to achieve here. The order of keys and values in python dict cannot be guaranteed if I'm not wrong. And even if yes, that would mean you are checking just for the first testcase, I guess. Or maybe I just don't get this right.
If time is permitted, please run "python parser.py testcase.cfg" It will output the data format after parsing. example: run it using the command above. #testcase.cfg domain:testa guestname fedora16 The data format is: [[{'domain:testa': {'guestname': 'fedora16'}}]] The variable "testcase" refer to "{'domain:testa': {'guestname': 'fedora16'}" The variable "activity" refet to [{'domain:testa': {'guestname': 'fedora16'}] Note: the code just to check the first inner list here. then, we use 'testcase_name'(domain:testa) as the key to fetch two global variable that defined in testa.py one is "required_params", the other is "optional_params", then compare them with "actual_params" by invoking _check_params(...) Tips: the proxy.py will place the two references to the global params in a data format like {'domain:testa':[required_params, optional_params]} Guannan Ren

--- proxy.py | 78 ++++++++++++++++++++++++++++++++++++++----------------------- 1 files changed, 48 insertions(+), 30 deletions(-) diff --git a/proxy.py b/proxy.py index 3cd31bd..990e1f0 100644 --- a/proxy.py +++ b/proxy.py @@ -20,7 +20,6 @@ import exception - class Proxy(object): """ The Proxy class is used for getting real function call reference """ @@ -30,59 +29,75 @@ class Proxy(object): def get_func_call_dict(self): """Return running function reference dictionary """ - self.func_dict = dict() + func_dict = dict() for testcase_name in self.testcases_names: - # Get programming package, casename + # Get module, casename elements = testcase_name.split(":") - package = elements[0] + module = elements[0] casename = elements[1] func = casename if len(elements) == 3: - keyword = elements[2] - func = casename + keyword + # flag is like ":_clean" in testcases_names + # this func is for _clean function in testcase + flag = elements[2] + func = casename + flag - # Dispatch functions - funcs = getattr(self, "get_call_dict") - func_ref = None - func_ref = funcs(package, casename, func) + func_ref = self.get_call_dict(module, casename, func) # Construct function call dictionary - key = package + ":" + casename + ":" + func - self.func_dict[key] = func_ref - return self.func_dict + key = module + ":" + casename + ":" + func + func_dict[key] = func_ref + + return func_dict def get_clearfunc_call_dict(self): """ Return a clearing function reference dictionary. """ - self.func_dict = dict() + func_dict = dict() for testcase_name in self.testcases_names: - # Get programming package, casename + # Get module, casename elements = testcase_name.split(":") if len(elements) == 3: continue - package = testcase_name.split(":")[0] + module = testcase_name.split(":")[0] casename = testcase_name.split(":")[1] - - # According to language kind to dispatch function - funcs = getattr(self, "get_call_dict") - func_ref = None func = casename + "_clean" - func_ref = funcs(package, casename, func) + func_ref = self.get_call_dict(module, casename, func) # Construct function call dictionary - key = package + ":" + casename + ":" + func - self.func_dict[key] = func_ref - return self.func_dict + key = module + ":" + casename + ":" + func + func_dict[key] = func_ref + + return func_dict - def get_call_dict(self, *args): + def get_params_variables(self): + """ Return the reference to global variable 'required_params' + in testcase + """ + case_params = {} + for testcase_name in self.testcases_names: + elements = testcase_name.split(":") + + if len(elements) == 3: + continue + + module = testcase_name.split(":")[0] + casename = testcase_name.split(":")[1] + + mod_ref = self.get_call_dict(module, casename) + case_params[testcase_name] = \ + [mod_ref.required_params, mod_ref.optional_params] + + return case_params + + def get_call_dict(self, module, casename, func = None): """ Return testing function reference dictionary """ - (package, casename, func) = args - case_abs_path = '%s.%s.%s' % ('repos', package, casename) + case_abs_path = '%s.%s.%s' % ('repos', module, casename) - # Main function name is the same as casename here + # import tescase file case_mod = __import__(case_abs_path) components = case_abs_path.split('.') @@ -91,6 +106,9 @@ class Proxy(object): if component == "": raise exception.CaseConfigfileError("Missing module name after \":\"") case_mod = getattr(case_mod, component) - main_function_ref = getattr(case_mod, func) - return main_function_ref + if func: + main_function_ref = getattr(case_mod, func) + return main_function_ref + + return case_mod -- 1.7.7.5

libvirt-test-api.py --- libvirt-test-api.py | 52 ++++++++++++++++++++++---------------------------- 1 files changed, 23 insertions(+), 29 deletions(-) diff --git a/libvirt-test-api.py b/libvirt-test-api.py index d4ce4f2..877104c 100644 --- a/libvirt-test-api.py +++ b/libvirt-test-api.py @@ -28,6 +28,8 @@ import env_clear import process from utils import log from logxmlparser import LogXMLParser +from activityfilter import Filter +from casecfgcheck import CaseCfgCheck def usage(): print "Usage: libvirt_test_api.py <OPTIONS> <ARGUS>" @@ -58,7 +60,7 @@ def append_path(): else: sys.path.append(pwd) -class LibvirtTestAPI(object): +class Main(object): """ The class provides methods to run a new test and manage testing log and records """ @@ -104,28 +106,22 @@ class LibvirtTestAPI(object): times = int(options_list[0]['options']["times"]) activities_list = activities_list * times - # extract the string of combination of - # language, package, testname of a testcase. - all_testcases_names = [] - prev_casename = '' - for activity in activities_list: - for testcase in activity: - testcases_names = testcase.keys() - if 'sleep' in testcases_names: - testcases_names.remove('sleep') - if not cmp('clean', testcases_names[0]): - all_testcases_names += [prev_casename + ":_clean"] - continue + filterobj = Filter(activities_list) - prev_casename = testcases_names[0] - all_testcases_names += testcases_names + unique_testcases = filterobj.unique_testcases() + # check the options to each testcase in case config file + casechk = CaseCfgCheck(unique_testcases, activities_list) + if casechk.check(): + return 1 - unique_testcases_names = list(set(all_testcases_names)) + # get a list of unique testcase + # with 'clean' flag appended to its previous testcase + unique_testcase_keys = filterobj.unique_testcase_cleansuffix() # call and initilize proxy component to # get a list of reference of testcases - proxy_obj = proxy.Proxy(unique_testcases_names) + proxy_obj = proxy.Proxy(unique_testcase_keys) cases_func_ref_dict = proxy_obj.get_func_call_dict() @@ -216,8 +212,7 @@ class LibvirtTestAPI(object): if failnum: return 1 - else: - return 0 + return 0 def remove_log(self, testrunid, testid = None): """ to remove log item in the log xmlfile """ @@ -310,16 +305,16 @@ if __name__ == "__main__": usage() sys.exit(1) - libvirt_test_api = LibvirtTestAPI(casefile, logxml, loglevel, bugstxt) - libvirt_test_api.remove_log(testrunid, testid) + main = Main(casefile, logxml, loglevel, bugstxt) + main.remove_log(testrunid, testid) sys.exit(0) if o == "-m" or o == "--merge": if len(args) == 2: logxml_one = args[0] logxml_two = args[1] - libvirt_test_api = LibvirtTestAPI(casefile, logxml_one, loglevel, bugstxt) - libvirt_test_api.merge_logxmls(logxml_two) + main = Main(casefile, logxml_one, loglevel, bugstxt) + main.merge_logxmls(logxml_two) sys.exit(0) else: usage() @@ -334,15 +329,14 @@ if __name__ == "__main__": for testid in args[1:]: testid = int(testid) testid_list.append(testid) - libvirt_test_api = LibvirtTestAPI(casefile, logxml, loglevel, bugstxt) - libvirt_test_api.rerun(testrunid, testid_list) + main = Main(casefile, logxml, loglevel, bugstxt) + main.rerun(testrunid, testid_list) sys.exit(0) # Add root path of libvirt-test-API into sys.path append_path() - libvirt_test_api = LibvirtTestAPI(casefile, logxml, loglevel, bugstxt) - if libvirt_test_api.run(): + main = Main(casefile, logxml, loglevel, bugstxt) + if main.run(): sys.exit(1) - else: - sys.exit(0) + sys.exit(0) -- 1.7.7.5

I don't think pushing this series without a review was a good idea. You actualy broke all of the tests in the repos/ as you didn't do the modifications to the parameter checking algorithm in a way that didn't require modification of the tests, neither did you change the tests to cope with the new code. The result is now: exception.TestCaseError: 'required_params or optional_params not found in interface:destroy' or similar for every test case. Peter

On 04/12/2012 07:53 PM, Peter Krempa wrote:
I don't think pushing this series without a review was a good idea. You actualy broke all of the tests in the repos/ as you didn't do the modifications to the parameter checking algorithm in a way that didn't require modification of the tests, neither did you change the tests to cope with the new code. The result is now:
exception.TestCaseError: 'required_params or optional_params not found in interface:destroy'
or similar for every test case.
Peter
Yes, sorry about this. There is some new feature and cleanup work on my hand, I don't know the exact time to get review. The error is generated by framework. the part job of framework is done. The cleanup work on testcase is ongoing, I am sure that I will finish the work today. Guannan Ren

On 04/12/2012 09:43 PM, Guannan Ren wrote:
On 04/12/2012 07:53 PM, Peter Krempa wrote:
I don't think pushing this series without a review was a good idea. You actualy broke all of the tests in the repos/ as you didn't do the modifications to the parameter checking algorithm in a way that didn't require modification of the tests, neither did you change the tests to cope with the new code. The result is now:
exception.TestCaseError: 'required_params or optional_params not found in interface:destroy'
or similar for every test case.
Peter
Yes, sorry about this. There is some new feature and cleanup work on my hand, I don't know the exact time to get review. The error is generated by framework. the part job of framework is done. The cleanup work on testcase is ongoing, I am sure that I will finish the work today.
The cleanup is done and pushed. I only wan to send framework code here, the cleaning code in testcases is huge and mechanical, maybe nobody likes seeing it :) Sorry about the intact commit again. Guannan Ren

On 04/12/2012 07:03 PM, Guannan Ren wrote:
On 04/12/2012 09:43 PM, Guannan Ren wrote:
On 04/12/2012 07:53 PM, Peter Krempa wrote:
I don't think pushing this series without a review was a good idea. You actualy broke all of the tests in the repos/ as you didn't do the modifications to the parameter checking algorithm in a way that didn't require modification of the tests, neither did you change the tests to cope with the new code. The result is now:
exception.TestCaseError: 'required_params or optional_params not found in interface:destroy'
or similar for every test case.
Peter
Yes, sorry about this. There is some new feature and cleanup work on my hand, I don't know the exact time to get review. The error is generated by framework. the part job of framework is done. The cleanup work on testcase is ongoing, I am sure that I will finish the work today.
The cleanup is done and pushed. I only wan to send framework code here, the cleaning code in testcases is huge and mechanical, maybe nobody likes seeing it :) Sorry about the intact commit again.
Guannan Ren
I was writing next email about this when the internet at my place (and thus VPN) started disconnecting me. I had a thought in mind how we can keep all the tests working without any change. However if this is now fixed then the thought is not needed anymore. Next time if there is some major change like this, then I'd like to keep it that way. In case we don't rewrite it from scratch of course :) Martin

On 04/13/2012 08:19 PM, Martin Kletzander wrote:
On 04/12/2012 09:43 PM, Guannan Ren wrote:
On 04/12/2012 07:53 PM, Peter Krempa wrote:
I don't think pushing this series without a review was a good idea. You actualy broke all of the tests in the repos/ as you didn't do the modifications to the parameter checking algorithm in a way that didn't require modification of the tests, neither did you change the tests to cope with the new code. The result is now:
exception.TestCaseError: 'required_params or optional_params not found in interface:destroy'
or similar for every test case.
Peter
Yes, sorry about this. There is some new feature and cleanup work on my hand, I don't know the exact time to get review. The error is generated by framework. the part job of framework is done. The cleanup work on testcase is ongoing, I am sure that I will finish the work today.
The cleanup is done and pushed. I only wan to send framework code here, the cleaning code in testcases is huge and mechanical, maybe nobody likes seeing it :) Sorry about the intact commit again.
Guannan Ren I was writing next email about this when the internet at my place (and
On 04/12/2012 07:03 PM, Guannan Ren wrote: thus VPN) started disconnecting me. I had a thought in mind how we can keep all the tests working without any change. However if this is now fixed then the thought is not needed anymore. Next time if there is some major change like this, then I'd like to keep it that way. In case we don't rewrite it from scratch of course :)
Martin
Any change to the framework will lead to big changes to all existing testcases. It worth though, but don't worry, I like to do the labor work. you guys just focus on framework. Guannan Ren
participants (3)
-
Guannan Ren
-
Martin Kletzander
-
Peter Krempa