4
4
from unittest .mock import patch , Mock , PropertyMock
5
5
from bson .objectid import ObjectId
6
6
7
- from todo .views .auth import (
8
- GoogleCallbackView ,
9
- )
10
-
11
- from todo .utils .google_jwt_utils import (
12
- generate_google_token_pair ,
13
- )
14
- from todo .constants .messages import AppMessages , AuthErrorMessages
7
+ from todo .views .auth import GoogleCallbackView
8
+ from todo .utils .google_jwt_utils import generate_google_token_pair
9
+ from todo .constants .messages import AppMessages
10
+ from todo .tests .fixtures .user import google_auth_user_payload , users_db_data
15
11
16
12
17
13
class GoogleLoginViewTests (APITestCase ):
@@ -21,7 +17,7 @@ def setUp(self):
21
17
self .url = reverse ("google_login" )
22
18
23
19
@patch ("todo.services.google_oauth_service.GoogleOAuthService.get_authorization_url" )
24
- def test_get_returns_redirect_url_for_html_request (self , mock_get_auth_url ):
20
+ def test_get_returns_redirect_for_html_request (self , mock_get_auth_url ):
25
21
mock_auth_url = "https://accounts.google.com/o/oauth2/auth"
26
22
mock_state = "test_state"
27
23
mock_get_auth_url .return_value = (mock_auth_url , mock_state )
@@ -41,12 +37,31 @@ def test_get_returns_json_for_json_request(self, mock_get_auth_url):
41
37
response = self .client .get (self .url , HTTP_ACCEPT = "application/json" )
42
38
43
39
self .assertEqual (response .status_code , status .HTTP_200_OK )
40
+ self .assertEqual (response .data ["statusCode" ], status .HTTP_200_OK )
41
+ self .assertEqual (response .data ["message" ], "Google OAuth URL generated successfully" )
44
42
self .assertEqual (response .data ["data" ]["authUrl" ], mock_auth_url )
45
43
self .assertEqual (response .data ["data" ]["state" ], mock_state )
46
44
mock_get_auth_url .assert_called_once_with (None )
47
45
48
46
@patch ("todo.services.google_oauth_service.GoogleOAuthService.get_authorization_url" )
49
- def test_get_with_redirect_url (self , mock_get_auth_url ):
47
+ def test_get_returns_json_with_format_parameter (self , mock_get_auth_url ):
48
+ """Test that format=json parameter returns JSON response"""
49
+ mock_auth_url = "https://accounts.google.com/o/oauth2/auth"
50
+ mock_state = "test_state"
51
+ mock_get_auth_url .return_value = (mock_auth_url , mock_state )
52
+
53
+ response = self .client .get (f"{ self .url } ?format=json" )
54
+
55
+ self .assertEqual (response .status_code , status .HTTP_200_OK )
56
+ self .assertEqual (response .data ["statusCode" ], status .HTTP_200_OK )
57
+ self .assertEqual (response .data ["message" ], "Google OAuth URL generated successfully" )
58
+ self .assertEqual (response .data ["data" ]["authUrl" ], mock_auth_url )
59
+ self .assertEqual (response .data ["data" ]["state" ], mock_state )
60
+ mock_get_auth_url .assert_called_once_with (None )
61
+
62
+ @patch ("todo.services.google_oauth_service.GoogleOAuthService.get_authorization_url" )
63
+ def test_get_with_redirect_url_html_request (self , mock_get_auth_url ):
64
+ """Test HTML request with redirect URL"""
50
65
mock_auth_url = "https://accounts.google.com/o/oauth2/auth"
51
66
mock_state = "test_state"
52
67
mock_get_auth_url .return_value = (mock_auth_url , mock_state )
@@ -58,6 +73,33 @@ def test_get_with_redirect_url(self, mock_get_auth_url):
58
73
self .assertEqual (response .url , mock_auth_url )
59
74
mock_get_auth_url .assert_called_once_with (redirect_url )
60
75
76
+ @patch ("todo.services.google_oauth_service.GoogleOAuthService.get_authorization_url" )
77
+ def test_get_with_redirect_url_json_request (self , mock_get_auth_url ):
78
+ """Test JSON request with redirect URL"""
79
+ mock_auth_url = "https://accounts.google.com/o/oauth2/auth"
80
+ mock_state = "test_state"
81
+ mock_get_auth_url .return_value = (mock_auth_url , mock_state )
82
+ redirect_url = "http://localhost:3000/callback"
83
+
84
+ response = self .client .get (f"{ self .url } ?redirectURL={ redirect_url } " , HTTP_ACCEPT = "application/json" )
85
+
86
+ self .assertEqual (response .status_code , status .HTTP_200_OK )
87
+ self .assertEqual (response .data ["data" ]["authUrl" ], mock_auth_url )
88
+ self .assertEqual (response .data ["data" ]["state" ], mock_state )
89
+ mock_get_auth_url .assert_called_once_with (redirect_url )
90
+
91
+ @patch ("todo.services.google_oauth_service.GoogleOAuthService.get_authorization_url" )
92
+ def test_stores_state_in_session (self , mock_get_auth_url ):
93
+ """Test that state is stored in session for both request types"""
94
+ mock_auth_url = "https://accounts.google.com/o/oauth2/auth"
95
+ mock_state = "test_state"
96
+ mock_get_auth_url .return_value = (mock_auth_url , mock_state )
97
+
98
+ response = self .client .get (self .url , HTTP_ACCEPT = "application/json" )
99
+
100
+ self .assertEqual (response .status_code , status .HTTP_200_OK )
101
+ self .assertEqual (self .client .session .get ("oauth_state" ), mock_state )
102
+
61
103
62
104
class GoogleCallbackViewTests (APITestCase ):
63
105
def setUp (self ):
@@ -66,6 +108,8 @@ def setUp(self):
66
108
self .url = reverse ("google_callback" )
67
109
self .factory = APIRequestFactory ()
68
110
self .view = GoogleCallbackView .as_view ()
111
+
112
+ self .test_user_data = users_db_data [0 ]
69
113
70
114
def test_get_redirects_for_oauth_error (self ):
71
115
error = "access_denied"
@@ -80,67 +124,37 @@ def test_get_redirects_for_missing_code(self):
80
124
self .assertEqual (response .status_code , status .HTTP_302_FOUND )
81
125
self .assertIn ("error=missing_code" , response .url )
82
126
83
- @patch ("todo.services.google_oauth_service.GoogleOAuthService.handle_callback" )
84
- @patch ("todo.services.user_service.UserService.create_or_update_user" )
85
- def test_get_redirects_for_valid_code_and_state (self , mock_create_user , mock_handle_callback ):
86
- mock_google_data = {
87
- "id" : "test_google_id" ,
88
-
89
- "name" : "Test User" ,
90
- }
91
- user_id = str (ObjectId ())
92
- mock_user = Mock ()
93
- mock_user .id = ObjectId (user_id )
94
- mock_user .google_id = mock_google_data ["id" ]
95
- mock_user .email_id = mock_google_data ["email" ]
96
- mock_user .name = mock_google_data ["name" ]
97
- type(mock_user ).id = PropertyMock (return_value = ObjectId (user_id ))
98
-
99
- mock_handle_callback .return_value = mock_google_data
100
- mock_create_user .return_value = mock_user
101
-
102
- session = self .client .session
103
- session ["oauth_state" ] = "test_state"
104
- session .save ()
105
-
106
- response = self .client .get (f"{ self .url } ?code=test_code&state=test_state" )
127
+ def test_get_redirects_for_missing_state (self ):
128
+ response = self .client .get (f"{ self .url } ?code=test_code" )
107
129
108
130
self .assertEqual (response .status_code , status .HTTP_302_FOUND )
109
- self .assertIn ("success=true" , response .url )
110
- self .assertIn ("ext-access" , response .cookies )
111
- self .assertIn ("ext-refresh" , response .cookies )
112
- self .assertNotIn ("oauth_state" , self .client .session )
131
+ self .assertIn ("error=missing_state" , response .url )
113
132
114
- def test_post_returns_error_for_missing_code (self ):
115
- response = self .client .post (self .url , {})
116
-
117
- self .assertEqual (response .status_code , status .HTTP_400_BAD_REQUEST )
118
- self .assertEqual (response .data ["message" ], "No authorization code received from Google" )
119
-
120
- def test_post_returns_error_for_invalid_state (self ):
133
+ def test_get_redirects_for_invalid_state (self ):
121
134
session = self .client .session
122
- session ["oauth_state" ] = "different_state "
135
+ session ["oauth_state" ] = "correct_state "
123
136
session .save ()
124
137
125
- response = self .client .post ( self .url , { " code" : " test_code" , " state" : "invalid_state" } )
138
+ response = self .client .get ( f" { self .url } ? code= test_code& state=wrong_state" )
126
139
127
- self .assertEqual (response .status_code , status .HTTP_400_BAD_REQUEST )
128
- self .assertEqual ( response . data [ "message" ], "Invalid state parameter" )
140
+ self .assertEqual (response .status_code , status .HTTP_302_FOUND )
141
+ self .assertIn ( "error=invalid_state" , response . url )
129
142
130
143
@patch ("todo.services.google_oauth_service.GoogleOAuthService.handle_callback" )
131
144
@patch ("todo.services.user_service.UserService.create_or_update_user" )
132
- def test_post_handles_callback_successfully (self , mock_create_user , mock_handle_callback ):
145
+ def test_get_redirects_for_valid_code_and_state (self , mock_create_user , mock_handle_callback ):
133
146
mock_google_data = {
134
- "id" : "test_google_id" ,
135
-
136
- "name" : "Test User" ,
147
+ "id" : self . test_user_data [ "google_id" ] ,
148
+ "email" : self . test_user_data [ "email_id" ] ,
149
+ "name" : self . test_user_data [ "name" ] ,
137
150
}
151
+
138
152
user_id = str (ObjectId ())
139
153
mock_user = Mock ()
140
154
mock_user .id = ObjectId (user_id )
141
- mock_user .google_id = mock_google_data [ "id " ]
142
- mock_user .email_id = mock_google_data [ "email " ]
143
- mock_user .name = mock_google_data ["name" ]
155
+ mock_user .google_id = self . test_user_data [ "google_id " ]
156
+ mock_user .email_id = self . test_user_data [ "email_id " ]
157
+ mock_user .name = self . test_user_data ["name" ]
144
158
type(mock_user ).id = PropertyMock (return_value = ObjectId (user_id ))
145
159
146
160
mock_handle_callback .return_value = mock_google_data
@@ -150,50 +164,26 @@ def test_post_handles_callback_successfully(self, mock_create_user, mock_handle_
150
164
session ["oauth_state" ] = "test_state"
151
165
session .save ()
152
166
153
- response = self .client .post ( self .url , { " code" : " test_code" , " state" : " test_state"} )
167
+ response = self .client .get ( f" { self .url } ? code= test_code& state= test_state" )
154
168
155
- self .assertEqual (response .status_code , status .HTTP_200_OK )
156
- self .assertEqual (response .data ["data" ]["user" ]["id" ], user_id )
157
- self .assertEqual (response .data ["data" ]["user" ]["name" ], mock_user .name )
158
- self .assertEqual (response .data ["data" ]["user" ]["email" ], mock_user .email_id )
159
- self .assertEqual (response .data ["data" ]["user" ]["google_id" ], mock_user .google_id )
169
+ self .assertEqual (response .status_code , status .HTTP_302_FOUND )
170
+ self .assertIn ("success=true" , response .url )
160
171
self .assertIn ("ext-access" , response .cookies )
161
172
self .assertIn ("ext-refresh" , response .cookies )
162
173
self .assertNotIn ("oauth_state" , self .client .session )
163
174
164
- class GoogleRefreshViewTests (APITestCase ):
165
- def setUp (self ):
166
- super ().setUp ()
167
- self .client = APIClient ()
168
- self .url = reverse ("google_refresh" )
169
-
170
- def test_get_returns_401_when_no_refresh_token (self ):
171
- response = self .client .get (self .url )
172
-
173
- self .assertEqual (response .status_code , status .HTTP_401_UNAUTHORIZED )
174
- self .assertEqual (response .data ["message" ], AuthErrorMessages .NO_REFRESH_TOKEN )
175
- self .assertEqual (response .data ["authenticated" ], False )
176
- self .assertEqual (response .data ["statusCode" ], status .HTTP_401_UNAUTHORIZED )
177
-
178
- @patch ("todo.utils.google_jwt_utils.validate_google_refresh_token" )
179
- def test_get_refreshes_token_successfully (self , mock_validate_token ):
180
- user_data = {
181
- "user_id" : str (ObjectId ()),
182
- "google_id" : "test_google_id" ,
183
-
184
- "name" : "Test User" ,
185
- }
186
- tokens = generate_google_token_pair (user_data )
187
- mock_validate_token .return_value = user_data
175
+ @patch ("todo.services.google_oauth_service.GoogleOAuthService.handle_callback" )
176
+ def test_get_redirects_for_callback_exception (self , mock_handle_callback ):
177
+ mock_handle_callback .side_effect = Exception ("OAuth service error" )
188
178
189
- self .client .cookies ["ext-refresh" ] = tokens ["refresh_token" ]
179
+ session = self .client .session
180
+ session ["oauth_state" ] = "test_state"
181
+ session .save ()
190
182
191
- response = self .client .get (self .url , HTTP_ACCEPT = "application/json " )
183
+ response = self .client .get (f" { self .url } ?code=test_code&state=test_state " )
192
184
193
- self .assertEqual (response .status_code , status .HTTP_200_OK )
194
- self .assertEqual (response .data ["data" ]["success" ], True )
195
- self .assertEqual (response .data ["message" ], AppMessages .TOKEN_REFRESHED )
196
- self .assertIn ("ext-access" , response .cookies )
185
+ self .assertEqual (response .status_code , status .HTTP_302_FOUND )
186
+ self .assertIn ("error=auth_failed" , response .url )
197
187
198
188
199
189
class GoogleLogoutViewTests (APITestCase ):
@@ -202,52 +192,57 @@ def setUp(self):
202
192
self .client = APIClient ()
203
193
self .url = reverse ("google_logout" )
204
194
205
- def test_get_returns_success_and_clears_cookies (self ):
206
- user_data = {
207
- "user_id" : str (ObjectId ()),
208
- "google_id" : "test_google_id" ,
209
-
210
- "name" : "Test User" ,
211
- }
212
- tokens = generate_google_token_pair (user_data )
213
- self .client .cookies ["ext-access" ] = tokens ["access_token" ]
214
- self .client .cookies ["ext-refresh" ] = tokens ["refresh_token" ]
215
-
216
- response = self .client .get (self .url , HTTP_ACCEPT = "application/json" )
217
-
218
- self .assertEqual (response .status_code , status .HTTP_200_OK )
219
- self .assertEqual (response .data ["data" ]["success" ], True )
220
- self .assertEqual (response .data ["message" ], AppMessages .GOOGLE_LOGOUT_SUCCESS )
221
- self .assertEqual (response .cookies .get ("ext-access" ).value , "" )
222
- self .assertEqual (response .cookies .get ("ext-refresh" ).value , "" )
223
-
224
- def test_get_redirects_when_not_json_request (self ):
195
+ def test_get_returns_json_response (self ):
225
196
redirect_url = "http://localhost:3000"
226
197
self .client .cookies ["ext-access" ] = "test_access_token"
227
198
self .client .cookies ["ext-refresh" ] = "test_refresh_token"
228
199
229
200
response = self .client .get (f"{ self .url } ?redirectURL={ redirect_url } " )
230
201
231
- self .assertEqual (response .status_code , status .HTTP_302_FOUND )
232
- self .assertEqual (response .url , redirect_url )
202
+ self .assertEqual (response .status_code , status .HTTP_200_OK )
203
+ self .assertEqual (response .data ["data" ]["success" ], True )
204
+ self .assertEqual (response .data ["message" ], AppMessages .GOOGLE_LOGOUT_SUCCESS )
233
205
self .assertEqual (response .cookies .get ("ext-access" ).value , "" )
234
206
self .assertEqual (response .cookies .get ("ext-refresh" ).value , "" )
235
207
236
208
def test_post_returns_success_and_clears_cookies (self ):
209
+ """Test that POST requests return JSON"""
237
210
user_data = {
238
211
"user_id" : str (ObjectId ()),
239
- "google_id" : "test_google_id" ,
240
-
241
- "name" : "Test User" ,
212
+ "google_id" : google_auth_user_payload [ "google_id" ] ,
213
+ "email" : google_auth_user_payload [ "email" ] ,
214
+ "name" : google_auth_user_payload [ "name" ] ,
242
215
}
243
216
tokens = generate_google_token_pair (user_data )
244
217
self .client .cookies ["ext-access" ] = tokens ["access_token" ]
245
218
self .client .cookies ["ext-refresh" ] = tokens ["refresh_token" ]
246
219
247
- response = self .client .post (self .url , HTTP_ACCEPT = "application/json" )
220
+ response = self .client .post (self .url )
248
221
249
222
self .assertEqual (response .status_code , status .HTTP_200_OK )
250
223
self .assertEqual (response .data ["data" ]["success" ], True )
251
224
self .assertEqual (response .data ["message" ], AppMessages .GOOGLE_LOGOUT_SUCCESS )
252
225
self .assertEqual (response .cookies .get ("ext-access" ).value , "" )
253
226
self .assertEqual (response .cookies .get ("ext-refresh" ).value , "" )
227
+
228
+ def test_logout_clears_session (self ):
229
+ """Test that logout clears session data"""
230
+ session = self .client .session
231
+ session ["oauth_state" ] = "test_state"
232
+ session ["some_other_data" ] = "test_data"
233
+ session .save ()
234
+
235
+ response = self .client .post (self .url )
236
+
237
+ self .assertEqual (response .status_code , status .HTTP_200_OK )
238
+ self .assertNotIn ("oauth_state" , self .client .session )
239
+ self .assertNotIn ("some_other_data" , self .client .session )
240
+
241
+ def test_logout_clears_sessionid_cookie (self ):
242
+ """Test that logout clears sessionid cookie"""
243
+ self .client .cookies ["sessionid" ] = "test_session_id"
244
+
245
+ response = self .client .post (self .url )
246
+
247
+ self .assertEqual (response .status_code , status .HTTP_200_OK )
248
+ self .assertEqual (response .cookies .get ("sessionid" ).value , "" )
0 commit comments