From 0fea265cfbdb17c9fb80696a641a9b42e227be9a Mon Sep 17 00:00:00 2001 From: Amirhossein Khalili Date: Thu, 14 May 2026 23:24:09 +0330 Subject: [PATCH] test(users): cover google signup otp gating --- apps/users/tests/test_api_views.py | 92 +++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 21 deletions(-) diff --git a/apps/users/tests/test_api_views.py b/apps/users/tests/test_api_views.py index ed2150a..00a3e43 100644 --- a/apps/users/tests/test_api_views.py +++ b/apps/users/tests/test_api_views.py @@ -733,13 +733,11 @@ class GoogleOAuthApiTests(APITestCase): self.assertEqual(response.data["code"], "google_email_mobile_conflict") self.assertEqual(response.data["mobile_hint"], "09*****0002") - @patch("apps.users.services.google_oauth.requests.get") - def test_google_complete_new_mobile_creates_user_and_link(self, requests_get): - avatar_response = Mock() - avatar_response.content = b"avatar-bytes" - avatar_response.headers = {"Content-Type": "image/png"} - avatar_response.raise_for_status.return_value = None - requests_get.return_value = avatar_response + @patch("apps.users.services.google_oauth.generate_and_send_otp") + def test_google_complete_new_mobile_moves_flow_to_claim_required_without_creating_user( + self, + generate_and_send_otp, + ): cache.set( "google_oauth_flow:new-flow", { @@ -767,20 +765,10 @@ class GoogleOAuthApiTests(APITestCase): ) self.assertEqual(response.status_code, 200) - self.assertEqual(response.data["status"], "authenticated") - created_user = User.objects.get(mobile="09125550009") - self.assertFalse(created_user.has_usable_password()) - self.assertEqual(created_user.email, "created@example.com") - self.assertEqual(created_user.first_name, "Created") - self.assertEqual(created_user.last_name, "User") - self.assertTrue(bool(created_user.profile_picture)) - self.assertTrue( - UserSocialAccount.objects.filter( - user=created_user, - provider=UserSocialAccount.ProviderType.GOOGLE, - provider_user_id="google-sub-4", - ).exists() - ) + self.assertEqual(response.data["status"], "claim_required") + self.assertEqual(response.data["resolution"], "new_account") + self.assertFalse(User.objects.filter(mobile="09125550009").exists()) + generate_and_send_otp.assert_called_once_with("09125550009", "register") @patch("apps.users.services.google_oauth.generate_and_send_otp") def test_google_complete_existing_blank_email_mobile_moves_flow_to_claim_required( @@ -937,6 +925,68 @@ class GoogleOAuthApiTests(APITestCase): ).exists() ) + @patch("apps.users.services.google_oauth.requests.get") + @patch("apps.users.services.google_oauth.get_tokens_for_user") + def test_google_claim_verify_creates_new_user_only_after_otp_confirmation( + self, + get_tokens_for_user, + requests_get, + ): + get_tokens_for_user.return_value = {"access": "a", "refresh": "r"} + avatar_response = Mock() + avatar_response.content = b"avatar-bytes" + avatar_response.headers = {"Content-Type": "image/png"} + avatar_response.raise_for_status.return_value = None + requests_get.return_value = avatar_response + cache.set( + "google_oauth_flow:new-claim-verify-flow", + { + "status": "claim_required", + "google_profile": { + "provider_user_id": "google-sub-new-verify", + "email": "new-verified@example.com", + "email_verified": True, + "first_name": "Verified", + "last_name": "Signup", + "avatar_url": "https://example.com/new-verify.png", + }, + "mobile": "09125550010", + "user_id": None, + "resolution": "new_account", + "email": "new-verified@example.com", + "mobile_hint": None, + "detail": "claim", + }, + 900, + ) + + with patch("django_redis.get_redis_connection") as get_redis_connection: + redis_mock = get_redis_connection.return_value + redis_mock.get.return_value = b"12345" + + response = self.client.post( + "/api/users/oauth/google/claim/verify/", + {"flow": "new-claim-verify-flow", "code": "12345"}, + format="json", + ) + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data["status"], "authenticated") + created_user = User.objects.get(mobile="09125550010") + self.assertTrue(created_user.is_verified) + self.assertFalse(created_user.has_usable_password()) + self.assertEqual(created_user.email, "new-verified@example.com") + self.assertEqual(created_user.first_name, "Verified") + self.assertEqual(created_user.last_name, "Signup") + self.assertTrue(bool(created_user.profile_picture)) + self.assertTrue( + UserSocialAccount.objects.filter( + user=created_user, + provider=UserSocialAccount.ProviderType.GOOGLE, + provider_user_id="google-sub-new-verify", + ).exists() + ) + class GoogleOAuthAuditCommandTests(APITestCase): def test_audit_google_social_links_reports_suspicious_links(self):