~tribaal/txaws/xss-hardening

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
from twisted.trial.unittest import TestCase

from txaws.server.method import Method
from txaws.server.registry import Registry
from txaws.server.exception import APIError

try:
    from txaws.server.tests.fixtures import (
        has_venusian, importerror, amodule)
    from txaws.server.tests.fixtures.amodule import TestMethod
    from txaws.server.tests.fixtures.importerror.amodule import (
        TestMethod as testmethod)
    no_class_decorators = False
except SyntaxError:
    no_class_decorators = True
    has_venusian = False


class RegistryTestCase(TestCase):

    if no_class_decorators:
        skip = ("Your version of Python doesn't seem to support class "
                "decorators.")

    def setUp(self):
        super(RegistryTestCase, self).setUp()
        self.registry = Registry()

    def test_add(self):
        """
        L{MethodRegistry.add} registers a method class for the given action
        and version.
        """
        self.registry.add(TestMethod, "test", "1.0")
        self.registry.add(TestMethod, "test", "2.0")
        self.registry.check("test", "1.0")
        self.registry.check("test", "2.0")
        self.assertIdentical(TestMethod, self.registry.get("test", "1.0"))
        self.assertIdentical(TestMethod, self.registry.get("test", "2.0"))

    def test_add_duplicate_method(self):
        """
        L{MethodRegistry.add} fails if a method class for the given action
        and version was already registered.
        """

        class TestMethod2(Method):
            pass

        self.registry.add(TestMethod, "test", "1.0")
        self.assertRaises(RuntimeError, self.registry.add, TestMethod2,
                          "test", "1.0")

    def test_get(self):
        """
        L{MethodRegistry.get} returns the method class registered for the
        given action and version.
        """

        class TestMethod2(Method):
            pass

        self.registry.add(TestMethod, "test", "1.0")
        self.registry.add(TestMethod, "test", "2.0")
        self.registry.add(TestMethod2, "test", "3.0")
        self.assertIdentical(TestMethod, self.registry.get("test", "1.0"))
        self.assertIdentical(TestMethod, self.registry.get("test", "2.0"))
        self.assertIdentical(TestMethod2, self.registry.get("test", "3.0"))

    def test_check_with_missing_action(self):
        """
        L{MethodRegistry.get} fails if the given action is not registered.
        """
        error = self.assertRaises(APIError, self.registry.check, "boom", "1.0")
        self.assertEqual(400, error.status)
        self.assertEqual("InvalidAction", error.code)
        self.assertEqual("The action boom is not valid for this web service.",
                         error.message)

    def test_check_with_missing_version(self):
        """
        L{MethodRegistry.get} fails if the given action is not registered.
        """
        self.registry.add(TestMethod, "test", "1.0")
        error = self.assertRaises(APIError, self.registry.check, "test", "2.0")
        self.assertEqual(400, error.status)
        self.assertEqual("InvalidVersion", error.code)
        self.assertEqual("Invalid API version.", error.message)

    def test_scan(self):
        """
        L{MethodRegistry.scan} registers the L{Method}s decorated with L{api}.
        """
        self.registry.scan(amodule)
        self.assertIdentical(TestMethod, self.registry.get("TestMethod", None))

    def test_scan_raises_error_on_importerror(self):
        """
        L{MethodRegistry.scan} raises an error by default when an error happens
        and there is no onerror callback is passed.
        """
        self.assertRaises(ImportError, self.registry.scan, importerror)

    def test_scan_swallows_with_onerror(self):
        """
        L{MethodRegistry.scan} accepts an onerror callback that can be used to
        deal with scanning errors.
        """
        swallowed = []

        def swallow(error):
            swallowed.append(error)

        self.registry.scan(importerror, onerror=swallow)
        self.assertEqual(1, len(swallowed))
        self.assertEqual(testmethod, self.registry.get("TestMethod"))

    if not has_venusian:
        test_scan.skip = "venusian module not available"
        test_scan_raises_error_on_importerror.skip = (
            "venusian module not available")
        test_scan_swallows_with_onerror.skip = "venusian module not available"