Esempio n. 1
0
    def setUp(self):
        """
        Create a newsletter, newsletter issue and some
        subscriptions to test with.
        """
        # Create some newsletters
        self.newsletter1 = _make_newsletter("Test Newsletter 1")
        self.newsletter2 = _make_newsletter("Test Newsletter 2")

        # Create some approvers
        self.newsletter1.approvers = """\
        [email protected]
        [email protected]
        [email protected]
        [email protected]"""
        self.newsletter1.save()

        self.template = "<html><head></head><body><h1>Test</h1></body></html>"

        self.plaintext = "****\nTest\n****"

        # Create an issue for each newsletter
        self.newsletter_issue1 = NewsletterIssue()
        self.newsletter_issue1.subject = 'Test Newsletter Issue 1'
        self.newsletter_issue1.template = self.template
        self.newsletter_issue1.newsletter = self.newsletter1
        self.newsletter_issue1.save()

        self.newsletter_issue2 = NewsletterIssue()
        self.newsletter_issue2.subject = 'Test Newsletter Issue 2'
        self.newsletter_issue2.template = self.template
        self.newsletter_issue2.newsletter = self.newsletter2
        self.newsletter_issue2.save()

        # Create some email addresses and subscribe them to a newsletter
        emails = [
            '*****@*****.**', '*****@*****.**',
            '*****@*****.**'
        ]
        for email in emails:
            email_address = EmailAddress.objects.create_with_random_token(
                email=email)
            email_address.confirmed = True
            email_address.save()
            Subscription.objects.create(email_address=email_address,
                                        newsletter=self.newsletter1)

        # Create an unconfirmed email address
        self.unconfirmed_email = EmailAddress.objects.create_with_random_token(
            '*****@*****.**')
        Subscription.objects.create(email_address=self.unconfirmed_email,
                                    newsletter=self.newsletter1)

        # Create an extra email address and subscribe it to the second newsletter
        self.exclude_email = EmailAddress.objects.create_with_random_token(
            '*****@*****.**')
        self.exclude_email.confirmed = True
        self.exclude_email.save()
        Subscription.objects.create(email_address=self.exclude_email,
                                    newsletter=self.newsletter2)
Esempio n. 2
0
    def test_default_tracking_domain(self):
        """
        Verify that on save a NewsletterIssue is assigned
        a default tracking domain from the parent Newsletter.
        """
        tracking_domain = 'darkhorse.com'
        self.newsletter1.default_tracking_domain = tracking_domain
        self.newsletter1.save()

        # Sanity check
        self.assertEqual(self.newsletter1.default_tracking_domain,
                         tracking_domain)

        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.newsletter = self.newsletter1
        issue.save()

        self.assertTrue(issue.tracking_domain not in (
            '',
            None,
        ))
        self.assertEqual(issue.tracking_domain,
                         issue.newsletter.default_tracking_domain)

        # Verify an existing tracking domain is not overwritten
        tracking_domain = 'tfaw.com'
        issue.tracking_domain = tracking_domain
        issue.save()

        self.assertEqual(tracking_domain, issue.tracking_domain)
        self.assertNotEqual(issue.tracking_domain,
                            issue.newsletter.default_tracking_domain)
Esempio n. 3
0
    def test_default_template(self):
        """
        Verify that on save a NewsletterIssue is assigned
        a default template from the parent Newsletter.
        """
        template_name = 'nova/test.html'
        self.newsletter1.default_template = template_name
        self.newsletter1.save()

        # Sanity check
        self.assertEqual(self.newsletter1.default_template, template_name)

        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.newsletter = self.newsletter1
        issue.save()

        self.assertTrue(issue.template not in (
            '',
            None,
        ))

        context = Context({})
        expected_template = render_to_string(template_name, context)
        issue_template = Template(issue.template).render(context)
        self.assertEqual(expected_template, issue_template)

        # Verify an existing template is not overwritten
        new_template = 'hai'
        issue.template = new_template
        issue.save()
        self.assertEqual(new_template,
                         NewsletterIssue.objects.get(pk=issue.pk).template)
