Skip to content

Commit a4e4aa1

Browse files
committed
add tests
1 parent 9f6c21a commit a4e4aa1

File tree

3 files changed

+266
-2
lines changed

3 files changed

+266
-2
lines changed

src/sentry/core/endpoints/organization_details.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ class OrganizationSerializer(BaseOrganizationSerializer):
339339
ingestThroughTrustedRelaysOnly = serializers.ChoiceField(
340340
choices=[("enabled", "enabled"), ("disabled", "disabled")], required=False
341341
)
342+
hasGranularReplayPermissions = serializers.BooleanField(required=False)
342343
replayAccessMembers = serializers.ListField(
343344
child=serializers.IntegerField(),
344345
required=False,
@@ -588,8 +589,7 @@ def save(self, **kwargs):
588589
organization=org, key=option_key, defaults={"value": new_value}
589590
)
590591

591-
if new_value or created:
592-
changed_data["hasGranularReplayPermissions"] = f"to {new_value}"
592+
changed_data["hasGranularReplayPermissions"] = f"to {new_value}"
593593

594594
if "replayAccessMembers" in data:
595595
member_ids = data["replayAccessMembers"]

tests/sentry/api/serializers/test_organization.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from sentry.models.deploy import Deploy
1818
from sentry.models.environment import Environment
1919
from sentry.models.options.organization_option import OrganizationOption
20+
from sentry.models.organizationmemberreplayaccess import OrganizationMemberReplayAccess
2021
from sentry.models.organizationonboardingtask import (
2122
OnboardingTask,
2223
OnboardingTaskStatus,
@@ -162,6 +163,72 @@ def test_detailed(self) -> None:
162163
assert isinstance(result["teamRoleList"], list)
163164
assert result["requiresSso"] == acc.requires_sso
164165

166+
def test_granular_replay_permissions_disabled_without_feature(self) -> None:
167+
user = self.create_user()
168+
organization = self.create_organization(owner=user)
169+
acc = access.from_user(user, organization)
170+
171+
serializer = DetailedOrganizationSerializer()
172+
result = serialize(organization, user, serializer, access=acc)
173+
174+
assert result["hasGranularReplayPermissions"] is False
175+
assert result["replayAccessMembers"] == []
176+
177+
def test_granular_replay_permissions_flag_with_feature(self) -> None:
178+
user = self.create_user()
179+
organization = self.create_organization(owner=user)
180+
acc = access.from_user(user, organization)
181+
182+
with self.feature("organizations:granular-replay-permissions"):
183+
serializer = DetailedOrganizationSerializer()
184+
result = serialize(organization, user, serializer, access=acc)
185+
assert result["hasGranularReplayPermissions"] is False
186+
assert result["replayAccessMembers"] == []
187+
188+
OrganizationOption.objects.set_value(
189+
organization=organization,
190+
key="sentry:granular-replay-permissions",
191+
value=True,
192+
)
193+
194+
result = serialize(organization, user, serializer, access=acc)
195+
assert result["hasGranularReplayPermissions"] is True
196+
assert result["replayAccessMembers"] == []
197+
198+
def test_replay_access_members_serialized(self) -> None:
199+
user = self.create_user()
200+
organization = self.create_organization(owner=user)
201+
member1 = self.create_member(
202+
organization=organization, user=self.create_user(), role="member"
203+
)
204+
member2 = self.create_member(
205+
organization=organization, user=self.create_user(), role="member"
206+
)
207+
OrganizationMemberReplayAccess.objects.create(
208+
organization=organization, organizationmember=member1
209+
)
210+
OrganizationMemberReplayAccess.objects.create(
211+
organization=organization, organizationmember=member2
212+
)
213+
acc = access.from_user(user, organization)
214+
215+
with self.feature("organizations:granular-replay-permissions"):
216+
serializer = DetailedOrganizationSerializer()
217+
result = serialize(organization, user, serializer, access=acc)
218+
219+
assert set(result["replayAccessMembers"]) == {member1.id, member2.id}
220+
221+
def test_replay_access_members_empty_when_none_set(self) -> None:
222+
user = self.create_user()
223+
organization = self.create_organization(owner=user)
224+
acc = access.from_user(user, organization)
225+
226+
with self.feature("organizations:granular-replay-permissions"):
227+
serializer = DetailedOrganizationSerializer()
228+
result = serialize(organization, user, serializer, access=acc)
229+
230+
assert result["replayAccessMembers"] == []
231+
165232

166233
class DetailedOrganizationSerializerWithProjectsAndTeamsTest(TestCase):
167234
def test_detailed_org_projs_teams(self) -> None:

tests/sentry/core/endpoints/test_organization_details.py

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from sentry.models.options.project_option import ProjectOption
3232
from sentry.models.organization import Organization, OrganizationStatus
3333
from sentry.models.organizationmapping import OrganizationMapping
34+
from sentry.models.organizationmemberreplayaccess import OrganizationMemberReplayAccess
3435
from sentry.models.organizationslugreservation import OrganizationSlugReservation
3536
from sentry.signals import project_created
3637
from sentry.silo.safety import unguarded_write
@@ -1476,6 +1477,202 @@ def test_enable_seer_coding_can_be_enabled(self) -> None:
14761477

14771478
assert self.organization.get_option("sentry:enable_seer_coding") is True
14781479

1480+
@with_feature("organizations:granular-replay-permissions")
1481+
def test_granular_replay_permissions_flag_set(self) -> None:
1482+
with assume_test_silo_mode_of(AuditLogEntry):
1483+
AuditLogEntry.objects.filter(organization_id=self.organization.id).delete()
1484+
1485+
data = {"hasGranularReplayPermissions": True}
1486+
with outbox_runner():
1487+
self.get_success_response(self.organization.slug, **data)
1488+
1489+
option_value = OrganizationOption.objects.get(
1490+
organization=self.organization, key="sentry:granular-replay-permissions"
1491+
)
1492+
assert option_value.value is True
1493+
1494+
with assume_test_silo_mode_of(AuditLogEntry):
1495+
log = AuditLogEntry.objects.get(organization_id=self.organization.id)
1496+
assert "to True" in log.data["hasGranularReplayPermissions"]
1497+
1498+
@with_feature("organizations:granular-replay-permissions")
1499+
def test_granular_replay_permissions_flag_unset(self) -> None:
1500+
self.organization.update_option("sentry:granular-replay-permissions", True)
1501+
with assume_test_silo_mode_of(AuditLogEntry):
1502+
AuditLogEntry.objects.filter(organization_id=self.organization.id).delete()
1503+
1504+
data = {"hasGranularReplayPermissions": False}
1505+
with outbox_runner():
1506+
self.get_success_response(self.organization.slug, **data)
1507+
1508+
option_value = OrganizationOption.objects.get(
1509+
organization=self.organization, key="sentry:granular-replay-permissions"
1510+
)
1511+
assert option_value.value is False
1512+
1513+
with assume_test_silo_mode_of(AuditLogEntry):
1514+
log = AuditLogEntry.objects.get(organization_id=self.organization.id)
1515+
1516+
assert "to False" in log.data["hasGranularReplayPermissions"]
1517+
1518+
def test_granular_replay_permissions_flag_requires_feature(self) -> None:
1519+
data = {"hasGranularReplayPermissions": True}
1520+
response = self.get_error_response(self.organization.slug, **data, status_code=400)
1521+
assert "hasGranularReplayPermissions" in response.data
1522+
1523+
@with_feature("organizations:granular-replay-permissions")
1524+
def test_granular_replay_permissions_flag_requires_admin_scope(self) -> None:
1525+
member_user = self.create_user()
1526+
self.create_member(
1527+
organization=self.organization, user=member_user, role="member", teams=[]
1528+
)
1529+
self.login_as(member_user)
1530+
1531+
data = {"hasGranularReplayPermissions": True}
1532+
response = self.get_error_response(self.organization.slug, **data, status_code=403)
1533+
assert response.status_code == 403
1534+
1535+
@with_feature("organizations:granular-replay-permissions")
1536+
def test_replay_access_members_add(self) -> None:
1537+
member1 = self.create_member(
1538+
organization=self.organization, user=self.create_user(), role="member"
1539+
)
1540+
member2 = self.create_member(
1541+
organization=self.organization, user=self.create_user(), role="member"
1542+
)
1543+
with assume_test_silo_mode_of(AuditLogEntry):
1544+
AuditLogEntry.objects.filter(organization_id=self.organization.id).delete()
1545+
1546+
data = {"replayAccessMembers": [member1.id, member2.id]}
1547+
with outbox_runner():
1548+
self.get_success_response(self.organization.slug, **data)
1549+
1550+
access_members = list(
1551+
OrganizationMemberReplayAccess.objects.filter(
1552+
organization=self.organization
1553+
).values_list("organizationmember_id", flat=True)
1554+
)
1555+
assert set(access_members) == {member1.id, member2.id}
1556+
1557+
with assume_test_silo_mode_of(AuditLogEntry):
1558+
log = AuditLogEntry.objects.get(organization_id=self.organization.id)
1559+
assert "added 2 member(s)" in log.data["replayAccessMembers"]
1560+
assert "total: 2 member(s)" in log.data["replayAccessMembers"]
1561+
1562+
@with_feature("organizations:granular-replay-permissions")
1563+
def test_replay_access_members_remove(self) -> None:
1564+
member1 = self.create_member(
1565+
organization=self.organization, user=self.create_user(), role="member"
1566+
)
1567+
member2 = self.create_member(
1568+
organization=self.organization, user=self.create_user(), role="member"
1569+
)
1570+
OrganizationMemberReplayAccess.objects.create(
1571+
organization=self.organization, organizationmember=member1
1572+
)
1573+
OrganizationMemberReplayAccess.objects.create(
1574+
organization=self.organization, organizationmember=member2
1575+
)
1576+
with assume_test_silo_mode_of(AuditLogEntry):
1577+
AuditLogEntry.objects.filter(organization_id=self.organization.id).delete()
1578+
1579+
data = {"replayAccessMembers": [member1.id]}
1580+
with outbox_runner():
1581+
self.get_success_response(self.organization.slug, **data)
1582+
1583+
access_members = list(
1584+
OrganizationMemberReplayAccess.objects.filter(
1585+
organization=self.organization
1586+
).values_list("organizationmember_id", flat=True)
1587+
)
1588+
assert access_members == [member1.id]
1589+
1590+
with assume_test_silo_mode_of(AuditLogEntry):
1591+
log = AuditLogEntry.objects.get(organization_id=self.organization.id)
1592+
assert "removed 1 member(s)" in log.data["replayAccessMembers"]
1593+
assert "total: 1 member(s)" in log.data["replayAccessMembers"]
1594+
1595+
@with_feature("organizations:granular-replay-permissions")
1596+
def test_replay_access_members_add_and_remove(self) -> None:
1597+
member1 = self.create_member(
1598+
organization=self.organization, user=self.create_user(), role="member"
1599+
)
1600+
member2 = self.create_member(
1601+
organization=self.organization, user=self.create_user(), role="member"
1602+
)
1603+
member3 = self.create_member(
1604+
organization=self.organization, user=self.create_user(), role="member"
1605+
)
1606+
OrganizationMemberReplayAccess.objects.create(
1607+
organization=self.organization, organizationmember=member1
1608+
)
1609+
with assume_test_silo_mode_of(AuditLogEntry):
1610+
AuditLogEntry.objects.filter(organization_id=self.organization.id).delete()
1611+
1612+
data = {"replayAccessMembers": [member2.id, member3.id]}
1613+
with outbox_runner():
1614+
self.get_success_response(self.organization.slug, **data)
1615+
1616+
access_members = set(
1617+
OrganizationMemberReplayAccess.objects.filter(
1618+
organization=self.organization
1619+
).values_list("organizationmember_id", flat=True)
1620+
)
1621+
assert access_members == {member2.id, member3.id}
1622+
1623+
with assume_test_silo_mode_of(AuditLogEntry):
1624+
log = AuditLogEntry.objects.get(organization_id=self.organization.id)
1625+
assert "added 2 member(s)" in log.data["replayAccessMembers"]
1626+
assert "removed 1 member(s)" in log.data["replayAccessMembers"]
1627+
assert "total: 2 member(s)" in log.data["replayAccessMembers"]
1628+
1629+
@with_feature("organizations:granular-replay-permissions")
1630+
def test_replay_access_members_clear_all(self) -> None:
1631+
member1 = self.create_member(
1632+
organization=self.organization, user=self.create_user(), role="member"
1633+
)
1634+
OrganizationMemberReplayAccess.objects.create(
1635+
organization=self.organization, organizationmember=member1
1636+
)
1637+
with assume_test_silo_mode_of(AuditLogEntry):
1638+
AuditLogEntry.objects.filter(organization_id=self.organization.id).delete()
1639+
1640+
data = {"replayAccessMembers": []}
1641+
with outbox_runner():
1642+
self.get_success_response(self.organization.slug, **data)
1643+
1644+
access_count = OrganizationMemberReplayAccess.objects.filter(
1645+
organization=self.organization
1646+
).count()
1647+
assert access_count == 0
1648+
1649+
with assume_test_silo_mode_of(AuditLogEntry):
1650+
log = AuditLogEntry.objects.get(organization_id=self.organization.id)
1651+
assert "removed 1 member(s)" in log.data["replayAccessMembers"]
1652+
assert "total: 0 member(s)" in log.data["replayAccessMembers"]
1653+
1654+
def test_replay_access_members_requires_feature(self) -> None:
1655+
member1 = self.create_member(
1656+
organization=self.organization, user=self.create_user(), role="member"
1657+
)
1658+
data = {"replayAccessMembers": [member1.id]}
1659+
response = self.get_error_response(self.organization.slug, **data, status_code=400)
1660+
assert "hasGranularReplayPermissions" in response.data
1661+
1662+
@with_feature("organizations:granular-replay-permissions")
1663+
def test_replay_access_members_requires_admin_scope(self) -> None:
1664+
member_user = self.create_user()
1665+
self.create_member(
1666+
organization=self.organization, user=member_user, role="member", teams=[]
1667+
)
1668+
self.login_as(member_user)
1669+
1670+
other_member = self.create_member(
1671+
organization=self.organization, user=self.create_user(), role="member"
1672+
)
1673+
data = {"replayAccessMembers": [other_member.id]}
1674+
self.get_error_response(self.organization.slug, **data, status_code=403)
1675+
14791676

14801677
class OrganizationDeleteTest(OrganizationDetailsTestBase):
14811678
method = "delete"

0 commit comments

Comments
 (0)