Create package conf where rules and hooks are put

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
This commit is contained in:
Zihang Chen 2014-03-13 18:27:19 +08:00 committed by Giuseppe Scrivano
parent 42e482ad99
commit 195393bf41
19 changed files with 293 additions and 108 deletions

View File

@ -1,3 +1,31 @@
2014-03-13 Zihang Chen <chsc4698@gmail.com>
* 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 and post_hook_call utilizing the conf package.
* conf/hook_sample.py: (new file) sample for hooks
* conf/rule_sample.py: (new file) sample for rules
* REAMDE: Update sections about customizing rules and hooks.
2014-03-13 Zihang Chen <chsc4698@gmail.com>
* exc: (new package) package for miscellaneous exceptions

View File

@ -29,6 +29,9 @@ Structure:
* exc: This package contains custom exception classes used in this test
suite.
* conf: This package contains the configuration classes for servers to be
configured with.
* misc: This package contains several helper modules used in this test
suite.
- colour_terminal.py: A custom module for printing coloured output to
@ -199,7 +202,8 @@ The test_options dictionary defines the commands to be used when the Test is
executed. The currently supported options are:
* Urls : A list of the filenames that Wget must attempt to
download. The complete URL will be created and passed to Wget automatically.
download. The complete URL will be created and passed to Wget
automatically. (alias URLs)
* WgetCommands : A string consisting of the various commandline switches
sent to Wget upon invokation. Any data placed between {{ }} in this string
will be replaced with the contents of self.<data> before being passed to
@ -216,7 +220,7 @@ hooks are usually used to run checks on the data, files downloaded, return code,
etc. The following hooks are currently supported:
* ExpectedRetcode : This is an integer value of the ReturnCode with which
Wget is expected to exit.
Wget is expected to exit. (alias ExpectedRetCode)
* ExpectedFiles : This is a list of WgetFile objects of the files that
must exist locally on disk in the Test directory.
* FilesCrawled : This requires a list of the Requests that the server is
@ -232,11 +236,31 @@ recommended method for writing new Test Case files is to copy Test-Proto.py and
modify it to ones needs.
In case you require any functionality that is not currently defined in List of
Rules defined above, you should add the required code in WgetTest.py.
In most cases, one requires a new Rule to be added for the Server to follow.
In such a case, create a new Class in WgetTest.py with the same name as the Rule
and define an __init__ () function to handle the data. A method must also be
defined in HTTPTest / FTPTest modules to handle the said Rule.
Rules defined above, you should implement a new class in the conf package. The
file name doesn't matter (though it's better to give it an appropriate name).
The new rule or hook class should be like this:
============================================
from conf import rule
@rule()
class MyNewRule:
def __init__(self, rule_arg):
self.rule_arg = rule_arg
# your rule initialization code goes here
============================================
from conf import hook
@hook()
class MyNewHook:
def __init__(self, hook_arg):
self.hook_arg = hook_arg
# your hook initialization code goes here
def __call__(self, test_obj):
# your hook code goes here
============================================
Once a new Test File is created, it must be added to the TESTS variable in
Makefile.am. This way the Test will be executed on running a 'make check'.

View File

@ -10,6 +10,7 @@ from subprocess import call
from misc.colour_terminal import print_red, print_green, print_blue
from difflib import unified_diff
from exc.test_failed import TestFailed
import conf
HTTP = "HTTP"
HTTPS = "HTTPS"
@ -96,7 +97,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:
@ -121,35 +122,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,
@ -157,60 +129,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. """
@ -263,23 +185,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)
@ -289,12 +215,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 ()

47
testenv/conf/__init__.py Normal file
View File

@ -0,0 +1,47 @@
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()
hook = rule = _register
__all__ = ['hook', 'rule']
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())
__all__.append(module_name)

View File

@ -0,0 +1,9 @@
from conf import rule
@rule()
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']

View File

@ -0,0 +1,7 @@
from conf import rule
@rule()
class ExpectHeader:
def __init__(self, header_obj):
self.headers = header_obj

View File

@ -0,0 +1,10 @@
from conf import hook
@hook()
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)

View File

@ -0,0 +1,13 @@
from exc.test_failed import TestFailed
from conf import hook
@hook(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)

View File

@ -0,0 +1,18 @@
from misc.colour_terminal import print_red
from conf import hook
from exc.test_failed import TestFailed
@hook()
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")

View File

@ -0,0 +1,15 @@
from exc.test_failed import TestFailed
from conf import hook
# this file is a hook example
@hook(alias='SampleHookAlias')
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

View File

@ -0,0 +1,13 @@
from conf import hook
@hook()
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 ()

View File

@ -0,0 +1,7 @@
from conf import rule
@rule()
class RejectHeader:
def __init__ (self, header_obj):
self.headers = header_obj

7
testenv/conf/response.py Normal file
View File

@ -0,0 +1,7 @@
from conf import rule
@rule()
class Response:
def __init__(self, ret_code):
self.response_code = ret_code

View File

@ -0,0 +1,10 @@
from conf import rule
@rule(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

View File

@ -0,0 +1,7 @@
from conf import rule
@rule()
class SendHeader:
def __init__(self, header_obj):
self.headers = header_obj

View File

@ -0,0 +1,11 @@
from conf import hook
@hook()
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)

View File

@ -0,0 +1,18 @@
from conf import hook
@hook()
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)

10
testenv/conf/urls.py Normal file
View File

@ -0,0 +1,10 @@
from conf import hook
@hook(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

View File

@ -0,0 +1,10 @@
from conf import hook
@hook()
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)