Esempio n. 4
0
    def setUp(self):
        """
        Create a newsletter, newsletter issue and some
        subscriptions to test with.
        """
        # Create some newsletters
        self.newsletter1 = _make_newsletter("Test Newsletter 1")
        self.newsletter2 = _make_newsletter("Test Newsletter 2")

        # Create some approvers
        self.newsletter1.approvers = """\
        [email protected]
        [email protected]
        [email protected]
        [email protected]"""
        self.newsletter1.save()

        self.template = "<html><head></head><body><h1>Test</h1></body></html>"

        self.plaintext = "****\nTest\n****"

        # Create an issue for each newsletter
        self.newsletter_issue1 = NewsletterIssue()
        self.newsletter_issue1.subject = 'Test Newsletter Issue 1'
        self.newsletter_issue1.template = self.template
        self.newsletter_issue1.newsletter = self.newsletter1
        self.newsletter_issue1.save()

        self.newsletter_issue2 = NewsletterIssue()
        self.newsletter_issue2.subject = 'Test Newsletter Issue 2'
        self.newsletter_issue2.template = self.template
        self.newsletter_issue2.newsletter = self.newsletter2
        self.newsletter_issue2.save()

        # Create some email addresses and subscribe them to a newsletter
        emails = ['*****@*****.**', '*****@*****.**', '*****@*****.**']
        for email in emails:
            email_address = EmailAddress.objects.create_with_random_token(email=email)
            email_address.confirmed = True
            email_address.save()
            Subscription.objects.create(email_address=email_address, newsletter=self.newsletter1)

        # Create an unconfirmed email address
        self.unconfirmed_email = EmailAddress.objects.create_with_random_token('*****@*****.**')
        Subscription.objects.create(email_address=self.unconfirmed_email, newsletter=self.newsletter1)

        # Create an extra email address and subscribe it to the second newsletter
        self.exclude_email = EmailAddress.objects.create_with_random_token('*****@*****.**')
        self.exclude_email.confirmed = True
        self.exclude_email.save()
        Subscription.objects.create(email_address=self.exclude_email, newsletter=self.newsletter2)
Esempio n. 5
0
    def test_render(self):
        """
        Verify that the NewsletterIssue template is correctly
        rendered.
        """
        email = '*****@*****.**'

        template = """\
        Issue ID: {{ issue.pk }}
        Date: {% now "Y-m-d" %}
        Email: {{ email }}"""

        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.template = template
        issue.newsletter = self.newsletter1
        issue.save()

        expected_template = """\
        Issue ID: {issue_id}
        Date: {date:%Y-%m-%d}
        Email: {email}""".format(issue_id=issue.pk,
                                 date=datetime.now(),
                                 email=email)

        rendered_template = issue.render(template=template,
                                         extra_context={'email': email})
        self.assertEqual(rendered_template, expected_template)
Esempio n. 6
0
    def test_default_tracking_domain(self):
        """
        Verify that on save a NewsletterIssue is assigned
        a default tracking domain from the parent Newsletter.
        """
        tracking_domain = 'darkhorse.com'
        self.newsletter1.default_tracking_domain = tracking_domain
        self.newsletter1.save()

        # Sanity check
        self.assertEqual(self.newsletter1.default_tracking_domain, tracking_domain)

        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.newsletter = self.newsletter1
        issue.save()

        self.assertTrue(issue.tracking_domain not in ('', None,))
        self.assertEqual(issue.tracking_domain, issue.newsletter.default_tracking_domain)

        # Verify an existing tracking domain is not overwritten
        tracking_domain = 'tfaw.com'
        issue.tracking_domain = tracking_domain
        issue.save()

        self.assertEqual(tracking_domain, issue.tracking_domain)
        self.assertNotEqual(issue.tracking_domain, issue.newsletter.default_tracking_domain)
