1+ import asyncio
12import os
23from unittest import mock
34
45os .environ .setdefault ("GITLAB__URL" , "https://gitlab.example.com" )
5- import pr_agent .servers .gitlab_webhook as gitlab_webhook
6+ import pr_agent .servers .gitlab_webhook as gitlab_webhook # noqa: E402
67
78
89class TestIsBotAssignedAsReviewer :
910 BOT_ID = 516
1011
11- @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , return_value = BOT_ID )
12- def test_detects_new_assignment (self , _mock_bot_id ):
12+ @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , new_callable = mock .AsyncMock )
13+ def test_detects_new_assignment (self , mock_bot_id ):
14+ mock_bot_id .return_value = self .BOT_ID
1315 data = {
1416 "changes" : {
1517 "reviewers" : {
@@ -18,10 +20,11 @@ def test_detects_new_assignment(self, _mock_bot_id):
1820 }
1921 }
2022 }
21- assert gitlab_webhook .is_bot_assigned_as_reviewer (data ) is True
23+ assert asyncio . run ( gitlab_webhook .is_bot_assigned_as_reviewer (data ) ) is True
2224
23- @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , return_value = BOT_ID )
24- def test_ignores_already_assigned (self , _mock_bot_id ):
25+ @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , new_callable = mock .AsyncMock )
26+ def test_ignores_already_assigned (self , mock_bot_id ):
27+ mock_bot_id .return_value = self .BOT_ID
2528 data = {
2629 "changes" : {
2730 "reviewers" : {
@@ -30,28 +33,31 @@ def test_ignores_already_assigned(self, _mock_bot_id):
3033 }
3134 }
3235 }
33- assert gitlab_webhook .is_bot_assigned_as_reviewer (data ) is False
36+ assert asyncio . run ( gitlab_webhook .is_bot_assigned_as_reviewer (data ) ) is False
3437
35- @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , return_value = BOT_ID )
36- def test_no_reviewers_key (self , _mock_bot_id ):
38+ @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , new_callable = mock .AsyncMock )
39+ def test_no_reviewers_key (self , mock_bot_id ):
40+ mock_bot_id .return_value = self .BOT_ID
3741 data = {"changes" : {"updated_at" : {"previous" : "old" , "current" : "new" }}}
38- assert gitlab_webhook .is_bot_assigned_as_reviewer (data ) is False
42+ assert asyncio . run ( gitlab_webhook .is_bot_assigned_as_reviewer (data ) ) is False
3943
4044 def test_changes_not_dict (self ):
4145 data = {"changes" : "not-a-dict" }
42- assert gitlab_webhook .is_bot_assigned_as_reviewer (data ) is False
46+ assert asyncio . run ( gitlab_webhook .is_bot_assigned_as_reviewer (data ) ) is False
4347
44- @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , return_value = BOT_ID )
45- def test_reviewers_not_dict (self , _mock_bot_id ):
48+ @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , new_callable = mock .AsyncMock )
49+ def test_reviewers_not_dict (self , mock_bot_id ):
50+ mock_bot_id .return_value = self .BOT_ID
4651 data = {"changes" : {"reviewers" : "not-a-dict" }}
47- assert gitlab_webhook .is_bot_assigned_as_reviewer (data ) is False
52+ assert asyncio . run ( gitlab_webhook .is_bot_assigned_as_reviewer (data ) ) is False
4853
4954 def test_no_changes_key (self ):
5055 data = {"object_kind" : "merge_request" }
51- assert gitlab_webhook .is_bot_assigned_as_reviewer (data ) is False
56+ assert asyncio . run ( gitlab_webhook .is_bot_assigned_as_reviewer (data ) ) is False
5257
53- @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , return_value = None )
54- def test_bot_id_unresolvable (self , _mock_bot_id ):
58+ @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , new_callable = mock .AsyncMock )
59+ def test_bot_id_unresolvable (self , mock_bot_id ):
60+ mock_bot_id .return_value = None
5561 data = {
5662 "changes" : {
5763 "reviewers" : {
@@ -60,10 +66,11 @@ def test_bot_id_unresolvable(self, _mock_bot_id):
6066 }
6167 }
6268 }
63- assert gitlab_webhook .is_bot_assigned_as_reviewer (data ) is False
69+ assert asyncio . run ( gitlab_webhook .is_bot_assigned_as_reviewer (data ) ) is False
6470
65- @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , return_value = BOT_ID )
66- def test_previous_with_non_dict_entries (self , _mock_bot_id ):
71+ @mock .patch .object (gitlab_webhook , "_get_bot_user_id" , new_callable = mock .AsyncMock )
72+ def test_previous_with_non_dict_entries (self , mock_bot_id ):
73+ mock_bot_id .return_value = self .BOT_ID
6774 data = {
6875 "changes" : {
6976 "reviewers" : {
@@ -72,50 +79,53 @@ def test_previous_with_non_dict_entries(self, _mock_bot_id):
7279 }
7380 }
7481 }
75- assert gitlab_webhook .is_bot_assigned_as_reviewer (data ) is True
82+ assert asyncio . run ( gitlab_webhook .is_bot_assigned_as_reviewer (data ) ) is True
7683
7784
7885class TestGetBotUserId :
86+ @staticmethod
87+ def _make_fake_gitlab (user_id ):
88+ fake = mock .MagicMock ()
89+ fake .Gitlab .return_value .auth .return_value = None
90+ fake .Gitlab .return_value .user .id = user_id
91+ return fake
92+
93+ @staticmethod
94+ def _make_settings (url , token ):
95+ s = mock .MagicMock ()
96+ s .get .side_effect = lambda k , d = None : {
97+ "GITLAB.URL" : url ,
98+ "GITLAB.PERSONAL_ACCESS_TOKEN" : token ,
99+ "GITLAB.SSL_VERIFY" : True ,
100+ "GITLAB.AUTH_TYPE" : "oauth_token" ,
101+ }.get (k , d )
102+ return s
103+
79104 def test_caches_by_credential (self , monkeypatch ):
80105 gitlab_webhook ._bot_user_id_cache .clear ()
81106
82- from unittest .mock import MagicMock
83-
84- def make_settings (url , token ):
85- s = MagicMock ()
86- s .get .side_effect = lambda k , d = None : {"GITLAB.URL" : url , "GITLAB.PERSONAL_ACCESS_TOKEN" : token , "GITLAB.SSL_VERIFY" : True , "GITLAB.AUTH_TYPE" : "oauth_token" }.get (k , d )
87- return s
88-
89- gl_mock = MagicMock ()
90- gl_mock .user .id = 111
91- mock_gitlab_cls = MagicMock (return_value = gl_mock )
107+ with mock .patch ("pr_agent.servers.gitlab_webhook.get_settings" ,
108+ return_value = self ._make_settings ("https://a.example.com" , "token-a" )):
109+ with mock .patch .dict ("sys.modules" , {"gitlab" : self ._make_fake_gitlab (111 )}):
110+ assert asyncio .run (gitlab_webhook ._get_bot_user_id ()) == 111
92111
93- with mock .patch ("pr_agent.servers.gitlab_webhook.get_settings" , return_value = make_settings ("https://a.example.com" , "token-a" )):
94- with mock .patch ("pr_agent.servers.gitlab_webhook.gitlab.Gitlab" , mock_gitlab_cls ):
95- assert gitlab_webhook ._get_bot_user_id () == 111
96-
97- gl_mock .user .id = 222
98- with mock .patch ("pr_agent.servers.gitlab_webhook.get_settings" , return_value = make_settings ("https://a.example.com" , "token-b" )):
99- with mock .patch ("pr_agent.servers.gitlab_webhook.gitlab.Gitlab" , mock_gitlab_cls ):
100- assert gitlab_webhook ._get_bot_user_id () == 222
112+ with mock .patch ("pr_agent.servers.gitlab_webhook.get_settings" ,
113+ return_value = self ._make_settings ("https://a.example.com" , "token-b" )):
114+ with mock .patch .dict ("sys.modules" , {"gitlab" : self ._make_fake_gitlab (222 )}):
115+ assert asyncio .run (gitlab_webhook ._get_bot_user_id ()) == 222
101116
102117 assert len (gitlab_webhook ._bot_user_id_cache ) >= 2
103118
104119 def test_negative_cache_on_failure (self , monkeypatch ):
105120 gitlab_webhook ._bot_user_id_cache .clear ()
106121
107- from unittest .mock import MagicMock
108-
109- def make_settings ():
110- s = MagicMock ()
111- s .get .side_effect = lambda k , d = None : {"GITLAB.URL" : "https://x.example.com" , "GITLAB.PERSONAL_ACCESS_TOKEN" : "fail-token" , "GITLAB.SSL_VERIFY" : True , "GITLAB.AUTH_TYPE" : "oauth_token" }.get (k , d )
112- return s
122+ fake = self ._make_fake_gitlab (0 )
123+ fake .Gitlab .side_effect = RuntimeError ("auth failed" )
113124
114- mock_gitlab_cls = MagicMock (side_effect = RuntimeError ("auth failed" ))
115-
116- with mock .patch ("pr_agent.servers.gitlab_webhook.get_settings" , return_value = make_settings ()):
117- with mock .patch ("pr_agent.servers.gitlab_webhook.gitlab.Gitlab" , mock_gitlab_cls ):
118- assert gitlab_webhook ._get_bot_user_id () is None
125+ with mock .patch ("pr_agent.servers.gitlab_webhook.get_settings" ,
126+ return_value = self ._make_settings ("https://x.example.com" , "fail-token" )):
127+ with mock .patch .dict ("sys.modules" , {"gitlab" : fake }):
128+ assert asyncio .run (gitlab_webhook ._get_bot_user_id ()) is None
119129
120130 assert len (gitlab_webhook ._bot_user_id_cache ) == 1
121131 cached_val = next (iter (gitlab_webhook ._bot_user_id_cache .values ()))
@@ -124,32 +134,34 @@ def make_settings():
124134 def test_respects_auth_type_private_token (self ):
125135 gitlab_webhook ._bot_user_id_cache .clear ()
126136
127- from unittest .mock import MagicMock
128-
129- def make_settings ():
130- s = MagicMock ()
131- s .get .side_effect = lambda k , d = None : {"GITLAB.URL" : "https://x.example.com" , "GITLAB.PERSONAL_ACCESS_TOKEN" : "tok" , "GITLAB.SSL_VERIFY" : True , "GITLAB.AUTH_TYPE" : "private_token" }.get (k , d )
132- return s
137+ s = mock .MagicMock ()
138+ s .get .side_effect = lambda k , d = None : {
139+ "GITLAB.URL" : "https://x.example.com" ,
140+ "GITLAB.PERSONAL_ACCESS_TOKEN" : "tok" ,
141+ "GITLAB.SSL_VERIFY" : True ,
142+ "GITLAB.AUTH_TYPE" : "private_token" ,
143+ }.get (k , d )
133144
134- gl_mock = MagicMock ()
135- gl_mock .user .id = 99
136- mock_gitlab_cls = MagicMock (return_value = gl_mock )
145+ fake_gitlab = self ._make_fake_gitlab (99 )
137146
138- with mock .patch ("pr_agent.servers.gitlab_webhook.get_settings" , return_value = make_settings () ):
139- with mock .patch ( "pr_agent.servers.gitlab_webhook.gitlab.Gitlab " , mock_gitlab_cls ):
140- assert gitlab_webhook ._get_bot_user_id () == 99
147+ with mock .patch ("pr_agent.servers.gitlab_webhook.get_settings" , return_value = s ):
148+ with mock .patch . dict ( "sys.modules " , { "gitlab" : fake_gitlab } ):
149+ assert asyncio . run ( gitlab_webhook ._get_bot_user_id () ) == 99
141150
142- call_kwargs = mock_gitlab_cls .call_args .kwargs
151+ call_kwargs = fake_gitlab . Gitlab .call_args .kwargs
143152 assert "private_token" in call_kwargs
144153 assert call_kwargs ["private_token" ] == "tok"
145154
146155 def test_no_token_returns_none (self , monkeypatch ):
147156 gitlab_webhook ._bot_user_id_cache .clear ()
148157
149- from unittest .mock import MagicMock
150-
151- s = MagicMock ()
152- s .get .side_effect = lambda k , d = None : {"GITLAB.URL" : "https://x.example.com" , "GITLAB.PERSONAL_ACCESS_TOKEN" : None , "GITLAB.SSL_VERIFY" : True , "GITLAB.AUTH_TYPE" : "oauth_token" }.get (k , d )
158+ s = mock .MagicMock ()
159+ s .get .side_effect = lambda k , d = None : {
160+ "GITLAB.URL" : "https://x.example.com" ,
161+ "GITLAB.PERSONAL_ACCESS_TOKEN" : None ,
162+ "GITLAB.SSL_VERIFY" : True ,
163+ "GITLAB.AUTH_TYPE" : "oauth_token" ,
164+ }.get (k , d )
153165
154166 with mock .patch ("pr_agent.servers.gitlab_webhook.get_settings" , return_value = s ):
155- assert gitlab_webhook ._get_bot_user_id () is None
167+ assert asyncio . run ( gitlab_webhook ._get_bot_user_id () ) is None
0 commit comments