Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Isolated testing and SentryOptions tests #80

Draft
wants to merge 36 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c182831
Add some sentry options tests
limbonaut Jan 29, 2025
5a8bc3a
Some tests for error logger
limbonaut Jan 29, 2025
301fa62
Add logger limits tests
limbonaut Jan 30, 2025
f8da579
Reorganize testing files
limbonaut Jan 30, 2025
42fd616
Fix CI unit tests dir
limbonaut Jan 30, 2025
123ffa0
Add script to run isolated tests
limbonaut Jan 30, 2025
c3f284f
Run isolated tests in CI
limbonaut Jan 30, 2025
5833894
Clean up script
limbonaut Jan 30, 2025
506d197
Explain isolated testing in comments
limbonaut Jan 30, 2025
04a318f
Add script description
limbonaut Jan 30, 2025
abbccba
Describe options integrity test
limbonaut Jan 30, 2025
8bbd306
Add test for "events_per_frame" limit
limbonaut Jan 30, 2025
aa4becd
Add test reports dir to git ignore
limbonaut Jan 30, 2025
310738f
Add tests for throttling limits
limbonaut Jan 30, 2025
71ec692
Highlight important messages in the script
limbonaut Jan 30, 2025
4c57ef9
Test "repeated_error_window_ms" limit
limbonaut Jan 30, 2025
1e88cd5
Refactor, fix and clean up tests
limbonaut Jan 30, 2025
8e69de8
Simplify options tests
limbonaut Jan 30, 2025
17ddc4f
Fix script compat with sh
limbonaut Jan 30, 2025
31f9f2a
Merge remote-tracking branch 'upstream' into test/isolated-and-option…
limbonaut Jan 30, 2025
cd2aec6
Test options.dist
limbonaut Jan 30, 2025
0930fe4
Clarify colors in the script
limbonaut Jan 30, 2025
6348c2c
Test error logger event and breadcrumb masks
limbonaut Jan 30, 2025
9cee1f0
Tidy up test_options
limbonaut Jan 30, 2025
e1288ec
Merge remote-tracking branch 'upstream' into test/isolated-and-option…
limbonaut Jan 30, 2025
ac3f7c3
Test SentrySDK.set_tag()
limbonaut Jan 31, 2025
72dfe31
Test disabled logger
limbonaut Jan 31, 2025
45d021f
Test SentrySDK.remove_tag()
limbonaut Jan 31, 2025
b96a863
Style fixes
limbonaut Jan 31, 2025
5f00372
Fix signal monitoring
limbonaut Jan 31, 2025
720e2b0
Fix issue running these tests with full path
limbonaut Feb 7, 2025
c60d7e3
Merge branch 'main' into test/isolated-and-options-tests
limbonaut Feb 7, 2025
6aefa3c
Rewrite run-isolated-tests script in PowerShell
limbonaut Feb 7, 2025
a108dfa
Merge branch 'main' into test/isolated-and-options-tests
limbonaut Feb 8, 2025
4209bc2
Tweak script
limbonaut Feb 8, 2025
b4c3f79
Use the new script in CI
limbonaut Feb 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
chmod u+x ${bin}
ls -l
./${bin} --version
echo "GODOT_BIN=${GITHUB_WORKSPACE}/godot/${bin}" >> $GITHUB_ENV
echo "GODOT=${GITHUB_WORKSPACE}/godot/${bin}" >> $GITHUB_ENV

- name: Diagnostic info
shell: bash
Expand All @@ -66,15 +66,22 @@ jobs:
scons project/addons/gdUnit4
chmod +x project/addons/sentrysdk/bin/{linux,macos}/crashpad_handler
echo "--- Rebuilding import cache.."
${GODOT_BIN} --headless --editor --path project/ --quit-after 2000 || true
${GODOT} --headless --editor --path project/ --quit-after 2000 || true
echo "--- Finished rebuilding import cache."

- name: Run tests
shell: bash
timeout-minutes: 5
run: |
# Exit status codes: 0 - success, 100 - ends with test failures, 101 - ends with test warnings.
${GODOT_BIN} --headless --path project/ -s -d "res://addons/gdUnit4/bin/GdUnitCmdTool.gd" --ignoreHeadlessMode -c -a test
${GODOT} --headless --path project/ -s -d "res://addons/gdUnit4/bin/GdUnitCmdTool.gd" --ignoreHeadlessMode -c -a test/suites/

- name: Run isolated tests
if: success() || failure()
shell: bash
timeout-minutes: 5
run: |
./scripts/run-isolated-tests.sh

- name: Upload results
if: always() # do this step even if the tests fail
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
project/addons
project/export_presets.cfg
project/.vscode
project/reports
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For information, reports are created when unit tests are executed in the editor or from CLI.


src/sdk_version.gen.h

Expand Down
3 changes: 3 additions & 0 deletions project/example_configuration.gd
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ func _configure(options: SentryOptions) -> void:
options.before_send = _before_send
options.on_crash = _on_crash

