|
16 | 16 | Dashboard, |
17 | 17 | DashboardFavoriteUser, |
18 | 18 | DashboardLastVisited, |
| 19 | + DashboardRevision, |
19 | 20 | DashboardTombstone, |
20 | 21 | ) |
21 | 22 | from sentry.models.dashboard_permissions import DashboardPermissions |
@@ -4012,6 +4013,118 @@ def test_text_widget_errors_provided_queries(self) -> None: |
4012 | 4013 | assert "queries" in response.data["widgets"][1], response.data |
4013 | 4014 | assert response.data["widgets"][1]["queries"][0] == "Text widgets don't have queries" |
4014 | 4015 |
|
| 4016 | + def test_put_creates_dashboard_revision_when_feature_enabled(self) -> None: |
| 4017 | + original_title = self.dashboard.title |
| 4018 | + with self.feature("organizations:dashboards-revisions"): |
| 4019 | + response = self.do_request( |
| 4020 | + "put", self.url(self.dashboard.id), data={"title": "Updated Title"} |
| 4021 | + ) |
| 4022 | + assert response.status_code == 200, response.data |
| 4023 | + |
| 4024 | + revisions = DashboardRevision.objects.filter(dashboard=self.dashboard) |
| 4025 | + assert revisions.count() == 1 |
| 4026 | + revision = revisions.first() |
| 4027 | + assert revision is not None |
| 4028 | + assert revision.title == original_title |
| 4029 | + assert revision.snapshot["title"] == original_title |
| 4030 | + assert revision.snapshot_schema_version == 1 |
| 4031 | + assert revision.created_by_id == self.user.id |
| 4032 | + |
| 4033 | + def test_put_does_not_create_revision_when_feature_disabled(self) -> None: |
| 4034 | + response = self.do_request( |
| 4035 | + "put", self.url(self.dashboard.id), data={"title": "Updated Title"} |
| 4036 | + ) |
| 4037 | + assert response.status_code == 200, response.data |
| 4038 | + assert DashboardRevision.objects.filter(dashboard=self.dashboard).count() == 0 |
| 4039 | + |
| 4040 | + def test_put_snapshot_contains_pre_save_state(self) -> None: |
| 4041 | + with self.feature("organizations:dashboards-revisions"): |
| 4042 | + self.do_request("put", self.url(self.dashboard.id), data={"title": "New Title"}) |
| 4043 | + |
| 4044 | + revision = DashboardRevision.objects.get(dashboard=self.dashboard) |
| 4045 | + # Snapshot reflects the state before the update |
| 4046 | + assert revision.snapshot["title"] == self.dashboard.title |
| 4047 | + assert revision.title == self.dashboard.title |
| 4048 | + # The dashboard itself was updated |
| 4049 | + self.dashboard.refresh_from_db() |
| 4050 | + assert self.dashboard.title == "New Title" |
| 4051 | + |
| 4052 | + def test_put_deletes_revisions_beyond_retention_limit(self) -> None: |
| 4053 | + # Create 10 existing revisions |
| 4054 | + for i in range(10): |
| 4055 | + DashboardRevision.objects.create( |
| 4056 | + dashboard=self.dashboard, |
| 4057 | + created_by_id=self.user.id, |
| 4058 | + title=f"Revision {i}", |
| 4059 | + snapshot={}, |
| 4060 | + snapshot_schema_version=1, |
| 4061 | + ) |
| 4062 | + |
| 4063 | + assert DashboardRevision.objects.filter(dashboard=self.dashboard).count() == 10 |
| 4064 | + |
| 4065 | + with self.feature("organizations:dashboards-revisions"): |
| 4066 | + response = self.do_request( |
| 4067 | + "put", self.url(self.dashboard.id), data={"title": "Updated Title"} |
| 4068 | + ) |
| 4069 | + assert response.status_code == 200, response.data |
| 4070 | + |
| 4071 | + # After creating the 11th revision, the oldest should be deleted to maintain 10 |
| 4072 | + assert DashboardRevision.objects.filter(dashboard=self.dashboard).count() == 10 |
| 4073 | + |
| 4074 | + def test_put_snapshot_includes_widgets_and_queries(self) -> None: |
| 4075 | + with self.feature("organizations:dashboards-revisions"): |
| 4076 | + self.do_request("put", self.url(self.dashboard.id), data={"title": "New Title"}) |
| 4077 | + |
| 4078 | + revision = DashboardRevision.objects.get(dashboard=self.dashboard) |
| 4079 | + snapshot_widgets = revision.snapshot["widgets"] |
| 4080 | + |
| 4081 | + assert len(snapshot_widgets) == 4 |
| 4082 | + assert snapshot_widgets[0]["id"] == str(self.widget_1.id) |
| 4083 | + assert snapshot_widgets[0]["title"] == self.widget_1.title |
| 4084 | + assert len(snapshot_widgets[0]["queries"]) == 2 |
| 4085 | + assert snapshot_widgets[1]["id"] == str(self.widget_2.id) |
| 4086 | + assert snapshot_widgets[1]["title"] == self.widget_2.title |
| 4087 | + assert len(snapshot_widgets[1]["queries"]) == 1 |
| 4088 | + assert snapshot_widgets[2]["id"] == str(self.widget_3.id) |
| 4089 | + assert snapshot_widgets[3]["id"] == str(self.widget_4.id) |
| 4090 | + |
| 4091 | + def test_put_snapshot_captures_widget_state_before_widget_edit(self) -> None: |
| 4092 | + original_widget_title = self.widget_1.title |
| 4093 | + with self.feature("organizations:dashboards-revisions"): |
| 4094 | + self.do_request( |
| 4095 | + "put", |
| 4096 | + self.url(self.dashboard.id), |
| 4097 | + data={ |
| 4098 | + "title": self.dashboard.title, |
| 4099 | + "widgets": [ |
| 4100 | + {"id": str(self.widget_1.id), "title": "Updated Widget Title"}, |
| 4101 | + {"id": str(self.widget_2.id)}, |
| 4102 | + {"id": str(self.widget_3.id)}, |
| 4103 | + {"id": str(self.widget_4.id)}, |
| 4104 | + ], |
| 4105 | + }, |
| 4106 | + ) |
| 4107 | + |
| 4108 | + revision = DashboardRevision.objects.get(dashboard=self.dashboard) |
| 4109 | + snapshot_widget = revision.snapshot["widgets"][0] |
| 4110 | + # Snapshot reflects the widget state before the edit |
| 4111 | + assert snapshot_widget["id"] == str(self.widget_1.id) |
| 4112 | + assert snapshot_widget["title"] == original_widget_title |
| 4113 | + # The widget itself was updated |
| 4114 | + self.widget_1.refresh_from_db() |
| 4115 | + assert self.widget_1.title == "Updated Widget Title" |
| 4116 | + |
| 4117 | + def test_put_does_not_create_revision_for_prebuilt_tombstone(self) -> None: |
| 4118 | + with self.feature("organizations:dashboards-revisions"): |
| 4119 | + response = self.do_request( |
| 4120 | + "put", |
| 4121 | + self.url("default-overview"), |
| 4122 | + data={"title": "default-overview"}, |
| 4123 | + ) |
| 4124 | + assert response.status_code == 200, response.data |
| 4125 | + # No revision should be created for a pre-built dashboard that hasn't been saved yet |
| 4126 | + assert DashboardRevision.objects.count() == 0 |
| 4127 | + |
4015 | 4128 |
|
4016 | 4129 | class OrganizationDashboardDetailsOnDemandTest(OrganizationDashboardDetailsTestCase): |
4017 | 4130 | widget_type = DashboardWidgetTypes.TRANSACTION_LIKE |
|
0 commit comments