77from sentry .constants import ObjectStatus
88from sentry .integrations .github .integration import GitHubIntegrationProvider
99from sentry .integrations .github .tasks .link_all_repos import link_all_repos
10+ from sentry .integrations .source_code_management .metrics import LinkAllReposHaltReason
11+ from sentry .integrations .types import EventLifecycleOutcome
1012from sentry .models .repository import Repository
1113from sentry .shared_integrations .exceptions import ApiError
1214from sentry .silo .base import SiloMode
1315from sentry .testutils .cases import IntegrationTestCase
1416from sentry .testutils .silo import assume_test_silo_mode , control_silo_test
17+ from tests .sentry .integrations .utils .test_assert_metrics import (
18+ assert_failure_metric ,
19+ assert_halt_metric ,
20+ )
1521
1622
1723@control_silo_test
@@ -41,8 +47,9 @@ def _add_responses(self):
4147 },
4248 )
4349
50+ @patch ("sentry.integrations.utils.metrics.EventLifecycle.record_event" )
4451 @patch ("sentry.integrations.github.tasks.link_all_repos.metrics" )
45- def test_link_all_repos_inactive_integration (self , mock_metrics , _ ):
52+ def test_link_all_repos_inactive_integration (self , mock_metrics , mock_record , _ ):
4653 self .integration .update (status = ObjectStatus .DISABLED )
4754
4855 link_all_repos (
@@ -55,8 +62,14 @@ def test_link_all_repos_inactive_integration(self, mock_metrics, _):
5562 "github.link_all_repos.error" , tags = {"type" : "missing_integration" }
5663 )
5764
65+ start , halt = mock_record .mock_calls
66+ assert start .args [0 ] == EventLifecycleOutcome .STARTED
67+ assert halt .args [0 ] == EventLifecycleOutcome .FAILURE
68+ assert_failure_metric (mock_record , LinkAllReposHaltReason .MISSING_INTEGRATION .value )
69+
5870 @responses .activate
59- def test_link_all_repos (self , _ ):
71+ @patch ("sentry.integrations.utils.metrics.EventLifecycle.record_event" )
72+ def test_link_all_repos (self , mock_record , _ ):
6073 self ._add_responses ()
6174
6275 link_all_repos (
@@ -76,8 +89,13 @@ def test_link_all_repos(self, _):
7689 assert repos [0 ].name == "getsentry/sentry"
7790 assert repos [1 ].name == "getsentry/snuba"
7891
92+ start , halt = mock_record .mock_calls
93+ assert start .args [0 ] == EventLifecycleOutcome .STARTED
94+ assert halt .args [0 ] == EventLifecycleOutcome .SUCCESS
95+
7996 @responses .activate
80- def test_link_all_repos_api_response_keyerror (self , _ ):
97+ @patch ("sentry.integrations.utils.metrics.EventLifecycle.record_event" )
98+ def test_link_all_repos_api_response_keyerror (self , mock_record , _ ):
8199
82100 responses .add (
83101 responses .GET ,
@@ -112,8 +130,48 @@ def test_link_all_repos_api_response_keyerror(self, _):
112130
113131 assert repos [0 ].name == "getsentry/snuba"
114132
133+ start , halt = mock_record .mock_calls
134+ assert start .args [0 ] == EventLifecycleOutcome .STARTED
135+ assert halt .args [0 ] == EventLifecycleOutcome .SUCCESS
136+
137+ @responses .activate
138+ @patch ("sentry.integrations.utils.metrics.EventLifecycle.record_event" )
139+ def test_link_all_repos_api_response_keyerror_single_repo (self , mock_record , _ ):
140+
141+ responses .add (
142+ responses .GET ,
143+ self .base_url + "/installation/repositories?per_page=100" ,
144+ status = 200 ,
145+ json = {
146+ "total_count" : 2 ,
147+ "repositories" : [
148+ {
149+ "full_name" : "getsentry/sentry" ,
150+ },
151+ ],
152+ },
153+ )
154+
155+ link_all_repos (
156+ integration_key = self .key ,
157+ integration_id = self .integration .id ,
158+ organization_id = self .organization .id ,
159+ )
160+
161+ with assume_test_silo_mode (SiloMode .REGION ):
162+ repos = Repository .objects .all ()
163+ assert len (repos ) == 0
164+
165+ start , halt = mock_record .mock_calls
166+
167+ start , halt = mock_record .mock_calls
168+ assert start .args [0 ] == EventLifecycleOutcome .STARTED
169+ assert halt .args [0 ] == EventLifecycleOutcome .HALTED
170+ assert_halt_metric (mock_record , LinkAllReposHaltReason .REPOSITORY_NOT_CREATED .value )
171+
172+ @patch ("sentry.integrations.utils.metrics.EventLifecycle.record_event" )
115173 @patch ("sentry.integrations.github.tasks.link_all_repos.metrics" )
116- def test_link_all_repos_missing_integration (self , mock_metrics , _ ):
174+ def test_link_all_repos_missing_integration (self , mock_metrics , mock_record , _ ):
117175 link_all_repos (
118176 integration_key = self .key ,
119177 integration_id = 0 ,
@@ -123,8 +181,14 @@ def test_link_all_repos_missing_integration(self, mock_metrics, _):
123181 "github.link_all_repos.error" , tags = {"type" : "missing_integration" }
124182 )
125183
184+ start , halt = mock_record .mock_calls
185+ assert start .args [0 ] == EventLifecycleOutcome .STARTED
186+ assert halt .args [0 ] == EventLifecycleOutcome .FAILURE
187+ assert_failure_metric (mock_record , LinkAllReposHaltReason .MISSING_INTEGRATION .value )
188+
189+ @patch ("sentry.integrations.utils.metrics.EventLifecycle.record_event" )
126190 @patch ("sentry.integrations.github.tasks.link_all_repos.metrics" )
127- def test_link_all_repos_missing_organization (self , mock_metrics , _ ):
191+ def test_link_all_repos_missing_organization (self , mock_metrics , mock_record , _ ):
128192 link_all_repos (
129193 integration_key = self .key ,
130194 integration_id = self .integration .id ,
@@ -134,9 +198,15 @@ def test_link_all_repos_missing_organization(self, mock_metrics, _):
134198 "github.link_all_repos.error" , tags = {"type" : "missing_organization" }
135199 )
136200
201+ start , halt = mock_record .mock_calls
202+ assert start .args [0 ] == EventLifecycleOutcome .STARTED
203+ assert halt .args [0 ] == EventLifecycleOutcome .FAILURE
204+ assert_failure_metric (mock_record , LinkAllReposHaltReason .MISSING_ORGANIZATION .value )
205+
206+ @patch ("sentry.integrations.utils.metrics.EventLifecycle.record_event" )
137207 @patch ("sentry.integrations.github.tasks.link_all_repos.metrics" )
138208 @responses .activate
139- def test_link_all_repos_api_error (self , mock_metrics , _ ):
209+ def test_link_all_repos_api_error (self , mock_metrics , mock_record , _ ):
140210
141211 responses .add (
142212 responses .GET ,
@@ -150,11 +220,16 @@ def test_link_all_repos_api_error(self, mock_metrics, _):
150220 integration_id = self .integration .id ,
151221 organization_id = self .organization .id ,
152222 )
153- mock_metrics .incr .assert_called_with ("github.link_all_repos.api_error" )
223+ mock_metrics .incr .assert_called_with ("github.link_all_repos.api_error" )
154224
225+ start , halt = mock_record .mock_calls
226+ assert start .args [0 ] == EventLifecycleOutcome .STARTED
227+ assert halt .args [0 ] == EventLifecycleOutcome .FAILURE
228+
229+ @patch ("sentry.integrations.utils.metrics.EventLifecycle.record_event" )
155230 @patch ("sentry.integrations.github.integration.metrics" )
156231 @responses .activate
157- def test_link_all_repos_api_error_rate_limited (self , mock_metrics , _ ):
232+ def test_link_all_repos_api_error_rate_limited (self , mock_metrics , mock_record , _ ):
158233
159234 responses .add (
160235 responses .GET ,
@@ -173,10 +248,16 @@ def test_link_all_repos_api_error_rate_limited(self, mock_metrics, _):
173248 )
174249 mock_metrics .incr .assert_called_with ("github.link_all_repos.rate_limited_error" )
175250
251+ start , halt = mock_record .mock_calls
252+ assert start .args [0 ] == EventLifecycleOutcome .STARTED
253+ assert halt .args [0 ] == EventLifecycleOutcome .HALTED
254+ assert_halt_metric (mock_record , LinkAllReposHaltReason .RATE_LIMITED .value )
255+
256+ @patch ("sentry.integrations.utils.metrics.EventLifecycle.record_event" )
176257 @patch ("sentry.models.Repository.objects.create" )
177258 @patch ("sentry.integrations.github.tasks.link_all_repos.metrics" )
178259 @responses .activate
179- def test_link_all_repos_repo_creation_error (self , mock_metrics , mock_repo , _ ):
260+ def test_link_all_repos_repo_creation_error (self , mock_metrics , mock_repo , mock_record , _ ):
180261 mock_repo .side_effect = IntegrityError
181262
182263 self ._add_responses ()
@@ -189,11 +270,17 @@ def test_link_all_repos_repo_creation_error(self, mock_metrics, mock_repo, _):
189270
190271 mock_metrics .incr .assert_called_with ("sentry.integration_repo_provider.repo_exists" )
191272
273+ start , halt = mock_record .mock_calls
274+ assert start .args [0 ] == EventLifecycleOutcome .STARTED
275+ assert halt .args [0 ] == EventLifecycleOutcome .HALTED
276+ assert_halt_metric (mock_record , LinkAllReposHaltReason .REPOSITORY_NOT_CREATED .value )
277+
278+ @patch ("sentry.integrations.utils.metrics.EventLifecycle.record_event" )
192279 @patch ("sentry.integrations.services.repository.repository_service.create_repository" )
193280 @patch ("sentry.plugins.providers.IntegrationRepositoryProvider.on_delete_repository" )
194281 @responses .activate
195282 def test_link_all_repos_repo_creation_exception (
196- self , mock_delete_repo , mock_create_repository , _
283+ self , mock_delete_repo , mock_create_repository , mock_record , _
197284 ):
198285 mock_create_repository .return_value = None
199286 mock_delete_repo .side_effect = Exception
@@ -206,3 +293,7 @@ def test_link_all_repos_repo_creation_exception(
206293 integration_id = self .integration .id ,
207294 organization_id = self .organization .id ,
208295 )
296+
297+ start , halt = mock_record .mock_calls
298+ assert start .args [0 ] == EventLifecycleOutcome .STARTED
299+ assert halt .args [0 ] == EventLifecycleOutcome .FAILURE
0 commit comments