Server IP : 85.214.239.14 / Your IP : 3.136.18.192 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /srv/modoboa/env/lib64/python3.5/site-packages/modoboa_radicale/ |
Upload File : |
# coding: utf-8 """Radicale extension unit tests.""" import mock import os import tempfile from configparser import ConfigParser from django.urls import reverse from django.utils import six from django.core import management from modoboa.admin import factories as admin_factories from modoboa.admin import models as admin_models from modoboa.core import factories as core_factories from modoboa.core import models as core_models from modoboa.lib.tests import ModoTestCase, ModoAPITestCase from modoboa.admin.factories import populate_database from . import factories from . import models from . import mocks class TestDataMixin(object): """Create some data.""" @classmethod def setUpTestData(cls): """Create test data.""" super(TestDataMixin, cls).setUpTestData() admin_factories.populate_database() cls.account = core_models.User.objects.get(username="user@test.com") cls.calendar = factories.UserCalendarFactory( mailbox=cls.account.mailbox) cls.admin_account = core_models.User.objects.get( username="admin@test.com") cls.calendar2 = factories.UserCalendarFactory( mailbox=cls.admin_account.mailbox) cls.acr1 = factories.AccessRuleFactory( calendar=cls.calendar, mailbox=cls.admin_account.mailbox, read=True, write=True) cls.account2 = core_factories.UserFactory( username="user2@test.com", groups=("SimpleUsers",), ) admin_factories.MailboxFactory.create( address="user2", domain=cls.account.mailbox.domain, user=cls.account2) cls.domain = admin_models.Domain.objects.get(name="test.com") cls.scalendar = factories.SharedCalendarFactory( domain=cls.domain) cls.domain2 = admin_models.Domain.objects.get(name="test2.com") cls.scalendar2 = factories.SharedCalendarFactory( domain=cls.domain2) class ViewsTestCase(TestDataMixin, ModoTestCase): """Check views.""" def setUp(self): """Initiate test context.""" self.client.force_login(self.account) # def test_index(self): # """Test index view.""" # url = reverse("modoboa_radicale:calendar_detail_view") # response = self.client.get(url) # self.assertContains(response, '<div id="app">') def test_admin_access(self): """Check admin access with no mailbox.""" self.client.login(username="admin", password="password") url = reverse("modoboa_radicale:calendar_detail_view") response = self.client.get(url) self.assertContains( response, "Permission denied: A mailbox is required") class AccessRuleTestCase(ModoTestCase): @classmethod def setUpTestData(cls): """Create test data.""" super(AccessRuleTestCase, cls).setUpTestData() populate_database() def setUp(self): """Initialize tests.""" super(AccessRuleTestCase, self).setUp() self.rights_file_path = tempfile.mktemp() self.set_global_parameter( "rights_file_path", self.rights_file_path, app="modoboa_radicale") def tearDown(self): os.unlink(self.rights_file_path) def test_rights_file_generation(self): mbox = admin_models.Mailbox.objects.get( address="admin", domain__name="test.com") cal = factories.UserCalendarFactory(mailbox=mbox) factories.AccessRuleFactory( mailbox=admin_models.Mailbox.objects.get( address="user", domain__name="test.com"), calendar=cal, read=True) management.call_command("generate_rights", verbosity=False) cfg = ConfigParser() with open(self.rights_file_path) as fpo: if six.PY3: cfg.read_file(fpo) else: cfg.readfp(fpo) # Check mandatory rules self.assertTrue(cfg.has_section("domain-shared-calendars")) self.assertTrue(cfg.has_section("owners-access")) # Check user-defined rules section = "user@test.com-to-User calendar 0-acr" self.assertTrue(cfg.has_section(section)) self.assertEqual(cfg.get(section, "user"), "user@test.com") self.assertEqual( cfg.get(section, "collection"), "admin@test.com/User calendar 0" ) self.assertEqual(cfg.get(section, "permission"), "r") # Call a second time management.call_command("generate_rights", verbosity=False) def test_rights_file_generation_with_admin(self): self.set_global_parameter( "allow_calendars_administration", True, app="modoboa_radicale") management.call_command("generate_rights", verbosity=False) cfg = ConfigParser() with open(self.rights_file_path) as fpo: if six.PY3: cfg.read_file(fpo) else: cfg.readfp(fpo) # Check mandatory rules self.assertTrue(cfg.has_section("domain-shared-calendars")) self.assertTrue(cfg.has_section("owners-access")) # Super admin rules section = "sa-admin-acr" self.assertTrue(cfg.has_section(section)) # Domain admin rules for section in ["da-admin@test.com-to-test.com-acr", "da-admin@test2.com-to-test2.com-acr"]: self.assertTrue(cfg.has_section(section)) class UserCalendarViewSetTestCase(TestDataMixin, ModoAPITestCase): """UserCalendar viewset tests.""" def setUp(self): """Initiate test context.""" self.client.force_login(self.account) self.set_global_parameter("server_location", "http://localhost:5232") def test_get_calendars(self): """List or retrieve calendars.""" url = reverse("api:user-calendar-list") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) url = reverse("api:user-calendar-detail", args=[self.calendar.pk]) response = self.client.get(url) self.assertEqual(response.status_code, 200) @mock.patch("caldav.DAVClient") def test_create_calendar(self, client_mock): """Create a new calendar.""" client_mock.return_value = mocks.DAVClientMock() data = {"username": "user@test.com", "password": "toto"} response = self.client.post(reverse("core:login"), data) data = { "name": "Test calendaré", "color": "#ffffff" } url = reverse("api:user-calendar-list") response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, 201) @mock.patch("caldav.DAVClient") @mock.patch("caldav.Calendar") def test_update_calendar(self, cal_mock, client_mock): """Update existing calendar.""" client_mock.return_value = mocks.DAVClientMock() cal_mock.return_value = mocks.Calendar() data = {"username": "user@test.com", "password": "toto"} self.client.post(reverse("core:login"), data) data = {"name": "Modified calendar", "color": "#ffffff"} url = reverse("api:user-calendar-detail", args=[self.calendar.pk]) response = self.client.put(url, data, format="json") self.assertEqual(response.status_code, 200) oldpath = self.calendar.path self.calendar.refresh_from_db() self.assertEqual(self.calendar.name, data["name"]) self.assertEqual(self.calendar.path, oldpath) def test_delete_calendar(self): """Delete existing calendar.""" url = reverse("api:user-calendar-detail", args=[self.calendar.pk]) response = self.client.delete(url) self.assertEqual(response.status_code, 204) with self.assertRaises(models.UserCalendar.DoesNotExist): self.calendar.refresh_from_db() def test_check_token(self): """Check token access.""" url = reverse("api:user-calendar-check-token") data = { "calendar": self.calendar._path, "token": self.calendar.access_token } response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, 200) self.assertEqual(response.json()["status"], "ok") data["token"] = "pouet" response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, 200) self.assertEqual(response.json()["status"], "ko") data["calendar"] = "unknown" response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, 404) class SharedCalendarViewSetTestCase(TestDataMixin, ModoAPITestCase): """SharedCalendar viewset tests.""" def setUp(self): """Initiate test context.""" self.client.force_login(self.admin_account) self.set_global_parameter("server_location", "http://localhost:5232") def test_get_calendars(self): """List or retrieve calendars.""" url = reverse("api:shared-calendar-list") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) url = reverse("api:shared-calendar-detail", args=[self.scalendar.pk]) response = self.client.get(url) self.assertEqual(response.status_code, 200) account = core_models.User.objects.get(username="user@test.com") self.client.force_login(account) url = reverse("api:shared-calendar-list") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) @mock.patch("caldav.DAVClient") def test_create_calendar(self, client_mock): """Create a new calendar.""" client_mock.return_value = mocks.DAVClientMock() data = {"username": "admin@test.com", "password": "toto"} response = self.client.post(reverse("core:login"), data) data = { "name": "Shared calendar", "color": "#ffffff", "domain": { "pk": self.domain.pk, "name": "test.com" } } url = reverse("api:shared-calendar-list") response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, 201) @mock.patch("caldav.DAVClient") @mock.patch("caldav.Calendar") def test_update_calendar(self, cal_mock, client_mock): """Update existing calendar.""" client_mock.return_value = mocks.DAVClientMock() cal_mock.return_value = mocks.Calendar() data = {"username": "admin@test.com", "password": "toto"} self.client.post(reverse("core:login"), data) data = { "name": "Modified calendar", "color": "#ffffff", "domain": { "pk": self.domain.pk, "name": "test.com" } } url = reverse("api:shared-calendar-detail", args=[self.scalendar.pk]) response = self.client.put(url, data, format="json") self.assertEqual(response.status_code, 200) oldpath = self.scalendar.path self.scalendar.refresh_from_db() self.assertEqual(self.scalendar.name, data["name"]) self.assertEqual(self.scalendar.path, oldpath) def test_delete_calendar(self): """Delete existing calendar.""" url = reverse("api:shared-calendar-detail", args=[self.scalendar.pk]) response = self.client.delete(url) self.assertEqual(response.status_code, 204) with self.assertRaises(models.SharedCalendar.DoesNotExist): self.scalendar.refresh_from_db() def test_check_token(self): """Check token access.""" url = reverse("api:shared-calendar-check-token") data = { "calendar": self.scalendar._path, "token": self.scalendar.access_token } response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, 200) self.assertEqual(response.json()["status"], "ok") data["token"] = "pouet" response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, 200) self.assertEqual(response.json()["status"], "ko") data["calendar"] = "unknown" response = self.client.post(url, data, format="json") self.assertEqual(response.status_code, 404) class AccessRuleViewSetTestCase(TestDataMixin, ModoAPITestCase): """AccessRule viewset tests.""" def setUp(self): """Initiate test context.""" self.client.force_login(self.account) def test_get_accessrules(self): """Test access rule retrieval.""" url = reverse("api:access-rule-list") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) def test_create_accessrule(self): data = { "mailbox": { "pk": self.account2.mailbox.pk, "full_address": self.account2.mailbox.full_address }, "read": True, "calendar": self.calendar.pk } url = reverse("api:access-rule-list") response = self.client.post(url, data=data, format="json") self.assertEqual(response.status_code, 201) def test_update_accessrule(self): """Test access rule modification.""" data = { "mailbox": { "pk": self.admin_account.pk, "full_address": self.admin_account.email }, "calendar": self.calendar.pk, "read": False, "write": True } url = reverse("api:access-rule-detail", args=[self.acr1.pk]) response = self.client.put(url, data=data, format="json") self.assertEqual(response.status_code, 200) self.acr1.refresh_from_db() self.assertFalse(self.acr1.read) def test_update_accessrule_permission(self): """Try to modify an access rule the user does not own.""" calendar = factories.UserCalendarFactory( mailbox=self.admin_account.mailbox) acr = factories.AccessRuleFactory( calendar=calendar, mailbox=self.account.mailbox, read=True, write=True) data = { "mailbox": self.account.pk, "calendar": calendar.pk, "read": False, "write": True } url = reverse("api:access-rule-detail", args=[acr.pk]) response = self.client.put(url, data=data, format="json") self.assertEqual(response.status_code, 404) def test_delete_accessrule(self): """Test access rule removal.""" url = reverse("api:access-rule-detail", args=[self.acr1.pk]) response = self.client.delete(url) self.assertEqual(response.status_code, 204) with self.assertRaises(models.AccessRule.DoesNotExist): self.acr1.refresh_from_db() class EventViewSetTestCase(TestDataMixin, ModoAPITestCase): """Event viewset tests.""" def setUp(self): """Initiate test context.""" patcher1 = mock.patch("caldav.DAVClient") self.client_mock = patcher1.start() self.client_mock.return_value = mocks.DAVClientMock() self.addCleanup(patcher1.stop) patcher2 = mock.patch("caldav.Calendar") self.cal_mock = patcher2.start() self.cal_mock.return_value = mocks.Calendar(client=self.client_mock) self.addCleanup(patcher2.stop) self.client.force_login(self.account) self.set_global_parameter("server_location", "http://localhost") def test_get_user_events(self): """Test event(s) retrieval.""" data = {"username": "user@test.com", "password": "toto"} self.client.post(reverse("core:login"), data) # FIXME: drf nested routers does not handle reverse() properly url = "/api/v1/user-calendars/{}/events/{}/".format( self.calendar.pk, 1234) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertTrue(response.json()["title"].startswith("Bastille")) url = "/api/v1/user-calendars/{}/events/".format(self.calendar.pk) url = "{}?start={}&end={}".format( url, "20060712T182145Z", "20070712T182145Z" ) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 2) def test_get_shared_events(self): """Test event(s) retrieval.""" data = {"username": "user@test.com", "password": "toto"} self.client.post(reverse("core:login"), data) # FIXME: drf nested routers does not handle reverse() properly url = "/api/v1/shared-calendars/{}/events/{}/".format( self.scalendar.pk, 1234) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertTrue(response.json()["title"].startswith("Bastille")) url = "/api/v1/shared-calendars/{}/events/".format(self.scalendar.pk) url = "{}?start={}&end={}".format( url, "20060712T182145Z", "20070712T182145Z" ) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 2) def test_create_event(self): """Test event creation.""" data = {"username": "user@test.com", "password": "toto"} self.client.post(reverse("core:login"), data) url = "/api/v1/user-calendars/{}/events/".format(self.calendar.pk) data = { "title": "Test event", "start": "2018-03-27T00:00:00Z", "end": "2018-03-28T00:00:00Z", "allDay": True, "color": "#ffdddd", "description": "Description", "calendar": self.calendar.pk } response = self.client.post(url, data=data, format="json") self.assertEqual(response.status_code, 201) self.assertIn("id", response.json()) url = "/api/v1/shared-calendars/{}/events/".format(self.scalendar.pk) data = { "title": "Test event 2", "start": "2018-03-27T00:00:00Z", "end": "2018-03-28T00:00:00Z", "allDay": False, "color": "#ffdddd", "description": "Description", "calendar": self.scalendar.pk } response = self.client.post(url, data=data, format="json") self.assertEqual(response.status_code, 201) self.assertIn("id", response.json()) def test_update_event(self): """Test event update.""" data = {"username": "user@test.com", "password": "toto"} self.client.post(reverse("core:login"), data) url = "/api/v1/user-calendars/{}/events/1234/".format( self.calendar.pk) data = { "title": "Test event", "start": "2018-03-27T00:00:00Z", "end": "2018-03-28T00:00:00Z", "allDay": True, "color": "#ffdddd", "description": "Description", "calendar": self.calendar.pk, # "attendees": [{ # "display_name": "Test User", # "email": "user@domain.test", # }] } response = self.client.put(url, data=data, format="json") self.assertEqual(response.status_code, 200) self.assertIn("id", response.json()) def test_patch_event(self): """Test event partial update.""" data = {"username": "user@test.com", "password": "toto"} self.client.post(reverse("core:login"), data) url = "/api/v1/user-calendars/{}/events/1234/".format( self.calendar.pk) data = { "start": "2018-03-27T00:00:00Z", "end": "2018-03-28T00:00:00Z", "allDay": True, } response = self.client.patch(url, data=data, format="json") self.assertEqual(response.status_code, 200) def test_move_event_between_cals(self): """Move an event.""" data = {"username": "user@test.com", "password": "toto"} self.client.post(reverse("core:login"), data) data = { "title": "Test event", "start": "2018-03-27T00:00:00Z", "end": "2018-03-28T00:00:00Z", "allDay": True, "color": "#ffdddd", "description": "Description", "calendar": self.scalendar.pk, "new_calendar_type": "shared" } url = "/api/v1/user-calendars/{}/events/1234/".format( self.calendar.pk) response = self.client.put(url, data=data, format="json") self.assertEqual(response.status_code, 200) def test_delete_event(self): """Test event deletion.""" data = {"username": "user@test.com", "password": "toto"} self.client.post(reverse("core:login"), data) url = "/api/v1/shared-calendars/{}/events/1234/".format( self.scalendar.pk) response = self.client.delete(url) self.assertEqual(response.status_code, 200) def test_import_from_file(self): """Check import feature.""" data = {"username": "user@test.com", "password": "toto"} self.client.post(reverse("core:login"), data) url = reverse( "api:user-event-import-from-file", args=[self.calendar.pk] ) path = os.path.join( os.path.abspath(os.path.dirname(__file__)), "test_data/events.ics" ) # File too big => fails self.set_global_parameter("max_ics_file_size", "1") with open(path) as fp: data = { "ics_file": fp } response = self.client.post(url, data) self.assertEqual(response.status_code, 400) self.set_global_parameter("max_ics_file_size", "2048") with open(path) as fp: data = { "ics_file": fp } response = self.client.post(url, data) self.assertEqual(response.status_code, 200) self.assertEqual(response.json()['counter'], 2) class AttendeeViewSetTestCase(ModoAPITestCase): """Attendee viewset test case.""" @classmethod def setUpTestData(cls): super(AttendeeViewSetTestCase, cls).setUpTestData() populate_database() cls.account = core_models.User.objects.get(username="user@test.com") def setUp(self): """Initiate test context.""" self.client.force_login(self.account) def test_get_attendees(self): """Test attendees retrieval.""" url = reverse("api:attendee-list") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) class MailboxViewSetTestCase(ModoAPITestCase): """Mailbox viewset test case.""" @classmethod def setUpTestData(cls): super(MailboxViewSetTestCase, cls).setUpTestData() populate_database() cls.account = core_models.User.objects.get(username="user@test.com") def setUp(self): """Initiate test context.""" self.client.force_login(self.account) def test_get_mailboxes(self): """Test mailbox retrieval.""" url = reverse("api:mailbox-list") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1)