Esempio n. 7
0
    def test_default_template(self):
        """
        Verify that on save a NewsletterIssue is assigned
        a default template from the parent Newsletter.
        """
        template_name = 'nova/test.html'
        self.newsletter1.default_template = template_name
        self.newsletter1.save()

        # Sanity check
        self.assertEqual(self.newsletter1.default_template, template_name)

        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.newsletter = self.newsletter1
        issue.save()

        self.assertTrue(issue.template not in ('', None,))

        context = Context({})
        expected_template = render_to_string(template_name, context)
        issue_template = Template(issue.template).render(context)
        self.assertEqual(expected_template, issue_template)

        # Verify an existing template is not overwritten
        new_template = 'hai'
        issue.template = new_template
        issue.save()
        self.assertEqual(new_template,
            NewsletterIssue.objects.get(pk=issue.pk).template)
Esempio n. 8
0
    def test_render(self):
        """
        Verify that the NewsletterIssue template is correctly
        rendered.
        """
        email = '*****@*****.**'

        template = """\
        Issue ID: {{ issue.pk }}
        Date: {% now "Y-m-d" %}
        Email: {{ email }}"""
        
        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.template = template
        issue.newsletter = self.newsletter1
        issue.save()

        expected_template = """\
        Issue ID: {issue_id}
        Date: {date:%Y-%m-%d}
        Email: {email}""".format(issue_id=issue.pk, date=datetime.now(), email=email)

        rendered_template = issue.render(template=template, extra_context={'email': email})
        self.assertEqual(rendered_template, expected_template)
Esempio n. 9
0
    def test_nova_context_processors(self):
        """
        Verify that NewsletterIssues use NOVA_CONTEXT_PROCESSORS to render themselves when
        render() is called
        """
        old_settings = getattr(settings, 'NOVA_CONTEXT_PROCESSORS', '!unset')
        settings.NOVA_CONTEXT_PROCESSORS = ['nova.tests.test_context_processor']

        try:
            issue = NewsletterIssue(template="{{ test }}")
            issue.newsletter = self.newsletter1
            issue.save()

            self.assertEqual('extra test context', issue.render(extra_context={
                'email': EmailAddress(email='*****@*****.**')}))
        finally:
            if old_settings == '!unset':
                del settings.NOVA_CONTEXT_PROCESSORS
            else:
                settings.NOVA_CONTEXT_PROCESSORS = old_settings
Esempio n. 10
0
    def test_nova_context_processors(self):
        """
        Verify that NewsletterIssues use NOVA_CONTEXT_PROCESSORS to render themselves when
        render() is called
        """
        old_settings = getattr(settings, 'NOVA_CONTEXT_PROCESSORS', '!unset')
        settings.NOVA_CONTEXT_PROCESSORS = [
            'nova.tests.test_context_processor'
        ]

        try:
            issue = NewsletterIssue(template="{{ test }}")
            issue.newsletter = self.newsletter1
            issue.save()

            self.assertEqual(
                'extra test context',
                issue.render(extra_context={
                    'email': EmailAddress(email='*****@*****.**')
                }))
        finally:
            if old_settings == '!unset':
                del settings.NOVA_CONTEXT_PROCESSORS
            else:
                settings.NOVA_CONTEXT_PROCESSORS = old_settings