# Unit testing hooks (if you're exploring the demo project, pretend the following line doesn't exist).
TestingConfiguration.configure_options(options)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allowing unit tests to hook into our configuration script. I call such tests isolated, as they need to be executed separately from other similar tests. There is a new script that automates running them in a batch.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: This would break if the demo project were shipped without unit test files, which is how we currently do it.



## before_send callback example
func _before_send(ev: SentryEvent) -> SentryEvent:
Expand Down
20 changes: 20 additions & 0 deletions project/test/isolated/configuration.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class_name TestingConfiguration
extends RefCounted


## Detects whether an isolated test suite is running and calls its static `configure_options()` method.
## - Since SentryOptions can be configured only once, such test suites must be executed separately.
## - This method is called from "example_configuration.gd".
static func configure_options(options: SentryOptions):
var args: PackedStringArray = OS.get_cmdline_args()
var idx := args.find("-a")
if idx == -1 or args.size() == idx + 1:
return
var path := "res://" + args[idx + 1]
if not path.ends_with(".gd"):
return
if not FileAccess.file_exists(path):
return
var scr: GDScript = load(path)
if scr.has_method(&"configure_options"):
scr.call(&"configure_options", options)
35 changes: 35 additions & 0 deletions project/test/isolated/test_limit_events_per_frame.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
extends GdUnitTestSuite
## Test "events_per_frame" error logger limit.


signal callback_processed

var _num_events: int = 0


static func configure_options(options: SentryOptions) -> void:
# Only one error is allowed to be logged as event per processed frame.
options.error_logger_limits.events_per_frame = 1
# Make sure other limits are not interfering.
options.error_logger_limits.repeated_error_window_ms = 0
options.error_logger_limits.throttle_events = 88


func before_test() -> void:
SentrySDK._set_before_send(_before_send)


func _before_send(_ev: SentryEvent) -> SentryEvent:
_num_events += 1
callback_processed.emit()
return null


## Only one error should be logged within 1 processed frame.
func test_events_per_frame_limit() -> void:
push_error("dummy-error")
push_error("dummy-error")
push_error("dummy-error")
assert_signal(self).is_emitted("callback_processed")
limbonaut marked this conversation as resolved.
Show resolved Hide resolved
await get_tree().create_timer(0.1).timeout
assert_int(_num_events).is_equal(1)
41 changes: 41 additions & 0 deletions project/test/isolated/test_limit_repeating_error_window.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
extends GdUnitTestSuite
## Test "repeated_error_window_ms" error logger limit.


signal callback_processed

var _num_events: int = 0


static func configure_options(options: SentryOptions) -> void:
# Ignore duplicate errors within 1 second window.
options.error_logger_limits.repeated_error_window_ms = 1000
# Make sure other limits are not interfering.
options.error_logger_limits.events_per_frame = 88
options.error_logger_limits.throttle_events = 88


func before_test() -> void:
SentrySDK._set_before_send(_before_send)


func _before_send(_ev: SentryEvent) -> SentryEvent:
_num_events += 1
callback_processed.emit()
return null


## Only one error should be logged within 1 second time window, and another one after 1 second passes.
func test_repeating_error_window_limit() -> void:
push_error("dummy-error")
push_error("dummy-error")
await assert_signal(self).is_emitted("callback_processed")
assert_int(_num_events).is_equal(1)

# Wait for 1 second window to expire.
await get_tree().create_timer(1.0).timeout

push_error("dummy-error")
push_error("dummy-error")
await assert_signal(self).is_emitted("callback_processed")
assert_int(_num_events).is_equal(2)
48 changes: 48 additions & 0 deletions project/test/isolated/test_limit_throttling.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
extends GdUnitTestSuite
## Test error logger throttling limits.


signal callback_processed

var _num_events: int = 0


static func configure_options(options: SentryOptions) -> void:
# Allow only two errors to be logged as events within 1 second time window.
options.error_logger_limits.throttle_events = 2
options.error_logger_limits.throttle_window_ms = 1000
# Make sure other limits are not interfering.
options.error_logger_limits.events_per_frame = 88
options.error_logger_limits.repeated_error_window_ms = 0


func before_test() -> void:
SentrySDK._set_before_send(_before_send)


func _before_send(_ev: SentryEvent) -> SentryEvent:
_num_events += 1
callback_processed.emit()
return null


## Only two errors should be logged within the assigned time window.
func test_throttling_limits() -> void:
push_error("dummy-error")
push_error("dummy-error")
push_error("dummy-error")
await assert_signal(self).is_emitted("callback_processed")
await assert_signal(self).is_emitted("callback_processed")
await get_tree().create_timer(0.1).timeout
assert_int(_num_events).is_equal(2)

# Wait for throttling window to expire.
await get_tree().create_timer(1.0).timeout

