create mode 100644 testenv/conf/__init__.py create mode 100644 testenv/conf/authentication.py create mode 100644 testenv/conf/expect_header.py create mode 100644 testenv/conf/expected_files.py create mode 100644 testenv/conf/expected_ret_code.py create mode 100644 testenv/conf/files_crawled.py create mode 100644 testenv/conf/hook_sample.py create mode 100644 testenv/conf/local_files.py create mode 100644 testenv/conf/reject_header.py create mode 100644 testenv/conf/response.py create mode 100644 testenv/conf/rule_sample.py create mode 100644 testenv/conf/send_header.py create mode 100644 testenv/conf/server_conf.py create mode 100644 testenv/conf/server_files.py create mode 100644 testenv/conf/urls.py create mode 100644 testenv/conf/wget_commands.py
diff --git a/testenv/ChangeLog b/testenv/ChangeLog index 0bc03e0..73b92e7 100644 --- a/testenv/ChangeLog +++ b/testenv/ChangeLog @@ -1,4 +1,30 @@ 2014-03-13 Zihang Chen <[email protected]> + * conf: (new package) package for rule classes and hook methods + * WgetTest.py: + (CommonMethods.Authentication): Move to conf/authentication.py. + (CommonMethods.ExpectHeader): Move to conf/expect_header.py. + (CommonMethods.RejectHeader): Move to conf/reject_header.py. + (CommonMethods.Response): Move to conf/response.py. + (CommonMethods.SendHeader): Move to conf/send_header.py. + (CommonMethods.ServerFiles): Move to conf/server_files.py. + (CommonMethods.LocalFiles): Move to conf/local_files.py. + (CommonMethods.ServerConf): Move to conf/server_conf.py. + (CommonMethods.WgetCommands): Move to conf/wget_commands.py. + (CommonMethods.Urls): Move to conf/urls.py. + (CommonMethods.ExpectedRetcode): Move to conf/expected_retcode.py. + (CommonMethods.ExpectedFiles): Move to conf/expected_files.py. + (CommonMethods.FilesCrawled): Move to conf/files_crawled.py. + (CommonMethods.__check_downloaded_files): Rename to + _check_downloaded_files, so that the method is callable from outside the + class. + (CommomMethods.get_server_rules): Modify so that it utilizes the conf + package. + (HTTPTest): Add a method hook_call(configs, name) to reduce duplications + in pre_hook_call, call_test, post_hook_call and utilize the conf + package. + * conf/hook_sample.py: (new file) sample for hooks + * conf/rule_sample.py: (new file) sample for rules +2014-03-13 Zihang Chen <[email protected]> * exc: (new package) package for miscellaneous exceptions * WgetTest.py: Move TestFailed to exc/test_failed.py. 2014-03-13 Zihang Chen <[email protected]> diff --git a/testenv/WgetTest.py b/testenv/WgetTest.py index 1b73d6a..6076012 100644 --- a/testenv/WgetTest.py +++ b/testenv/WgetTest.py @@ -9,6 +9,7 @@ from subprocess import call from difflib import unified_diff import HTTPServer +import conf from exc.test_failed import TestFailed from misc.colour_terminal import print_red, print_green, print_blue @@ -98,7 +99,7 @@ class CommonMethods: return file_sys - def __check_downloaded_files (self, exp_filesys): + def _check_downloaded_files (self, exp_filesys): local_filesys = self.__gen_local_filesys () for files in exp_filesys: if files.name in local_filesys: @@ -123,35 +124,6 @@ class CommonMethods: return string - """ Test Rule Definitions """ - """ This should really be taken out soon. All this extra stuff to ensure - re-use of old code is crap. Someone needs to re-write it. The new rework - branch is much better written, but integrating it requires effort. - All these classes should never exist. The whole server needs to modified. - """ - - class Authentication: - def __init__ (self, auth_obj): - self.auth_type = auth_obj['Type'] - self.auth_user = auth_obj['User'] - self.auth_pass = auth_obj['Pass'] - - class ExpectHeader: - def __init__ (self, header_obj): - self.headers = header_obj - - class RejectHeader: - def __init__ (self, header_obj): - self.headers = header_obj - - class Response: - def __init__ (self, retcode): - self.response_code = retcode - - class SendHeader: - def __init__ (self, header_obj): - self.headers = header_obj - def get_server_rules (self, file_obj): """ The handling of expect header could be made much better when the options are parsed in a true and better fashion. For an example, @@ -159,60 +131,10 @@ class CommonMethods: """ server_rules = dict () for rule in file_obj.rules: - r_obj = getattr (self, rule) (file_obj.rules[rule]) + r_obj = conf.find_conf(rule)(file_obj.rules[rule]) server_rules[rule] = r_obj return server_rules - """ Pre-Test Hook Function Calls """ - - def ServerFiles (self, server_files): - for i in range (0, self.servers): - file_list = dict () - server_rules = dict () - for file_obj in server_files[i]: - content = self._replace_substring (file_obj.content) - file_list[file_obj.name] = content - rule_obj = self.get_server_rules (file_obj) - server_rules[file_obj.name] = rule_obj - self.server_list[i].server_conf (file_list, server_rules) - - def LocalFiles (self, local_files): - for file_obj in local_files: - file_handler = open (file_obj.name, "w") - file_handler.write (file_obj.content) - file_handler.close () - - def ServerConf (self, server_settings): - for i in range (0, self.servers): - self.server_list[i].server_sett (server_settings) - - """ Test Option Function Calls """ - - def WgetCommands (self, command_list): - self.options = self._replace_substring (command_list) - - def Urls (self, url_list): - self.urls = url_list - - """ Post-Test Hook Function Calls """ - - def ExpectedRetcode (self, retcode): - if self.act_retcode != retcode: - pr = "Return codes do not match.\nExpected: " + str(retcode) + "\nActual: " + str(self.act_retcode) - raise TestFailed (pr) - - def ExpectedFiles (self, exp_filesys): - self.__check_downloaded_files (exp_filesys) - - def FilesCrawled (self, Request_Headers): - for i in range (0, self.servers): - headers = set(Request_Headers[i]) - o_headers = self.Request_remaining[i] - header_diff = headers.symmetric_difference (o_headers) - if len(header_diff) is not 0: - print_red(header_diff) - raise TestFailed ("Not all files were crawled correctly") - """ Class for HTTP Tests. """ @@ -265,23 +187,27 @@ class HTTPTest (CommonMethods): self.call_test (test_params) self.post_hook_call (post_hook) - def pre_hook_call (self, pre_hook): - for pre_hook_func in pre_hook: + + def hook_call(self, configs, name): + for conf_name, conf_arg in configs.items(): try: - assert hasattr (self, pre_hook_func) - except AssertionError as ae: - self.stop_HTTP_Server () - raise TestFailed ("Pre Test Function " + pre_hook_func + " not defined.") - getattr (self, pre_hook_func) (pre_hook[pre_hook_func]) + # conf.find_conf(conf_name) returns the required conf class, + # then the class is instantiated with conf_arg, then the + # conf instance is called with this test instance itself to + # invoke the desired hook + conf.find_conf(conf_name)(conf_arg)(self) + except AttributeError as e: + print(e) + self.stop_HTTP_Server() + raise TestFailed("%s %s not defined." % + (name, conf_name)) + + + def pre_hook_call (self, pre_hook): + self.hook_call(pre_hook, 'Pre Test Function') def call_test (self, test_params): - for test_func in test_params: - try: - assert hasattr (self, test_func) - except AssertionError as ae: - self.stop_HTTP_Server () - raise TestFailed ("Test Option " + test_func + " unknown.") - getattr (self, test_func) (test_params[test_func]) + self.hook_call(test_params, 'Test Option') try: self.act_retcode = self.exec_wget (self.options, self.urls, self.domain_list) @@ -291,12 +217,7 @@ class HTTPTest (CommonMethods): self.stop_HTTP_Server () def post_hook_call (self, post_hook): - for post_hook_func in post_hook: - try: - assert hasattr (self, post_hook_func) - except AssertionError as ae: - raise TestFailed ("Post Test Function " + post_hook_func + " not defined.") - getattr (self, post_hook_func) (post_hook[post_hook_func]) + self.hook_call(post_hook, 'Post Test Function') def init_HTTP_Server (self): server = HTTPServer.HTTPd () diff --git a/testenv/conf/__init__.py b/testenv/conf/__init__.py new file mode 100644 index 0000000..2b37f79 --- /dev/null +++ b/testenv/conf/__init__.py @@ -0,0 +1,44 @@ +import os + +# this file implements the mechanism of conf class auto-registration, +# don't modify this file if you have no idea what you're doing + +def gen_hook(): + hook_table = {} + + class Wrapper: + """ + Decorator class which implements the conf class registration. + """ + def __init__(self, alias=None): + self.alias = alias + + + def __call__(self, cls): + # register the class object with the name of the class + hook_table[cls.__name__] = cls + if self.alias: + # also register the alias of the class + hook_table[self.alias] = cls + + return cls + + def find_hook(name): + if name in hook_table: + return hook_table[name] + else: + raise AttributeError + + return Wrapper, find_hook + +register, find_conf = gen_hook() + +for module in os.listdir(os.path.dirname(__file__)): + # import every module under this package except __init__.py, + # so that the decorator `register` applies + # (nothing happens if the script is not loaded) + if module != '__init__.py' and module.endswith('.py'): + module_name = module[:-3] + mod = __import__('%s.%s' % (__name__, module_name), + globals(), + locals()) \ No newline at end of file diff --git a/testenv/conf/authentication.py b/testenv/conf/authentication.py new file mode 100644 index 0000000..4a944b4 --- /dev/null +++ b/testenv/conf/authentication.py @@ -0,0 +1,9 @@ +from conf import register + + +@register() +class Authentication: + def __init__ (self, auth_obj): + self.auth_type = auth_obj['Type'] + self.auth_user = auth_obj['User'] + self.auth_pass = auth_obj['Pass'] \ No newline at end of file diff --git a/testenv/conf/expect_header.py b/testenv/conf/expect_header.py new file mode 100644 index 0000000..ef4eee3 --- /dev/null +++ b/testenv/conf/expect_header.py @@ -0,0 +1,7 @@ +from conf import register + + +@register() +class ExpectHeader: + def __init__(self, header_obj): + self.headers = header_obj diff --git a/testenv/conf/expected_files.py b/testenv/conf/expected_files.py new file mode 100644 index 0000000..5bf35db --- /dev/null +++ b/testenv/conf/expected_files.py @@ -0,0 +1,15 @@ +from difflib import unified_diff +import os +import sys +from conf import register +from exc.test_failed import TestFailed + + +@register() +class ExpectedFiles: + def __init__(self, exp_filesys): + self.exp_filesys = exp_filesys + + + def __call__(self, test_obj): + test_obj._check_downloaded_files (self.exp_filesys) diff --git a/testenv/conf/expected_ret_code.py b/testenv/conf/expected_ret_code.py new file mode 100644 index 0000000..db11105 --- /dev/null +++ b/testenv/conf/expected_ret_code.py @@ -0,0 +1,14 @@ +from exc.test_failed import TestFailed +from conf import register + + +@register(alias='ExpectedRetcode') +class ExpectedRetCode: + def __init__(self, retcode): + self.retcode = retcode + + + def __call__(self, test_obj): + if test_obj.act_retcode != self.retcode: + pr = "Return codes do not match.\nExpected: " + str(self.retcode) + "\nActual: " + str(test_obj.act_retcode) + raise TestFailed (pr) \ No newline at end of file diff --git a/testenv/conf/files_crawled.py b/testenv/conf/files_crawled.py new file mode 100644 index 0000000..ef0af44 --- /dev/null +++ b/testenv/conf/files_crawled.py @@ -0,0 +1,19 @@ +from misc.colour_terminal import print_red +from conf import register +from exc.test_failed import TestFailed + + +@register() +class FilesCrawled: + def __init__(self, Request_Headers): + self.Request_Headers = Request_Headers + + + def __call__(self, test_obj): + for i in range (0, test_obj.servers): + headers = set(self.Request_Headers[i]) + o_headers = test_obj.Request_remaining[i] + header_diff = headers.symmetric_difference (o_headers) + if len(header_diff) is not 0: + print_red(header_diff) + raise TestFailed ("Not all files were crawled correctly") \ No newline at end of file diff --git a/testenv/conf/hook_sample.py b/testenv/conf/hook_sample.py new file mode 100644 index 0000000..82abe7e --- /dev/null +++ b/testenv/conf/hook_sample.py @@ -0,0 +1,16 @@ +from exc.test_failed import TestFailed +from conf import register + +# this file is a hook example + +@register(alias='SampleAlias') +class SampleHook: + def __init__(self, sample_hook_arg): + # do conf initialization here + self.arg = sample_hook_arg + + + def __call__(self, test_obj): + # implement hook here + # if you need the test case instance, refer to test_obj + pass diff --git a/testenv/conf/local_files.py b/testenv/conf/local_files.py new file mode 100644 index 0000000..504715c --- /dev/null +++ b/testenv/conf/local_files.py @@ -0,0 +1,14 @@ +from conf import register + + +@register() +class LocalFiles: + def __init__(self, local_files): + self.local_files = local_files + + + def __call__(self, _): + for file_obj in self.local_files: + file_handler = open (file_obj.name, "w") + file_handler.write (file_obj.content) + file_handler.close () \ No newline at end of file diff --git a/testenv/conf/reject_header.py b/testenv/conf/reject_header.py new file mode 100644 index 0000000..81c76c4 --- /dev/null +++ b/testenv/conf/reject_header.py @@ -0,0 +1,7 @@ +from conf import register + + +@register() +class RejectHeader: + def __init__ (self, header_obj): + self.headers = header_obj diff --git a/testenv/conf/response.py b/testenv/conf/response.py new file mode 100644 index 0000000..32a639a --- /dev/null +++ b/testenv/conf/response.py @@ -0,0 +1,7 @@ +from conf import register + + +@register() +class Response: + def __init__(self, ret_code): + self.response_code = ret_code diff --git a/testenv/conf/rule_sample.py b/testenv/conf/rule_sample.py new file mode 100644 index 0000000..6544af1 --- /dev/null +++ b/testenv/conf/rule_sample.py @@ -0,0 +1,10 @@ +from conf import register + + +@register(alias='SampleRuleAlias') +class SampleRule: + def __init__(self, rule): + # do rule initialization here + # you may also need to implement a method the same name of this + # class in server/protocol/protocol_server.py to apply this rule. + self.rule = rule diff --git a/testenv/conf/send_header.py b/testenv/conf/send_header.py new file mode 100644 index 0000000..6ef20fd --- /dev/null +++ b/testenv/conf/send_header.py @@ -0,0 +1,7 @@ +from conf import register + + +@register() +class SendHeader: + def __init__(self, header_obj): + self.headers = header_obj diff --git a/testenv/conf/server_conf.py b/testenv/conf/server_conf.py new file mode 100644 index 0000000..9c86b0c --- /dev/null +++ b/testenv/conf/server_conf.py @@ -0,0 +1,11 @@ +from conf import register + + +class ServerConf: + def __init__(self, server_settings): + self.server_settings = server_settings + + + def __call__(self, test_obj): + for i in range (0, test_obj.servers): + test_obj.server_list[i].server_sett (self.server_settings) \ No newline at end of file diff --git a/testenv/conf/server_files.py b/testenv/conf/server_files.py new file mode 100644 index 0000000..4207d23 --- /dev/null +++ b/testenv/conf/server_files.py @@ -0,0 +1,19 @@ +from conf import register + + +@register() +class ServerFiles: + def __init__(self, server_files): + self.server_files = server_files + + + def __call__(self, test_obj): + for i in range (0, test_obj.servers): + file_list = dict () + server_rules = dict () + for file_obj in self.server_files[i]: + content = test_obj._replace_substring (file_obj.content) + file_list[file_obj.name] = content + rule_obj = test_obj.get_server_rules (file_obj) + server_rules[file_obj.name] = rule_obj + test_obj.server_list[i].server_conf (file_list, server_rules) \ No newline at end of file diff --git a/testenv/conf/urls.py b/testenv/conf/urls.py new file mode 100644 index 0000000..0207a4b --- /dev/null +++ b/testenv/conf/urls.py @@ -0,0 +1,11 @@ +from conf import register + + +@register(alias='Urls') +class URLs: + def __init__(self, url_list): + self.url_list = url_list + + + def __call__(self, test_obj): + test_obj.urls = self.url_list \ No newline at end of file diff --git a/testenv/conf/wget_commands.py b/testenv/conf/wget_commands.py new file mode 100644 index 0000000..43140eb --- /dev/null +++ b/testenv/conf/wget_commands.py @@ -0,0 +1,11 @@ +from conf import register + + +@register() +class WgetCommands: + def __init__(self, command_list): + self.command_list = command_list + + + def __call__(self, test_obj): + test_obj.options = test_obj._replace_substring (self.command_list) \ No newline at end of file -- 1.8.3.2
