def test_initialize(): app_name = 'app-name' token = 'token' collector_url = 'collector_url' metadata_only = False disable_on_timeout = False debug = True trace = trace_factory.get_or_create_trace() trace.initialize(app_name, token, collector_url, metadata_only, disable_on_timeout, debug) assert trace.app_name == app_name assert trace.token == token assert trace.collector_url == collector_url assert trace.disable_timeout_send == disable_on_timeout assert trace.debug == debug trace.initialize(app_name, '', '', False, False, False) assert trace.app_name == app_name assert trace.token == '' assert trace.collector_url == '' assert trace.metadata_only == False assert trace.disable_timeout_send == False assert trace.debug == False trace.initialize('', '', '', True, True, False) assert trace.app_name == '' assert trace.token == '' assert trace.collector_url == '' assert trace.metadata_only == True assert trace.disable_timeout_send == True assert trace.debug == False
def test_prepare(): trace = trace_factory.get_or_create_trace() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') trace.prepare() assert not trace.events assert trace.exceptions == [] assert len(w) == 1 trace.clear_events() trace.add_event(EventMock()) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') trace.prepare() assert not trace.events assert trace.exceptions == [] assert len(w) == 1 trace.clear_events() trace.add_event(EventMock()) with warnings.catch_warnings(record=True) as w: trace.prepare() trace.prepare() # this call should NOT trigger a warning assert not trace.events assert trace.exceptions == [] assert len(w) == 1
def test_add_exception_with_additional_data(): stack_trace_format = 'stack trace %d' message_format = 'message %d' tested_exception_types = [ ZeroDivisionError, RuntimeError, NameError, TypeError ] additional_data = {'key': 'value', 'key2': 'othervalue'} trace = trace_factory.get_or_create_trace() for i, exception_type in enumerate(tested_exception_types): try: raise exception_type(message_format % i) except exception_type as e: trace.add_exception(e, stack_trace_format % i, additional_data) assert len(trace.exceptions) == len(tested_exception_types) for i, exception_type in enumerate(tested_exception_types): current_exception = trace.exceptions[i] assert current_exception['type'] == str(exception_type) assert current_exception['message'] == message_format % i assert current_exception['traceback'] == stack_trace_format % i assert type(current_exception['time']) == float assert current_exception['additional_data'] == additional_data
def _test(func): func(lambda: None, [], [], {}) trace = trace_factory.get_or_create_trace() assert len(trace.exceptions) == 1 assert trace.exceptions[0]['message'] == EXCEPTION_MESSAGE assert trace.exceptions[0]['type'] == str(EXCEPTION_TYPE) assert 'time' in trace.exceptions[0].keys() assert len(trace.exceptions[0]['traceback']) > 0
def test_send_traces_sanity(wrapped_post): trace = trace_factory.get_or_create_trace() trace_factory.send_traces() wrapped_post.assert_called_with( 'POST', 'collector', body=json.dumps(trace.to_dict()), timeout=epsagon.constants.SEND_TIMEOUT, )
def test_send_traces_sanity(wrapped_post): trace = trace_factory.get_or_create_trace() trace.token = 'a' trace_factory.send_traces() wrapped_post.assert_called_with( '', data=json.dumps(trace.to_dict()), timeout=epsagon.constants.SEND_TIMEOUT, headers={'Authorization': 'Bearer {}'.format(trace.token)})
def test_add_event(): event = EventMock() trace = trace_factory.get_or_create_trace() trace.clear_events() for i in range(10): # verify we can add more then 1 event trace.add_event(event) assert event is trace.events[i] assert event.terminated
def test_set_error_sanity(): event = RunnerEventMock() trace = trace_factory.get_or_create_trace() trace.clear_events() trace.set_runner(event) msg = 'oops' trace.set_error(ValueError(msg)) assert trace.to_dict()['events'][0]['exception']['message'] == msg assert len(trace.to_dict()['events'][0]['exception']['traceback']) > 1
def test_trace_url_sanity(): event = RunnerEventMock() trace = trace_factory.get_or_create_trace() trace.clear_events() trace.set_runner(event) trace_url = trace.get_trace_url() assert trace_url == TRACE_URL_PREFIX.format( id=event.resource['metadata']['trace_id'], start_time=int(event.start_time) )
def test_send_with_sample_good_rate_with_error(wrapped_post, _): trace = trace_factory.get_or_create_trace() trace.runner = RunnerEventMock() trace.sample_rate = 0.6 trace.runner.error_code = ErrorCode.ERROR trace.add_event(trace.runner) trace.token = 'a' trace.add_event(EventMock()) trace_factory.send_traces() wrapped_post.assert_called_once()
def test_runner_duration(_wrapped_post): runner = RunnerEventMock() runner.terminated = False trace = trace_factory.get_or_create_trace() trace.token = 'a' trace.set_runner(runner) time.sleep(0.2) trace_factory.send_traces() assert 0.2 < runner.duration < 0.3
def test_send_on_error_only_off_no_error(wrapped_post): trace = trace_factory.get_or_create_trace() trace.token = 'a' trace.runner = RunnerEventMock() trace.runner.error_code = ErrorCode.OK event = EventMock() event.resource['metadata'] = datetime.fromtimestamp(1000) trace.add_event(event) trace_factory.send_traces() wrapped_post.assert_called_once()
def test_send_traces_unicode(wrapped_post): trace = trace_factory.get_or_create_trace() runner = UnicodeReturnValueEventMock() trace.set_runner(runner) trace_factory.send_traces() wrapped_post.assert_called_with( 'POST', 'collector', body=json.dumps(trace.to_dict(), ensure_ascii=False), timeout=epsagon.constants.SEND_TIMEOUT, )
def test_set_error_string(): event = RunnerEventMock() trace = trace_factory.get_or_create_trace() trace.clear_events() trace.set_runner(event) msg = 'oops' trace.set_error(msg) assert trace.to_dict()['events'][0]['exception']['message'] == msg assert trace.to_dict()['events'][0]['exception']['type'] == ( EpsagonException.__name__)
def test_send_on_error_only_with_error(wrapped_post): trace = trace_factory.get_or_create_trace() trace.send_trace_only_on_error = True trace.runner = mock.MagicMock() trace.runner.error_code = ErrorCode.ERROR trace.token = 'a' event = EventMock() event.resource['metadata'] = datetime.fromtimestamp(1000) trace.add_event(event) trace.send_traces() wrapped_post.assert_called_once()
def test_custom_labels_override_trace(): event = RunnerEventMock() trace = trace_factory.get_or_create_trace() trace.clear_events() trace.set_runner(event) trace.add_label('test_label', 'test_value1') trace.add_label('test_label', 'test_value2') trace_metadata = trace.to_dict()['events'][0]['resource']['metadata'] assert trace_metadata.get('labels') is not None assert json.loads(trace_metadata['labels']) == {'test_label': 'test_value2'}
def test_set_error_with_traceback(): event = RunnerEventMock() trace = trace_factory.get_or_create_trace() trace.clear_events() trace.set_runner(event) msg = 'oops' traceback_data = 'test_value' trace.set_error(ValueError(msg), traceback_data=traceback_data) assert trace.to_dict()['events'][0]['exception']['message'] == msg assert (trace.to_dict()['events'][0]['exception']['traceback'] == traceback_data)
def test_send_with_split_on_small_trace(wrapped_post, monkeypatch): # Should be low enough to force trace split. monkeypatch.setenv('EPSAGON_MAX_TRACE_SIZE', '500') trace = trace_factory.get_or_create_trace() trace.runner = RunnerEventMock() trace.add_event(trace.runner) trace.token = 'a' trace.split_on_send = True event = EventMock() trace.add_event(event) trace_factory.send_traces() wrapped_post.assert_called_once()
def test_lambda_trace_url_sanity(): event = LambdaRunnerEventMock() trace = trace_factory.get_or_create_trace() trace.clear_events() trace.set_runner(event) trace_url = trace.get_trace_url() assert trace_url == LAMBDA_TRACE_URL_PREFIX.format( aws_account=event.resource['metadata']['aws_account'], region=event.resource['metadata']['region'], function_name=event.resource['name'], request_id=event.event_id, request_time=int(event.start_time) )
def test_send_with_split_on_small_trace(wrapped_post): # Should be low enough to force trace split. os.environ['EPSAGON_MAX_TRACE_SIZE'] = '500' trace = trace_factory.get_or_create_trace() trace.runner = mock.MagicMock() trace.add_event(trace.runner) trace.token = 'a' trace.split_on_send = True event = EventMock() trace.add_event(event) trace.send_traces() wrapped_post.assert_called_once() os.environ.pop('EPSAGON_MAX_TRACE_SIZE')
def test_send_with_split_off(wrapped_post): # Should be low enough to force trace split. os.environ['EPSAGON_MAX_TRACE_SIZE'] = '500' trace = trace_factory.get_or_create_trace() trace.runner = RunnerEventMock() trace.add_event(trace.runner) trace.token = 'a' trace.split_on_send = False for _ in range(10): event = EventMock() trace.add_event(event) trace_factory.send_traces() wrapped_post.assert_called_once()
def test_event_with_datetime(wrapped_post): trace = trace_factory.get_or_create_trace() trace.token = 'a' event = EventMock() event.resource['metadata'] = datetime.fromtimestamp(1000) trace.add_event(event) trace_factory.send_traces() wrapped_post.assert_called_with( '', data=json.dumps(trace.to_dict(), cls=TraceEncoder), timeout=epsagon.constants.SEND_TIMEOUT, headers={'Authorization': 'Bearer {}'.format(trace.token)})
def test_event_with_datetime(wrapped_post): epsagon.utils.init(token='token', app_name='app-name', collector_url='collector') trace = trace_factory.get_or_create_trace() event = EventMock() event.resource['metadata'] = datetime.fromtimestamp(1000) trace.add_event(event) trace_factory.send_traces() wrapped_post.assert_called_with( 'POST', 'collector', body=json.dumps(trace.to_dict(), cls=TraceEncoder), timeout=epsagon.constants.SEND_TIMEOUT, )
def test_httptransport_timeout(): start_time = time.time() # non-routable IP address, will result in a timeout http_transport = HTTPTransport('http://10.255.255.1', 'token') trace = trace_factory.get_or_create_trace() # This will make sure we get TimeoutError and not MaxRetryError with pytest.raises(urllib3.exceptions.TimeoutError): http_transport.send(trace) duration = time.time() - start_time # Making sure that an unreachable url will result in duration almost equal to the # timeout duration set assert http_transport.timeout < duration < http_transport.timeout + 0.3
def test_timeout_handler_called(wrapped_post): """ Sanity """ context = ContextMock(DEFAULT_SEND_TIMEOUT_MS * 1.1) runner = RunnerEventMock() trace = trace_factory.get_or_create_trace() trace.token = 'a' trace.set_timeout_handler(context) trace.set_runner(runner) time.sleep((DEFAULT_SEND_TIMEOUT_MS / 1000) * 1.5) trace.reset_timeout_handler() assert trace.trace_sent assert wrapped_post.called
def test_timeout_handler_called(wrapped_post): """ Sanity """ context = ContextMock(300) runner = RunnerEventMock() trace = trace_factory.get_or_create_trace() trace.token = 'a' trace.set_timeout_handler(context) trace.set_runner(runner) time.sleep(0.5) trace.reset_timeout_handler() assert trace.trace_sent assert wrapped_post.called
def test_timeout_send_not_called_twice(wrapped_post): """ In case of a timeout send trace, validate no trace is sent afterwards (if the flow continues) """ context = ContextMock(300) runner = RunnerEventMock() trace = trace_factory.get_or_create_trace() trace.token = 'a' trace.set_timeout_handler(context) trace.set_runner(runner) time.sleep(0.5) trace.reset_timeout_handler() assert trace.trace_sent assert wrapped_post.call_count == 1
def test_return_value_key_to_ignore(wrapped_post): key_to_ignore = 'key_to_ignore_in_return_value' os.environ['EPSAGON_IGNORED_KEYS'] = key_to_ignore keys_to_ignore = [key_to_ignore] # reset traces created at setup function trace_factory.traces = {} epsagon.utils.init(token='token', app_name='app-name', collector_url='collector', metadata_only=False) trace = trace_factory.get_or_create_trace() return_value = { key_to_ignore: 'f', 's': { 'a': 1, 'b': 2, 'c': { 'f': 1, key_to_ignore: '1', 'g': { key_to_ignore: '1' } } } } copied_return_value = return_value.copy() runner = ReturnValueEventMock(return_value) trace.set_runner(runner) trace.token = 'a' trace_factory.send_traces() assert len(trace.to_dict()['events']) == 1 event = trace.to_dict()['events'][0] assert event['origin'] == 'runner' actual_return_value = event['resource']['metadata']['return_value'] _assert_key_not_exist(actual_return_value, key_to_ignore) # check that original return value hasn't been changed assert copied_return_value == return_value wrapped_post.assert_called_with( 'collector', data=json.dumps(trace.to_dict()), timeout=epsagon.constants.SEND_TIMEOUT, headers={'Authorization': 'Bearer {}'.format(trace.token)}) os.environ.pop('EPSAGON_IGNORED_KEYS')
def test_custom_labels_sanity(): event = RunnerEventMock() trace = trace_factory.get_or_create_trace() trace.clear_events() trace.set_runner(event) trace.add_label('test_label', 'test_value') trace.add_label('test_label_2', 42) trace.add_label('test_label_3', 42.2) trace.add_label('test_label_invalid', {}) trace_metadata = trace.to_dict()['events'][0]['resource']['metadata'] assert trace_metadata.get('labels') is not None assert json.loads(trace_metadata['labels']) == { 'test_label': 'test_value', 'test_label_2': '42', 'test_label_3': '42.2', }
def test_multi_value_labels_sanity(): event = RunnerEventMock() trace = trace_factory.get_or_create_trace() trace.clear_events() trace.set_runner(event) trace.add_label('test_label', { 'test2_label': 15, 'test3_label': 'test', 4: 'hey' }) trace_metadata = trace.to_dict()['events'][0]['resource']['metadata'] assert trace_metadata.get('labels') is not None assert json.loads(trace_metadata['labels']) == { 'test_label.test2_label': '15', 'test_label.test3_label': 'test', 'test_label.4': 'hey', }