def test_exclude_multiple(self):
        """Show that passing a sequence to exclude excludes them all."""
        SimpleEvent.notify('*****@*****.**').activate().save()
        user1 = user(email='*****@*****.**', save=True)
        SimpleEvent.notify(user1).activate().save()
        user2 = user(email='*****@*****.**', save=True)
        SimpleEvent.notify(user2).activate().save()

        SimpleEvent().fire(exclude=[user1, user2])

        eq_(1, len(mail.outbox))
        eq_(['*****@*****.**'], mail.outbox[0].to)
    def test_filtered(self):
        """Make sure watches cull properly by additional filters."""
        # A watch with just the filter we're searching for:
        registered_user = user(email='*****@*****.**', save=True)
        exact_watch = watch(event_type=TYPE, user=registered_user, save=True)
        watch_filter(watch=exact_watch, name='color', value=1).save()

        # A watch with extra filters:
        extra_watch = watch(event_type=TYPE, email='*****@*****.**', save=True)
        watch_filter(watch=extra_watch, name='color', value=1).save()
        watch_filter(watch=extra_watch, name='flavor', value=2).save()

        # A watch with no row for the filter we're searching on:
        watch(event_type=TYPE, email='*****@*****.**').save()

        # A watch with a mismatching filter--shouldn't be found
        mismatch_watch = watch(event_type=TYPE, email='*****@*****.**',
                               save=True)
        watch_filter(watch=mismatch_watch, name='color', value=3).save()

        self._emails_eq(['*****@*****.**', '*****@*****.**', '*****@*****.**'],
                        FilteredEvent(), color=1)

        # Search on multiple filters to test joining the filters table twice.
        # We provide values that match for both filters, as [email protected]
        # suffices to test exclusion.
        self._emails_eq(['*****@*****.**', '*****@*****.**', '*****@*****.**'],
                        FilteredEvent(), color=1, flavor=2)
 def test_simple(self):
     """Test whether a watch scoped only by event type fires for both
     anonymous and registered users."""
     registered_user = user(email='*****@*****.**', save=True)
     watch(event_type=TYPE, user=registered_user).save()
     watch(event_type=TYPE, email='*****@*****.**').save()
     watch(event_type='something else', email='*****@*****.**').save()
     self._emails_eq(['*****@*****.**', '*****@*****.**'], SimpleEvent())
    def test_duplicates(self):
        """Don't return duplicate email addresses."""
        watch(event_type=TYPE, user=user(email='*****@*****.**', save=True),
              save=True)
        watch(event_type=TYPE, email='*****@*****.**').save()
        watch(event_type=TYPE, email='*****@*****.**').save()
        eq_(3, Watch.objects.all().count())  # We created what we meant to.

        self._emails_eq(['*****@*****.**'], SimpleEvent())
    def test_merging(self):
        """Test that duplicate emails across multiple events get merged."""
        watch(event_type=TYPE, email='*****@*****.**').save()
        watch(event_type=TYPE, email='*****@*****.**').save()
        registered_user = user(email='*****@*****.**', save=True)
        watch(event_type=ANOTHER_TYPE, user=registered_user).save()

        self._emails_eq(['*****@*****.**', '*****@*****.**'],
                        EventUnion(SimpleEvent(), AnotherEvent()))
    def test_duplicates_case_insensitive(self):
        """De-duping should compare case-insensitively."""
        watch(event_type=TYPE, user=user(email='*****@*****.**', save=True),
              save=True)
        watch(event_type=TYPE, email='*****@*****.**').save()
        watch(event_type=TYPE, email='*****@*****.**').save()
        eq_(3, Watch.objects.all().count())  # We created what we meant to.

        addresses = [u.email
                     for u, w in SimpleEvent()._users_watching_by_filter()]
        eq_(1, len(addresses))
        eq_('*****@*****.**', addresses[0].lower())
    def test_mixed(self):
        """Make sure having mixed watches claims right ones."""
        # Watch before registering.
        watch(email='*****@*****.**', save=True)
        watch(email='*****@*****.**', save=True)

        # Register nobody.
        user(email='*****@*****.**', save=True)

        # Then register somebody and watch something after registering.
        u = user(email='*****@*****.**', save=True)
        watch(user=u, save=True)

        claim_watches(u)

        # Original anonymous watch is claimed.
        assert not Watch.objects.filter(email='*****@*****.**').exists()
        eq_(2, Watch.objects.filter(email=None).count())

        # No other watches are affected.
        assert Watch.objects.filter(email='*****@*****.**').exists()
    def test_exclude(self):
        """Assert the `exclude` arg to fire() excludes the given user."""
        SimpleEvent.notify('*****@*****.**').activate().save()
        registered_user = user(email='*****@*****.**', save=True)
        SimpleEvent.notify(registered_user).activate().save()

        SimpleEvent().fire(exclude=registered_user)

        eq_(1, len(mail.outbox))
        first_mail = mail.outbox[0]
        eq_(['*****@*****.**'], first_mail.to)
        eq_('Subject!', first_mail.subject)
 def test_content_type(self):
     """Make sure watches filter properly by content type."""
     watch_type = ContentType.objects.get_for_model(Watch)
     content_type_type = ContentType.objects.get_for_model(ContentType)
     registered_user = user(email='*****@*****.**', save=True)
     watch(event_type=TYPE, content_type=content_type_type,
           user=registered_user).save()
     watch(event_type=TYPE, content_type=content_type_type,
           email='*****@*****.**').save()
     watch(event_type=TYPE, content_type=watch_type,
           email='*****@*****.**').save()
     self._emails_eq(['*****@*****.**', '*****@*****.**'],
                     ContentTypeEvent())
    def test_registered_users_favored(self):
        """When removing duplicates, make sure registered users are kept in
        favor of anonymous ones having the same email address."""
        def make_anonymous_watches():
            for x in xrange(3):
                watch(event_type=TYPE, email='*****@*****.**').save()

        # Throw some anonymous watches in there in the hope that they would
        # come out on top if we didn't purposely favor registered users.
        # Suggestions on how to make this test more reliable are welcome.
        make_anonymous_watches()

        # File the registered watch:
        watch(event_type=TYPE,
              user=user(first_name='Jed', email='*****@*****.**',
                        save=True)).save()

        # A few more anonymous watches in case the BTrees flop in the other
        # direction:
        make_anonymous_watches()

        users_and_watches = list(SimpleEvent()._users_watching_by_filter())
        u, w = users_and_watches[0]
        eq_('Jed', u.first_name)
    def test_unique_by_email_watch_collection(self):
        """Make sure _unique_by_email() collects all watches in each cluster."""
        w1, w2, w3 = watch(), watch(), watch(email='hi')
        w4, w5, w6 = watch(), watch(), watch(email='lo')
        users_and_watches = [
            (user(email='hi'), [w1]),
            (user(email='hi'), [w2]),
            (user(), [w3]),

            (user(email='lo'), [w4]),
            (user(email='lo'), [w5]),
            (user(), [w6])]
        result = list(_unique_by_email(users_and_watches))

        _, watches = result[0]
        eq_(set([w1, w2, w3]), set(watches))

        # Make sure the watches accumulator gets cleared between clusters:
        _, watches = result[1]
        eq_(set([w4, w5, w6]), set(watches))
 def _users_watching(self):
     return [(user(email='*****@*****.**'), [watch()])]
 def test_instance_registered(self):
     """Watch with a registered user."""
     registered_user = user(email='*****@*****.**', save=True)
     self._test_user_or_email(registered_user)
    def test_unique_by_email_user_selection(self):
        """Test the routine that sorts through users and watches having the
        same email addresses."""
        # Test the best in a cluster coming first, in the middle, and last.
        # We mark the correct choices with first_name='a'.
        users_and_watches = [
            (user(first_name='a', email='hi'), [watch()]),
            (user(email='hi'), [watch()]),
            (user(), [watch(email='hi')]),

            (user(), [watch(email='mid')]),
            (user(first_name='a', email='mid'), [watch()]),
            (user(), [watch(email='mid')]),

            (user(), [watch(email='lo')]),
            (user(), [watch(email='lo')]),
            (user(first_name='a', email='lo'), [watch()]),

            (user(), [watch(email='none', secret='a')]),
            (user(), [watch(email='none')])]

        favorites = list(_unique_by_email(users_and_watches))
        eq_(4, len(favorites))

        # Test that we chose the correct users, where there are distinguishable
        # (registered) users to choose from:
        eq_(['a'] * 3, [u.first_name for u, w in favorites[:3]])
 def test_notify_idempotence(self):
     """Assure notify() returns an existing watch when possible."""
     u = user(save=True)
     w = FilteredContentTypeEvent.notify(u, color=3, flavor=4)
     eq_(w.pk, FilteredContentTypeEvent.notify(u, color=3, flavor=4).pk)
     eq_(1, Watch.objects.all().count())
 def _users_watching(self):
     return [(user(email='*****@*****.**'), [watch()]),
             (user(email='*****@*****.**'), [watch()])]
 def test_none(self):
     """No anonymous watches to claim."""
     u = user(email='*****@*****.**', save=True)
     claim_watches(u)
 def test_unsaved_exclude(self):
     """Excluding an unsaved user should throw a ValueError."""
     self.assertRaises(ValueError,
                       SimpleEvent()._users_watching_by_filter,
                       exclude=user())