diff options
Diffstat (limited to 'testenv/conf')
-rw-r--r-- | testenv/conf/__init__.py | 48 | ||||
-rw-r--r-- | testenv/conf/authentication.py | 23 | ||||
-rw-r--r-- | testenv/conf/domains.py | 9 | ||||
-rw-r--r-- | testenv/conf/expect_header.py | 12 | ||||
-rw-r--r-- | testenv/conf/expected_files.py | 58 | ||||
-rw-r--r-- | testenv/conf/expected_ret_code.py | 27 | ||||
-rw-r--r-- | testenv/conf/files_crawled.py | 27 | ||||
-rw-r--r-- | testenv/conf/hook_sample.py | 22 | ||||
-rw-r--r-- | testenv/conf/local_files.py | 26 | ||||
-rw-r--r-- | testenv/conf/reject_header.py | 13 | ||||
-rw-r--r-- | testenv/conf/response.py | 11 | ||||
-rw-r--r-- | testenv/conf/rule_sample.py | 10 | ||||
-rw-r--r-- | testenv/conf/send_header.py | 12 | ||||
-rw-r--r-- | testenv/conf/server_files.py | 26 | ||||
-rw-r--r-- | testenv/conf/urls.py | 14 | ||||
-rw-r--r-- | testenv/conf/wget_commands.py | 15 |
16 files changed, 353 insertions, 0 deletions
diff --git a/testenv/conf/__init__.py b/testenv/conf/__init__.py new file mode 100644 index 0000000..55433c9 --- /dev/null +++ b/testenv/conf/__init__.py @@ -0,0 +1,48 @@ +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): + try: + return hook_table[name] + except: + 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) diff --git a/testenv/conf/authentication.py b/testenv/conf/authentication.py new file mode 100644 index 0000000..ca5149c --- /dev/null +++ b/testenv/conf/authentication.py @@ -0,0 +1,23 @@ +from conf import rule + +""" Rule: Authentication +This file defines an authentication rule which when applied to any file will +cause the server to prompt the client for the required authentication details +before serving it. +auth_type must be either of: Basic, Digest, Both or Both-inline +When auth_type is Basic or Digest, the server asks for the respective +authentication in its response. When auth_type is Both, the server sends two +Authenticate headers, one requesting Basic and the other requesting Digest +authentication. If auth_type is Both-inline, the server sends only one +Authenticate header, but lists both Basic and Digest as supported mechanisms in +that. +""" + + +@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'] + self.auth_parm = auth_obj.get('Parm', None) diff --git a/testenv/conf/domains.py b/testenv/conf/domains.py new file mode 100644 index 0000000..ac03fe1 --- /dev/null +++ b/testenv/conf/domains.py @@ -0,0 +1,9 @@ +from conf import hook + +@hook(alias='Domains') +class Domains: + def __init__(self, domains): + self.domains = domains + + def __call__(self, test_obj): + test_obj.domains = self.domains diff --git a/testenv/conf/expect_header.py b/testenv/conf/expect_header.py new file mode 100644 index 0000000..055099f --- /dev/null +++ b/testenv/conf/expect_header.py @@ -0,0 +1,12 @@ +from conf import rule + +""" Rule: ExpectHeader +This rule defines a dictionary of headers and their value which the server +should expect in each request for the file to which the rule was applied. +""" + + +@rule() +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..65adb70 --- /dev/null +++ b/testenv/conf/expected_files.py @@ -0,0 +1,58 @@ +from difflib import unified_diff +import os +import sys +from conf import hook +from exc.test_failed import TestFailed + +""" Post-Test Hook: ExpectedFiles +This is a Post-Test hook that checks the test directory for the files it +contains. A dictionary object is passed to it, which contains a mapping of +filenames and contents of all the files that the directory is expected to +contain. +Raises a TestFailed exception if the expected files are not found or if extra +files are found, else returns gracefully. +""" + + +@hook() +class ExpectedFiles: + def __init__(self, expected_fs): + self.expected_fs = expected_fs + + @staticmethod + def gen_local_fs_snapshot(): + snapshot = {} + for parent, dirs, files in os.walk('.'): + for name in files: + # pubring.gpg, pubring.kbx, dirmngr.conf, gpg.conf will be created by libgpgme + # if $HOME doesn't contain the .gnupg directory. + # setting $HOME to CWD (in base_test.py) breaks two Metalink tests, so we skip this file here. + if name in [ 'pubring.gpg', 'pubring.kbx', 'dirmngr.conf', 'gpg.conf' ]: + continue + + f = {'content': ''} + file_path = os.path.join(parent, name) + with open(file_path) as fp: + f['content'] = fp.read() + snapshot[file_path[2:]] = f + + return snapshot + + def __call__(self, test_obj): + local_fs = self.gen_local_fs_snapshot() + for file in self.expected_fs: + if file.name in local_fs: + local_file = local_fs.pop(file.name) + formatted_content = test_obj._replace_substring(file.content) + if formatted_content != local_file['content']: + for line in unified_diff(local_file['content'], + formatted_content, + fromfile='Actual', + tofile='Expected'): + print(line, file=sys.stderr) + raise TestFailed('Contents of %s do not match' % file.name) + else: + raise TestFailed('Expected file %s not found.' % file.name) + if local_fs: + print(local_fs) + raise TestFailed('Extra files downloaded.') diff --git a/testenv/conf/expected_ret_code.py b/testenv/conf/expected_ret_code.py new file mode 100644 index 0000000..87cba13 --- /dev/null +++ b/testenv/conf/expected_ret_code.py @@ -0,0 +1,27 @@ +from exc.test_failed import TestFailed +from conf import hook + +""" Post-Test Hook: ExpectedRetCode +This is a post-test hook which checks if the exit code of the Wget instance +under test is the same as that expected. As a result, this is a very important +post test hook which is checked in all the tests. +Returns a TestFailed exception if the return code does not match the expected +value. Else returns gracefully. +""" + + +@hook(alias='ExpectedRetcode') +class ExpectedRetCode: + def __init__(self, expected_ret_code): + self.expected_ret_code = expected_ret_code + + def __call__(self, test_obj): + if test_obj.ret_code != self.expected_ret_code: + if test_obj.ret_code == 45: + failure = "Memory Leak Found by Valgrind" + else: + failure = "Return codes do not match.\n" \ + "Expected: %s\n" \ + "Actual: %s" % (self.expected_ret_code, + test_obj.ret_code) + raise TestFailed(failure) diff --git a/testenv/conf/files_crawled.py b/testenv/conf/files_crawled.py new file mode 100644 index 0000000..7db8392 --- /dev/null +++ b/testenv/conf/files_crawled.py @@ -0,0 +1,27 @@ +from misc.colour_terminal import print_red +from conf import hook +from exc.test_failed import TestFailed + +""" Post-Test Hook: FilesCrawled +This is a post test hook that is invoked in tests that check wget's behaviour +in recursive mode. It expects an ordered list of the request lines that Wget +must send to the server. If the requests received by the server do not match +the provided list, IN THE GIVEN ORDER, then it raises a TestFailed exception. +Such a test can be used to check the implementation of the recursion algorithm +in Wget too. +""" + + +@hook() +class FilesCrawled: + def __init__(self, request_headers): + self.request_headers = request_headers + + def __call__(self, test_obj): + for headers, remaining in zip(map(set, self.request_headers), + test_obj.request_remaining()): + diff = headers.symmetric_difference(remaining) + + if diff: + print_red(str(diff)) + raise TestFailed('Not all files were crawled correctly.') diff --git a/testenv/conf/hook_sample.py b/testenv/conf/hook_sample.py new file mode 100644 index 0000000..591ec3b --- /dev/null +++ b/testenv/conf/hook_sample.py @@ -0,0 +1,22 @@ +from exc.test_failed import TestFailed +from conf import hook + +""" Hook: SampleHook +This a sample file for how a new hook should be defined. +Any errors should always be reported by raising a TestFailed exception instead +of returning a true or false value. +""" + + +@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 + if False: + raise TestFailed("Reason") + pass diff --git a/testenv/conf/local_files.py b/testenv/conf/local_files.py new file mode 100644 index 0000000..908ced1 --- /dev/null +++ b/testenv/conf/local_files.py @@ -0,0 +1,26 @@ +from os import utime +from time import strptime +from calendar import timegm +from conf import hook + +""" Pre-Test Hook: LocalFiles +This is a pre-test hook used to generate the specific environment before a test +is run. The LocalFiles hook creates the files which should exist on disk before +invoking Wget. +""" + + +@hook() +class LocalFiles: + def __init__(self, local_files): + self.local_files = local_files + + def __call__(self, _): + for f in self.local_files: + with open(f.name, 'w') as fp: + fp.write(f.content) + if f.timestamp is not None: + tstamp = timegm(strptime(f.timestamp, '%Y-%m-%d %H:%M:%S')) + atime = tstamp + mtime = tstamp + utime(f.name, (atime, mtime)) diff --git a/testenv/conf/reject_header.py b/testenv/conf/reject_header.py new file mode 100644 index 0000000..0dcf463 --- /dev/null +++ b/testenv/conf/reject_header.py @@ -0,0 +1,13 @@ +from conf import rule + +""" Rule: RejectHeader +This is a server side rule which expects a dictionary object of Headers and +their values which should be blacklisted by the server for a particular file's +requests. +""" + + +@rule() +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..976a9ce --- /dev/null +++ b/testenv/conf/response.py @@ -0,0 +1,11 @@ +from conf import rule + +""" Rule: Response +When this rule is set against a certain file, the server will unconditionally +respond to any request for the said file with the provided response code. """ + + +@rule() +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..6345a3c --- /dev/null +++ b/testenv/conf/rule_sample.py @@ -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 diff --git a/testenv/conf/send_header.py b/testenv/conf/send_header.py new file mode 100644 index 0000000..1ac54cc --- /dev/null +++ b/testenv/conf/send_header.py @@ -0,0 +1,12 @@ +from conf import rule + +""" Rule: SendHeader +Have the server send custom headers when responding to a request for the file +this rule is applied to. The header_obj object is expected to be dictionary +mapping headers to their contents. """ + + +@rule() +class SendHeader: + def __init__(self, header_obj): + self.headers = header_obj diff --git a/testenv/conf/server_files.py b/testenv/conf/server_files.py new file mode 100644 index 0000000..eaa9cd0 --- /dev/null +++ b/testenv/conf/server_files.py @@ -0,0 +1,26 @@ +from conf import hook + +""" Pre-Test Hook: ServerFiles +This hook is used to define a set of files on the server's virtual filesystem. +server_files is expected to be dictionary that maps filenames to their +contents. In the future, this can be used to add additional metadata to the +files using the WgetFile class too. + +This hook also does some additional processing on the contents of the file. Any +text between {{and}} is replaced by the contents of a class variable of the +same name. This is useful in creating files that contain an absolute link to +another file on the same server. """ + + +@hook() +class ServerFiles: + def __init__(self, server_files): + self.server_files = server_files + + def __call__(self, test_obj): + for server, files in zip(test_obj.servers, self.server_files): + files_content = {f.name: test_obj._replace_substring(f.content) + for f in files} + files_rules = {f.name: test_obj.get_server_rules(f) + for f in files} + server.server_conf(files_content, files_rules) diff --git a/testenv/conf/urls.py b/testenv/conf/urls.py new file mode 100644 index 0000000..f34c13e --- /dev/null +++ b/testenv/conf/urls.py @@ -0,0 +1,14 @@ +from conf import hook + +""" Pre-Test Hook: URLS +This hook is used to define the paths of the files on the test server that wget +will send a request for. """ + + +@hook(alias='Urls') +class URLs: + def __init__(self, urls): + self.urls = urls + + def __call__(self, test_obj): + test_obj.urls = self.urls diff --git a/testenv/conf/wget_commands.py b/testenv/conf/wget_commands.py new file mode 100644 index 0000000..fb379be --- /dev/null +++ b/testenv/conf/wget_commands.py @@ -0,0 +1,15 @@ +from conf import hook + +""" Pre-Test Hook: WgetCommands +This hook is used to specify the test specific switches that must be passed to +wget on invocation. Default switches are hard coded in the test suite itself. +""" + + +@hook() +class WgetCommands: + def __init__(self, commands): + self.commands = commands + + def __call__(self, test_obj): + test_obj.wget_options = test_obj._replace_substring(self.commands) |