|
11 | 11 | from sentry.models.commitcomparison import CommitComparison |
12 | 12 | from sentry.models.repository import Repository |
13 | 13 | from sentry.preprod.models import PreprodArtifact, PreprodArtifactSizeMetrics |
14 | | -from sentry.preprod.vcs.status_checks.size.tasks import create_preprod_status_check_task |
| 14 | +from sentry.preprod.vcs.status_checks.size.tasks import ( |
| 15 | + StatusCheckErrorType, |
| 16 | + create_preprod_status_check_task, |
| 17 | +) |
15 | 18 | from sentry.shared_integrations.exceptions import IntegrationConfigurationError |
16 | 19 | from sentry.testutils.cases import TestCase |
17 | 20 | from sentry.testutils.silo import region_silo_test |
@@ -988,3 +991,165 @@ def test_sibling_deduplication_with_same_app_id_different_platforms(self): |
988 | 991 | assert ( |
989 | 992 | ios_artifact.id not in sibling_ids_from_ios_new |
990 | 993 | ), "Old iOS artifact should be deduplicated (not the triggering artifact)" |
| 994 | + |
| 995 | + def test_posted_status_check_success(self): |
| 996 | + """Test that successful status check posts are recorded in artifact extras.""" |
| 997 | + preprod_artifact = self._create_preprod_artifact( |
| 998 | + state=PreprodArtifact.ArtifactState.PROCESSED |
| 999 | + ) |
| 1000 | + |
| 1001 | + PreprodArtifactSizeMetrics.objects.create( |
| 1002 | + preprod_artifact=preprod_artifact, |
| 1003 | + metrics_artifact_type=PreprodArtifactSizeMetrics.MetricsArtifactType.MAIN_ARTIFACT, |
| 1004 | + state=PreprodArtifactSizeMetrics.SizeAnalysisState.COMPLETED, |
| 1005 | + min_download_size=1024 * 1024, |
| 1006 | + max_download_size=1024 * 1024, |
| 1007 | + min_install_size=2 * 1024 * 1024, |
| 1008 | + max_install_size=2 * 1024 * 1024, |
| 1009 | + ) |
| 1010 | + |
| 1011 | + _, mock_provider, client_patch, provider_patch = self._create_working_status_check_setup( |
| 1012 | + preprod_artifact |
| 1013 | + ) |
| 1014 | + mock_provider.create_status_check.return_value = "check_12345" |
| 1015 | + |
| 1016 | + with client_patch, provider_patch: |
| 1017 | + with self.tasks(): |
| 1018 | + create_preprod_status_check_task(preprod_artifact.id) |
| 1019 | + |
| 1020 | + preprod_artifact.refresh_from_db() |
| 1021 | + assert preprod_artifact.extras is not None |
| 1022 | + assert "posted_status_checks" in preprod_artifact.extras |
| 1023 | + assert "size" in preprod_artifact.extras["posted_status_checks"] |
| 1024 | + assert preprod_artifact.extras["posted_status_checks"]["size"]["success"] is True |
| 1025 | + assert preprod_artifact.extras["posted_status_checks"]["size"]["check_id"] == "check_12345" |
| 1026 | + |
| 1027 | + def test_posted_status_check_failure_null_check_id(self): |
| 1028 | + """Test that failed status check posts (null check_id) are recorded in artifact extras.""" |
| 1029 | + preprod_artifact = self._create_preprod_artifact( |
| 1030 | + state=PreprodArtifact.ArtifactState.PROCESSED |
| 1031 | + ) |
| 1032 | + |
| 1033 | + PreprodArtifactSizeMetrics.objects.create( |
| 1034 | + preprod_artifact=preprod_artifact, |
| 1035 | + metrics_artifact_type=PreprodArtifactSizeMetrics.MetricsArtifactType.MAIN_ARTIFACT, |
| 1036 | + state=PreprodArtifactSizeMetrics.SizeAnalysisState.COMPLETED, |
| 1037 | + min_download_size=1024 * 1024, |
| 1038 | + max_download_size=1024 * 1024, |
| 1039 | + min_install_size=2 * 1024 * 1024, |
| 1040 | + max_install_size=2 * 1024 * 1024, |
| 1041 | + ) |
| 1042 | + |
| 1043 | + _, mock_provider, client_patch, provider_patch = self._create_working_status_check_setup( |
| 1044 | + preprod_artifact |
| 1045 | + ) |
| 1046 | + mock_provider.create_status_check.return_value = None # Simulate API returning no check_id |
| 1047 | + |
| 1048 | + with client_patch, provider_patch: |
| 1049 | + with self.tasks(): |
| 1050 | + create_preprod_status_check_task(preprod_artifact.id) |
| 1051 | + |
| 1052 | + preprod_artifact.refresh_from_db() |
| 1053 | + assert preprod_artifact.extras is not None |
| 1054 | + assert "posted_status_checks" in preprod_artifact.extras |
| 1055 | + assert "size" in preprod_artifact.extras["posted_status_checks"] |
| 1056 | + assert preprod_artifact.extras["posted_status_checks"]["size"]["success"] is False |
| 1057 | + assert ( |
| 1058 | + preprod_artifact.extras["posted_status_checks"]["size"]["error_type"] |
| 1059 | + == StatusCheckErrorType.UNKNOWN.value |
| 1060 | + ) |
| 1061 | + |
| 1062 | + @responses.activate |
| 1063 | + def test_posted_status_check_failure_integration_error(self): |
| 1064 | + """Test that integration errors during status check creation are recorded in artifact extras.""" |
| 1065 | + preprod_artifact = self._create_preprod_artifact( |
| 1066 | + state=PreprodArtifact.ArtifactState.PROCESSED |
| 1067 | + ) |
| 1068 | + |
| 1069 | + PreprodArtifactSizeMetrics.objects.create( |
| 1070 | + preprod_artifact=preprod_artifact, |
| 1071 | + metrics_artifact_type=PreprodArtifactSizeMetrics.MetricsArtifactType.MAIN_ARTIFACT, |
| 1072 | + state=PreprodArtifactSizeMetrics.SizeAnalysisState.COMPLETED, |
| 1073 | + min_download_size=1024 * 1024, |
| 1074 | + max_download_size=1024 * 1024, |
| 1075 | + min_install_size=2 * 1024 * 1024, |
| 1076 | + max_install_size=2 * 1024 * 1024, |
| 1077 | + ) |
| 1078 | + |
| 1079 | + integration = self.create_integration( |
| 1080 | + organization=self.organization, |
| 1081 | + external_id="test-integration-error", |
| 1082 | + provider="github", |
| 1083 | + metadata={"access_token": "test_token", "expires_at": "2099-01-01T00:00:00Z"}, |
| 1084 | + ) |
| 1085 | + |
| 1086 | + Repository.objects.create( |
| 1087 | + organization_id=self.organization.id, |
| 1088 | + name="owner/repo", |
| 1089 | + provider="integrations:github", |
| 1090 | + integration_id=integration.id, |
| 1091 | + ) |
| 1092 | + |
| 1093 | + responses.add( |
| 1094 | + responses.POST, |
| 1095 | + "https://api.github.com/repos/owner/repo/check-runs", |
| 1096 | + status=403, |
| 1097 | + json={ |
| 1098 | + "message": "Resource not accessible by integration", |
| 1099 | + "documentation_url": "https://docs.github.com/rest/checks/runs#create-a-check-run", |
| 1100 | + }, |
| 1101 | + ) |
| 1102 | + |
| 1103 | + with self.tasks(): |
| 1104 | + try: |
| 1105 | + create_preprod_status_check_task(preprod_artifact.id) |
| 1106 | + except IntegrationConfigurationError: |
| 1107 | + pass # Expected |
| 1108 | + |
| 1109 | + preprod_artifact.refresh_from_db() |
| 1110 | + assert preprod_artifact.extras is not None |
| 1111 | + assert "posted_status_checks" in preprod_artifact.extras |
| 1112 | + assert "size" in preprod_artifact.extras["posted_status_checks"] |
| 1113 | + assert preprod_artifact.extras["posted_status_checks"]["size"]["success"] is False |
| 1114 | + assert ( |
| 1115 | + preprod_artifact.extras["posted_status_checks"]["size"]["error_type"] |
| 1116 | + == StatusCheckErrorType.INTEGRATION_ERROR.value |
| 1117 | + ) |
| 1118 | + |
| 1119 | + def test_posted_status_check_preserves_existing_extras(self): |
| 1120 | + """Test that recording status check result preserves other fields in extras.""" |
| 1121 | + preprod_artifact = self._create_preprod_artifact( |
| 1122 | + state=PreprodArtifact.ArtifactState.PROCESSED |
| 1123 | + ) |
| 1124 | + preprod_artifact.extras = {"existing_field": "existing_value", "another_field": 123} |
| 1125 | + preprod_artifact.save() |
| 1126 | + |
| 1127 | + PreprodArtifactSizeMetrics.objects.create( |
| 1128 | + preprod_artifact=preprod_artifact, |
| 1129 | + metrics_artifact_type=PreprodArtifactSizeMetrics.MetricsArtifactType.MAIN_ARTIFACT, |
| 1130 | + state=PreprodArtifactSizeMetrics.SizeAnalysisState.COMPLETED, |
| 1131 | + min_download_size=1024 * 1024, |
| 1132 | + max_download_size=1024 * 1024, |
| 1133 | + min_install_size=2 * 1024 * 1024, |
| 1134 | + max_install_size=2 * 1024 * 1024, |
| 1135 | + ) |
| 1136 | + |
| 1137 | + _, mock_provider, client_patch, provider_patch = self._create_working_status_check_setup( |
| 1138 | + preprod_artifact |
| 1139 | + ) |
| 1140 | + mock_provider.create_status_check.return_value = "check_67890" |
| 1141 | + |
| 1142 | + with client_patch, provider_patch: |
| 1143 | + with self.tasks(): |
| 1144 | + create_preprod_status_check_task(preprod_artifact.id) |
| 1145 | + |
| 1146 | + preprod_artifact.refresh_from_db() |
| 1147 | + assert preprod_artifact.extras is not None |
| 1148 | + # Verify existing fields are preserved |
| 1149 | + assert preprod_artifact.extras["existing_field"] == "existing_value" |
| 1150 | + assert preprod_artifact.extras["another_field"] == 123 |
| 1151 | + # Verify new field is added |
| 1152 | + assert "posted_status_checks" in preprod_artifact.extras |
| 1153 | + assert "size" in preprod_artifact.extras["posted_status_checks"] |
| 1154 | + assert preprod_artifact.extras["posted_status_checks"]["size"]["success"] is True |
| 1155 | + assert preprod_artifact.extras["posted_status_checks"]["size"]["check_id"] == "check_67890" |
0 commit comments