def test_get_autoassign_owners_when_codeowners_and_issueowners_exists(self): self.team = self.create_team( organization=self.organization, slug="tiger-team", members=[self.user] ) self.team2 = self.create_team( organization=self.organization, slug="dolphin-team", members=[self.user] ) self.project = self.create_project( organization=self.organization, teams=[self.team, self.team2] ) self.code_mapping = self.create_code_mapping(project=self.project) rule_a = Rule(Matcher("path", "*.py"), [Owner("team", self.team.slug)]) rule_b = Rule(Matcher("path", "src/*"), [Owner("user", self.user.email)]) rule_c = Rule(Matcher("path", "*.py"), [Owner("team", self.team2.slug)]) ProjectOwnership.objects.create( project_id=self.project.id, schema=dump_schema([rule_a, rule_b]), fallthrough=True ) self.create_codeowners( self.project, self.code_mapping, raw="*.py @tiger-team", schema=dump_schema([rule_c]) ) # No autoassignment on match assert ProjectOwnership.get_autoassign_owners( self.project.id, {"stacktrace": {"frames": [{"filename": "api/foo.py"}]}} ) == (False, [self.team, self.team2], False) # autoassignment is True owner = ProjectOwnership.objects.get(project_id=self.project.id) owner.auto_assignment = True owner.save() assert ProjectOwnership.get_autoassign_owners( self.project.id, {"stacktrace": {"frames": [{"filename": "api/foo.py"}]}} ) == (True, [self.team, self.team2], False) # # more than 2 matches assert ProjectOwnership.get_autoassign_owners( self.project.id, {"stacktrace": {"frames": [{"filename": "src/foo.py"}]}} ) == (True, [self.user, self.team], False)
def setUp(self): from sentry.ownership.grammar import Rule self.user = self.create_user(email="*****@*****.**", is_active=True) self.user2 = self.create_user(email="*****@*****.**", is_active=True) self.organization = self.create_organization(owner=self.user) self.team = self.create_team(organization=self.organization) self.project = self.create_project(name="Test", teams=[self.team]) OrganizationMemberTeam.objects.create( organizationmember=OrganizationMember.objects.get( user=self.user, organization=self.organization), team=self.team, ) self.create_member(user=self.user2, organization=self.organization, teams=[self.team]) self.group = self.create_group( first_seen=timezone.now(), last_seen=timezone.now(), project=self.project, message="hello world", logger="root", ) ProjectOwnership.objects.create( project_id=self.project.id, schema=dump_schema([ Rule(Matcher("path", "*.py"), [Owner("team", self.team.slug)]), Rule(Matcher("path", "*.jx"), [Owner("user", self.user2.email)]), Rule( Matcher("path", "*.cbl"), [ Owner("user", self.user.email), Owner("user", self.user2.email) ], ), ]), fallthrough=True, )
def test_load_schema(): assert load_schema( { "$version": 1, "rules": [ { "matcher": {"type": "path", "pattern": "*.js"}, "owners": [{"type": "team", "identifier": "frontend"}], } ], } ) == [Rule(Matcher("path", "*.js"), [Owner("team", "frontend")])]
def test_parse_rules(): assert parse_rules(fixture_data) == [ Rule(Matcher("path", "*.js"), [Owner("team", "frontend"), Owner("user", "*****@*****.**")]), Rule(Matcher("url", "http://google.com/*"), [Owner("team", "backend")]), Rule(Matcher("path", "src/sentry/*"), [Owner("user", "*****@*****.**")]), Rule(Matcher("tags.foo", "bar"), [Owner("user", "*****@*****.**")]), Rule(Matcher("tags.foo", "bar baz"), [Owner("user", "*****@*****.**")]), Rule(Matcher("module", "foo.bar"), [Owner("team", "workflow")]), Rule(Matcher("module", "foo bar"), [Owner("user", "*****@*****.**")]), ]
def setUp(self): from sentry.ownership.grammar import Rule self.user = self.create_user(email='*****@*****.**', is_active=True) self.user2 = self.create_user(email='*****@*****.**', is_active=True) self.organization = self.create_organization(owner=self.user) self.team = self.create_team(organization=self.organization) self.project = self.create_project(name='Test', teams=[self.team]) OrganizationMemberTeam.objects.create( organizationmember=OrganizationMember.objects.get( user=self.user, organization=self.organization, ), team=self.team, ) self.create_member(user=self.user2, organization=self.organization, teams=[self.team]) self.group = self.create_group( first_seen=timezone.now(), last_seen=timezone.now(), project=self.project, message='hello world', logger='root', ) ProjectOwnership.objects.create( project_id=self.project.id, schema=dump_schema([ Rule(Matcher('path', '*.py'), [ Owner('team', self.team.slug), ]), Rule(Matcher('path', '*.jx'), [ Owner('user', self.user2.email), ]), Rule(Matcher('path', '*.cbl'), [ Owner('user', self.user.email), Owner('user', self.user2.email), ]) ]), fallthrough=True, )
def test_owner_assignment_when_owners_have_been_unassigned(self): """ Test that ensures that if certain assignees get unassigned, and project rules are changed then the new group assignees should be re-calculated and re-assigned """ # Create rules and check assignees self.make_ownership() event = self.store_event( data={ "message": "oh no", "platform": "python", "stacktrace": {"frames": [{"filename": "src/app/example.py"}]}, }, project_id=self.project.id, ) cache_key = write_event_to_cache(event) post_process_group( is_new=False, is_regression=False, is_new_group_environment=False, cache_key=cache_key, group_id=event.group_id, ) assignee = event.group.assignee_set.first() assert assignee.user == self.user user_3 = self.create_user() self.create_team_membership(self.team, user=user_3) # De-assign group assignees GroupAssignee.objects.deassign(event.group, self.user) assert event.group.assignee_set.first() is None # Change ProjectOwnership rules rules = [ Rule(Matcher("path", "src/*"), [Owner("user", user_3.email)]), ] self.prj_ownership.schema = dump_schema(rules) self.prj_ownership.save() cache_key = write_event_to_cache(event) post_process_group( is_new=False, is_regression=False, is_new_group_environment=False, cache_key=cache_key, group_id=event.group_id, ) # Group should be re-assigned to the new group owner assignee = event.group.assignee_set.first() assert assignee.user == user_3
def setUp(self): self.user2 = self.create_user(email="*****@*****.**", is_active=True) self.create_member(user=self.user2, organization=self.organization, teams=[self.team]) ProjectOwnership.objects.create( project_id=self.project.id, schema=dump_schema([ grammar.Rule(Matcher("path", "*.py"), [Owner("team", self.team.slug)]), grammar.Rule(Matcher("path", "*.jx"), [Owner("user", self.user2.email)]), grammar.Rule( Matcher("path", "*.cbl"), [ Owner("user", self.user.email), Owner("user", self.user2.email) ], ), ]), fallthrough=True, )
def test_abs_path_when_filename_present(self): frame = { "filename": "computer.cpp", "abs_path": "C:\\My\\Path\\computer.cpp", } rule = Rule(Matcher("path", "*My\\Path*"), [Owner("team", self.team.slug)]) ProjectOwnership.objects.create(project_id=self.project.id, schema=dump_schema([rule]), fallthrough=True) assert ProjectOwnership.get_owners( self.project.id, {"stacktrace": { "frames": [frame] }}) == ([ActorTuple(self.team.id, Team)], [rule])
def test_multiple_owners_order_matters(self): users = [self.user, self.user2, self.user3] rules = [ Rule(Matcher("path", "*.py"), [Owner("user", users[0].email)]), Rule(Matcher("path", "*foo*"), [Owner("user", users[1].email)]), Rule(Matcher("path", "*"), [Owner("user", users[2].email)]), ] rules.reverse() ProjectOwnership.objects.create(project_id=self.project.id, schema=dump_schema(rules), fallthrough=True) event1 = self.store_event( data={"stacktrace": { "frames": [{ "filename": "foo.py" }] }}, project_id=self.project.id) self.path = reverse( "sentry-api-0-event-owners", kwargs={ "organization_slug": self.organization.slug, "project_slug": self.project.slug, "event_id": event1.event_id, }, ) resp = self.client.get(self.path) assert resp.status_code == 200 assert len(resp.data["owners"]) == 3 assert [o["id"] for o in resp.data["owners"] ] == [six.text_type(u.id) for u in reversed(users)] assert resp.data["rule"] == Matcher("path", "*") assert len(resp.data["rules"]) == 3
def setUp(self): self.user = self.create_user(email="*****@*****.**", is_active=True) self.user2 = self.create_user(email="*****@*****.**", is_active=True) self.user3 = self.create_user(email="*****@*****.**", is_active=True) self.organization = self.create_organization(owner=self.user) self.team = self.create_team(organization=self.organization, members=[self.user2, self.user3]) self.team2 = self.create_team(organization=self.organization, members=[self.user]) self.project = self.create_project(name="Test", teams=[self.team, self.team2]) self.group = self.create_group( first_seen=timezone.now(), last_seen=timezone.now(), project=self.project, message="hello world", logger="root", ) ProjectOwnership.objects.create( project_id=self.project.id, schema=dump_schema([ grammar.Rule(Matcher("path", "*.py"), [Owner("team", self.team.slug)]), grammar.Rule(Matcher("path", "*.jx"), [Owner("user", self.user2.email)]), grammar.Rule( Matcher("path", "*.cbl"), [ Owner("user", self.user.email), Owner("user", self.user2.email), Owner("user", self.user3.email), ], ), ]), fallthrough=True, )
def test_matcher_test_url(): data = {"request": {"url": "http://example.com/foo.js"}} assert Matcher("url", "*.js").test(data) assert Matcher("url", "http://*.com/foo.js").test(data) assert not Matcher("url", "*.py").test(data) assert not Matcher("url", "*.jsx").test(data) assert not Matcher("path", "*.js").test(data) assert not Matcher("url", "*.js").test({})
def test_load_schema(): assert load_schema({ '$version': 1, 'rules': [{ 'matcher': { 'type': 'path', 'pattern': '*.js', }, 'owners': [{ 'type': 'team', 'identifier': 'frontend', }] }] }) == [Rule(Matcher('path', '*.js'), [Owner('team', 'frontend')])]
def test_matcher_test_stacktrace(): data = { "stacktrace": { "frames": [{"filename": "foo/file.py"}, {"abs_path": "/usr/local/src/other/app.py"}] } } assert Matcher("path", "*.py").test(data) assert Matcher("path", "foo/*.py").test(data) assert Matcher("path", "/usr/local/src/*/app.py").test(data) assert not Matcher("path", "*.js").test(data) assert not Matcher("path", "*.jsx").test(data) assert not Matcher("url", "*.py").test(data) assert not Matcher("path", "*.py").test({})
def test_get_owners_basic(self): matcher = Matcher('path', '*.py') ProjectOwnership.objects.create( project_id=self.project.id, schema=dump_schema([ Rule(matcher, [ Owner('user', self.user.email), Owner('team', self.team.slug), ]), ]), fallthrough=True, ) # No data matches assert ProjectOwnership.get_owners(self.project.id, {}) == (ProjectOwnership.Everyone, None) assert ProjectOwnership.get_owners(self.project.id, { 'sentry.interfaces.Stacktrace': { 'frames': [{ 'filename': 'foo.py', }] } }) == ([Actor(self.user.id, User), Actor(self.team.id, Team)], matcher) assert ProjectOwnership.get_owners(self.project.id, { 'sentry.interfaces.Stacktrace': { 'frames': [{ 'filename': 'xxxx', }] } }) == (ProjectOwnership.Everyone, None) # When fallthrough = False, we don't implicitly assign to Everyone ProjectOwnership.objects.filter( project_id=self.project.id, ).update(fallthrough=False) assert ProjectOwnership.get_owners(self.project.id, { 'sentry.interfaces.Stacktrace': { 'frames': [{ 'filename': 'xxxx', }] } }) == ([], None)
def test_owner_assignment_existing_owners(self): with self.feature("projects:workflow-owners-ingestion"): extra_user = self.create_user() self.create_team_membership(self.team, user=extra_user) self.make_ownership([ Rule(Matcher("path", "src/app/things/in/*"), [Owner("user", extra_user.email)]) ], ) GroupOwner.objects.create( group=self.group, project=self.project, organization=self.organization, user=self.user, type=GroupOwnerType.OWNERSHIP_RULE.value, ) event = self.store_event( data={ "message": "oh no", "platform": "python", "stacktrace": { "frames": [{ "filename": "src/app/things/in/a/path/example2.py" }] }, }, project_id=self.project.id, ) cache_key = write_event_to_cache(event) post_process_group( is_new=False, is_regression=False, is_new_group_environment=False, cache_key=cache_key, group_id=event.group_id, ) assignee = event.group.assignee_set.first() assert assignee.user == extra_user assert assignee.team is None owners = list(GroupOwner.objects.filter(group=event.group)) assert len(owners) == 2 assert set([(extra_user.id, None), (None, self.team.id)]) == {(o.user_id, o.team_id) for o in owners}
def test_matcher_test_url(): data = { 'request': { 'url': 'http://example.com/foo.js', } } assert Matcher('url', '*.js').test(data) assert Matcher('url', 'http://*.com/foo.js').test(data) assert not Matcher('url', '*.py').test(data) assert not Matcher('url', '*.jsx').test(data) assert not Matcher('path', '*.js').test(data) assert not Matcher('url', '*.js').test({})
def test_owner_assignment_existing_owners(self): extra_team = self.create_team() ProjectTeam.objects.create(team=extra_team, project=self.project) self.make_ownership([ Rule(Matcher("path", "src/app/things/in/*"), [Owner("team", extra_team.slug)]) ], ) GroupOwner.objects.create( group=self.group, project=self.project, organization=self.organization, user=self.user, type=GroupOwnerType.OWNERSHIP_RULE.value, ) event = self.store_event( data={ "message": "oh no", "platform": "python", "stacktrace": { "frames": [{ "filename": "src/app/things/in/a/path/example2.py" }] }, }, project_id=self.project.id, ) cache_key = write_event_to_cache(event) post_process_group( is_new=False, is_regression=False, is_new_group_environment=False, cache_key=cache_key, group_id=event.group_id, ) assignee = event.group.assignee_set.first() assert assignee.user is None assert assignee.team == extra_team owners = list(GroupOwner.objects.filter(group=event.group)) assert {(None, extra_team.id), (self.user.id, None)} == {(o.user_id, o.team_id) for o in owners}
def test_matcher_test_url(): data = { 'sentry.interfaces.Http': { 'url': 'http://example.com/foo.js', } } assert Matcher('url', '*.js').test(data) assert Matcher('url', 'http://*.com/foo.js').test(data) assert not Matcher('url', '*.py').test(data) assert not Matcher('url', '*.jsx').test(data) assert not Matcher('path', '*.js').test(data) assert not Matcher('url', '*.js').test({})
def test_matcher_test_stacktrace(): data = { 'sentry.interfaces.Stacktrace': { 'frames': [ {'filename': 'foo/file.py'}, {'abs_path': '/usr/local/src/other/app.py'}, ], } } assert Matcher('path', '*.py').test(data) assert Matcher('path', 'foo/*.py').test(data) assert Matcher('path', '/usr/local/src/*/app.py').test(data) assert not Matcher('path', '*.js').test(data) assert not Matcher('path', '*.jsx').test(data) assert not Matcher('url', '*.py').test(data) assert not Matcher('path', '*.py').test({})
def test_team_without_members(self): team = self.create_team() project = self.create_project(teams=[team], fire_project_created=True) ProjectOwnership.objects.create( project_id=project.id, schema=dump_schema([Rule(Matcher("path", "*.cpp"), [Owner("team", team.slug)])]), fallthrough=True, ) rule = project.rule_set.all()[0] records = [ event_to_record(event, (rule,)) for event in self.create_events_from_filenames( project, ["hello.py", "goodbye.py", "hola.py", "adios.py"] ) ] digest = build_digest(project, sort_records(records)) user_ids = [member.user_id for member in team.member_set] assert not user_ids for user_id, user_digest in get_personalized_digests(project.id, digest, user_ids): assert False # no users in this team no digests should be processed
def test_owners_of_different_types_ordered_correctly(self): owners = [ self.user, self.team3, self.user2, self.team2, self.user3, self.team ] rules = [ Rule(Matcher("path", "*.py"), [Owner("user", owners[0].email)]), Rule(Matcher("path", "*py"), [Owner("team", owners[1].slug)]), Rule(Matcher("path", "*foo*"), [Owner("user", owners[2].email)]), Rule(Matcher("path", "*y"), [Owner("team", owners[3].slug)]), Rule(Matcher("path", "*"), [Owner("user", owners[4].email)]), Rule(Matcher("path", "*o.py"), [Owner("team", owners[5].slug)]), ] ProjectOwnership.objects.create(project_id=self.project.id, schema=dump_schema(rules), fallthrough=True) event1 = self.store_event( data={"stacktrace": { "frames": [{ "filename": "foo.py" }] }}, project_id=self.project.id) self.path = reverse( "sentry-api-0-event-owners", kwargs={ "organization_slug": self.organization.slug, "project_slug": self.project.slug, "event_id": event1.event_id, }, ) resp = self.client.get(self.path) assert resp.status_code == 200 assert len(resp.data["owners"]) == 6 assert [o["id"] for o in resp.data["owners"] ] == [six.text_type(o.id) for o in owners] assert [o["type"] for o in resp.data["owners"]] == ["user", "team"] * 3 assert resp.data["rule"] == Matcher("path", "*.py") assert len(resp.data["rules"]) == 6
def test_team_without_members(self): team = self.create_team() project = self.create_project(teams=[team], fire_project_created=True) ProjectOwnership.objects.create( project_id=project.id, schema=dump_schema([Rule(Matcher("path", "*.cpp"), [Owner("team", team.slug)])]), fallthrough=True, ) rule = project.rule_set.all()[0] records = [ event_to_record(event, (rule,)) for event in self.create_events_from_filenames( project, ["hello.py", "goodbye.py", "hola.py", "adios.py"] ) ] digest = build_digest(project, sort_records(records))[0] user_ids = [member.user_id for member in team.member_set] assert not user_ids participants_by_provider_by_event = get_participants_by_event(digest, project) assert not { actor for actors in participants_by_provider_by_event.values() for actor in actors } # no users in this team no digests should be processed
def test_get_autoassign_owners_only_codeowners_exists(self): # This case will never exist bc we create a ProjectOwnership record if none exists when creating a ProjectCodeOwner record. # We have this testcase for potential corrupt data. self.team = self.create_team( organization=self.organization, slug="tiger-team", members=[self.user] ) self.code_mapping = self.create_code_mapping(project=self.project) rule_a = Rule(Matcher("path", "*.js"), [Owner("team", self.team.slug)]) self.create_codeowners( self.project, self.code_mapping, raw="*.js @tiger-team", schema=dump_schema([rule_a]), ) # No data matches assert ProjectOwnership.get_autoassign_owners(self.project.id, {}) == (False, [], False) # No autoassignment on match assert ProjectOwnership.get_autoassign_owners( self.project.id, {"stacktrace": {"frames": [{"filename": "foo.js"}]}} ) == (False, [self.team], True)
def test_owner_assignment_extra_groups(self): extra_user = self.create_user() self.create_team_membership(self.team, user=extra_user) self.make_ownership([ Rule(Matcher("path", "src/app/things/in/*"), [Owner("user", extra_user.email)]) ], ) event = self.store_event( data={ "message": "oh no", "platform": "python", "stacktrace": { "frames": [{ "filename": "src/app/things/in/a/path/example2.py" }] }, }, project_id=self.project.id, ) cache_key = write_event_to_cache(event) post_process_group( is_new=False, is_regression=False, is_new_group_environment=False, cache_key=cache_key, group_id=event.group_id, ) assignee = event.group.assignee_set.first() assert assignee.user == extra_user assert assignee.team is None owners = list(GroupOwner.objects.filter(group=event.group)) assert len(owners) == 2 assert {(extra_user.id, None), (self.user.id, None)} == {(o.user_id, o.team_id) for o in owners}
def test_team_without_members(self): team = self.create_team() project = self.create_project(teams=[team]) ProjectOwnership.objects.create( project_id=project.id, schema=dump_schema([ Rule(Matcher('path', '*.cpp'), [ Owner('team', team.slug), ]), ]), fallthrough=True, ) rule = project.rule_set.all()[0] records = [ event_to_record(event, (rule, )) for event in self.create_events(timezone.now( ), project, ['hello.py', 'goodbye.py', 'hola.py', 'adios.py']) ] digest = build_digest(project, sort_records(records)) user_ids = [member.user_id for member in team.member_set] assert not user_ids for user_id, user_digest in get_personalized_digests( project.id, digest, user_ids): assert False # no users in this team no digests should be processed
def setUp(self): self.user1 = self.create_user() self.user2 = self.create_user() self.user3 = self.create_user() self.user4 = self.create_user() self.user5 = self.create_user() # this user has no events self.user_ids = [ self.user1.id, self.user2.id, self.user3.id, self.user4.id, self.user5.id ] self.team1 = self.create_team() self.team2 = self.create_team() self.team3 = self.create_team() self.project = self.create_project( teams=[self.team1, self.team2, self.team3]) self.create_member(user=self.user1, organization=self.organization, teams=[self.team1]) self.create_member(user=self.user2, organization=self.organization, teams=[self.team2]) self.create_member(user=self.user3, organization=self.organization, teams=[self.team1, self.team2]) self.create_member(user=self.user4, organization=self.organization, teams=[self.team3]) self.create_member(user=self.user5, organization=self.organization, teams=[self.team3]) start_time = timezone.now() self.team1_events = self.create_events( start_time, self.project, ["hello.py", "goodbye.py", "hola.py", "adios.py"]) self.team2_events = self.create_events( start_time, self.project, ["old.cbl", "retro.cbl", "cool.cbl", "gem.cbl"]) self.user4_events = [ self.create_event( group=self.create_group(project=self.project), data=self.create_event_data("foo.bar", "helloworld.org"), ), self.create_event( group=self.create_group(project=self.project), data=self.create_event_data("bar.foo", "helloworld.org"), ), ] self.team1_matcher = Matcher("path", "*.py") self.team2_matcher = Matcher("path", "*.cbl") self.user4_matcher = Matcher("url", "*.org") ProjectOwnership.objects.create( project_id=self.project.id, schema=dump_schema([ Rule( self.team1_matcher, [ Owner("team", self.team1.slug), Owner("user", self.user3.email) ], ), Rule(self.team2_matcher, [Owner("team", self.team2.slug)]), Rule(self.user4_matcher, [Owner("user", self.user4.email)]), ]), fallthrough=True, )
def test_matcher_test_none(): data = {"request": {"url": None}} assert not Matcher("url", "").test(data)
def test_get_owners_basic(self): rule_a = Rule(Matcher("path", "*.py"), [Owner("team", self.team.slug)]) rule_b = Rule(Matcher("path", "src/*"), [Owner("user", self.user.email)]) ProjectOwnership.objects.create(project_id=self.project.id, schema=dump_schema([rule_a, rule_b]), fallthrough=True) # No data matches assert ProjectOwnership.get_owners(self.project.id, {}) == (ProjectOwnership.Everyone, None) # Match only rule_a self.assert_ownership_equals( ProjectOwnership.get_owners( self.project.id, {"stacktrace": { "frames": [{ "filename": "foo.py" }] }}), ([Actor(self.team.id, Team)], [rule_a]), ) # Match only rule_b self.assert_ownership_equals( ProjectOwnership.get_owners( self.project.id, {"stacktrace": { "frames": [{ "filename": "src/thing.txt" }] }}), ([Actor(self.user.id, User)], [rule_b]), ) # Matches both rule_a and rule_b self.assert_ownership_equals( ProjectOwnership.get_owners( self.project.id, {"stacktrace": { "frames": [{ "filename": "src/foo.py" }] }}), ([Actor(self.user.id, User), Actor(self.team.id, Team)], [rule_a, rule_b]), ) assert ProjectOwnership.get_owners( self.project.id, {"stacktrace": { "frames": [{ "filename": "xxxx" }] }}) == (ProjectOwnership.Everyone, None) # When fallthrough = False, we don't implicitly assign to Everyone owner = ProjectOwnership.objects.get(project_id=self.project.id) owner.fallthrough = False owner.save() assert ProjectOwnership.get_owners( self.project.id, {"stacktrace": { "frames": [{ "filename": "xxxx" }] }}) == ([], None)
def test_get_owners_basic(self): rule_a = Rule( Matcher('path', '*.py'), [ Owner('team', self.team.slug), ]) rule_b = Rule( Matcher('path', 'src/*'), [ Owner('user', self.user.email), ]) ProjectOwnership.objects.create( project_id=self.project.id, schema=dump_schema([rule_a, rule_b]), fallthrough=True, ) # No data matches assert ProjectOwnership.get_owners(self.project.id, {}) == (ProjectOwnership.Everyone, None) # Match only rule_a self.assert_ownership_equals(ProjectOwnership.get_owners( self.project.id, { 'sentry.interfaces.Stacktrace': { 'frames': [{ 'filename': 'foo.py', }] } } ), ([Actor(self.team.id, Team)], [rule_a])) # Match only rule_b self.assert_ownership_equals(ProjectOwnership.get_owners( self.project.id, { 'sentry.interfaces.Stacktrace': { 'frames': [{ 'filename': 'src/thing.txt', }] } } ), ([Actor(self.user.id, User)], [rule_b])) # Matches both rule_a and rule_b self.assert_ownership_equals(ProjectOwnership.get_owners( self.project.id, { 'sentry.interfaces.Stacktrace': { 'frames': [{ 'filename': 'src/foo.py', }] } } ), ([Actor(self.user.id, User), Actor(self.team.id, Team)], [rule_a, rule_b])) assert ProjectOwnership.get_owners( self.project.id, { 'sentry.interfaces.Stacktrace': { 'frames': [{ 'filename': 'xxxx', }] } } ) == (ProjectOwnership.Everyone, None) # When fallthrough = False, we don't implicitly assign to Everyone ProjectOwnership.objects.filter( project_id=self.project.id, ).update(fallthrough=False) assert ProjectOwnership.get_owners( self.project.id, { 'sentry.interfaces.Stacktrace': { 'frames': [{ 'filename': 'xxxx', }] } } ) == ([], None)
def test_matcher_test_tags_without_tag_data(data): assert not Matcher("tags.foo", "foo_value").test(data) assert not Matcher("tags.bar", "barval").test(data)