Skip to content

Commit

Permalink
added concurrency tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike Rumpler committed Jul 5, 2021
1 parent de8b62c commit c228503
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 23 deletions.
35 changes: 12 additions & 23 deletions src/sentry_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,13 @@ sentry__should_skip_upload(void)
int
sentry_init(sentry_options_t *options)
{
// this function is to be called only once, so we do not allow more than
// one call to be active. If the function is called twice, create an error
// and return fail (1)
// this function is to be called only once, so we do not allow more than one
// caller
sentry__mutex_lock(&g_initclose_lock);

// pre-init here, so we can consistently use bailing out to :fail
sentry_transport_t *transport = NULL;

if (g_options != NULL) {
SENTRY_ERROR("sentry_init() may only be called once");
goto fail;
}
sentry_close();

sentry_logger_t logger = { NULL, NULL };
if (options->debug) {
Expand Down Expand Up @@ -150,9 +145,7 @@ sentry_init(sentry_options_t *options)
last_crash = backend->get_last_crash_func(backend);
}

sentry__mutex_lock(&g_options_lock);
g_options = options;
sentry__mutex_unlock(&g_options_lock);

// *after* setting the global options, trigger a scope and consent flush,
// since at least crashpad needs that.
Expand Down Expand Up @@ -194,21 +187,20 @@ sentry_init(sentry_options_t *options)
int
sentry_close(void)
{
// this function is to be called only once, so we do not allow more than one
// caller
sentry__mutex_lock(&g_initclose_lock);
if (g_options == NULL) {
SENTRY_DEBUG("sentry_close() called, but options was empty");
}

// keep the global options until end of function if other calls need the
// data while we still clean up to avoid crashes
sentry__mutex_lock(&g_options_lock);
sentry_options_t *options = g_options;
if (options) {
sentry_end_session();
}
g_options = NULL;
sentry__mutex_unlock(&g_options_lock);

size_t dumped_envelopes = 0;
if (options) {
sentry_end_session();

if (options->backend && options->backend->shutdown_func) {
SENTRY_TRACE("shutting down backend");
options->backend->shutdown_func(options->backend);
Expand All @@ -227,21 +219,18 @@ sentry_close(void)
if (!dumped_envelopes
&& (!options->backend
|| !options->backend->can_capture_after_shutdown)) {
SENTRY_DEBUGF("# of dumped envelopes is %i", (int)dumped_envelopes);
sentry__run_clean(options->run);
}

sentry_options_free(options);
} else {
SENTRY_DEBUG("sentry_close() called, but options was empty");
}

sentry__scope_cleanup();
sentry_clear_modulecache();

sentry__mutex_lock(&g_options_lock);
g_options = NULL;
sentry__mutex_unlock(&g_options_lock);

sentry__mutex_unlock(&g_initclose_lock);

return (int)dumped_envelopes;
}

Expand Down
1 change: 1 addition & 0 deletions tests/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ add_executable(sentry_test_unit
test_attachments.c
test_basic.c
test_consent.c
test_concurrency.c
test_envelopes.c
test_failures.c
test_fuzzfailures.c
Expand Down
116 changes: 116 additions & 0 deletions tests/unit/test_concurrency.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include "sentry_core.h"
#include "sentry_testsupport.h"
#include <pthread.h>
#include <sentry.h>
#include <sentry_sync.h>

static sentry_mutex_t func_lock = SENTRY__MUTEX_INIT;

static void
send_envelope_test_concurrent(const sentry_envelope_t *envelope, void *data)
{
sentry__mutex_lock(&func_lock);
uint64_t *called = data;
*called += 1;

sentry_value_t event = sentry_envelope_get_event(envelope);
if (sentry_value_is_null(event)) {
sentry__mutex_unlock(&func_lock);
return;
}
TEST_CHECK(!sentry_value_is_null(event));
const char *event_id
= sentry_value_as_string(sentry_value_get_by_key(event, "event_id"));
TEST_CHECK_STRING_EQUAL(event_id, "4c035723-8638-4c3a-923f-2ab9d08b4018");

if (*called == 1) {
const char *msg = sentry_value_as_string(sentry_value_get_by_key(
sentry_value_get_by_key(event, "message"), "formatted"));
TEST_CHECK_STRING_EQUAL(msg, "Hello World!");
const char *release
= sentry_value_as_string(sentry_value_get_by_key(event, "release"));
TEST_CHECK_STRING_EQUAL(release, "prod");
const char *trans = sentry_value_as_string(
sentry_value_get_by_key(event, "transaction"));
TEST_CHECK_STRING_EQUAL(trans, "demo-trans");
}
sentry__mutex_unlock(&func_lock);
}

static void
init_framework(uint64_t *called)
{
sentry_options_t *options = sentry_options_new();
sentry_options_set_dsn(options, "https://foo@sentry.invalid/42");
sentry_options_set_transport(options,
sentry_new_function_transport(send_envelope_test_concurrent, called));
sentry_options_set_release(options, "prod");
sentry_options_set_require_user_consent(options, false);
sentry_options_set_auto_session_tracking(options, true);
sentry_options_set_debug(options, true);
sentry_init(options);
}

SENTRY_TEST(multiple_inits)
{
uint64_t called = 0;

init_framework(&called);
init_framework(&called);

sentry_set_transaction("demo-trans");

sentry_capture_event(sentry_value_new_message_event(
SENTRY_LEVEL_INFO, "root", "Hello World!"));

sentry_value_t obj = sentry_value_new_object();
// something that is not a uuid, as this will be forcibly changed
sentry_value_set_by_key(obj, "event_id", sentry_value_new_int32(1234));
sentry_capture_event(obj);

sentry_close();
sentry_close();

TEST_CHECK_INT_EQUAL(called, 4);
}

static void *
thread_worker(void *vargp)
{
sentry_set_transaction("demo-trans");

sentry_capture_event(sentry_value_new_message_event(
SENTRY_LEVEL_INFO, "root", "Hello World!"));

sentry_value_t obj = sentry_value_new_object();
// something that is not a uuid, as this will be forcibly changed
sentry_value_set_by_key(obj, "event_id", sentry_value_new_int32(1234));
sentry_capture_event(obj);

return NULL;
}

SENTRY_TEST(concurrent_init)
{
uint64_t called_m = 0;
sentry_threadid_t thread_id1, thread_id2, thread_id3;

init_framework(&called_m);

sentry__thread_init(&thread_id1);
sentry__thread_init(&thread_id2);
sentry__thread_init(&thread_id3);
sentry__thread_spawn(&thread_id1, &thread_worker, NULL);
sentry__thread_spawn(&thread_id2, &thread_worker, NULL);
sentry__thread_spawn(&thread_id3, &thread_worker, NULL);
sentry__thread_join(thread_id1);
sentry__thread_join(thread_id2);
sentry__thread_join(thread_id3);
sentry__thread_free(&thread_id1);
sentry__thread_free(&thread_id2);
sentry__thread_free(&thread_id3);

sentry_close();

TEST_CHECK_INT_EQUAL(called_m, 7);
}
3 changes: 3 additions & 0 deletions tests/unit/test_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,12 @@ send_sampled_envelope(const sentry_envelope_t *envelope, void *data)
{
session_assertion_t *assertion = data;

SENTRY_DEBUG("send_sampled_envelope");
if (assertion->assert_session) {
assertion->called += 1;

SENTRY_DEBUG("assertion + 1");

TEST_CHECK_INT_EQUAL(sentry__envelope_get_item_count(envelope), 1);

const sentry_envelope_item_t *item
Expand Down
2 changes: 2 additions & 0 deletions tests/unit/tests.inc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ XX(basic_http_request_preparation_for_event)
XX(basic_http_request_preparation_for_event_with_attachment)
XX(basic_http_request_preparation_for_minidump)
XX(buildid_fallback)
XX(concurrent_init)
XX(count_sampled_events)
XX(custom_logger)
XX(dsn_parsing_complete)
Expand All @@ -22,6 +23,7 @@ XX(module_addr)
XX(module_finder)
XX(mpack_newlines)
XX(mpack_removed_tags)
XX(multiple_inits)
XX(os)
XX(page_allocator)
XX(path_basics)
Expand Down

0 comments on commit c228503

Please sign in to comment.