push_error("dummy-error")
push_error("dummy-error")
push_error("dummy-error")
await assert_signal(self).is_emitted("callback_processed")
await assert_signal(self).is_emitted("callback_processed")
await get_tree().create_timer(0.1).timeout
assert_int(_num_events).is_equal(4)
36 changes: 36 additions & 0 deletions project/test/isolated/test_logger_disabled.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
extends GdUnitTestSuite
## Events should not be logged for errors when the logger is disabled.


signal callback_processed

var _num_events: int = 0


static func configure_options(options: SentryOptions) -> void:
options.error_logger_enabled = false

# Make sure other limits are not interfering.
options.error_logger_limits.events_per_frame = 88
options.error_logger_limits.throttle_events = 88
options.error_logger_limits.repeated_error_window_ms = 0
options.error_logger_limits.throttle_window_ms = 0


func before_test() -> void:
SentrySDK._set_before_send(_before_send)


func _before_send(_ev: SentryEvent) -> SentryEvent:
_num_events += 1
callback_processed.emit()
return null


func test_event_and_breadcrumb_masks() -> void:
push_error("dummy-error")
push_warning("dummy-warning")

await assert_signal(self).is_not_emitted("callback_processed")

assert_int(_num_events).is_equal(0)
41 changes: 41 additions & 0 deletions project/test/isolated/test_logger_with_masks.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
extends GdUnitTestSuite
## Events and breadcrumbs should be logged when "error_logger_event_mask" and
## "error_logger_breadcrumb_mask" are configured to include all categories.


signal callback_processed

var _num_events: int = 0


static func configure_options(options: SentryOptions) -> void:
var mask = SentryOptions.MASK_ERROR | SentryOptions.MASK_SCRIPT | SentryOptions.MASK_SHADER | SentryOptions.MASK_WARNING
options.error_logger_event_mask = mask
options.error_logger_breadcrumb_mask = mask

# Make sure other limits are not interfering.
options.error_logger_limits.events_per_frame = 88
options.error_logger_limits.throttle_events = 88
options.error_logger_limits.repeated_error_window_ms = 0
options.error_logger_limits.throttle_window_ms = 0


func before_test() -> void:
SentrySDK._set_before_send(_before_send)


func _before_send(_ev: SentryEvent) -> SentryEvent:
_num_events += 1
callback_processed.emit()
return null


## Both events or breadcrumbs should be logged for error and warning.
## TODO: can't verify breadcrumbs yet, maybe later.
func test_event_and_breadcrumb_masks() -> void:
push_error("dummy-error")
push_warning("dummy-warning")
await assert_signal(self).is_emitted("callback_processed")

await get_tree().create_timer(0.1).timeout
assert_int(_num_events).is_equal(2)
34 changes: 34 additions & 0 deletions project/test/isolated/test_logger_with_masks_empty.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
extends GdUnitTestSuite
## Events and breadcrumbs should not be logged when both "error_logger_event_mask"
## and "error_logger_breadcrumb_mask" are set to zero.


signal callback_processed

var _num_events: int = 0


static func configure_options(options: SentryOptions) -> void:
options.error_logger_event_mask = 0
options.error_logger_breadcrumb_mask = 0


func before_test() -> void:
SentrySDK._set_before_send(_before_send)


func _before_send(_ev: SentryEvent) -> SentryEvent:
_num_events += 1
callback_processed.emit()
return null


## No events or breadcrumbs should be logged for errors.
## TODO: can't verify breadcrumbs yet, maybe later.
func test_event_and_breadcrumb_masks() -> void:
push_error("dummy-error")
push_warning("dummy-warning")
await assert_signal(self).is_not_emitted("callback_processed")

await get_tree().create_timer(0.1).timeout
assert_int(_num_events).is_equal(0)
28 changes: 28 additions & 0 deletions project/test/isolated/test_options_integrity.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
extends GdUnitTestSuite
## Verify that the options set in a configuration callback are correctly reflected in event objects.


signal callback_processed


static func configure_options(options: SentryOptions) -> void:
options.release = "1.2.3"
options.environment = "testing"


func before_test() -> void:
SentrySDK._set_before_send(_before_send)


func _before_send(ev: SentryEvent) -> SentryEvent:
assert_str(ev.release).is_equal("1.2.3")
assert_str(ev.environment).is_equal("testing")
callback_processed.emit()
return null


## Verify that the options are correctly propagated to event objects.
func test_options_integrity() -> void:
var ev := SentrySDK.create_event()
SentrySDK.capture_event(ev)
assert_signal(self).is_emitted("callback_processed")
limbonaut marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class_name TestEvent
extends GdUnitTestSuite
## Basic tests for the SentryEvent class.


## SentryEvent.id should not be empty on event creation.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class_name TestEventIntegrity
extends GdUnitTestSuite
## Verify that event properties are preserved through the SDK flow.


signal callback_processed

Expand Down
Loading