Esempio n. 11
0
class TestNewsletterIssueModel(TestCase):
    """
    Model API unit tests
    """
    def setUp(self):
        """
        Create a newsletter, newsletter issue and some
        subscriptions to test with.
        """
        # Create some newsletters
        self.newsletter1 = _make_newsletter("Test Newsletter 1")
        self.newsletter2 = _make_newsletter("Test Newsletter 2")

        # Create some approvers
        self.newsletter1.approvers = """\
        [email protected]
        [email protected]
        [email protected]
        [email protected]"""
        self.newsletter1.save()

        self.template = "<html><head></head><body><h1>Test</h1></body></html>"

        self.plaintext = "****\nTest\n****"

        # Create an issue for each newsletter
        self.newsletter_issue1 = NewsletterIssue()
        self.newsletter_issue1.subject = 'Test Newsletter Issue 1'
        self.newsletter_issue1.template = self.template
        self.newsletter_issue1.newsletter = self.newsletter1
        self.newsletter_issue1.save()

        self.newsletter_issue2 = NewsletterIssue()
        self.newsletter_issue2.subject = 'Test Newsletter Issue 2'
        self.newsletter_issue2.template = self.template
        self.newsletter_issue2.newsletter = self.newsletter2
        self.newsletter_issue2.save()

        # Create some email addresses and subscribe them to a newsletter
        emails = [
            '*****@*****.**', '*****@*****.**',
            '*****@*****.**'
        ]
        for email in emails:
            email_address = EmailAddress.objects.create_with_random_token(
                email=email)
            email_address.confirmed = True
            email_address.save()
            Subscription.objects.create(email_address=email_address,
                                        newsletter=self.newsletter1)

        # Create an unconfirmed email address
        self.unconfirmed_email = EmailAddress.objects.create_with_random_token(
            '*****@*****.**')
        Subscription.objects.create(email_address=self.unconfirmed_email,
                                    newsletter=self.newsletter1)

        # Create an extra email address and subscribe it to the second newsletter
        self.exclude_email = EmailAddress.objects.create_with_random_token(
            '*****@*****.**')
        self.exclude_email.confirmed = True
        self.exclude_email.save()
        Subscription.objects.create(email_address=self.exclude_email,
                                    newsletter=self.newsletter2)

    def test_default_template(self):
        """
        Verify that on save a NewsletterIssue is assigned
        a default template from the parent Newsletter.
        """
        template_name = 'nova/test.html'
        self.newsletter1.default_template = template_name
        self.newsletter1.save()

        # Sanity check
        self.assertEqual(self.newsletter1.default_template, template_name)

        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.newsletter = self.newsletter1
        issue.save()

        self.assertTrue(issue.template not in (
            '',
            None,
        ))

        context = Context({})
        expected_template = render_to_string(template_name, context)
        issue_template = Template(issue.template).render(context)
        self.assertEqual(expected_template, issue_template)

        # Verify an existing template is not overwritten
        new_template = 'hai'
        issue.template = new_template
        issue.save()
        self.assertEqual(new_template,
                         NewsletterIssue.objects.get(pk=issue.pk).template)

    def test_default_tracking_domain(self):
        """
        Verify that on save a NewsletterIssue is assigned
        a default tracking domain from the parent Newsletter.
        """
        tracking_domain = 'darkhorse.com'
        self.newsletter1.default_tracking_domain = tracking_domain
        self.newsletter1.save()

        # Sanity check
        self.assertEqual(self.newsletter1.default_tracking_domain,
                         tracking_domain)

        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.newsletter = self.newsletter1
        issue.save()

        self.assertTrue(issue.tracking_domain not in (
            '',
            None,
        ))
        self.assertEqual(issue.tracking_domain,
                         issue.newsletter.default_tracking_domain)

        # Verify an existing tracking domain is not overwritten
        tracking_domain = 'tfaw.com'
        issue.tracking_domain = tracking_domain
        issue.save()

        self.assertEqual(tracking_domain, issue.tracking_domain)
        self.assertNotEqual(issue.tracking_domain,
                            issue.newsletter.default_tracking_domain)

    def test_premailer(self):
        """
        If the premailer script is enabled, test the premailer method
        which calls out to the external script.
        """
        if getattr(settings, 'NOVA_USE_PREMAILER', False):
            template = """\
            <html>
            <head>
            <style>
            .foo {
                color: red;
            }
            </style>
            </head>
            <body>
            <p class="foo">Some Text</p>
            </body>
            </html>"""

            expected_html = """\
            <html>
            <head>
            
            </head>
            <body>
            <p class="foo" style="color: red;">Some Text</p>
            </body>
            </html>"""

            # Ensure the expected html has been returned from premailer
            premailed_html = self.newsletter_issue1.premailer(template)
            self.assertEqual(premailed_html, expected_html)

            # Ensure that the expected plaintext has been returned from premailer
            premailed_plaintext = self.newsletter_issue1.premailer(
                template, plaintext=True)
            self.assertTrue('Some Text' in premailed_plaintext)
            self.assertTrue('html' not in premailed_plaintext)
        else:
            print '\nNOVA_USE_PREMAILER is False or undefined. Skipping...'

    def test_premail(self):
        """
        Ensure that the premail method calls the expected helper
        functions on the newsletter template. The helper functions themselves
        are to be tested separately.
        """
        with patch(
                'nova.models.canonicalize_links') as mock_canonicalize_links:
            self.newsletter_issue1.premail(track=False)
            self.assertTrue(mock_canonicalize_links.called)

        with patch('nova.models.track_document') as mock_track_document:
            self.newsletter_issue1.premail(canonicalize=False)
            self.assertTrue(mock_track_document.called)

        if getattr(settings, 'NOVA_USE_PREMAILER', False):
            with patch(
                    'nova.models.NewsletterIssue.premailer') as mock_premailer:
                html, plaintext = self.newsletter_issue1.premail()
                self.assertTrue(mock_premailer.called)
                self.assertTrue(html is not None)
                self.assertTrue(plaintext is not None)

    def test_render(self):
        """
        Verify that the NewsletterIssue template is correctly
        rendered.
        """
        email = '*****@*****.**'

        template = """\
        Issue ID: {{ issue.pk }}
        Date: {% now "Y-m-d" %}
        Email: {{ email }}"""

        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.template = template
        issue.newsletter = self.newsletter1
        issue.save()

        expected_template = """\
        Issue ID: {issue_id}
        Date: {date:%Y-%m-%d}
        Email: {email}""".format(issue_id=issue.pk,
                                 date=datetime.now(),
                                 email=email)

        rendered_template = issue.render(template=template,
                                         extra_context={'email': email})
        self.assertEqual(rendered_template, expected_template)

    def test_nova_context_processors(self):
        """
        Verify that NewsletterIssues use NOVA_CONTEXT_PROCESSORS to render themselves when
        render() is called
        """
        old_settings = getattr(settings, 'NOVA_CONTEXT_PROCESSORS', '!unset')
        settings.NOVA_CONTEXT_PROCESSORS = [
            'nova.tests.test_context_processor'
        ]

        try:
            issue = NewsletterIssue(template="{{ test }}")
            issue.newsletter = self.newsletter1
            issue.save()

            self.assertEqual(
                'extra test context',
                issue.render(extra_context={
                    'email': EmailAddress(email='*****@*****.**')
                }))
        finally:
            if old_settings == '!unset':
                del settings.NOVA_CONTEXT_PROCESSORS
            else:
                settings.NOVA_CONTEXT_PROCESSORS = old_settings

    def test_send_test(self):
        """
        Verify the send_test method only sends an issue
        to the email addresses listed in the approvers field
        on the Newsletter model and doesn't blow up if approvers
        is empty.
        """
        approvers = self.newsletter1.approvers.split()
        self.assertEqual(len(approvers), 4)

        self.newsletter_issue1.send_test()

        self.assertEqual(len(mail.outbox), 4)

        expected_subject = "FOR APPROVERS: %s" % self.newsletter_issue1.subject

        for message in mail.outbox:
            self.assertTrue(message.to[0] in approvers)
            self.assertEqual(message.subject, expected_subject)
            self.assertEqual(message.alternatives[0][1], 'text/html')
            self.assertEqual(message.alternatives[0][0],
                             self.newsletter_issue1.template)

    def test_send(self):
        """
        Ensure that a newsletter issue is successfully sent
        to all *confirmed* subscribers of that newsletter.
        """
        self.assertEqual(self.newsletter1.subscribers.count(), 3)

        self.newsletter_issue1.send()

        self.assertEqual(len(mail.outbox), 3)

        for message in mail.outbox:
            self.assertNotEqual(self.unconfirmed_email.email, message.to[0])
            self.assertNotEqual(self.exclude_email.email, message.to[0])
            self.assertEqual(message.subject, self.newsletter_issue1.subject)
            self.assertEqual(message.alternatives[0][1], 'text/html')
            self.assertEqual(message.alternatives[0][0],
                             self.newsletter_issue1.template)

    def test_send_custom_list(self):
        """
        Ensure that a newsletter issue is successfully sent to
        a custom list of recipients.
        """
        emails = ['*****@*****.**', '*****@*****.**']
        email_addresses = []
        for email in emails:
            e = EmailAddress.objects.create(email=email)
            email_addresses.append(e)

        # Sanity Check
        self.assertEqual(len(email_addresses), 2)
        self.assertEqual(self.newsletter1.subscribers.count(), 3)

        self.newsletter_issue1.send(email_addresses=email_addresses)

        self.assertEqual(len(mail.outbox), 2)

        subscribers = [email.email for email in self.newsletter1.subscribers]

        for message in mail.outbox:
            self.assertTrue(message.to[0] not in subscribers)
            self.assertNotEqual(self.unconfirmed_email.email, message.to[0])
            self.assertNotEqual(self.exclude_email.email, message.to[0])
            self.assertEqual(message.subject, self.newsletter_issue1.subject)
            self.assertEqual(message.alternatives[0][1], 'text/html')
            self.assertEqual(message.alternatives[0][0],
                             self.newsletter_issue1.template)

    def test_send_unsubscribe(self):
        """
        Verify that a subscriber who once received issues, can
        successfully opt-out by unsubscribing.
        """
        newsletter_issue = self.newsletter_issue1
        email_address = newsletter_issue.newsletter.subscribers[0]

        # Unsubscribe email
        email_address.unsubscribe()

        # Verify unsubscribe
        self.assertTrue(
            email_address not in newsletter_issue.newsletter.subscribers)

        # Verify unsubscribed email not in sent issues
        newsletter_issue.send()

        for message in mail.outbox:
            self.assertNotEqual(email_address.email, message.to[0])
