<NME> tests.py
<BEF> """relaydomains unit tests."""

from django.core.files.base import ContentFile
from django.test import TestCase
from django.urls import reverse

from modoboa.admin import factories as admin_factories, models as admin_models
from modoboa.core.factories import UserFactory
from modoboa.lib.test_utils import MapFilesTestCaseMixin
from modoboa.lib.tests import ModoTestCase
from modoboa.limits import utils as limits_utils
from modoboa.transport import factories as tr_factories, models as tr_models
from . import models
from modoboa.limits import utils as limits_utils

from .factories import RelayDomainFactory
from .models import RelayDomain, Service


class Operations(object):

    def _create_relay_domain(self, name, status=200):
        srv, created = Service.objects.get_or_create(name='dummy')
        values = {
            "name": name, "create_dom_admin": False, "type": "relaydomain",
            "target_host": "external.host.tld", "service": srv.id,
            "stepid": "step3",
            "quota": 0,
            "default_mailbox_quota": 0
        }
        values.update(kwargs)
        )

    def _relay_domain_alias_operation(self, optype, rdomain, name, status=200):
        rdom = RelayDomain.objects.get(domain__name=rdomain)
        values = {
            "name": rdom.domain.name, "target_host": rdom.target_host,
            "type": "relaydomain", "service": rdom.service.id
        values = {
            "name": domain.name,
            "service": "relay",
            "relay_target_host": transport._settings["relay_target_host"],
            "relay_target_port": transport._settings["relay_target_port"],
            "type": "relaydomain",
            "quota": domain.quota,
            "default_mailbox_quota": domain.default_mailbox_quota
        }
        aliases = [alias.name for alias in domain.domainalias_set.all()]
        if optype == "add":
            aliases.append(name)
        else:
            aliases.remove(name)
        for cpt, alias in enumerate(aliases):
            fname = "aliases" if not cpt else "aliases_%d" % cpt
            values[fname] = alias
        return self.ajax_post(
            reverse("admin:domain_change",
                    args=[domain.id]),
            values, status
        )

    def _check_limit(self, name, curvalue, maxvalue):
        limit = self.user.userobjectlimit_set.get(name=name)
        self.assertEqual(limit.current_value, curvalue)
        super(RelayDomainsTestCase, cls).setUpTestData()
        admin_factories.populate_database()
        cls.rdom = RelayDomainFactory(domain__name="relaydomain.tld")
        admin_factories.DomainAliasFactory(
            name="relaydomainalias.tld", target=cls.rdom.domain)
        admin_factories.MailboxFactory(
        super(RelayDomainsTestCase, cls).setUpTestData()
        admin_factories.populate_database()
        cls.transport = tr_factories.TransportFactory(
            pattern="relaydomain.tld", service="relay",
            _settings={
                "relay_target_host": "external.host.tld",
                "relay_target_port": "25",
                "relay_verify_recipients": False
            }
        )
        cls.dom = admin_factories.DomainFactory(
            name="relaydomain.tld", type="relaydomain",
            transport=cls.transport)
        admin_factories.DomainAliasFactory(
            name="relaydomainalias.tld", target=cls.dom)
        admin_factories.MailboxFactory(
            domain=cls.dom, address="local",
            user__username="local@relaydomain.tld",
            user__groups=("SimpleUsers", )
        )
        FIXME: add a check for domain alias.
        """
        self._create_relay_domain('relaydomain1.tld')
        rdom = RelayDomain.objects.get(domain__name='relaydomain1.tld')
        self.assertEqual(rdom.target_host, 'external.host.tld')
        self.assertEqual(rdom.service.name, 'dummy')
        self.assertEqual(rdom.domain.enabled, True)
        self.assertIn("relaydomain.tld", content["rows"])
        self.assertIn("Relay domain", content["rows"])

    def test_create_relaydomain(self):
        """Test the creation of a relay domain.

        We also check that unique constraints are respected: domain,
        relay domain alias.

        FIXME: add a check for domain alias.
        """
        self._create_relay_domain("relaydomain1.tld")
        transport = tr_models.Transport.objects.get(pattern="relaydomain1.tld")
        self.assertEqual(
            transport._settings["relay_target_host"], "external.host.tld")
        self.assertEqual(
            transport._settings["relay_verify_recipients"], False)

        resp = self._create_relay_domain("test.com", 400)
        self.assertEqual(resp["form_errors"]["name"][0],
                         "Domain with this Name already exists.")
        resp = self._create_relay_domain("relaydomainalias.tld", 400)
        self.assertEqual(
            resp["form_errors"]["name"][0],
            "A domain alias with this name already exists"
        )

    def test_create_relaydomainalias(self):
        """Test the creation of a relay domain alias.

        We also check that unique constraints are respected: domain,
        relay domain.

        FIXME: add a check for domain alias.
        """
        self._relay_domain_alias_operation(
            "add", self.dom, "relaydomainalias1.tld"
        )
        resp = self._relay_domain_alias_operation(
            "add", self.dom, "test.com", 400
        Rename 'relaydomain.tld' domain to 'relaydomain.org'
        """
        values = {
            'name': "relaydomain.org", "target_host": self.rdom.target_host,
            "type": "relaydomain", "enabled": True,
            "service": self.rdom.service.id
        }
        self.ajax_post(
            reverse('admin:domain_change',
                    args=[self.rdom.domain.id]),
            values
        )
        RelayDomain.objects.get(domain__name='relaydomain.org')

    def test_relaydomain_domain_switch(self):
        """Check domain <-> relaydomain transitions."""
        Rename 'relaydomain.tld' domain to 'relaydomain.org'
        """
            "name": "relaydomain.tld",
            "type": "domain",
            "enabled": True,
        }
        self.ajax_post(
            reverse('admin:domain_change', args=[domain.pk]), values)
        self.assertFalse(
            RelayDomain.objects.filter(
                domain__name="relaydomain.tld").exists())
        self.assertEqual(
            admin_models.Domain.objects.get(name="relaydomain.tld").type,
            "domain")
        )
        self.transport.refresh_from_db()
        self.assertEqual(
            self.transport._settings["relay_target_port"], 4040)
        self.assertTrue(
            models.RecipientAccess.objects.filter(
                pattern=values["name"]).exists())
        values["relay_verify_recipients"] = False
            admin_models.Domain.objects.get(name="relaydomain.tld").type,
            "relaydomain")
        self.assertTrue(
            RelayDomain.objects.filter(
                domain__name="relaydomain.tld").exists())

    def test_edit_relaydomainalias(self):

    def test_relaydomain_domain_switch(self):
        """Check domain <-> relaydomain transitions."""
        domain_pk = self.dom.pk
        values = {
            "name": "relaydomain.tld",
            "type": "domain",
            "quota": 0,
            "default_mailbox_quota": 0,
            "enabled": True,
            "service": "relay",
            "relay_target_host": self.transport._settings["relay_target_host"],
            "relay_target_port": self.transport._settings["relay_target_port"]
        }
        self.ajax_post(
            reverse("admin:domain_change", args=[domain_pk]), values)
        with self.assertRaises(tr_models.Transport.DoesNotExist):
            self.transport.refresh_from_db()
        self.dom.refresh_from_db()
        self.assertEqual(self.dom.type, "domain")
        values = {
            "name": "relaydomain.tld",
                    args=[self.rdom.domain.id]),
            {}
        )
        with self.assertRaises(RelayDomain.DoesNotExist):
            RelayDomain.objects.get(domain__name='relaydomain.tld')

    def test_delete_relaydomainalias(self):
        """Test the removal of a relay domain alias."""
        self._relay_domain_alias_operation(
            'del', self.rdom.domain.name, 'relaydomainalias.tld'
        )
        with self.assertRaises(RelayDomain.DoesNotExist):
            RelayDomain.objects.get(domain__name='relaydomainalias.tld')

    def test_alias_on_relaydomain(self):
        """Create an alias on a relay domain."""
        values = {
            "name": "relaydomain.org",
            "service": "relay",
            "relay_target_host": self.transport._settings["relay_target_host"],
            "relay_target_port": self.transport._settings["relay_target_port"],
            "type": "relaydomain",
            "aliases": "relaydomainalias.net",
            "quota": 0, "default_mailbox_quota": 0
        }
        self.ajax_post(
            reverse("admin:domain_change", args=[self.dom.id]),
            values
        )
        admin_models.DomainAlias.objects.get(name="relaydomainalias.net")
        with self.assertRaises(admin_models.DomainAlias.DoesNotExist):
            admin_models.DomainAlias.objects.get(name="relaydomainalias.tld")

    def test_delete_relaydomain(self):
        """Test the removal of a relay domain."""
        self.ajax_post(
            reverse("admin:domain_delete", args=[self.dom.id]),
            {}
        )
        with self.assertRaises(tr_models.Transport.DoesNotExist):
            self.transport.refresh_from_db()

    def test_delete_recipientaccess(self):
        """Test the removal of a recipient access."""
        self.transport._settings["relay_verify_recipients"] = True
        self.transport.save()
        self.ajax_post(
            reverse("admin:domain_delete", args=[self.dom.id]),
            {}
        )
        self.assertFalse(
            models.RecipientAccess.objects.filter(
                pattern=self.transport.pattern).exists())

    def test_alias_on_relaydomain(self):
        """Create an alias on a relay domain."""
        values = {
            "address": "alias@relaydomain.tld",
            "recipients": "recipient@relaydomain.tld",
            "enabled": True
        }
        self.ajax_post(reverse("admin:alias_add"), values)
        self.assertTrue(
            admin_models.Alias.objects.filter(
                address="alias@relaydomain.tld").exists())
        values = {
            "address": "alias2@relaydomain.tld",
            "recipients": "local@relaydomain.tld",
            "enabled": True
        }
        self.ajax_post(reverse("admin:alias_add"), values)
        self.assertTrue(
            admin_models.Alias.objects.filter(
                address="alias2@relaydomain.tld").exists())


class ImportTestCase(ModoTestCase):
    """Test import."""

    def test_webui_import(self):
        """Check if import from webui works."""
        f = ContentFile("relaydomain;relay.com;127.0.0.1;25;relay;True;True",
                        name="domains.csv")
        self.client.post(
            reverse("admin:domain_import"), {
                "sourcefile": f
            }
        )
        self.assertTrue(
            admin_models.Domain.objects.filter(
                name="relay.com", type="relaydomain").exists())


class LimitsTestCase(ModoTestCase, Operations):

    @classmethod
    def setUpTestData(cls):  # NOQA:N802
        """Create test data."""
        super(LimitsTestCase, cls).setUpTestData()
        for name, _definition in limits_utils.get_user_limit_templates():
            cls.localconfig.parameters.set_value(
                "deflt_user_{0}_limit".format(name), 2, app="limits")
        cls.localconfig.save()
        cls.user = UserFactory.create(
            username="reseller", groups=("Resellers",)
        )

    def setUp(self):
        """Initialize test."""
        super(LimitsTestCase, self).setUp()
        self.client.force_login(self.user)

    def test_relay_domains_limit(self):
        self._create_relay_domain(
            "relaydomain1.tld", quota=1, default_mailbox_quota=1)
        self._check_limit("domains", 1, 2)
        self._create_relay_domain(
            "relaydomain2.tld", quota=1, default_mailbox_quota=1)
        self._check_limit("domains", 2, 2)
        self._create_relay_domain("relaydomain3.tld", 403)
        self._check_limit("domains", 2, 2)
        domid = admin_models.Domain.objects.get(name="relaydomain2.tld").id
        self.ajax_post(
            reverse("admin:domain_delete", args=[domid]), {})
        self._check_limit("domains", 1, 2)

    def test_relay_domain_aliases_limit(self):
        self._create_relay_domain(
            "relaydomain1.tld", quota=1, default_mailbox_quota=1)
        domain = admin_models.Domain.objects.get(name="relaydomain1.tld")
        self._relay_domain_alias_operation(
            "add", domain, "relay-domain-alias1.tld"
        )
        self._check_limit("domain_aliases", 1, 2)
        self._relay_domain_alias_operation(
            "add", domain, "relay-domain-alias2.tld"
        )
        self._check_limit("domain_aliases", 2, 2)
        self._relay_domain_alias_operation(
            "add", domain, "relay-domain-alias3.tld", 403
        )
        self._check_limit("domain_aliases", 2, 2)
        self._relay_domain_alias_operation(
            "delete", domain, "relay-domain-alias2.tld"
        )
        self._check_limit("domain_aliases", 1, 2)


class MapFilesTestCase(MapFilesTestCaseMixin, TestCase):

    """Test case for relaydomains."""

    MAP_FILES = [
        "sql-relaydomains.cf",
        "sql-relay-recipient-verification.cf"
    ]

<MSG> Fixed tests.

<DFF> @@ -14,13 +14,13 @@ from modoboa.lib.test_utils import MapFilesTestCaseMixin
 from modoboa.limits import utils as limits_utils
 
 from .factories import RelayDomainFactory
-from .models import RelayDomain, Service
+from . import models
 
 
 class Operations(object):
 
     def _create_relay_domain(self, name, status=200):
-        srv, created = Service.objects.get_or_create(name='dummy')
+        srv, created = models.Service.objects.get_or_create(name='dummy')
         values = {
             "name": name, "create_dom_admin": False, "type": "relaydomain",
             "target_host": "external.host.tld", "service": srv.id,
@@ -32,7 +32,7 @@ class Operations(object):
         )
 
     def _relay_domain_alias_operation(self, optype, rdomain, name, status=200):
-        rdom = RelayDomain.objects.get(domain__name=rdomain)
+        rdom = models.RelayDomain.objects.get(domain__name=rdomain)
         values = {
             "name": rdom.domain.name, "target_host": rdom.target_host,
             "type": "relaydomain", "service": rdom.service.id
@@ -65,6 +65,8 @@ class RelayDomainsTestCase(ModoTestCase, Operations):
         super(RelayDomainsTestCase, cls).setUpTestData()
         admin_factories.populate_database()
         cls.rdom = RelayDomainFactory(domain__name="relaydomain.tld")
+        cls.rdom.domain.type = "relaydomain"
+        cls.rdom.domain.save()
         admin_factories.DomainAliasFactory(
             name="relaydomainalias.tld", target=cls.rdom.domain)
         admin_factories.MailboxFactory(
@@ -91,7 +93,7 @@ class RelayDomainsTestCase(ModoTestCase, Operations):
         FIXME: add a check for domain alias.
         """
         self._create_relay_domain('relaydomain1.tld')
-        rdom = RelayDomain.objects.get(domain__name='relaydomain1.tld')
+        rdom = models.RelayDomain.objects.get(domain__name='relaydomain1.tld')
         self.assertEqual(rdom.target_host, 'external.host.tld')
         self.assertEqual(rdom.service.name, 'dummy')
         self.assertEqual(rdom.domain.enabled, True)
@@ -138,16 +140,16 @@ class RelayDomainsTestCase(ModoTestCase, Operations):
         Rename 'relaydomain.tld' domain to 'relaydomain.org'
         """
         values = {
-            'name': "relaydomain.org", "target_host": self.rdom.target_host,
+            "name": "relaydomain.org", "target_host": self.rdom.target_host,
             "type": "relaydomain", "enabled": True,
             "service": self.rdom.service.id
         }
         self.ajax_post(
-            reverse('admin:domain_change',
+            reverse("admin:domain_change",
                     args=[self.rdom.domain.id]),
             values
         )
-        RelayDomain.objects.get(domain__name='relaydomain.org')
+        models.RelayDomain.objects.get(domain__name='relaydomain.org')
 
     def test_relaydomain_domain_switch(self):
         """Check domain <-> relaydomain transitions."""
@@ -156,12 +158,13 @@ class RelayDomainsTestCase(ModoTestCase, Operations):
             "name": "relaydomain.tld",
             "type": "domain",
             "enabled": True,
+            "target_host": self.rdom.target_host,
+            "service": self.rdom.service.pk
         }
         self.ajax_post(
-            reverse('admin:domain_change', args=[domain.pk]), values)
+            reverse("admin:domain_change", args=[domain.pk]), values)
         self.assertFalse(
-            RelayDomain.objects.filter(
-                domain__name="relaydomain.tld").exists())
+            models.RelayDomain.objects.filter(domain=domain).exists())
         self.assertEqual(
             admin_models.Domain.objects.get(name="relaydomain.tld").type,
             "domain")
@@ -176,7 +179,7 @@ class RelayDomainsTestCase(ModoTestCase, Operations):
             admin_models.Domain.objects.get(name="relaydomain.tld").type,
             "relaydomain")
         self.assertTrue(
-            RelayDomain.objects.filter(
+            models.RelayDomain.objects.filter(
                 domain__name="relaydomain.tld").exists())
 
     def test_edit_relaydomainalias(self):
@@ -205,16 +208,16 @@ class RelayDomainsTestCase(ModoTestCase, Operations):
                     args=[self.rdom.domain.id]),
             {}
         )
-        with self.assertRaises(RelayDomain.DoesNotExist):
-            RelayDomain.objects.get(domain__name='relaydomain.tld')
+        with self.assertRaises(models.RelayDomain.DoesNotExist):
+            models.RelayDomain.objects.get(domain__name='relaydomain.tld')
 
     def test_delete_relaydomainalias(self):
         """Test the removal of a relay domain alias."""
         self._relay_domain_alias_operation(
             'del', self.rdom.domain.name, 'relaydomainalias.tld'
         )
-        with self.assertRaises(RelayDomain.DoesNotExist):
-            RelayDomain.objects.get(domain__name='relaydomainalias.tld')
+        with self.assertRaises(models.RelayDomain.DoesNotExist):
+            models.RelayDomain.objects.get(domain__name='relaydomainalias.tld')
 
     def test_alias_on_relaydomain(self):
         """Create an alias on a relay domain."""

Fixed tests.