Browse Source

Add integration tests

Matt Robenolt 9 years ago
parent
commit
9c115684a5

+ 15 - 0
src/sentry/testutils/cases.py

@@ -145,6 +145,21 @@ class BaseTestCase(Fixtures, Exam):
             )
         return resp
 
+    def _postCspWithHeader(self, data, key=None, **extra):
+        if isinstance(data, dict):
+            body = json.dumps({'csp-report': data})
+        elif isinstance(data, basestring):
+            body = data
+        path = reverse('sentry-api-csp-report', kwargs={'project_id': self.project.id})
+        path += '?sentry_key=%s&sentry_version=5' % self.projectkey.public_key
+        with self.tasks():
+            return self.client.post(
+                path, data=body,
+                content_type='application/csp-report',
+                HTTP_USER_AGENT='awesome',
+                **extra
+            )
+
     def _getWithReferer(self, data, key=None, referer='getsentry.com', protocol='4'):
         if key is None:
             key = self.projectkey.public_key

+ 1 - 0
tests/integration/fixtures/csp/chrome_blocked_asset_input.json

@@ -0,0 +1 @@
+{"csp-report":{"document-uri":"http://localhost:8000/","referrer":"","violated-directive":"style-src cdn.example.com","effective-directive":"style-src","original-policy":"default-src 'none'; style-src cdn.example.com; report-uri http://requestb.in/1im8m061","blocked-uri":"http://localhost:8000/lol.css","status-code":200}}

+ 18 - 0
tests/integration/fixtures/csp/chrome_blocked_asset_output.json

@@ -0,0 +1,18 @@
+{
+  "message": "CSP Violation: blocked-uri 'http://localhost:8000/lol.css'",
+  "data": {
+    "sentry.interfaces.User": {"ip_address": "127.0.0.1"},
+    "sentry.interfaces.Csp": {
+      "blocked_uri": "http://localhost:8000/lol.css",
+      "status_code": 200,
+      "violated_directive": "style-src cdn.example.com",
+      "document_uri": "http://localhost:8000/",
+      "original_policy": "default-src 'none'; style-src cdn.example.com; report-uri http://requestb.in/1im8m061",
+      "effective_directive": "style-src"
+    },
+    "sentry.interfaces.Http": {
+      "url": "http://localhost:8000/",
+      "headers": [["User-Agent", "awesome"]]
+    }
+  }
+}

+ 1 - 0
tests/integration/fixtures/csp/chrome_input.json

@@ -0,0 +1 @@
+{"csp-report":{"document-uri":"http://localhost:8000/","referrer":"","violated-directive":"style-src cdn.example.com","effective-directive":"style-src","original-policy":"default-src 'none'; style-src cdn.example.com; report-uri http://requestb.in/1im8m061","blocked-uri":"http://localhost:8000/lol.css","status-code":200}}

+ 1 - 0
tests/integration/fixtures/csp/chrome_output.json

@@ -0,0 +1 @@
+{}

+ 1 - 0
tests/integration/fixtures/csp/firefox_blocked_asset_input.json

@@ -0,0 +1 @@
+{"csp-report":{"blocked-uri":"http://localhost:8000/lol.css","document-uri":"http://localhost:8000/","original-policy":"default-src 'none'; style-src http://cdn.example.com; report-uri http://requestb.in/1im8m061","referrer":"","violated-directive":"style-src http://cdn.example.com"}}

+ 16 - 0
tests/integration/fixtures/csp/firefox_blocked_asset_output.json

@@ -0,0 +1,16 @@
+{
+  "message": "CSP Violation: blocked-uri 'http://localhost:8000/lol.css'",
+  "data": {
+    "sentry.interfaces.User": {"ip_address": "127.0.0.1"},
+    "sentry.interfaces.Csp": {
+      "blocked_uri": "http://localhost:8000/lol.css",
+      "violated_directive": "style-src http://cdn.example.com",
+      "document_uri": "http://localhost:8000/",
+      "original_policy": "default-src 'none'; style-src http://cdn.example.com; report-uri http://requestb.in/1im8m061"
+    },
+    "sentry.interfaces.Http": {
+      "url": "http://localhost:8000/",
+      "headers": [["User-Agent", "awesome"]]
+    }
+  }
+}

