Merge branch 'master' of github.com:getsentry/raven-python

This commit is contained in:
Andrew Svetlov 2014-06-23 20:11:28 +03:00
commit 69940fc47c
38 changed files with 446 additions and 245 deletions

View File

@ -4,6 +4,8 @@ python:
- "2.7"
- "3.2"
- "3.3"
- "3.4"
- "pypy"
env:
matrix:
- DJANGO=Django==1.4.10
@ -46,6 +48,8 @@ matrix:
env: DJANGO=Django==1.4.10
- python: "3.3"
env: DJANGO=Django==1.4.10
- python: "3.4"
env: DJANGO=Django==1.4.10
- python: "2.6"
env: DJANGO="-e git+git://github.com/django/django.git#egg=Django"
- python: "2.6"

View File

@ -1,3 +1,9 @@
Version 5.0.0
-------------
* Sentry client protocol is now version 5.
* Various improvements to threaded transport.
Version 4.2.0
-------------

View File

@ -56,7 +56,7 @@ Add the following lines to your project's `.ini` file to setup `SentryHandler`:
[handler_sentry]
class = raven.handlers.logging.SentryHandler
args = ('SENTRY_DSN')
args = ('SENTRY_DSN',)
level = NOTSET
formatter = generic

View File

@ -115,17 +115,19 @@ class Client(object):
>>> print "Exception caught; reference is %s" % ident
"""
logger = logging.getLogger('raven')
protocol_version = '4'
protocol_version = '5'
_registry = TransportRegistry(transports=default_transports)
def __init__(self, dsn=None, **options):
def __init__(self, dsn=None, raise_send_errors=False, **options):
global Raven
o = options
self.configure_logging()
self.raise_send_errors = raise_send_errors
# configure loggers first
cls = self.__class__
self.state = ClientState()
@ -296,7 +298,7 @@ class Client(object):
if k not in data:
data[k] = v
if stack and 'sentry.interfaces.Stacktrace' not in data:
if stack and 'stacktrace' not in data:
if stack is True:
frames = iter_stack_frames()
@ -309,12 +311,12 @@ class Client(object):
capture_locals=self.capture_locals,
)
data.update({
'sentry.interfaces.Stacktrace': stack_info,
'stacktrace': stack_info,
})
if 'sentry.interfaces.Stacktrace' in data:
if 'stacktrace' in data:
if self.include_paths:
for frame in data['sentry.interfaces.Stacktrace']['frames']:
for frame in data['stacktrace']['frames']:
if frame.get('in_app') is not None:
continue
@ -332,10 +334,12 @@ class Client(object):
)
if not culprit:
if 'sentry.interfaces.Stacktrace' in data:
culprit = get_culprit(data['sentry.interfaces.Stacktrace']['frames'])
elif data.get('sentry.interfaces.Exception', {}).get('stacktrace'):
culprit = get_culprit(data['sentry.interfaces.Exception']['stacktrace']['frames'])
if 'stacktrace' in data:
culprit = get_culprit(data['stacktrace']['frames'])
elif 'exception' in data:
stacktrace = data['exception']['values'][0].get('stacktrace')
if stacktrace:
culprit = get_culprit(stacktrace['frames'])
if not data.get('level'):
data['level'] = kwargs.get('level') or logging.ERROR
@ -407,7 +411,7 @@ class Client(object):
>>> client.user_context({'email': 'foo@example.com'})
"""
return self.context.merge({
'sentry.interfaces.User': data,
'user': data,
})
def http_context(self, data, **kwargs):
@ -417,7 +421,7 @@ class Client(object):
>>> client.http_context({'url': 'http://example.com'})
"""
return self.context.merge({
'sentry.interfaces.Http': data,
'request': data,
})
def extra_context(self, data, **kwargs):
@ -448,7 +452,7 @@ class Client(object):
To use structured data (interfaces) with capture:
>>> capture('raven.events.Message', message='foo', data={
>>> 'sentry.interfaces.Http': {
>>> 'request': {
>>> 'url': '...',
>>> 'data': {},
>>> 'query_string': '...',
@ -546,9 +550,12 @@ class Client(object):
self.state.set_fail(retry_after=retry_after)
def send_remote(self, url, data, headers=None):
# If the client is configured to raise errors on sending,
# the implication is that the backoff and retry strategies
# will be handled by the calling application
if headers is None:
headers = {}
if not self.state.should_try():
if not self.raise_send_errors and not self.state.should_try():
message = self._get_log_message(data)
self.error_logger.error(message)
return
@ -569,6 +576,8 @@ class Client(object):
transport.send(data, headers)
self._successful_send()
except Exception as e:
if self.raise_send_errors:
raise
failed_send(e)
def send(self, auth_header=None, **data):

View File

@ -62,4 +62,9 @@ PROCESSORS = (
# Default Project ID
PROJECT = 1
CA_BUNDLE = os.path.join(ROOT, 'data', 'cacert.pem')
try:
# Try for certifi first since they likely keep their bundle more up to date
import certifi
CA_BUNDLE = certifi.where()
except ImportError:
CA_BUNDLE = os.path.join(ROOT, 'data', 'cacert.pem')

View File

@ -26,4 +26,4 @@ class AsyncClient(Client):
super(AsyncClient, self).send(**kwargs)
def send(self, **kwargs):
self.worker.queue(self.send_sync, kwargs)
self.worker.queue(self.send_sync, **kwargs)

View File

@ -26,7 +26,7 @@ def get_data_from_request(request):
formdata = {}
data = {
'sentry.interfaces.Http': {
'request': {
'url': '%s://%s%s' % (urlparts.scheme, urlparts.netloc, urlparts.path),
'query_string': urlparts.query,
'method': request.method,

View File

@ -58,7 +58,7 @@ class DjangoClient(Client):
result = {}
if hasattr(request, 'user') and isinstance(request.user, BaseUser):
result['sentry.interfaces.User'] = self.get_user_info(request.user)
result['user'] = self.get_user_info(request.user)
try:
uri = request.build_absolute_uri()
@ -90,7 +90,7 @@ class DjangoClient(Client):
environ = request.META
result.update({
'sentry.interfaces.Http': {
'request': {
'method': request.method,
'url': uri,
'query_string': request.META.get('QUERY_STRING'),
@ -106,10 +106,11 @@ class DjangoClient(Client):
def build_msg(self, *args, **kwargs):
data = super(DjangoClient, self).build_msg(*args, **kwargs)
stacks = (
data.get('sentry.interfaces.Stacktrace'),
data.get('sentry.interfaces.Exception', {}).get('stacktrace'),
)
stacks = [
data.get('stacktrace'),
]
if 'exception' in data:
stacks.append(data['exception']['values'][0]['stacktrace'])
for stacktrace in filter(bool, stacks):
for frame in stacktrace['frames']:
@ -181,6 +182,8 @@ class DjangoClient(Client):
try:
return self.send_integrated(kwargs)
except Exception as e:
if self.raise_send_errors:
raise
self.error_logger.error(
'Unable to record event: %s\nEvent was: %r', e,
kwargs['message'], exc_info=True)

View File

@ -142,7 +142,7 @@ def get_client(client=None):
class_name = str(class_name)
try:
instance = getattr(__import__(module, {}, {}, class_name), class_name)(**options)
Client = getattr(__import__(module, {}, {}, class_name), class_name)
except ImportError:
logger.exception('Failed to import client: %s', client)
if not _client[1]:
@ -150,6 +150,7 @@ def get_client(client=None):
client = 'raven.contrib.django.DjangoClient'
_client = (client, get_client(client))
else:
instance = Client(**options)
if not tmp_client:
_client = (client, instance)
return instance

View File

@ -41,7 +41,7 @@ def get_data_from_template(source):
context_line = source_lines[lineno]
return {
'sentry.interfaces.Template': {
'template': {
'filename': origin.loadname,
'abs_path': origin.name,
'pre_context': pre_context,

View File

@ -207,11 +207,17 @@ class Sentry(object):
def captureException(self, *args, **kwargs):
assert self.client, 'captureException called before application configured'
result = self.client.captureException(*args, **kwargs)
self.last_event_id = self.client.get_ident(result)
if result:
self.last_event_id = self.client.get_ident(result)
else:
self.last_event_id = None
return result
def captureMessage(self, *args, **kwargs):
assert self.client, 'captureMessage called before application configured'
result = self.client.captureMessage(*args, **kwargs)
self.last_event_id = self.client.get_ident(result)
if result:
self.last_event_id = self.client.get_ident(result)
else:
self.last_event_id = None
return result

View File

@ -183,7 +183,7 @@ class SentryMixin(object):
:param return: A dictionary.
"""
return {
'sentry.interfaces.Http': {
'request': {
'url': self.request.full_url(),
'method': self.request.method,
'data': self.request.body,
@ -202,7 +202,7 @@ class SentryMixin(object):
Truth calue testing
"""
return {
'sentry.interfaces.User': {
'user': {
'is_authenticated': True if self.get_current_user() else False
}
}

View File

@ -15,7 +15,7 @@ from raven.utils.wsgi import get_headers, get_environ
def get_data_from_request():
"""Returns request data extracted from web.ctx."""
return {
'sentry.interfaces.Http': {
'request': {
'url': '%s://%s%s' % (web.ctx['protocol'], web.ctx['host'], web.ctx['path']),
'query_string': web.ctx.query,
'method': web.ctx.method,

View File

@ -86,9 +86,8 @@ class ZopeSentryHandler(SentryHandler):
http['headers']['User-Agent'] = \
http['headers']['HTTP_USER_AGENT']
if 'QUERY_STRING' in http['headers']:
http['query_string'] = http['headers'
]['QUERY_STRING']
setattr(record, 'sentry.interfaces.Http', http)
http['query_string'] = http['headers']['QUERY_STRING']
setattr(record, 'request', http)
user = request.get('AUTHENTICATED_USER', None)
if user is not None:
user_dict = dict(id=user.getId(),
@ -96,7 +95,7 @@ class ZopeSentryHandler(SentryHandler):
email=user.getProperty('email') or '')
else:
user_dict = {'is_authenticated': False}
setattr(record, 'sentry.interfaces.User', user_dict)
setattr(record, 'user', user_dict)
except (AttributeError, KeyError):
logger.warning('Could not extract data from request', exc_info=True)
return super(ZopeSentryHandler, self).emit(record)

View File

@ -41,9 +41,10 @@ class Exception(BaseEvent):
- module '__builtin__' (i.e. __builtin__.TypeError)
- frames: a list of serialized frames (see _get_traceback_frames)
"""
name = 'exception'
def to_string(self, data):
exc = data['sentry.interfaces.Exception']
exc = data[self.name]['values'][0]
if exc['value']:
return '%s: %s' % (exc['type'], exc['value'])
return exc['type']
@ -71,11 +72,13 @@ class Exception(BaseEvent):
return {
'level': kwargs.get('level', logging.ERROR),
'sentry.interfaces.Exception': {
'value': to_unicode(exc_value),
'type': str(exc_type),
'module': to_unicode(exc_module),
'stacktrace': stack_info,
self.name: {
'values': [{
'value': to_unicode(exc_value),
'type': str(exc_type),
'module': to_unicode(exc_module),
'stacktrace': stack_info,
}],
},
}
finally:
@ -92,10 +95,12 @@ class Message(BaseEvent):
- message: 'My message from %s about %s'
- params: ('foo', 'bar')
"""
name = 'sentry.interfaces.Message'
def capture(self, message, params=(), formatted=None, **kwargs):
message = to_unicode(message)
data = {
'sentry.interfaces.Message': {
self.name: {
'message': message,
'params': self.transform(params),
},
@ -112,13 +117,15 @@ class Query(BaseEvent):
- query: 'SELECT * FROM table'
- engine: 'postgesql_psycopg2'
"""
name = 'sentry.interfaces.Query'
def to_string(self, data):
sql = data['sentry.interfaces.Query']
sql = data[self.name]
return sql['query']
def capture(self, query, engine, **kwargs):
return {
'sentry.interfaces.Query': {
self.name: {
'query': to_unicode(query),
'engine': str(engine),
}

View File

@ -23,7 +23,7 @@ class SentryHandler(logbook.Handler):
if len(args) == 1:
arg = args[0]
if isinstance(arg, six.string_types):
self.client = kwargs.pop('client_cls', Client)(dsn=arg)
self.client = kwargs.pop('client_cls', Client)(dsn=arg, **kwargs)
elif isinstance(arg, Client):
self.client = arg
else:
@ -48,6 +48,8 @@ class SentryHandler(logbook.Handler):
return self._emit(record)
except Exception:
if self.client.raise_send_errors:
raise
print("Top level Sentry exception caught - failed creating log record", file=sys.stderr)
print(to_string(record.msg), file=sys.stderr)
print(to_string(traceback.format_exc()))

View File

@ -32,7 +32,7 @@ class SentryHandler(logging.Handler, object):
if len(args) == 1:
arg = args[0]
if isinstance(arg, six.string_types):
self.client = client(dsn=arg)
self.client = client(dsn=arg, **kwargs)
elif isinstance(arg, Client):
self.client = arg
else:
@ -67,6 +67,8 @@ class SentryHandler(logging.Handler, object):
return self._emit(record)
except Exception:
if self.client.raise_send_errors:
raise
print("Top level Sentry exception caught - failed creating log record", file=sys.stderr)
print(to_string(record.msg), file=sys.stderr)
print(to_string(traceback.format_exc()), file=sys.stderr)
@ -159,7 +161,7 @@ class SentryHandler(logging.Handler, object):
handler_kwargs = {'exc_info': record.exc_info}
# HACK: discover a culprit when we normally couldn't
elif not (data.get('sentry.interfaces.Stacktrace') or data.get('culprit')) and (record.name or record.funcName):
elif not (data.get('stacktrace') or data.get('culprit')) and (record.name or record.funcName):
culprit = label_from_frame({'module': record.name, 'function': record.funcName})
if culprit:
data['culprit'] = culprit

View File

@ -25,15 +25,15 @@ class Processor(object):
if resp:
data = resp
if 'sentry.interfaces.Stacktrace' in data:
self.filter_stacktrace(data['sentry.interfaces.Stacktrace'])
if 'stacktrace' in data:
self.filter_stacktrace(data['stacktrace'])
if 'sentry.interfaces.Exception' in data:
if 'stacktrace' in data['sentry.interfaces.Exception']:
self.filter_stacktrace(data['sentry.interfaces.Exception']['stacktrace'])
if 'exception' in data:
if 'stacktrace' in data['exception']:
self.filter_stacktrace(data['exception']['stacktrace'])
if 'sentry.interfaces.Http' in data:
self.filter_http(data['sentry.interfaces.Http'])
if 'request' in data:
self.filter_http(data['request'])
return data

View File

@ -59,7 +59,7 @@ def send_test_message(client, options):
data = options.get('data', {
'culprit': 'raven.scripts.runner',
'logger': 'raven.test',
'sentry.interfaces.Http': {
'request': {
'method': 'GET',
'url': 'http://example.com',
}

View File

@ -9,10 +9,11 @@ from __future__ import absolute_import
import atexit
import logging
import time
import threading
import os
from time import sleep, time
from raven.transport.base import AsyncTransport
from raven.transport.http import HTTPTransport
from raven.utils.compat import Queue
@ -35,16 +36,67 @@ class AsyncWorker(object):
self.start()
def main_thread_terminated(self):
size = self._queue.qsize()
if size:
self._lock.acquire()
try:
if not self._thread:
# thread not started or already stopped - nothing to do
return
# wake the processing thread up
self._queue.put_nowait(self._terminator)
timeout = self.options['shutdown_timeout']
print("Sentry is attempting to send %s pending error messages" % size)
print("Waiting up to %s seconds" % timeout)
if os.name == 'nt':
print("Press Ctrl-Break to quit")
else:
print("Press Ctrl-C to quit")
self.stop(timeout=timeout)
# wait briefly, initially
initial_timeout = 0.1
if timeout < initial_timeout:
initial_timeout = timeout
if not self._timed_queue_join(initial_timeout):
# if that didn't work, wait a bit longer
# NB that size is an approximation, because other threads may
# add or remove items
size = self._queue.qsize()
print("Sentry is attempting to send %i pending error messages"
% size)
print("Waiting up to %s seconds" % timeout)
if os.name == 'nt':
print("Press Ctrl-Break to quit")
else:
print("Press Ctrl-C to quit")
self._timed_queue_join(timeout - initial_timeout)
self._thread = None
finally:
self._lock.release()
def _timed_queue_join(self, timeout):
"""
implementation of Queue.join which takes a 'timeout' argument
returns true on success, false on timeout
"""
deadline = time() + timeout
queue = self._queue
queue.all_tasks_done.acquire()
try:
while queue.unfinished_tasks:
delay = deadline - time()
if delay <= 0:
# timed out
return False
queue.all_tasks_done.wait(timeout=delay)
return True
finally:
queue.all_tasks_done.release()
def start(self):
"""
@ -77,17 +129,20 @@ class AsyncWorker(object):
self._queue.put_nowait((callback, args, kwargs))
def _target(self):
while 1:
while True:
record = self._queue.get()
if record is self._terminator:
break
callback, args, kwargs = record
try:
callback(*args, **kwargs)
except Exception:
logger.error('Failed processing job', exc_info=True)
if record is self._terminator:
break
callback, args, kwargs = record
try:
callback(*args, **kwargs)
except Exception:
logger.error('Failed processing job', exc_info=True)
finally:
self._queue.task_done()
time.sleep(0)
sleep(0)
class ThreadedHTTPTransport(AsyncTransport, HTTPTransport):

View File

@ -19,19 +19,22 @@ except:
class TornadoHTTPTransport(HTTPTransport):
scheme = ['tornado+http']
scheme = ['tornado+http', 'tornado+https']
def __init__(self, parsed_url):
def __init__(self, parsed_url, **kwargs):
if not has_tornado:
raise ImportError('TornadoHTTPTransport requires tornado.')
super(TornadoHTTPTransport, self).__init__(parsed_url)
super(TornadoHTTPTransport, self).__init__(parsed_url, **kwargs)
# remove the tornado+ from the protocol, as it is not a real protocol
self._url = self._url.split('+', 1)[-1]
def send(self, data, headers):
kwargs = dict(method='POST', headers=headers, body=data)
kwargs["validate_cert"] = self.verify_ssl
kwargs["connect_timeout"] = self.timeout
kwargs["ca_certs"] = self.ca_certs
# only use async if ioloop is running, otherwise it will never send
if ioloop.IOLoop.initialized():

View File

@ -6,6 +6,7 @@ raven.transport.udp
:license: BSD, see LICENSE for more details.
"""
from __future__ import absolute_import
from __future__ import unicode_literals
from raven.transport.base import Transport
@ -48,7 +49,7 @@ class BaseUDPTransport(Transport):
host, port = self._parsed_url.netloc.rsplit(':')
addr_info = self._get_addr_info(host, int(port))
self._send_data(auth_header + '\n\n' + data, addr_info)
self._send_data(auth_header.encode('utf-8') + b'\n\n' + data, addr_info)
class UDPTransport(BaseUDPTransport):

View File

@ -233,7 +233,7 @@ def get_stack_info(frames, transformer=transform, capture_locals=True,
# This changes /foo/site-packages/baz/bar.py into baz/bar.py
try:
base_filename = sys.modules[module_name.split('.', 1)[0]].__file__
filename = abs_path.split(base_filename.rsplit('/', 2)[0], 1)[-1][1:]
filename = abs_path.split(base_filename.rsplit('/', 2)[0], 1)[-1].lstrip("/")
except:
filename = abs_path

View File

@ -97,7 +97,7 @@ class PyTest(TestCommand):
setup(
name='raven',
version='4.2.1',
version='5.0.0',
author='David Cramer',
author_email='dcramer@gmail.com',
url='http://github.com/getsentry/raven-python',

View File

@ -187,7 +187,7 @@ class ClientTest(TestCase):
'Content-Type': 'application/octet-stream',
'X-Sentry-Auth': (
'Sentry sentry_timestamp=1328055286.51, '
'sentry_client=raven-python/%s, sentry_version=4, '
'sentry_client=raven-python/%s, sentry_version=5, '
'sentry_key=public, '
'sentry_secret=secret' % (raven.VERSION,))
},
@ -216,6 +216,35 @@ class ClientTest(TestCase):
},
)
@mock.patch('raven.transport.http.HTTPTransport.send')
@mock.patch('raven.base.ClientState.should_try')
def test_raise_exception_on_send_error(self, should_try, _send_remote):
should_try.return_value = True
client = Client(
servers=['sync+http://example.com'],
public_key='public',
secret_key='secret',
project=1,
)
# Test for the default behaviour in which a send error is handled by the client
_send_remote.side_effect = Exception()
client.capture('Message', data={}, date=None, time_spent=10,
extra={}, stack=None, tags=None, message='Test message')
assert client.state.status == client.state.ERROR
# Test for the case in which a send error is raised to the calling frame.
client = Client(
servers=['sync+http://example.com'],
public_key='public',
secret_key='secret',
project=1,
raise_send_errors=True,
)
with self.assertRaises(Exception):
client.capture('Message', data={}, date=None, time_spent=10,
extra={}, stack=None, tags=None, message='Test message')
def test_encode_decode(self):
data = {'foo': 'bar'}
encoded = self.client.encode(data)
@ -291,12 +320,12 @@ class ClientTest(TestCase):
self.assertEquals(len(self.client.events), 1)
event = self.client.events.pop(0)
self.assertEquals(event['message'], 'ValueError: foo')
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
self.assertTrue('exception' in event)
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ValueError')
self.assertEquals(exc['value'], 'foo')
self.assertEquals(exc['module'], ValueError.__module__) # this differs in some Python versions
assert 'sentry.interfaces.Stacktrace' not in event
assert 'stacktrace' not in event
stacktrace = exc['stacktrace']
self.assertEquals(len(stacktrace['frames']), 1)
frame = stacktrace['frames'][0]
@ -329,7 +358,7 @@ class ClientTest(TestCase):
self.assertEquals(len(self.client.events), 1)
event = self.client.events.pop(0)
self.assertEquals(event['message'], 'DecoratorTestException')
exc = event['sentry.interfaces.Exception']
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'DecoratorTestException')
self.assertEquals(exc['module'], self.DecoratorTestException.__module__)
stacktrace = exc['stacktrace']
@ -357,7 +386,7 @@ class ClientTest(TestCase):
self.assertEquals(len(self.client.events), 1)
event = self.client.events.pop(0)
self.assertEquals(event['message'], 'test')
self.assertFalse('sentry.interfaces.Stacktrace' in event)
assert 'stacktrace' not in event
self.assertTrue('timestamp' in event)
def test_context(self):
@ -386,9 +415,9 @@ class ClientTest(TestCase):
self.assertEquals(len(self.client.events), 1)
event = self.client.events.pop(0)
self.assertEquals(event['message'], 'test')
self.assertTrue('sentry.interfaces.Stacktrace' in event)
self.assertEquals(len(frames), len(event['sentry.interfaces.Stacktrace']['frames']))
for frame, frame_i in zip(frames, event['sentry.interfaces.Stacktrace']['frames']):
assert 'stacktrace' in event
self.assertEquals(len(frames), len(event['stacktrace']['frames']))
for frame, frame_i in zip(frames, event['stacktrace']['frames']):
self.assertEquals(frame[0].f_code.co_filename, frame_i['abs_path'])
self.assertEquals(frame[0].f_code.co_name, frame_i['function'])
@ -398,7 +427,7 @@ class ClientTest(TestCase):
self.assertEquals(len(self.client.events), 1)
event = self.client.events.pop(0)
self.assertEquals(event['message'], 'test')
self.assertTrue('sentry.interfaces.Stacktrace' in event)
self.assertTrue('stacktrace' in event)
self.assertTrue('timestamp' in event)
def test_site(self):

View File

@ -1,5 +1,3 @@
import logging
from exam import fixture
from webtest import TestApp
@ -66,14 +64,10 @@ class BottleTest(BaseTest):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Exception' in event)
assert 'exception' in event
exc = event['sentry.interfaces.Exception']
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ValueError')
self.assertEquals(exc['value'], 'hello world')
self.assertEquals(event['level'], logging.ERROR)
self.assertEquals(event['message'], 'ValueError: hello world')
self.assertEquals(event['culprit'], 'tests.contrib.bottle.tests in an_error')
def test_captureException_captures_http(self):
response = self.client.get('/capture/?foo=bar')
@ -83,8 +77,8 @@ class BottleTest(BaseTest):
event = self.raven.events.pop(0)
assert event['message'] == 'ValueError: Boom'
assert 'sentry.interfaces.Http' in event
assert 'sentry.interfaces.Exception' in event
assert 'request' in event
assert 'exception' in event
def test_captureMessage_captures_http(self):
response = self.client.get('/message/?foo=bar')
@ -93,5 +87,5 @@ class BottleTest(BaseTest):
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Message' in event)
self.assertTrue('sentry.interfaces.Http' in event)
assert 'sentry.interfaces.Message' in event
assert 'request' in event

View File

@ -147,8 +147,8 @@ class DjangoClientTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ValueError')
self.assertEquals(exc['value'], "invalid literal for int() with base 10: 'hello'")
self.assertEquals(event['level'], logging.ERROR)
@ -160,8 +160,8 @@ class DjangoClientTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'Exception')
self.assertEquals(exc['value'], 'view exception')
self.assertEquals(event['level'], logging.ERROR)
@ -178,7 +178,7 @@ class DjangoClientTest(TestCase):
assert len(self.raven.events) == 1
event = self.raven.events.pop(0)
assert 'sentry.interfaces.User' not in event
assert 'user' not in event
assert self.client.login(username='admin', password='admin')
@ -186,8 +186,8 @@ class DjangoClientTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
assert 'sentry.interfaces.User' in event
user_info = event['sentry.interfaces.User']
assert 'user' in event
user_info = event['user']
assert user_info == {
'is_authenticated': True,
'username': user.username,
@ -226,8 +226,8 @@ class DjangoClientTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ImportError')
self.assertEquals(exc['value'], 'request')
self.assertEquals(event['level'], logging.ERROR)
@ -243,8 +243,8 @@ class DjangoClientTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ImportError')
self.assertEquals(exc['value'], 'response')
self.assertEquals(event['level'], logging.ERROR)
@ -261,8 +261,8 @@ class DjangoClientTest(TestCase):
assert len(self.raven.events) == 2
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'Exception')
self.assertEquals(exc['value'], 'view exception')
self.assertEquals(event['level'], logging.ERROR)
@ -271,8 +271,8 @@ class DjangoClientTest(TestCase):
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ValueError')
self.assertEquals(exc['value'], 'handler500')
self.assertEquals(event['level'], logging.ERROR)
@ -286,8 +286,8 @@ class DjangoClientTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ImportError')
self.assertEquals(exc['value'], 'view')
self.assertEquals(event['level'], logging.ERROR)
@ -368,8 +368,8 @@ class DjangoClientTest(TestCase):
self.assertEquals(event['level'], logging.INFO)
self.assertEquals(event['logger'], 'http404')
self.assertTrue('sentry.interfaces.Http' in event)
http = event['sentry.interfaces.Http']
assert 'request' in event
http = event['request']
self.assertEquals(http['url'], 'http://testserver/non-existent-page')
self.assertEquals(http['method'], 'GET')
self.assertEquals(http['query_string'], '')
@ -434,8 +434,8 @@ class DjangoClientTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Http' in event)
http = event['sentry.interfaces.Http']
assert 'request' in event
http = event['request']
self.assertEquals(http['method'], 'POST')
self.assertEquals(http['data'], '<unavailable>')
@ -449,8 +449,8 @@ class DjangoClientTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Http' in event)
http = event['sentry.interfaces.Http']
assert 'request' in event
http = event['request']
self.assertEquals(http['method'], 'POST')
self.assertEquals(http['data'], {'foo': 'bar', 'ham': 'spam'})
@ -463,8 +463,8 @@ class DjangoClientTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Http' in event)
http = event['sentry.interfaces.Http']
assert 'request' in event
http = event['request']
self.assertEquals(http['method'], 'POST')
self.assertEquals(http['data'], '<unavailable>')
self.assertTrue('headers' in http)
@ -483,7 +483,7 @@ class DjangoClientTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
frames = event['sentry.interfaces.Exception']['stacktrace']['frames']
frames = event['exception']['values'][0]['stacktrace']['frames']
for frame in frames:
if frame['module'].startswith('django.'):
assert frame.get('in_app') is False
@ -527,8 +527,8 @@ class DjangoClientTest(TestCase):
request.META['HTTP_HOST'] = 'example.com'
result = self.raven.get_data_from_request(request)
build_absolute_uri.assert_called_once_with()
assert 'sentry.interfaces.Http' in result
assert result['sentry.interfaces.Http']['url'] == 'http://example.com/'
assert 'request' in result
assert result['request']['url'] == 'http://example.com/'
class DjangoTemplateTagTest(TestCase):
@ -568,8 +568,8 @@ class DjangoLoggingTest(TestCase):
self.assertEquals(len(self.raven.events), 1)
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Http' in event)
http = event['sentry.interfaces.Http']
assert 'request' in event
http = event['request']
self.assertEquals(http['method'], 'POST')

View File

@ -106,8 +106,8 @@ class FlaskTest(BaseTest):
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ValueError')
self.assertEquals(exc['value'], 'hello world')
self.assertEquals(event['level'], logging.ERROR)
@ -121,8 +121,8 @@ class FlaskTest(BaseTest):
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Http' in event)
http = event['sentry.interfaces.Http']
assert 'request' in event
http = event['request']
self.assertEquals(http['url'], 'http://localhost/an-error/')
self.assertEquals(http['query_string'], 'foo=bar')
self.assertEquals(http['method'], 'GET')
@ -148,8 +148,8 @@ class FlaskTest(BaseTest):
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Http' in event)
http = event['sentry.interfaces.Http']
assert 'request' in event
http = event['request']
self.assertEquals(http['url'], 'http://localhost/an-error/')
self.assertEquals(http['query_string'], 'biz=baz')
self.assertEquals(http['method'], 'POST')
@ -177,8 +177,8 @@ class FlaskTest(BaseTest):
self.assertEquals(event['event_id'], response.headers['X-Sentry-ID'])
assert event['message'] == 'ValueError: Boom'
assert 'sentry.interfaces.Http' in event
assert 'sentry.interfaces.Exception' in event
assert 'request' in event
assert 'exception' in event
def test_captureMessage_captures_http(self):
response = self.client.get('/message/?foo=bar')
@ -188,8 +188,8 @@ class FlaskTest(BaseTest):
event = self.raven.events.pop(0)
self.assertEquals(event['event_id'], response.headers['X-Sentry-ID'])
self.assertTrue('sentry.interfaces.Message' in event)
self.assertTrue('sentry.interfaces.Http' in event)
assert 'sentry.interfaces.Message' in event
assert 'request' in event
@patch('flask.wrappers.RequestBase._load_form_data')
def test_get_data_handles_disconnected_client(self, lfd):
@ -199,8 +199,8 @@ class FlaskTest(BaseTest):
event = self.raven.events.pop(0)
self.assertTrue('sentry.interfaces.Http' in event)
http = event['sentry.interfaces.Http']
assert 'request' in event
http = event['request']
self.assertEqual({}, http.get('data'))
def test_error_handler_with_ignored_exception(self):
@ -249,5 +249,5 @@ class FlaskLoginTest(BaseTest):
self.client.get('/an-error-logged-in/')
event = self.raven.events.pop(0)
assert event['message'] == 'ValueError: hello world'
assert 'sentry.interfaces.Http' in event
assert 'sentry.interfaces.User' in event
assert 'request' in event
assert 'user' in event

View File

@ -1,12 +1,6 @@
# -*- coding: utf-8 -*-
"""
tests
Test the tornado Async Client
"""
from __future__ import unicode_literals
import unittest
from mock import patch
from tornado import web, gen, testing
from raven.contrib.tornado import SentryMixin, AsyncSentryClient
@ -88,17 +82,17 @@ class TornadoAsyncClientTestCase(testing.AsyncHTTPTestCase):
self.assertEqual(send.call_count, 1)
args, kwargs = send.call_args
self.assertTrue(('sentry.interfaces.User' in kwargs))
self.assertTrue(('sentry.interfaces.Http' in kwargs))
self.assertTrue(('sentry.interfaces.Exception' in kwargs))
assert 'user' in kwargs
assert 'request' in kwargs
assert 'exception' in kwargs
http_data = kwargs['sentry.interfaces.Http']
http_data = kwargs['request']
self.assertEqual(http_data['cookies'], None)
self.assertEqual(http_data['url'], response.effective_url)
self.assertEqual(http_data['query_string'], 'qs=qs')
self.assertEqual(http_data['method'], 'GET')
user_data = kwargs['sentry.interfaces.User']
user_data = kwargs['user']
self.assertEqual(user_data['is_authenticated'], False)
@patch('raven.contrib.tornado.AsyncSentryClient.send')
@ -108,18 +102,18 @@ class TornadoAsyncClientTestCase(testing.AsyncHTTPTestCase):
self.assertEqual(send.call_count, 1)
args, kwargs = send.call_args
self.assertTrue(('sentry.interfaces.User' in kwargs))
self.assertTrue(('sentry.interfaces.Http' in kwargs))
self.assertTrue(('sentry.interfaces.Exception' in kwargs))
self.assertTrue(('extra' in kwargs))
assert 'user' in kwargs
assert 'request' in kwargs
assert 'exception' in kwargs
assert 'extra' in kwargs
http_data = kwargs['sentry.interfaces.Http']
http_data = kwargs['request']
self.assertEqual(http_data['cookies'], None)
self.assertEqual(http_data['url'], response.effective_url)
self.assertEqual(http_data['query_string'], 'qs=qs')
self.assertEqual(http_data['method'], 'GET')
user_data = kwargs['sentry.interfaces.User']
user_data = kwargs['user']
self.assertEqual(user_data['is_authenticated'], False)
assert 'extra_data' in kwargs['extra']
@ -136,18 +130,18 @@ class TornadoAsyncClientTestCase(testing.AsyncHTTPTestCase):
self.assertEqual(send.call_count, 1)
args, kwargs = send.call_args
self.assertTrue(('sentry.interfaces.User' in kwargs))
self.assertTrue(('sentry.interfaces.Http' in kwargs))
self.assertTrue(('sentry.interfaces.Exception' in kwargs))
self.assertTrue(('extra' in kwargs))
assert 'user' in kwargs
assert 'request' in kwargs
assert 'exception' in kwargs
assert 'extra' in kwargs
http_data = kwargs['sentry.interfaces.Http']
http_data = kwargs['request']
self.assertEqual(http_data['cookies'], None)
self.assertEqual(http_data['url'], response.effective_url)
self.assertEqual(http_data['query_string'], 'qs=qs')
self.assertEqual(http_data['method'], 'GET')
user_data = kwargs['sentry.interfaces.User']
user_data = kwargs['user']
self.assertEqual(user_data['is_authenticated'], False)
assert 'extra_data' in kwargs['extra']
@ -166,17 +160,17 @@ class TornadoAsyncClientTestCase(testing.AsyncHTTPTestCase):
self.assertEqual(send.call_count, 1)
args, kwargs = send.call_args
self.assertTrue(('sentry.interfaces.User' in kwargs))
self.assertTrue(('sentry.interfaces.Http' in kwargs))
self.assertTrue(('sentry.interfaces.Message' in kwargs))
assert 'user' in kwargs
assert 'request' in kwargs
assert 'sentry.interfaces.Message' in kwargs
http_data = kwargs['sentry.interfaces.Http']
http_data = kwargs['request']
self.assertEqual(http_data['cookies'], None)
self.assertEqual(http_data['url'], response.effective_url)
self.assertEqual(http_data['query_string'], 'qs=qs')
self.assertEqual(http_data['method'], 'GET')
user_data = kwargs['sentry.interfaces.User']
user_data = kwargs['user']
self.assertEqual(user_data['is_authenticated'], True)
@patch('raven.contrib.tornado.AsyncSentryClient.send')
@ -186,17 +180,17 @@ class TornadoAsyncClientTestCase(testing.AsyncHTTPTestCase):
self.assertEqual(send.call_count, 1)
args, kwargs = send.call_args
self.assertTrue(('sentry.interfaces.User' in kwargs))
self.assertTrue(('sentry.interfaces.Http' in kwargs))
self.assertTrue(('sentry.interfaces.Exception' in kwargs))
assert 'user' in kwargs
assert 'request' in kwargs
assert 'exception' in kwargs
http_data = kwargs['sentry.interfaces.Http']
http_data = kwargs['request']
self.assertEqual(http_data['cookies'], None)
self.assertEqual(http_data['url'], response.effective_url)
self.assertEqual(http_data['query_string'], 'qs=qs')
self.assertEqual(http_data['method'], 'GET')
user_data = kwargs['sentry.interfaces.User']
user_data = kwargs['user']
self.assertEqual(user_data['is_authenticated'], False)
@patch('raven.contrib.tornado.AsyncSentryClient.send')
@ -206,19 +200,15 @@ class TornadoAsyncClientTestCase(testing.AsyncHTTPTestCase):
self.assertEqual(send.call_count, 1)
args, kwargs = send.call_args
self.assertTrue(('sentry.interfaces.User' in kwargs))
self.assertTrue(('sentry.interfaces.Http' in kwargs))
self.assertTrue(('sentry.interfaces.Exception' in kwargs))
assert 'user' in kwargs
assert 'request' in kwargs
assert 'exception' in kwargs
http_data = kwargs['sentry.interfaces.Http']
http_data = kwargs['request']
self.assertEqual(http_data['cookies'], None)
self.assertEqual(http_data['url'], response.effective_url)
self.assertEqual(http_data['query_string'], 'qs=qs')
self.assertEqual(http_data['method'], 'GET')
user_data = kwargs['sentry.interfaces.User']
user_data = kwargs['user']
self.assertEqual(user_data['is_authenticated'], False)
if __name__ == '__main__':
unittest.main()

View File

@ -52,8 +52,8 @@ class WebPyTest(TestCase):
self.assertEquals(len(self.store.events), 1)
event = self.store.events.pop()
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ValueError')
self.assertEquals(exc['value'], 'That\'s what she said')
self.assertEquals(event['message'], 'ValueError: That\'s what she said')
@ -66,8 +66,8 @@ class WebPyTest(TestCase):
event = self.store.events.pop()
self.assertTrue('sentry.interfaces.Http' in event)
http = event['sentry.interfaces.Http']
assert 'request' in event
http = event['request']
self.assertEquals(http['url'], 'http://localhost/test')
self.assertEquals(http['query_string'], '?biz=baz')
self.assertEquals(http['method'], 'POST')

View File

@ -47,9 +47,9 @@ class ZeroRPCTest(TestCase):
except zerorpc.exceptions.RemoteError as ex:
self.assertEqual(ex.name, 'IndexError')
self.assertEqual(len(self._sentry.events), 1)
exc = self._sentry.events[0]['sentry.interfaces.Exception']
exc = self._sentry.events[0]['exception']
self.assertEqual(exc['type'], 'IndexError')
frames = self._sentry.events[0]['sentry.interfaces.Exception']['stacktrace']['frames']
frames = exc['stacktrace']['frames']
self.assertEqual(frames[0]['function'], 'choice')
self.assertEqual(frames[0]['module'], 'random')
else:
@ -68,9 +68,9 @@ class ZeroRPCTest(TestCase):
for attempt in xrange(0, 10):
gevent.sleep(0.1)
if len(self._sentry.events):
exc = self._sentry.events[0]['sentry.interfaces.Exception']
exc = self._sentry.events[0]['exception']
self.assertEqual(exc['type'], 'IndexError')
frames = self._sentry.events[0]['sentry.interfaces.Exception']['stacktrace']['frames']
frames = exc['stacktrace']['frames']
self.assertEqual(frames[0]['function'], 'choice')
self.assertEqual(frames[0]['module'], 'random')
return

View File

@ -37,7 +37,7 @@ class LogbookHandlerTest(TestCase):
self.assertEquals(event['logger'], __name__)
self.assertEquals(event['level'], 'error')
self.assertEquals(event['message'], 'This is a test error')
self.assertFalse('sentry.interfaces.Exception' in event)
self.assertFalse('exception' in event)
self.assertTrue('sentry.interfaces.Message' in event)
msg = event['sentry.interfaces.Message']
self.assertEquals(msg['message'], 'This is a test error')
@ -49,7 +49,7 @@ class LogbookHandlerTest(TestCase):
self.assertEquals(event['logger'], __name__)
self.assertEquals(event['level'], 'warning')
self.assertEquals(event['message'], 'This is a test warning')
self.assertFalse('sentry.interfaces.Exception' in event)
self.assertFalse('exception' in event)
self.assertTrue('sentry.interfaces.Message' in event)
msg = event['sentry.interfaces.Message']
self.assertEquals(msg['message'], 'This is a test warning')
@ -65,7 +65,7 @@ class LogbookHandlerTest(TestCase):
else:
expected = "u'http://example.com'"
self.assertEquals(event['extra']['url'], expected)
self.assertFalse('sentry.interfaces.Exception' in event)
self.assertFalse('exception' in event)
self.assertTrue('sentry.interfaces.Message' in event)
msg = event['sentry.interfaces.Message']
self.assertEquals(msg['message'], 'This is a test info with a url')
@ -80,8 +80,8 @@ class LogbookHandlerTest(TestCase):
event = client.events.pop(0)
self.assertEquals(event['message'], 'This is a test info with an exception')
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ValueError')
self.assertEquals(exc['value'], 'This is a test ValueError')
self.assertTrue('sentry.interfaces.Message' in event)
@ -94,7 +94,7 @@ class LogbookHandlerTest(TestCase):
self.assertEquals(len(client.events), 1)
event = client.events.pop(0)
self.assertEquals(event['message'], 'This is a test of args')
self.assertFalse('sentry.interfaces.Exception' in event)
assert 'exception' not in event
self.assertTrue('sentry.interfaces.Message' in event)
msg = event['sentry.interfaces.Message']
self.assertEquals(msg['message'], 'This is a test of {0}')

View File

@ -2,11 +2,13 @@ from __future__ import unicode_literals
import logging
import sys
from raven.utils.testutils import TestCase
from raven.utils import six
import mock
from raven.base import Client
from raven.handlers.logging import SentryHandler
from raven.utils import six
from raven.utils.stacks import iter_stack_frames
from raven.utils.testutils import TestCase
class TempStoreClient(Client):
@ -42,7 +44,7 @@ class LoggingIntegrationTest(TestCase):
self.assertEqual(event['logger'], 'root')
self.assertEqual(event['level'], logging.INFO)
self.assertEqual(event['message'], 'This is a test error')
self.assertFalse('sentry.interfaces.Exception' in event)
assert 'exception' not in event
self.assertTrue('sentry.interfaces.Message' in event)
msg = event['sentry.interfaces.Message']
self.assertEqual(msg['message'], 'This is a test error')
@ -61,6 +63,37 @@ class LoggingIntegrationTest(TestCase):
record = self.make_record("Test", name=test[0])
self.assertEqual(self.handler.can_record(record), test[1])
@mock.patch('raven.transport.http.HTTPTransport.send')
@mock.patch('raven.base.ClientState.should_try')
def test_exception_on_emit(self, should_try, _send_remote):
should_try.return_value = True
# Test for the default behaviour in which an exception is handled by the client or handler
client = Client(
servers=['sync+http://example.com'],
public_key='public',
secret_key='secret',
project=1,
)
handler = SentryHandler(client)
_send_remote.side_effect = Exception()
record = self.make_record('This is a test error')
handler.emit(record)
self.assertEquals(handler.client.state.status, handler.client.state.ERROR)
# Test for the case in which a send error is raised to the calling frame.
client = Client(
servers=['sync+http://example.com'],
public_key='public',
secret_key='secret',
project=1,
raise_send_errors=True,
)
handler = SentryHandler(client)
_send_remote.side_effect = Exception()
with self.assertRaises(Exception):
record = self.make_record('This is a test error')
handler.emit(record)
def test_logger_extra_data(self):
record = self.make_record('This is a test error', extra={'data': {
'url': 'http://example.com',
@ -89,8 +122,8 @@ class LoggingIntegrationTest(TestCase):
event = self.client.events.pop(0)
self.assertEqual(event['message'], 'This is a test info with an exception')
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEqual(exc['type'], 'ValueError')
self.assertEqual(exc['value'], 'This is a test ValueError')
self.assertTrue('sentry.interfaces.Message' in event)
@ -116,12 +149,12 @@ class LoggingIntegrationTest(TestCase):
self.assertEqual(len(self.client.events), 1)
event = self.client.events.pop(0)
self.assertTrue('sentry.interfaces.Stacktrace' in event)
frames = event['sentry.interfaces.Stacktrace']['frames']
self.assertTrue('stacktrace' in event)
frames = event['stacktrace']['frames']
self.assertNotEquals(len(frames), 1)
frame = frames[0]
self.assertEqual(frame['module'], 'raven.handlers.logging')
self.assertFalse('sentry.interfaces.Exception' in event)
assert 'exception' not in event
self.assertTrue('sentry.interfaces.Message' in event)
self.assertEqual(event['culprit'], 'root in make_record')
self.assertEqual(event['message'], 'This is a test of stacks')
@ -141,12 +174,12 @@ class LoggingIntegrationTest(TestCase):
self.assertEqual(len(self.client.events), 1)
event = self.client.events.pop(0)
assert 'sentry.interfaces.Stacktrace' in event
assert 'stacktrace' in event
assert 'culprit' in event
assert event['culprit'] == 'root in make_record'
self.assertTrue('message' in event, event)
self.assertEqual(event['message'], 'This is a test of stacks')
self.assertFalse('sentry.interfaces.Exception' in event)
assert 'exception' not in event
self.assertTrue('sentry.interfaces.Message' in event)
msg = event['sentry.interfaces.Message']
self.assertEqual(msg['message'], 'This is a test of stacks')

View File

@ -65,15 +65,15 @@ class MiddlewareTestCase(TestCase):
self.assertEquals(len(self.client.events), 1)
event = self.client.events.pop(0)
self.assertTrue('sentry.interfaces.Exception' in event)
exc = event['sentry.interfaces.Exception']
assert 'exception' in event
exc = event['exception']['values'][0]
self.assertEquals(exc['type'], 'ValueError')
self.assertEquals(exc['value'], 'hello world')
self.assertEquals(event['level'], logging.ERROR)
self.assertEquals(event['message'], 'ValueError: hello world')
self.assertTrue('sentry.interfaces.Http' in event)
http = event['sentry.interfaces.Http']
assert 'request' in event
http = event['request']
self.assertEquals(http['url'], 'http://localhost/an-error')
self.assertEquals(http['query_string'], 'foo=bar')
self.assertEquals(http['method'], 'GET')

View File

@ -37,7 +37,7 @@ class SantizePasswordsProcessorTest(TestCase):
def test_stacktrace(self):
data = {
'sentry.interfaces.Stacktrace': {
'stacktrace': {
'frames': [{'vars': VARS}],
}
}
@ -45,8 +45,8 @@ class SantizePasswordsProcessorTest(TestCase):
proc = SanitizePasswordsProcessor(Mock())
result = proc.process(data)
self.assertTrue('sentry.interfaces.Stacktrace' in result)
stack = result['sentry.interfaces.Stacktrace']
self.assertTrue('stacktrace' in result)
stack = result['stacktrace']
self.assertTrue('frames' in stack)
self.assertEquals(len(stack['frames']), 1)
frame = stack['frames'][0]
@ -55,7 +55,7 @@ class SantizePasswordsProcessorTest(TestCase):
def test_http(self):
data = {
'sentry.interfaces.Http': {
'request': {
'data': VARS,
'env': VARS,
'headers': VARS,
@ -66,26 +66,25 @@ class SantizePasswordsProcessorTest(TestCase):
proc = SanitizePasswordsProcessor(Mock())
result = proc.process(data)
self.assertTrue('sentry.interfaces.Http' in result)
http = result['sentry.interfaces.Http']
self.assertTrue('request' in result)
http = result['request']
for n in ('data', 'env', 'headers', 'cookies'):
self.assertTrue(n in http)
self._check_vars_sanitized(http[n], proc)
def test_querystring_as_string(self):
data = {
'sentry.interfaces.Http': {
'query_string':
'foo=bar&password=hello&the_secret=hello'
'&a_password_here=hello&api_key=secret_key',
'request': {
'query_string': 'foo=bar&password=hello&the_secret=hello'
'&a_password_here=hello&api_key=secret_key',
}
}
proc = SanitizePasswordsProcessor(Mock())
result = proc.process(data)
self.assertTrue('sentry.interfaces.Http' in result)
http = result['sentry.interfaces.Http']
self.assertTrue('request' in result)
http = result['request']
self.assertEquals(
http['query_string'],
'foo=bar&password=%(m)s&the_secret=%(m)s'
@ -93,7 +92,7 @@ class SantizePasswordsProcessorTest(TestCase):
def test_querystring_as_string_with_partials(self):
data = {
'sentry.interfaces.Http': {
'request': {
'query_string': 'foo=bar&password&baz=bar',
}
}
@ -101,8 +100,8 @@ class SantizePasswordsProcessorTest(TestCase):
proc = SanitizePasswordsProcessor(Mock())
result = proc.process(data)
self.assertTrue('sentry.interfaces.Http' in result)
http = result['sentry.interfaces.Http']
self.assertTrue('request' in result)
http = result['request']
self.assertEquals(http['query_string'], 'foo=bar&password&baz=bar' % dict(m=proc.MASK))
def test_sanitize_credit_card(self):
@ -120,7 +119,7 @@ class SantizePasswordsProcessorTest(TestCase):
class RemovePostDataProcessorTest(TestCase):
def test_does_remove_data(self):
data = {
'sentry.interfaces.Http': {
'request': {
'data': 'foo',
}
}
@ -128,22 +127,22 @@ class RemovePostDataProcessorTest(TestCase):
proc = RemovePostDataProcessor(Mock())
result = proc.process(data)
self.assertTrue('sentry.interfaces.Http' in result)
http = result['sentry.interfaces.Http']
self.assertTrue('request' in result)
http = result['request']
self.assertFalse('data' in http)
class RemoveStackLocalsProcessorTest(TestCase):
def test_does_remove_data(self):
data = {
'sentry.interfaces.Stacktrace': {
'frames': [{'vars': VARS,}],
'stacktrace': {
'frames': [{'vars': VARS}],
}
}
proc = RemoveStackLocalsProcessor(Mock())
result = proc.process(data)
self.assertTrue('sentry.interfaces.Stacktrace' in result)
stack = result['sentry.interfaces.Stacktrace']
assert 'stacktrace' in result
stack = result['stacktrace']
for frame in stack['frames']:
self.assertFalse('vars' in frame)

View File

@ -4,25 +4,27 @@ from raven.utils.testutils import TestCase
from raven.base import Client
from raven.transport.threaded import ThreadedHTTPTransport
from raven.utils.urlparse import urlparse
class DummyThreadedScheme(ThreadedHTTPTransport):
scheme = ['threaded+mock']
def __init__(self, *args, **kwargs):
super(ThreadedHTTPTransport, self).__init__(*args, **kwargs)
self.events = []
self.send_delay = 0
def send_sync(self, data, headers):
self.events.append((data, headers))
def send_sync(self, data, headers, success_cb, failure_cb):
# delay sending the message, to allow us to test that the shutdown
# hook waits correctly
time.sleep(self.send_delay)
self.events.append((data, headers, success_cb, failure_cb))
class ThreadedTransportTest(TestCase):
def setUp(self):
self.client = Client(
dsn="threaded+http://some_username:some_password@localhost:8143/1",
)
self.url = "threaded+http://some_username:some_password@localhost:8143/1"
self.client = Client(dsn=self.url)
@mock.patch('raven.transport.http.HTTPTransport.send')
def test_does_send(self, send):
@ -33,3 +35,18 @@ class ThreadedTransportTest(TestCase):
# TODO: This test could be more precise by ensuring it's sending the same params that are sent
# to the ThreadedHTTPTransport.send() method
self.assertEqual(send.call_count, 1)
def test_shutdown_waits_for_send(self):
url = urlparse(self.url)
transport = DummyThreadedScheme(url)
transport.send_delay = 0.5
data = self.client.build_msg('raven.events.Message', message='foo')
transport.async_send(data, None, None, None)
time.sleep(0.1)
# this should wait for the message to get sent
transport.get_worker().main_thread_terminated()
self.assertEqual(len(transport.events), 1)

View File

View File

@ -0,0 +1,36 @@
from __future__ import absolute_import
import mock
from raven.base import Client
from raven.utils.testutils import TestCase
class TornadoTransportTests(TestCase):
@mock.patch("raven.transport.tornado.HTTPClient")
def test_send(self, fake_client):
url = "https://user:pass@host:1234/1"
timeout = 1
verify_ssl = 1
ca_certs = "/some/path/somefile"
fake = fake_client.return_value
raven_client = Client(
dsn="tornado+{0}?timeout={1}&verify_ssl={2}&ca_certs={3}".
format(url, timeout, verify_ssl, ca_certs))
raven_client.captureMessage(message="test")
# make sure an instance of HTTPClient was created, since we are not in
# an IOLoop
fake_client.assert_called_once_with()
fake_fetch = fake.fetch
# make sure we called fetch() which does the sending
self.assertEqual(fake_fetch.call_count, 1)
# only verify the special kwargs that we should be passing through,
# no need to verify the urls and whatnot
args, kwargs = fake_fetch.call_args
self.assertEqual(kwargs["connect_timeout"], timeout)
self.assertEqual(kwargs["validate_cert"], bool(verify_ssl))
self.assertEqual(kwargs["ca_certs"], ca_certs)