mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
773 lines
27 KiB
Python
773 lines
27 KiB
Python
from sentry.rules.conditions.event_attribute import EventAttributeCondition
|
|
from sentry.rules.match import MatchType
|
|
from sentry.testutils.cases import RuleTestCase
|
|
from sentry.testutils.silo import region_silo_test
|
|
from sentry.testutils.skips import requires_snuba
|
|
|
|
pytestmark = [requires_snuba]
|
|
|
|
|
|
@region_silo_test
|
|
class EventAttributeConditionTest(RuleTestCase):
|
|
rule_cls = EventAttributeCondition
|
|
|
|
def get_event(self, **kwargs):
|
|
data = {
|
|
"message": "hello world",
|
|
"request": {"method": "GET", "url": "http://example.com/"},
|
|
"user": {
|
|
"id": "1",
|
|
"ip_address": "127.0.0.1",
|
|
"email": "[email protected]",
|
|
"username": "foo",
|
|
},
|
|
"exception": {
|
|
"values": [
|
|
{
|
|
"type": "SyntaxError",
|
|
"value": "hello world",
|
|
"stacktrace": {
|
|
"frames": [
|
|
{
|
|
"filename": "example.php",
|
|
"module": "example",
|
|
"context_line": 'echo "hello";',
|
|
"abs_path": "path/to/example.php",
|
|
}
|
|
]
|
|
},
|
|
"thread_id": 1,
|
|
}
|
|
]
|
|
},
|
|
"tags": [("environment", "production")],
|
|
"extra": {"foo": {"bar": "baz"}, "biz": ["baz"], "bar": "foo"},
|
|
"platform": "php",
|
|
"sdk": {"name": "sentry.javascript.react", "version": "6.16.1"},
|
|
"contexts": {
|
|
"response": {
|
|
"type": "response",
|
|
"status_code": 500,
|
|
},
|
|
"device": {
|
|
"screen_width_pixels": 1920,
|
|
"screen_height_pixels": 1080,
|
|
"screen_dpi": 123,
|
|
"screen_density": 2.5,
|
|
},
|
|
"app": {
|
|
"in_foreground": True,
|
|
},
|
|
"unreal": {
|
|
"crash_type": "crash",
|
|
},
|
|
},
|
|
"threads": {
|
|
"values": [
|
|
{
|
|
"id": 1,
|
|
"main": True,
|
|
},
|
|
],
|
|
},
|
|
}
|
|
data.update(kwargs)
|
|
event = self.store_event(data, project_id=self.project.id)
|
|
return event
|
|
|
|
def test_render_label(self):
|
|
rule = self.get_rule(data={"match": MatchType.EQUAL, "attribute": "\xc3", "value": "\xc4"})
|
|
assert rule.render_label() == "The event's \xc3 value equals \xc4"
|
|
|
|
def test_equals(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "platform", "value": "php"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "platform", "value": "python"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_does_not_equal(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.NOT_EQUAL, "attribute": "platform", "value": "php"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.NOT_EQUAL, "attribute": "platform", "value": "python"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
def test_starts_with(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.STARTS_WITH, "attribute": "platform", "value": "ph"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.STARTS_WITH, "attribute": "platform", "value": "py"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_does_not_start_with(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.NOT_STARTS_WITH, "attribute": "platform", "value": "ph"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.NOT_STARTS_WITH, "attribute": "platform", "value": "py"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
def test_ends_with(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.ENDS_WITH, "attribute": "platform", "value": "hp"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.ENDS_WITH, "attribute": "platform", "value": "thon"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_does_not_end_with(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.NOT_ENDS_WITH, "attribute": "platform", "value": "hp"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.NOT_ENDS_WITH, "attribute": "platform", "value": "thon"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
def test_contains(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.CONTAINS, "attribute": "platform", "value": "p"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.CONTAINS, "attribute": "platform", "value": "z"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_contains_message(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.CONTAINS, "attribute": "message", "value": "hello"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
# Validate that this searches message in the same way that snuba does
|
|
event = self.get_event(message="")
|
|
# This should still pass, even though the message is now empty
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.CONTAINS, "attribute": "message", "value": "hello"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
# The search should also include info from the exception if present
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.CONTAINS, "attribute": "message", "value": "SyntaxError"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.CONTAINS, "attribute": "message", "value": "not present"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_does_not_contain(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.NOT_CONTAINS, "attribute": "platform", "value": "p"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.NOT_CONTAINS, "attribute": "platform", "value": "z"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
def test_message(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "message", "value": "hello world"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "message", "value": "php"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_environment(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "environment", "value": "production"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "environment", "value": "staging"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_compares_case_insensitive(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "environment", "value": "PRODUCTION"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
def test_compare_int_value(self):
|
|
event = self.get_event()
|
|
event.data["extra"]["number"] = 1
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "extra.number", "value": "1"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
def test_http_method(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "http.method", "value": "get"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "http.method", "value": "post"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_http_url(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "http.url", "value": "http://example.com/"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "http.url", "value": "http://foo.com"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_http_status_code(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "http.status_code", "value": "500"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "http.status_code", "value": "400"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_user_id(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(data={"match": MatchType.EQUAL, "attribute": "user.id", "value": "1"})
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(data={"match": MatchType.EQUAL, "attribute": "user.id", "value": "2"})
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_user_ip_address(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "user.ip_address", "value": "127.0.0.1"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "user.ip_address", "value": "2"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_user_email(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "user.email", "value": "[email protected]"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "user.email", "value": "2"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_user_username(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "user.username", "value": "foo"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "user.username", "value": "2"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_exception_type(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "exception.type", "value": "SyntaxError"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "exception.type", "value": "TypeError"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_error_handled(self):
|
|
event = self.get_event(
|
|
exception={
|
|
"values": [
|
|
{
|
|
"type": "Generic",
|
|
"value": "hello world",
|
|
"mechanism": {"type": "UncaughtExceptionHandler", "handled": False},
|
|
}
|
|
]
|
|
}
|
|
)
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "error.handled", "value": "False"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "error.handled", "value": "True"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_error_handled_not_defined(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "error.handled", "value": "True"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_error_unhandled(self):
|
|
event = self.get_event(
|
|
exception={
|
|
"values": [
|
|
{
|
|
"type": "Generic",
|
|
"value": "hello world",
|
|
"mechanism": {"type": "UncaughtExceptionHandler", "handled": False},
|
|
}
|
|
],
|
|
}
|
|
)
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "error.unhandled", "value": "True"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "error.unhandled", "value": "False"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_exception_value(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "exception.value", "value": "hello world"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "exception.value", "value": "foo bar"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_sdk_name(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "sdk.name",
|
|
"value": "sentry.javascript.react",
|
|
}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "sdk.name", "value": "sentry.python"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_stacktrace_filename(self):
|
|
"""Stacktrace.filename should match frames anywhere in the stack."""
|
|
|
|
event = self.get_event(
|
|
exception={
|
|
"values": [
|
|
{
|
|
"type": "SyntaxError",
|
|
"value": "hello world",
|
|
"stacktrace": {
|
|
"frames": [
|
|
{"filename": "example.php", "module": "example"},
|
|
{"filename": "somecode.php", "module": "somecode"},
|
|
{"filename": "othercode.php", "module": "othercode"},
|
|
]
|
|
},
|
|
}
|
|
]
|
|
}
|
|
)
|
|
|
|
# correctly matching filenames, at various locations in the stacktrace
|
|
for value in ["example.php", "somecode.php", "othercode.php"]:
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "stacktrace.filename", "value": value}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
# non-matching filename
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "stacktrace.filename", "value": "foo.php"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_stacktrace_module(self):
|
|
"""Stacktrace.module should match frames anywhere in the stack."""
|
|
|
|
event = self.get_event(
|
|
exception={
|
|
"values": [
|
|
{
|
|
"type": "SyntaxError",
|
|
"value": "hello world",
|
|
"stacktrace": {
|
|
"frames": [
|
|
{"filename": "example.php", "module": "example"},
|
|
{"filename": "somecode.php", "module": "somecode"},
|
|
{"filename": "othercode.php", "module": "othercode"},
|
|
]
|
|
},
|
|
}
|
|
]
|
|
}
|
|
)
|
|
|
|
# correctly matching modules, at various locations in the stacktrace
|
|
for value in ["example", "somecode", "othercode"]:
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "stacktrace.module", "value": value}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
# non-matching module
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "stacktrace.module", "value": "foo"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_stacktrace_code(self):
|
|
"""Stacktrace.code should match frames anywhere in the stack."""
|
|
|
|
event = self.get_event(
|
|
exception={
|
|
"values": [
|
|
{
|
|
"type": "NameError",
|
|
"value": "name 'hi' is not defined",
|
|
"stacktrace": {
|
|
"frames": [
|
|
{
|
|
"filename": "example.py",
|
|
"module": "example",
|
|
"function": "foo",
|
|
"context_line": "somecode.bar()",
|
|
},
|
|
{
|
|
"filename": "somecode.py",
|
|
"module": "somecode",
|
|
"function": "bar",
|
|
"context_line": "othercode.baz()",
|
|
},
|
|
{
|
|
"filename": "othercode.py",
|
|
"module": "othercode",
|
|
"function": "baz",
|
|
"context_line": "hi()",
|
|
},
|
|
]
|
|
},
|
|
}
|
|
]
|
|
}
|
|
)
|
|
|
|
# correctly matching code, at various locations in the stacktrace
|
|
for value in ["somecode.bar()", "othercode.baz()", "hi()"]:
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "stacktrace.code", "value": value}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
# non-matching code
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "stacktrace.code", "value": "foo"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_extra_simple_value(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "extra.bar", "value": "foo"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "extra.bar", "value": "bar"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_extra_nested_value(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "extra.foo.bar", "value": "baz"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "extra.foo.bar", "value": "bar"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_extra_nested_list(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "extra.biz", "value": "baz"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "extra.biz", "value": "bar"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_event_type(self):
|
|
event = self.get_event()
|
|
event.data["type"] = "error"
|
|
rule = self.get_rule(data={"match": MatchType.EQUAL, "attribute": "type", "value": "error"})
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(data={"match": MatchType.EQUAL, "attribute": "type", "value": "csp"})
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_stacktrace_abs_path(self):
|
|
"""Stacktrace.abs_path should match frames anywhere in the stack."""
|
|
|
|
event = self.get_event(
|
|
exception={
|
|
"values": [
|
|
{
|
|
"type": "SyntaxError",
|
|
"value": "hello world",
|
|
"stacktrace": {
|
|
"frames": [
|
|
{
|
|
"filename": "example.php",
|
|
"module": "example",
|
|
"abs_path": "path/to/example.php",
|
|
},
|
|
{
|
|
"filename": "somecode.php",
|
|
"module": "somecode",
|
|
"abs_path": "path/to/somecode.php",
|
|
},
|
|
{
|
|
"filename": "othercode.php",
|
|
"module": "othercode",
|
|
"abs_path": "path/to/othercode.php",
|
|
},
|
|
]
|
|
},
|
|
}
|
|
]
|
|
}
|
|
)
|
|
|
|
# correctly matching filenames, at various locations in the stacktrace
|
|
for value in ["path/to/example.php", "path/to/somecode.php", "path/to/othercode.php"]:
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "stacktrace.abs_path", "value": value}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
# non-matching filename
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "stacktrace.abs_path",
|
|
"value": "path/to/foo.php",
|
|
}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_stacktrace_package(self):
|
|
"""Stacktrace.package should match frames anywhere in the stack."""
|
|
|
|
event = self.get_event(
|
|
exception={
|
|
"values": [
|
|
{
|
|
"type": "SyntaxError",
|
|
"value": "hello world",
|
|
"stacktrace": {
|
|
"frames": [
|
|
{"filename": "example.php", "package": "package/example.lib"},
|
|
{
|
|
"filename": "somecode.php",
|
|
"package": "package/otherpackage.lib",
|
|
},
|
|
{
|
|
"filename": "othercode.php",
|
|
"package": "package/somepackage.lib",
|
|
},
|
|
]
|
|
},
|
|
}
|
|
]
|
|
}
|
|
)
|
|
|
|
# correctly matching filenames, at various locations in the stacktrace
|
|
for value in ["package/example.lib", "package/otherpackage.lib", "package/somepackage.lib"]:
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "stacktrace.package", "value": value}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
# non-matching filename
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "stacktrace.package",
|
|
"value": "package/otherotherpackage.lib",
|
|
}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_device_screen_width_pixels(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "device.screen_width_pixels",
|
|
"value": "1920",
|
|
}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "device.screen_width_pixels",
|
|
"value": "400",
|
|
}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_device_screen_height_pixels(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "device.screen_height_pixels",
|
|
"value": "1080",
|
|
}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "device.screen_height_pixels",
|
|
"value": "400",
|
|
}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_device_screen_dpi(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "device.screen_dpi",
|
|
"value": "123",
|
|
}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "device.screen_dpi",
|
|
"value": "400",
|
|
}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_device_screen_density(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "device.screen_density",
|
|
"value": "2.5",
|
|
}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={
|
|
"match": MatchType.EQUAL,
|
|
"attribute": "device.screen_density",
|
|
"value": "400",
|
|
}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_app_in_foreground(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "app.in_foreground", "value": "True"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "app.in_foreground", "value": "False"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|
|
|
|
def test_unreal_crash_type(self):
|
|
event = self.get_event()
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "unreal.crash_type", "value": "Crash"}
|
|
)
|
|
self.assertPasses(rule, event)
|
|
|
|
rule = self.get_rule(
|
|
data={"match": MatchType.EQUAL, "attribute": "unreal.crash_type", "value": "NoCrash"}
|
|
)
|
|
self.assertDoesNotPass(rule, event)
|