Esempio n. 12
0
class TestNewsletterIssueModel(TestCase):
    """
    Model API unit tests
    """
    def setUp(self):
        """
        Create a newsletter, newsletter issue and some
        subscriptions to test with.
        """
        # Create some newsletters
        self.newsletter1 = _make_newsletter("Test Newsletter 1")
        self.newsletter2 = _make_newsletter("Test Newsletter 2")

        # Create some approvers
        self.newsletter1.approvers = """\
        [email protected]
        [email protected]
        [email protected]
        [email protected]"""
        self.newsletter1.save()

        self.template = "<html><head></head><body><h1>Test</h1></body></html>"

        self.plaintext = "****\nTest\n****"

        # Create an issue for each newsletter
        self.newsletter_issue1 = NewsletterIssue()
        self.newsletter_issue1.subject = 'Test Newsletter Issue 1'
        self.newsletter_issue1.template = self.template
        self.newsletter_issue1.newsletter = self.newsletter1
        self.newsletter_issue1.save()

        self.newsletter_issue2 = NewsletterIssue()
        self.newsletter_issue2.subject = 'Test Newsletter Issue 2'
        self.newsletter_issue2.template = self.template
        self.newsletter_issue2.newsletter = self.newsletter2
        self.newsletter_issue2.save()

        # Create some email addresses and subscribe them to a newsletter
        emails = ['*****@*****.**', '*****@*****.**', '*****@*****.**']
        for email in emails:
            email_address = EmailAddress.objects.create_with_random_token(email=email)
            email_address.confirmed = True
            email_address.save()
            Subscription.objects.create(email_address=email_address, newsletter=self.newsletter1)

        # Create an unconfirmed email address
        self.unconfirmed_email = EmailAddress.objects.create_with_random_token('*****@*****.**')
        Subscription.objects.create(email_address=self.unconfirmed_email, newsletter=self.newsletter1)

        # Create an extra email address and subscribe it to the second newsletter
        self.exclude_email = EmailAddress.objects.create_with_random_token('*****@*****.**')
        self.exclude_email.confirmed = True
        self.exclude_email.save()
        Subscription.objects.create(email_address=self.exclude_email, newsletter=self.newsletter2)

    def test_default_template(self):
        """
        Verify that on save a NewsletterIssue is assigned
        a default template from the parent Newsletter.
        """
        template_name = 'nova/test.html'
        self.newsletter1.default_template = template_name
        self.newsletter1.save()

        # Sanity check
        self.assertEqual(self.newsletter1.default_template, template_name)

        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.newsletter = self.newsletter1
        issue.save()

        self.assertTrue(issue.template not in ('', None,))

        context = Context({})
        expected_template = render_to_string(template_name, context)
        issue_template = Template(issue.template).render(context)
        self.assertEqual(expected_template, issue_template)

        # Verify an existing template is not overwritten
        new_template = 'hai'
        issue.template = new_template
        issue.save()
        self.assertEqual(new_template,
            NewsletterIssue.objects.get(pk=issue.pk).template)

    def test_default_tracking_domain(self):
        """
        Verify that on save a NewsletterIssue is assigned
        a default tracking domain from the parent Newsletter.
        """
        tracking_domain = 'darkhorse.com'
        self.newsletter1.default_tracking_domain = tracking_domain
        self.newsletter1.save()

        # Sanity check
        self.assertEqual(self.newsletter1.default_tracking_domain, tracking_domain)

        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.newsletter = self.newsletter1
        issue.save()

        self.assertTrue(issue.tracking_domain not in ('', None,))
        self.assertEqual(issue.tracking_domain, issue.newsletter.default_tracking_domain)

        # Verify an existing tracking domain is not overwritten
        tracking_domain = 'tfaw.com'
        issue.tracking_domain = tracking_domain
        issue.save()

        self.assertEqual(tracking_domain, issue.tracking_domain)
        self.assertNotEqual(issue.tracking_domain, issue.newsletter.default_tracking_domain)

    def test_premailer(self):
        """
        If the premailer script is enabled, test the premailer method
        which calls out to the external script.
        """
        if getattr(settings, 'NOVA_USE_PREMAILER', False):
            template = """\
            <html>
            <head>
            <style>
            .foo {
                color: red;
            }
            </style>
            </head>
            <body>
            <p class="foo">Some Text</p>
            </body>
            </html>"""

            expected_html = """\
            <html>
            <head>
            
            </head>
            <body>
            <p class="foo" style="color: red;">Some Text</p>
            </body>
            </html>"""

            # Ensure the expected html has been returned from premailer
            premailed_html = self.newsletter_issue1.premailer(template)
            self.assertEqual(premailed_html, expected_html)

            # Ensure that the expected plaintext has been returned from premailer
            premailed_plaintext = self.newsletter_issue1.premailer(template, plaintext=True)
            self.assertTrue('Some Text' in premailed_plaintext)
            self.assertTrue('html' not in premailed_plaintext)
        else:
            print '\nNOVA_USE_PREMAILER is False or undefined. Skipping...'

    def test_premail(self):
        """
        Ensure that the premail method calls the expected helper
        functions on the newsletter template. The helper functions themselves
        are to be tested separately.
        """
        with patch('nova.models.canonicalize_links') as mock_canonicalize_links:
            self.newsletter_issue1.premail(track=False)
            self.assertTrue(mock_canonicalize_links.called)

        with patch('nova.models.track_document') as mock_track_document:
            self.newsletter_issue1.premail(canonicalize=False)
            self.assertTrue(mock_track_document.called)

        if getattr(settings, 'NOVA_USE_PREMAILER', False):
            with patch('nova.models.NewsletterIssue.premailer') as mock_premailer:
                html, plaintext = self.newsletter_issue1.premail()
                self.assertTrue(mock_premailer.called)
                self.assertTrue(html is not None)
                self.assertTrue(plaintext is not None)

    def test_render(self):
        """
        Verify that the NewsletterIssue template is correctly
        rendered.
        """
        email = '*****@*****.**'

        template = """\
        Issue ID: {{ issue.pk }}
        Date: {% now "Y-m-d" %}
        Email: {{ email }}"""
        
        issue = NewsletterIssue()
        issue.subject = 'Test'
        issue.template = template
        issue.newsletter = self.newsletter1
        issue.save()

        expected_template = """\
        Issue ID: {issue_id}
        Date: {date:%Y-%m-%d}
        Email: {email}""".format(issue_id=issue.pk, date=datetime.now(), email=email)

        rendered_template = issue.render(template=template, extra_context={'email': email})
        self.assertEqual(rendered_template, expected_template)

    def test_nova_context_processors(self):
        """
        Verify that NewsletterIssues use NOVA_CONTEXT_PROCESSORS to render themselves when
        render() is called
        """
        old_settings = getattr(settings, 'NOVA_CONTEXT_PROCESSORS', '!unset')
        settings.NOVA_CONTEXT_PROCESSORS = ['nova.tests.test_context_processor']

        try:
            issue = NewsletterIssue(template="{{ test }}")
            issue.newsletter = self.newsletter1
            issue.save()

            self.assertEqual('extra test context', issue.render(extra_context={
                'email': EmailAddress(email='*****@*****.**')}))
        finally:
            if old_settings == '!unset':
                del settings.NOVA_CONTEXT_PROCESSORS
            else:
                settings.NOVA_CONTEXT_PROCESSORS = old_settings
    
    def test_send_test(self):
        """
        Verify the send_test method only sends an issue
        to the email addresses listed in the approvers field
        on the Newsletter model and doesn't blow up if approvers
        is empty.
        """
        approvers = self.newsletter1.approvers.split()
        self.assertEqual(len(approvers), 4)

        self.newsletter_issue1.send_test()

        self.assertEqual(len(mail.outbox), 4)

        expected_subject = "FOR APPROVERS: %s" % self.newsletter_issue1.subject
        
        for message in mail.outbox:
            self.assertTrue(message.to[0] in approvers)
            self.assertEqual(message.subject, expected_subject)
            self.assertEqual(message.alternatives[0][1], 'text/html')
            self.assertEqual(message.alternatives[0][0], self.newsletter_issue1.template)

    def test_send(self):
        """
        Ensure that a newsletter issue is successfully sent
        to all *confirmed* subscribers of that newsletter.
        """
        self.assertEqual(self.newsletter1.subscribers.count(), 3)

        self.newsletter_issue1.send()

        self.assertEqual(len(mail.outbox), 3)

        for message in mail.outbox:
            self.assertNotEqual(self.unconfirmed_email.email, message.to[0])
            self.assertNotEqual(self.exclude_email.email, message.to[0])
            self.assertEqual(message.subject, self.newsletter_issue1.subject)
            self.assertEqual(message.alternatives[0][1], 'text/html')
            self.assertEqual(message.alternatives[0][0], self.newsletter_issue1.template)

    def test_send_custom_list(self):
        """
        Ensure that a newsletter issue is successfully sent to
        a custom list of recipients.
        """
        emails = ['*****@*****.**', '*****@*****.**']
        email_addresses = []
        for email in emails:
            e = EmailAddress.objects.create(email=email)
            email_addresses.append(e)
            
        # Sanity Check
        self.assertEqual(len(email_addresses), 2)
        self.assertEqual(self.newsletter1.subscribers.count(), 3)

        self.newsletter_issue1.send(email_addresses=email_addresses)

        self.assertEqual(len(mail.outbox), 2)

        subscribers = [email.email for email in self.newsletter1.subscribers]

        for message in mail.outbox:
            self.assertTrue(message.to[0] not in subscribers)
            self.assertNotEqual(self.unconfirmed_email.email, message.to[0])
            self.assertNotEqual(self.exclude_email.email, message.to[0])
            self.assertEqual(message.subject, self.newsletter_issue1.subject)
            self.assertEqual(message.alternatives[0][1], 'text/html')
            self.assertEqual(message.alternatives[0][0], self.newsletter_issue1.template)

    def test_send_unsubscribe(self):
        """
        Verify that a subscriber who once received issues, can
        successfully opt-out by unsubscribing.
        """
        newsletter_issue = self.newsletter_issue1
        email_address = newsletter_issue.newsletter.subscribers[0]

        # Unsubscribe email
        email_address.unsubscribe()

        # Verify unsubscribe
        self.assertTrue(email_address not in newsletter_issue.newsletter.subscribers)

        # Verify unsubscribed email not in sent issues
        newsletter_issue.send()

        for message in mail.outbox:
            self.assertNotEqual(email_address.email, message.to[0])