+ 54 - 0
tests/integration/tests.py

@@ -2,6 +2,7 @@
 
 from __future__ import absolute_import, print_function
 
+import os
 import datetime
 import json
 import logging
@@ -70,6 +71,15 @@ DEPENDENCY_TEST_DATA = {
 }
 
 
+def get_fixture_path(name):
+    return os.path.join(os.path.dirname(__file__), 'fixtures', name)
+
+
+def load_fixture(name):
+    with open(get_fixture_path(name)) as fp:
+        return fp.read()
+
+
 class AssertHandler(logging.Handler):
     def emit(self, entry):
         raise AssertionError(entry.message)
@@ -380,3 +390,47 @@ class DepdendencyTest(TestCase):
 
     def test_validate_fails_on_pylibmc(self):
         self.validate_dependency(*DEPENDENCY_TEST_DATA['pylibmc'])
+
+
+def make_csp_test(f, func):
+    path = os.path.join(os.path.dirname(__file__), 'fixtures/csp', f)
+
+    def run(self):
+        with open(path + '_input.json', 'rb') as fp1:
+            input = fp1.read()
+        with open(path + '_output.json', 'rb') as fp2:
+            output = json.load(fp2)
+        func(self, input, output)
+    return run
+
+
+class _CspReportTestGenerator(type):
+    def __new__(cls, name, bases, attrs):
+        test_cases = []
+        for k, v in attrs.copy().iteritems():
+            if k.startswith('test_') and callable(v):
+                test_cases.append((k, v))
+                attrs.pop(k)
+        for f in attrs['fixtures']:
+            for name, func in test_cases:
+                test = make_csp_test(f, func)
+                test.__name__ = '%s:%s' % (name, f)
+                attrs[test.__name__] = test
+        return super(_CspReportTestGenerator, cls).__new__(cls, name, bases, attrs)
+
+
+class CspReportTest(TestCase):
+    __metaclass__ = _CspReportTestGenerator
+    fixtures = (
+        'chrome_blocked_asset',
+        'firefox_blocked_asset'
+    )
+
+    def test_successful(self, input, output):
+        resp = self._postCspWithHeader(input)
+        assert resp.status_code == 201, resp.content
+        assert Event.objects.count() == 1
+        e = Event.objects.all()[0]
+        Event.objects.bind_nodes([e], 'data')
+        assert e.message == output['message']
+        self.assertDictContainsSubset(output['data'], e.data.data, e.data.data)

+ 1 - 11
tests/sentry/web/api/tests.py

@@ -18,16 +18,6 @@ class CspReportViewTest(TestCase):
         path = reverse('sentry-api-csp-report', kwargs={'project_id': self.project.id})
         return path + '?sentry_key=%s&sentry_version=5' % self.projectkey.public_key
 
-    def _postWithHeader(self, data, key=None, **extra):
-        body = json.dumps({'csp-report': data})
-        with self.tasks():
-            return self.client.post(
-                self.path, data=body,
-                content_type='application/csp-report',
-                HTTP_USER_AGENT='awesome',
-                **extra
-            )
-
     def test_get_response(self):
         resp = self.client.get(self.path)
         assert resp.status_code == 405, resp.content
@@ -58,7 +48,7 @@ class CspReportViewTest(TestCase):
     @mock.patch('sentry.web.api.CspReportView.process')
     def test_post_success(self, process):
         process.return_value = 'ok'
-        resp = self._postWithHeader(dict(document_uri='http://example.com'))
+        resp = self._postCSPWithHeader({'csp-report': {'document_uri': 'http://example.com'}})
         assert resp.status_code == 201, resp.content