summaryrefslogtreecommitdiffstats
path: root/testenv/conf
diff options
context:
space:
mode:
Diffstat (limited to 'testenv/conf')
-rw-r--r--testenv/conf/__init__.py48
-rw-r--r--testenv/conf/authentication.py23
-rw-r--r--testenv/conf/domains.py9
-rw-r--r--testenv/conf/expect_header.py12
-rw-r--r--testenv/conf/expected_files.py58
-rw-r--r--testenv/conf/expected_ret_code.py27
-rw-r--r--testenv/conf/files_crawled.py27
-rw-r--r--testenv/conf/hook_sample.py22
-rw-r--r--testenv/conf/local_files.py26
-rw-r--r--testenv/conf/reject_header.py13
-rw-r--r--testenv/conf/response.py11
-rw-r--r--testenv/conf/rule_sample.py10
-rw-r--r--testenv/conf/send_header.py12
-rw-r--r--testenv/conf/server_files.py26
-rw-r--r--testenv/conf/urls.py14
-rw-r--r--testenv/conf/wget_commands.py15
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)