From d76b0ead442004794dd3c9ef9c3d42a3b6807021 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sat, 5 Oct 2024 20:19:28 -0700 Subject: [PATCH] Backend coverage --- src/paperless_mail/tests/test_mail.py | 92 ++++++++++++++ src/paperless_mail/tests/test_mail_oauth.py | 125 ++++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 src/paperless_mail/tests/test_mail_oauth.py diff --git a/src/paperless_mail/tests/test_mail.py b/src/paperless_mail/tests/test_mail.py index c8a8e5124..f8bf475a8 100644 --- a/src/paperless_mail/tests/test_mail.py +++ b/src/paperless_mail/tests/test_mail.py @@ -4,9 +4,11 @@ import random import uuid from collections import namedtuple from contextlib import AbstractContextManager +from datetime import timedelta from unittest import mock import pytest +from django.contrib.auth.models import User from django.core.management import call_command from django.db import DatabaseError from django.test import TestCase @@ -19,6 +21,8 @@ from imap_tools import MailboxLoginError from imap_tools import MailMessage from imap_tools import MailMessageFlags from imap_tools import errors +from rest_framework import status +from rest_framework.test import APITestCase from documents.models import Correspondent from documents.tests.utils import DirectoriesMixin @@ -1590,3 +1594,91 @@ class TestTasks(TestCase): tasks.process_mail_accounts() self.assertEqual(m.call_count, 0) + + +class TestMailAccountTestView(APITestCase): + def setUp(self): + self.user = User.objects.create_user( + username="testuser", + password="testpassword", + ) + self.client.force_authenticate(user=self.user) + self.url = "/api/mail_accounts/test/" + + @mock.patch("paperless_mail.mail.get_mailbox") + @mock.patch("paperless_mail.mail.mailbox_login") + def test_mail_account_test_view_success(self, mock_mailbox_login, mock_get_mailbox): + mock_get_mailbox.return_value.__enter__.return_value = mock.MagicMock() + mock_mailbox_login.return_value = True + data = { + "imap_server": "imap.example.com", + "imap_port": 993, + "imap_security": MailAccount.ImapSecurity.SSL, + "username": "testuser", + "password": "testpassword", + "account_type": MailAccount.MailAccountType.IMAP, + "is_token": False, + } + response = self.client.post(self.url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data, {"success": True}) + + @mock.patch("paperless_mail.mail.get_mailbox") + @mock.patch("paperless_mail.mail.mailbox_login") + def test_mail_account_test_view_mail_error( + self, + mock_mailbox_login, + mock_get_mailbox, + ): + mock_get_mailbox.return_value.__enter__.return_value = mock.MagicMock() + mock_mailbox_login.side_effect = MailError("Unable to connect to server") + data = { + "imap_server": "imap.example.com", + "imap_port": 993, + "imap_security": MailAccount.ImapSecurity.SSL, + "username": "testuser", + "password": "testpassword", + "account_type": MailAccount.MailAccountType.IMAP, + "is_token": False, + } + response = self.client.post(self.url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.content.decode(), "Unable to connect to server") + + @mock.patch("paperless_mail.views.MailAccount.objects.get") + @mock.patch("paperless_mail.mail.get_mailbox") + @mock.patch("paperless_mail.mail.mailbox_login") + def test_mail_account_test_view_refresh_token( + self, + mock_mailbox_login, + mock_get_mailbox, + mock_get, + ): + mock_get_mailbox.return_value.__enter__.return_value = mock.MagicMock() + existing_account = MailAccount( + imap_server="imap.example.com", + imap_port=993, + imap_security=MailAccount.ImapSecurity.SSL, + username="testuser", + password="oldpassword", + account_type=MailAccount.MailAccountType.IMAP, + refresh_token="oldtoken", + expiration=timezone.now() - timedelta(days=1), + is_token=True, + ) + mock_get.return_value = existing_account + + with mock.patch("paperless_mail.views.refresh_oauth_token", return_value=True): + data = { + "id": existing_account.id, + "imap_server": "imap.example.com", + "imap_port": 993, + "imap_security": MailAccount.ImapSecurity.SSL, + "username": "testuser", + "password": "********", + "account_type": MailAccount.MailAccountType.IMAP, + "is_token": True, + } + response = self.client.post(self.url, data, format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data, {"success": True}) diff --git a/src/paperless_mail/tests/test_mail_oauth.py b/src/paperless_mail/tests/test_mail_oauth.py new file mode 100644 index 000000000..a0a7efba4 --- /dev/null +++ b/src/paperless_mail/tests/test_mail_oauth.py @@ -0,0 +1,125 @@ +from datetime import timedelta +from unittest import mock + +from django.conf import settings +from django.contrib.auth.models import User +from django.test import TestCase +from django.utils import timezone +from rest_framework import status + +from paperless_mail.mail import MailAccountHandler +from paperless_mail.models import MailAccount + + +class TestMailOAuth( + TestCase, +): + def setUp(self) -> None: + self.user = User.objects.create_user("testuser") + self.client.force_login(self.user) + self.mail_account_handler = MailAccountHandler() + # Mock settings + settings.GMAIL_OAUTH_CLIENT_ID = "test_gmail_client_id" + settings.GMAIL_OAUTH_CLIENT_SECRET = "test_gmail_client_secret" + settings.OUTLOOK_OAUTH_CLIENT_ID = "test_outlook_client_id" + settings.OUTLOOK_OAUTH_CLIENT_SECRET = "test_outlook_client_secret" + super().setUp() + + @mock.patch("httpx.post") + def test_oauth_callback_view(self, mock_post): + """ + GIVEN: + - Mocked settings for Gmail and Outlook OAuth client IDs and secrets + WHEN: + - OAuth callback is called with a code and scope + THEN: + - Gmail mail account is created + """ + + mock_post.return_value.json.return_value = { + "access_token": "test_access_token", + "refresh_token": "test_refresh_token", + "expires_in": 3600, + } + + # Test Google OAuth callback + response = self.client.get( + "/api/oauth/callback/?code=test_code&scope=https://mail.google.com/", + ) + self.assertEqual(response.status_code, status.HTTP_302_FOUND) + self.assertIn("oauth_success=1", response.url) + mock_post.assert_called_once() + self.assertTrue( + MailAccount.objects.filter(imap_server="imap.gmail.com").exists(), + ) + + # Test Outlook OAuth callback + response = self.client.get("/api/oauth/callback/?code=test_code") + self.assertEqual(response.status_code, status.HTTP_302_FOUND) + self.assertIn("oauth_success=1", response.url) + self.assertTrue( + MailAccount.objects.filter(imap_server="outlook.office365.com").exists(), + ) + + @mock.patch("httpx.post") + def test_oauth_callback_view_error(self, mock_post): + """ + GIVEN: + - Mocked settings for Gmail and Outlook OAuth client IDs and secrets + WHEN: + - OAuth callback is called with an error + THEN: + - Error is logged + """ + + mock_post.return_value.json.return_value = { + "error": "test_error", + } + + response = self.client.get( + "/api/oauth/callback/?code=test_code&scope=https://mail.google.com/", + ) + self.assertEqual(response.status_code, status.HTTP_302_FOUND) + self.assertIn("oauth_success=0", response.url) + mock_post.assert_called_once() + self.assertFalse( + MailAccount.objects.filter(imap_server="imap.gmail.com").exists(), + ) + self.assertFalse( + MailAccount.objects.filter(imap_server="outlook.office365.com").exists(), + ) + + @mock.patch("paperless_mail.mail.get_mailbox") + @mock.patch("httpx.post") + def test_refresh_token_on_handle_mail_account(self, mock_post, mock_get_mailbox): + """ + GIVEN: + - Mail account with refresh token and expiration + WHEN: + - handle_mail_account is called + THEN: + - Refresh token is called + """ + + mock_mailbox = mock.MagicMock() + mock_get_mailbox.return_value.__enter__.return_value = mock_mailbox + + mail_account = MailAccount.objects.create( + name="test_mail_account", + username="test_username", + imap_security=MailAccount.ImapSecurity.SSL, + imap_port=993, + account_type=MailAccount.MailAccountType.GMAIL, + is_token=True, + refresh_token="test_refresh_token", + expiration=timezone.now() - timedelta(days=1), + ) + + mock_post.return_value.json.return_value = { + "access_token": "test_access_token", + "refresh_token": "test_refresh_token", + "expires_in": 3600, + } + + self.mail_account_handler.handle_mail_account(mail_account) + mock_post.assert_called_once()