Files
sentry-native/tests/test_api.cpp
T
2019-09-23 14:34:45 +02:00

346 lines
12 KiB
C++

#include <sentry.h>
#include <string>
#include <value.hpp>
#include <vector>
#include <vendor/catch.hpp>
#include "testutils.hpp"
TEST_CASE("init and shutdown", "[api]") {
for (size_t i = 0; i < 10; i++) {
sentry_options_t *options = sentry_options_new();
sentry_options_set_environment(options, "release");
sentry_init(options);
sentry_shutdown();
}
}
TEST_CASE("send basic event", "[api]") {
sentry_options_t *options = sentry_options_new();
sentry_options_set_environment(options, "demo-env");
sentry_options_set_release(options, "demo-app@1.0.0");
sentry_options_set_dist(options, "android");
WITH_MOCK_TRANSPORT(options) {
sentry_value_t event = sentry_value_new_event();
sentry_value_t msg = sentry_value_new_string("Hello World!");
sentry_value_set_by_key(event, "message", msg);
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
// Assert basic event attributes
REQUIRE(event_out.get_by_key("event_id").type() ==
SENTRY_VALUE_TYPE_STRING);
REQUIRE(event_out.get_by_key("debug_meta").type() ==
SENTRY_VALUE_TYPE_OBJECT);
REQUIRE(event_out.get_by_key("sdk").type() == SENTRY_VALUE_TYPE_OBJECT);
REQUIRE(event_out.get_by_key("timestamp").type() ==
SENTRY_VALUE_TYPE_STRING);
// Assert options attributes
REQUIRE(event_out.get_by_key("level").as_cstr() ==
std::string("error"));
REQUIRE(event_out.get_by_key("environment").as_cstr() ==
std::string("demo-env"));
REQUIRE(event_out.get_by_key("release").as_cstr() ==
std::string("demo-app@1.0.0"));
REQUIRE(event_out.get_by_key("dist").as_cstr() ==
std::string("android"));
}
}
TEST_CASE("send event with debug images", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
sentry::Value images = event_out.navigate("debug_meta.images");
REQUIRE(images.type() == SENTRY_VALUE_TYPE_LIST);
REQUIRE(images.length() > 0);
for (size_t i = 0; i < images.length(); i++) {
sentry::Value image = images.get_by_index(i);
REQUIRE(image.get_by_key("type").type() ==
SENTRY_VALUE_TYPE_STRING);
REQUIRE(((image.get_by_key("debug_id").type() ==
SENTRY_VALUE_TYPE_STRING) ||
(image.get_by_key("code_id").type() ==
SENTRY_VALUE_TYPE_STRING)));
REQUIRE(image.get_by_key("image_addr").type() ==
SENTRY_VALUE_TYPE_STRING);
}
}
}
static sentry_value_t dummy_before_send(sentry_value_t event,
void *hint,
void *data) {
sentry_value_t extra = sentry_value_new_object();
sentry_value_set_by_key(extra, "foo",
sentry_value_new_string((const char *)data));
sentry_value_set_by_key(event, "extra", extra);
return event;
}
TEST_CASE("send event with before_send callback", "[api]") {
sentry_options_t *options = sentry_options_new();
sentry_options_set_before_send(options, dummy_before_send,
(void *)"a value");
WITH_MOCK_TRANSPORT(options) {
sentry_add_breadcrumb(sentry_value_new_breadcrumb("default", "crumb1"));
sentry_add_breadcrumb(sentry_value_new_breadcrumb("http", "crumb2"));
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
sentry::Value foo_extra = event_out.navigate("extra.foo");
REQUIRE(foo_extra.as_cstr() == std::string("a value"));
}
}
TEST_CASE("send message event", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_value_t msg_event = sentry_value_new_message_event(
SENTRY_LEVEL_WARNING, "root_logger", "Hello World!");
sentry_capture_event(msg_event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
REQUIRE(event_out.get_by_key("level").as_cstr() ==
std::string("warning"));
REQUIRE(event_out.get_by_key("message").as_cstr() ==
std::string("Hello World!"));
REQUIRE(event_out.get_by_key("logger").as_cstr() ==
std::string("root_logger"));
}
}
TEST_CASE("send event with breadcrumbs disabled", "[api]") {
// Initialize explicitly without DSN
sentry_options_t *options = sentry_options_new();
WITH_MOCK_TRANSPORT(options) {
sentry_add_breadcrumb(sentry_value_new_breadcrumb("default", "crumb1"));
sentry_add_breadcrumb(sentry_value_new_breadcrumb("http", "crumb2"));
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
sentry::Value crumbs_out = event_out.navigate("breadcrumbs");
REQUIRE(crumbs_out.length() == -1);
}
}
TEST_CASE("send event with breadcrumbs", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_add_breadcrumb(sentry_value_new_breadcrumb("default", "crumb1"));
sentry_add_breadcrumb(sentry_value_new_breadcrumb("http", "crumb2"));
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
sentry::Value crumbs_out = event_out.navigate("breadcrumbs");
REQUIRE(crumbs_out.length() == 2);
REQUIRE(crumbs_out.navigate("0.type") ==
sentry::Value::new_string("default"));
REQUIRE(crumbs_out.navigate("0.message") ==
sentry::Value::new_string("crumb1"));
REQUIRE(crumbs_out.navigate("1.type") ==
sentry::Value::new_string("http"));
REQUIRE(crumbs_out.navigate("1.message") ==
sentry::Value::new_string("crumb2"));
}
}
TEST_CASE("send event with user", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_value_t user = sentry_value_new_object();
sentry_value_set_by_key(user, "id", sentry_value_new_int32(42));
sentry_set_user(user);
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
REQUIRE(event_out.navigate("user.id") == sentry::Value::new_int32(42));
}
}
TEST_CASE("send event with tag", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_set_tag("mytag", "myvalue");
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
REQUIRE(event_out.navigate("tags.mytag") ==
sentry::Value::new_string("myvalue"));
}
}
TEST_CASE("send event with extra", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_set_extra("extra1", sentry_value_new_string("foo"));
sentry_set_extra("extra2", sentry_value_new_int32(42));
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
REQUIRE(event_out.navigate("extra.extra1") ==
sentry::Value::new_string("foo"));
REQUIRE(event_out.navigate("extra.extra2") ==
sentry::Value::new_int32(42));
}
}
TEST_CASE("send event with custom context", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_value_t custom = sentry_value_new_object();
sentry_value_set_by_key(custom, "foo", sentry_value_new_string("bar"));
sentry_set_context("custom", custom);
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
REQUIRE(event_out.navigate("contexts.custom.foo") ==
sentry::Value::new_string("bar"));
}
}
TEST_CASE("send event with fingerprint", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_set_fingerprint("foo", "bar", 0);
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
sentry::Value fp_out = event_out.navigate("fingerprint");
REQUIRE(fp_out.length() == 2);
REQUIRE(fp_out.navigate("0") == sentry::Value::new_string("foo"));
REQUIRE(fp_out.navigate("1") == sentry::Value::new_string("bar"));
}
}
TEST_CASE("send event with transaction", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_set_transaction("my_transaction");
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
REQUIRE(event_out.navigate("transaction") ==
sentry::Value::new_string("my_transaction"));
}
}
TEST_CASE("send event with level", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_set_level(SENTRY_LEVEL_INFO);
sentry_value_t event = sentry_value_new_event();
sentry_capture_event(event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
REQUIRE(event_out.navigate("level") ==
sentry::Value::new_level(SENTRY_LEVEL_INFO));
}
}
// function is non static as dladdr on linux otherwise won't give us a name.
// For this test we however want to see if we can recover a name here.
void dummy_function() {
printf("dummy here\n");
}
TEST_CASE("send basic stacktrace", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_value_t msg_event = sentry_value_new_message_event(
SENTRY_LEVEL_WARNING, nullptr, "Hello World!");
void *addr = (void *)((char *)(void *)&dummy_function + 1);
sentry_event_value_add_stacktrace(msg_event, &addr, 1);
sentry_capture_event(msg_event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
sentry::Value frame =
event_out.navigate("threads.0.stacktrace.frames.0");
REQUIRE(frame.get_by_key("instruction_addr") ==
sentry::Value::new_addr((uint64_t)addr));
REQUIRE(frame.get_by_key("symbol_addr") ==
sentry::Value::new_addr((uint64_t)(void *)&dummy_function));
REQUIRE(strstr(frame.get_by_key("function").as_cstr(),
"dummy_function") != nullptr);
}
}
#ifdef _WIN32
#define OS_MAIN_FUNC "wmain"
#else
#define OS_MAIN_FUNC "main"
#endif
TEST_CASE("send basic stacktrace (unwound)", "[api]") {
WITH_MOCK_TRANSPORT(nullptr) {
sentry_value_t msg_event = sentry_value_new_message_event(
SENTRY_LEVEL_WARNING, nullptr, "Hello World!");
sentry_event_value_add_stacktrace(msg_event, nullptr, 0);
sentry_capture_event(msg_event);
REQUIRE(mock_transport.events.size() == 1);
sentry::Value event_out = mock_transport.events[0];
sentry::Value frames =
event_out.navigate("threads.0.stacktrace.frames");
REQUIRE(frames.length() > 5);
bool found_main = false;
for (size_t i = 0; i < frames.length(); i++) {
sentry::Value main_frame = frames.get_by_index(i);
const char *func = main_frame.get_by_key("function").as_cstr();
if (func == std::string(OS_MAIN_FUNC)) {
found_main = true;
break;
}
}
REQUIRE(found_main);
sentry::Value api_func_frame = frames.get_by_index(frames.length() - 2);
REQUIRE(api_func_frame.get_by_key("function").as_cstr() ==
std::string("sentry_event_value_add_stacktrace"));
}
}