Skip to content

Commit 8f3ffd5

Browse files
committed
Add tests
1 parent 6c75ccf commit 8f3ffd5

File tree

5 files changed

+287
-0
lines changed

5 files changed

+287
-0
lines changed

examples/example.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ main(int argc, char **argv)
506506
if (has_arg(argc, argv, "cache-keep")) {
507507
sentry_options_set_cache_keep(options, true);
508508
sentry_options_set_cache_max_size(options, 1000 * 8);
509+
sentry_options_set_cache_max_age(options, 5);
509510
}
510511

511512
if (0 != sentry_init(options)) {

tests/test_integration_cache.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import os
2+
import time
3+
import pytest
4+
5+
from . import run
6+
from .conditions import has_files
7+
8+
pytestmark = pytest.mark.skipif(not has_files, reason="tests need local filesystem")
9+
10+
11+
@pytest.mark.parametrize("cache_keep", [True, False])
12+
@pytest.mark.parametrize("backend", ["inproc", "breakpad"])
13+
def test_cache_keep(cmake, backend, cache_keep):
14+
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": backend})
15+
16+
run(
17+
tmp_path,
18+
"sentry_example",
19+
["log", "crash"] + (["cache-keep"] if cache_keep else []),
20+
expect_failure=True,
21+
)
22+
23+
cache_dir = tmp_path.joinpath(".sentry-native/cache")
24+
assert not cache_dir.exists() or len(list(cache_dir.glob("*.envelope"))) == 0
25+
26+
run(
27+
tmp_path,
28+
"sentry_example",
29+
["log", "no-setup"] + (["cache-keep"] if cache_keep else []),
30+
)
31+
32+
assert cache_dir.exists() or cache_keep is False
33+
if cache_keep:
34+
cache_files = list(cache_dir.glob("*.envelope"))
35+
assert len(cache_files) == 1
36+
37+
38+
@pytest.mark.parametrize("backend", ["inproc", "breakpad"])
39+
def test_cache_max_size(cmake, backend):
40+
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": backend})
41+
cache_dir = tmp_path.joinpath(".sentry-native/cache")
42+
43+
# 5 x 2mb
44+
for i in range(5):
45+
run(
46+
tmp_path,
47+
"sentry_example",
48+
["log", "cache-keep", "crash"],
49+
expect_failure=True,
50+
)
51+
52+
if cache_dir.exists():
53+
cache_files = list(cache_dir.glob("*.envelope"))
54+
for f in cache_files:
55+
with open(f, "r+b") as file:
56+
file.truncate(2048 * 1000)
57+
58+
run(
59+
tmp_path,
60+
"sentry_example",
61+
["log", "cache-keep", "no-setup"],
62+
)
63+
64+
# max 8mb
65+
assert cache_dir.exists()
66+
cache_files = list(cache_dir.glob("*.envelope"))
67+
assert len(cache_files) <= 4
68+
assert sum(f.stat().st_size for f in cache_files) <= 8 * 1000 * 1024
69+
70+
71+
@pytest.mark.parametrize("backend", ["inproc", "breakpad"])
72+
def test_cache_max_age(cmake, backend):
73+
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": backend})
74+
cache_dir = tmp_path.joinpath(".sentry-native/cache")
75+
76+
for i in range(5):
77+
run(
78+
tmp_path,
79+
"sentry_example",
80+
["log", "cache-keep", "crash"],
81+
expect_failure=True,
82+
)
83+
84+
# 2,4,6,8,10 days old
85+
assert cache_dir.exists()
86+
cache_files = list(cache_dir.glob("*.envelope"))
87+
for i, f in enumerate(cache_files):
88+
mtime = time.time() - ((i + 1) * 2 * 24 * 60 * 60)
89+
os.utime(str(f), (mtime, mtime))
90+
91+
# 0 days old
92+
run(
93+
tmp_path,
94+
"sentry_example",
95+
["log", "cache-keep", "no-setup"],
96+
)
97+
98+
# max 5 days
99+
cache_files = list(cache_dir.glob("*.envelope"))
100+
assert len(cache_files) == 3
101+
for f in cache_files:
102+
assert time.time() - f.stat().st_mtime <= 5 * 24 * 60 * 60

tests/unit/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_executable(sentry_test_unit
2323
sentry_testsupport.h
2424
test_attachments.c
2525
test_basic.c
26+
test_cache.c
2627
test_consent.c
2728
test_concurrency.c
2829
test_embedded_info.c

tests/unit/test_cache.c

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#include "sentry_core.h"
2+
#include "sentry_database.h"
3+
#include "sentry_envelope.h"
4+
#include "sentry_options.h"
5+
#include "sentry_path.h"
6+
#include "sentry_testsupport.h"
7+
#include "sentry_uuid.h"
8+
#include "sentry_value.h"
9+
10+
#ifdef SENTRY_PLATFORM_WINDOWS
11+
# include <windows.h>
12+
#else
13+
# include <utime.h>
14+
#endif
15+
16+
static int
17+
set_file_mtime(const sentry_path_t *path, time_t mtime)
18+
{
19+
#ifdef SENTRY_PLATFORM_WINDOWS
20+
HANDLE h = CreateFileW(path->path_w, FILE_WRITE_ATTRIBUTES, 0, NULL,
21+
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
22+
ULARGE_INTEGER ft
23+
= { (uint64_t)(mtime * 10000000ULL + 116444736000000000ULL) };
24+
BOOL rv = SetFileTime(h, NULL, NULL, (FILETIME *)&ft);
25+
CloseHandle(h);
26+
return rv ? 0 : -1;
27+
#else
28+
struct utimbuf times = { .modtime = mtime, .actime = mtime };
29+
return utime(path->path, &times);
30+
#endif
31+
}
32+
33+
SENTRY_TEST(cache_keep)
34+
{
35+
SENTRY_TEST_OPTIONS_NEW(options);
36+
sentry_options_set_dsn(options, "https://[email protected]/42");
37+
sentry_options_set_cache_keep(options, true);
38+
sentry_init(options);
39+
40+
sentry_path_t *cache_path
41+
= sentry__path_join_str(options->database_path, "cache");
42+
TEST_ASSERT(!!cache_path);
43+
TEST_ASSERT(sentry__path_remove_all(cache_path) == 0);
44+
45+
sentry_path_t *old_run_path
46+
= sentry__path_join_str(options->database_path, "old.run");
47+
TEST_ASSERT(!!old_run_path);
48+
TEST_ASSERT(sentry__path_create_dir_all(old_run_path) == 0);
49+
50+
sentry_envelope_t *envelope = sentry__envelope_new();
51+
TEST_ASSERT(!!envelope);
52+
sentry_uuid_t event_id = sentry_uuid_new_v4();
53+
sentry_value_t event = sentry__value_new_event_with_id(&event_id);
54+
sentry__envelope_add_event(envelope, event);
55+
56+
char *envelope_filename = sentry__uuid_as_filename(&event_id, ".envelope");
57+
TEST_ASSERT(!!envelope_filename);
58+
sentry_path_t *old_envelope_path
59+
= sentry__path_join_str(old_run_path, envelope_filename);
60+
TEST_ASSERT(
61+
sentry_envelope_write_to_path(envelope, old_envelope_path) == 0);
62+
sentry_envelope_free(envelope);
63+
64+
sentry_path_t *cached_envelope_path
65+
= sentry__path_join_str(cache_path, envelope_filename);
66+
TEST_ASSERT(!!cached_envelope_path);
67+
68+
TEST_ASSERT(sentry__path_is_file(old_envelope_path));
69+
TEST_ASSERT(!sentry__path_is_file(cached_envelope_path));
70+
71+
sentry__process_old_runs(options, 0);
72+
73+
TEST_ASSERT(!sentry__path_is_file(old_envelope_path));
74+
TEST_ASSERT(sentry__path_is_file(cached_envelope_path));
75+
76+
sentry__path_free(old_envelope_path);
77+
sentry__path_free(cached_envelope_path);
78+
sentry__path_free(old_run_path);
79+
sentry__path_free(cache_path);
80+
sentry_free(envelope_filename);
81+
sentry_close();
82+
}
83+
84+
SENTRY_TEST(cache_max_size)
85+
{
86+
SENTRY_TEST_OPTIONS_NEW(options);
87+
sentry_options_set_dsn(options, "https://[email protected]/42");
88+
sentry_options_set_cache_keep(options, true);
89+
sentry_options_set_cache_max_size(options, 10); // 10 kb
90+
sentry_init(options);
91+
92+
sentry_path_t *cache_path
93+
= sentry__path_join_str(options->database_path, "cache");
94+
TEST_ASSERT(!!cache_path);
95+
TEST_ASSERT(sentry__path_remove_all(cache_path) == 0);
96+
TEST_ASSERT(sentry__path_create_dir_all(cache_path) == 0);
97+
98+
// 10 x 5 kb files
99+
for (int i = 0; i < 10; i++) {
100+
sentry_uuid_t event_id = sentry_uuid_new_v4();
101+
char *filename = sentry__uuid_as_filename(&event_id, ".envelope");
102+
TEST_ASSERT(!!filename);
103+
sentry_path_t *filepath = sentry__path_join_str(cache_path, filename);
104+
sentry_free(filename);
105+
106+
sentry_filewriter_t *fw = sentry__filewriter_new(filepath);
107+
TEST_ASSERT(!!fw);
108+
for (int j = 0; j < 500; j++) {
109+
sentry__filewriter_write(fw, "0123456789", 10);
110+
}
111+
TEST_CHECK_INT_EQUAL(sentry__filewriter_byte_count(fw), 5000);
112+
sentry__filewriter_free(fw);
113+
sentry__path_free(filepath);
114+
}
115+
116+
sentry__cleanup_cache(options);
117+
118+
int cache_count = 0;
119+
size_t cache_size = 0;
120+
sentry_pathiter_t *iter = sentry__path_iter_directory(cache_path);
121+
const sentry_path_t *entry;
122+
while (iter && (entry = sentry__pathiter_next(iter)) != NULL) {
123+
cache_count++;
124+
cache_size += sentry__path_get_size(entry);
125+
}
126+
sentry__pathiter_free(iter);
127+
128+
TEST_CHECK_INT_EQUAL(cache_count, 2);
129+
TEST_CHECK(cache_size <= 10 * 1024);
130+
131+
sentry__path_free(cache_path);
132+
sentry_close();
133+
}
134+
135+
SENTRY_TEST(cache_max_age)
136+
{
137+
SENTRY_TEST_OPTIONS_NEW(options);
138+
sentry_options_set_dsn(options, "https://[email protected]/42");
139+
sentry_options_set_cache_keep(options, true);
140+
sentry_options_set_cache_max_age(options, 3); // 3 days
141+
sentry_init(options);
142+
143+
sentry_path_t *cache_path
144+
= sentry__path_join_str(options->database_path, "cache");
145+
TEST_ASSERT(!!cache_path);
146+
TEST_ASSERT(sentry__path_remove_all(cache_path) == 0);
147+
TEST_ASSERT(sentry__path_create_dir_all(cache_path) == 0);
148+
149+
// 10 files, 0-9 days old
150+
time_t now = time(NULL);
151+
for (int i = 0; i < 10; i++) {
152+
sentry_uuid_t event_id = sentry_uuid_new_v4();
153+
char *filename = sentry__uuid_as_filename(&event_id, ".envelope");
154+
TEST_ASSERT(!!filename);
155+
sentry_path_t *filepath = sentry__path_join_str(cache_path, filename);
156+
sentry_free(filename);
157+
158+
TEST_ASSERT(sentry__path_touch(filepath) == 0);
159+
time_t mtime = now - (i * 24 * 60 * 60); // N days ago
160+
TEST_CHECK(set_file_mtime(filepath, mtime) == 0);
161+
sentry__path_free(filepath);
162+
}
163+
164+
sentry__cleanup_cache(options);
165+
166+
int cache_count = 0;
167+
sentry_pathiter_t *iter = sentry__path_iter_directory(cache_path);
168+
const sentry_path_t *entry;
169+
while (iter && (entry = sentry__pathiter_next(iter)) != NULL) {
170+
cache_count++;
171+
time_t mtime = sentry__path_get_mtime(entry);
172+
TEST_CHECK(now - mtime <= (3 * 24 * 60 * 60));
173+
}
174+
sentry__pathiter_free(iter);
175+
176+
TEST_CHECK_INT_EQUAL(cache_count, 4);
177+
178+
sentry__path_free(cache_path);
179+
sentry_close();
180+
}

tests/unit/tests.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ XX(basic_write_envelope_to_file)
2727
XX(bgworker_flush)
2828
XX(breadcrumb_without_type_or_message_still_valid)
2929
XX(build_id_parser)
30+
XX(cache_keep)
31+
XX(cache_max_age)
32+
XX(cache_max_size)
3033
XX(capture_minidump_basic)
3134
XX(capture_minidump_invalid_path)
3235
XX(capture_minidump_null_path)

0 commit comments

Comments
 (0)