Beispiel #1
0
 def test_submitted_data(self):
     dsa = DocumentSpamAttempt(data=None)
     assert self.admin.submitted_data(dsa) == SUBMISSION_NOT_AVAILABLE
     data = '{"foo": "bar"}'
     dsa.data = data
     expected = '\n'.join(('<dl>', '  <dt>foo</dt><dd>bar</dd>', '</dl>'))
     assert self.admin.submitted_data(dsa) == expected
Beispiel #2
0
 def test_submitted_data(self):
     dsa = DocumentSpamAttempt(data=None)
     expected = self.admin.SUBMISSION_NOT_AVAILABLE
     assert self.admin.submitted_data(dsa) == expected
     dsa.data = '{"foo": "bar"}'
     assert self.admin.submitted_data(dsa) == ('{\n'
                                               '    "foo": "bar"\n'
                                               '}')
Beispiel #3
0
 def test_submitted_data(self):
     dsa = DocumentSpamAttempt(data=None)
     expected = self.admin.SUBMISSION_NOT_AVAILABLE
     assert self.admin.submitted_data(dsa) == expected
     dsa.data = '{"foo": "bar"}'
     assert self.admin.submitted_data(dsa) == (
         '{\n'
         '    "foo": "bar"\n'
         '}')
Beispiel #4
0
 def test_submitted_data(self):
     dsa = DocumentSpamAttempt(data=None)
     assert self.admin.submitted_data(dsa) == SUBMISSION_NOT_AVAILABLE
     data = '{"foo": "bar"}'
     dsa.data = data
     expected = '\n'.join((
         '<dl>',
         '  <dt>foo</dt><dd>bar</dd>',
         '</dl>'))
     assert self.admin.submitted_data(dsa) == expected
Beispiel #5
0
 def test_save_no_review(self, mock_requests):
     dsa = DocumentSpamAttempt(user=self.user,
                               title='Not reviewed',
                               slug='test/spam')
     assert not DocumentSpamAttempt.objects.exists()
     self.admin.save_model(self.request, dsa, None, True)
     self.assert_needs_review()
Beispiel #6
0
 def test_doc_short_short_slug_and_title(self):
     slug = 'NotSpam'
     html = '<p>This page is not spam.</p>'
     doc = document(title='blah', slug=slug, html=html, save=True)
     revision(document=doc, content=html, is_approved=True, save=True)
     dsa = DocumentSpamAttempt(slug=slug, document=doc)
     assert self.admin.doc_short(dsa) == u'/en-US/docs/NotSpam (blah)'
     assert self.admin.doc_short(dsa) == str(doc)
Beispiel #7
0
 def test_save_no_data(self, mock_requests):
     dsa = DocumentSpamAttempt(user=self.user,
                               title='No data',
                               slug='test/spam',
                               review=DocumentSpamAttempt.HAM)
     assert not DocumentSpamAttempt.objects.exists()
     self.admin.save_model(self.request, dsa, None, True)
     dsa = DocumentSpamAttempt.objects.get()
     assert dsa.review == DocumentSpamAttempt.HAM
     assert dsa.reviewer == self.admin_user
     assert dsa.reviewed is not None
Beispiel #8
0
 def test_save_false_positive_no_submission_flag(self, mock_requests):
     dsa = DocumentSpamAttempt(user=self.user,
                               title='No data',
                               slug='test/spam',
                               data=self.sample_data,
                               review=DocumentSpamAttempt.HAM)
     assert not DocumentSpamAttempt.objects.exists()
     mock_requests.post(VERIFY_URL, content='valid')
     mock_requests.post(HAM_URL, content=Akismet.submission_success)
     self.admin.save_model(self.request, dsa, None, True)
     self.assert_needs_review()
Beispiel #9
0
 def test_save_confirm_spam(self, mock_requests):
     dsa = DocumentSpamAttempt(user=self.user,
                               title='Confirmed as Spam',
                               slug='test/spam',
                               data=self.sample_data,
                               review=DocumentSpamAttempt.SPAM)
     assert not DocumentSpamAttempt.objects.exists()
     self.admin.save_model(self.request, dsa, None, True)
     dsa = DocumentSpamAttempt.objects.get()
     assert dsa.review == DocumentSpamAttempt.SPAM
     assert dsa.reviewer == self.admin_user
     assert dsa.reviewed is not None
Beispiel #10
0
 def test_doc_short_long_unicode(self):
     slug = u'Web/Guide/HTML/HTML5_ডকুমেন্টের_সেকশন_এবং_আউটলাইন'
     title = u'HTML5 ডকুমেন্টের সেকশন এবং আউটলাইন'
     html = '<p>This Bengali page is not spam.</p>'
     doc = document(title=title,
                    slug=slug,
                    html=html,
                    save=True,
                    locale='bn-BD')
     revision(document=doc, content=html, is_approved=True, save=True)
     dsa = DocumentSpamAttempt(slug=slug, document=doc)
     expected = u'/bn-BD/docs/Web/Guide/HT… (HTML5 ডকুমেন্টের সেকশন এব…)'
     assert self.admin.doc_short(dsa) == expected
Beispiel #11
0
 def test_doc_short_long_slug_and_title(self):
     slug = 'Web/Guide/HTML/Sections_and_Outlines_of_an_HTML5_document'
     title = 'Sections and Outlines of an HTML5 Document'
     html = '<p>This German page is not spam.</p>'
     doc = document(title=title,
                    slug=slug,
                    html=html,
                    save=True,
                    locale='de')
     revision(document=doc, content=html, is_approved=True, save=True)
     dsa = DocumentSpamAttempt(slug=slug, document=doc)
     expected = u'/de/docs/Web/Guide/HTML/… (Sections and Outlines of…)'
     assert self.admin.doc_short(dsa) == expected
Beispiel #12
0
 def test_save_false_positive_no_akismet(self, mock_requests):
     flag, created = Flag.objects.get_or_create(name=SPAM_SUBMISSIONS_FLAG)
     flag.users.add(self.admin_user)
     dsa = DocumentSpamAttempt(user=self.user,
                               title='No data',
                               slug='test/spam',
                               data=self.sample_data,
                               review=DocumentSpamAttempt.HAM)
     assert not DocumentSpamAttempt.objects.exists()
     mock_requests.post(VERIFY_URL, content='valid')
     mock_requests.post(HAM_URL, content=Akismet.submission_success)
     self.admin.save_model(self.request, dsa, None, True)
     self.assert_needs_review()
Beispiel #13
0
 def test_title_short(self):
     dsa = DocumentSpamAttempt(title='A short title')
     assert self.admin.title_short(dsa) == 'A short title'
     dsa.title = 'A long title that will need to be truncated.'
     assert self.admin.title_short(dsa) == 'A long title that will...'
Beispiel #14
0
    def test_spam_trends_stats(self, mock_analytics_upageviews):
        """Test that the correct stats show up on the spam trends dashboard."""
        # Period length
        days_in_week = 7
        days_in_month = 28
        days_in_quarter = 91
        # Dates
        today = datetime.datetime.today()
        yesterday = today - datetime.timedelta(days=1)
        three_days_ago = today - datetime.timedelta(days=3)
        weekly_start_date = today - datetime.timedelta(days=days_in_week)
        ten_days_ago = today - datetime.timedelta(days=10)
        monthly_start_date = today - datetime.timedelta(days=days_in_month)
        thirtyfive_days_ago = today - datetime.timedelta(days=35)
        quarterly_start_date = today - datetime.timedelta(days=days_in_quarter)
        hundred_days_ago = today - datetime.timedelta(days=100)

        # Revisions made by self.testuser: 3 made today, 3 made 3 days ago,
        # 3 made 10 days ago, 3 made 35 days ago, 3 made 100 days ago
        revs = self.create_revisions(num=15, creator=self.testuser, document=self.document)
        for i in range(0, 3):
            revs[i].created = today
        for i in range(3, 6):
            revs[i].created = three_days_ago
        for i in range(6, 9):
            revs[i].created = ten_days_ago
        for i in range(9, 12):
            revs[i].created = thirtyfive_days_ago
        for i in range(12, 15):
            revs[i].created = hundred_days_ago
        for rev in revs:
            rev.save()

        # Published spam by self.testuser
        spam_rev_today = revs[2]
        spam_rev_3_days_ago = revs[5]
        spam_rev_10_days_ago = revs[8]
        spam_rev_35_days_ago = revs[11]
        spam_rev_100_days_ago = revs[14]
        spam_revs = [spam_rev_today, spam_rev_3_days_ago, spam_rev_10_days_ago,
                     spam_rev_35_days_ago, spam_rev_100_days_ago]
        # Summary of spam submissions
        spam_weekly = [spam_rev_3_days_ago]
        spam_monthly = [spam_rev_3_days_ago, spam_rev_10_days_ago]
        spam_quarterly = [spam_rev_3_days_ago, spam_rev_10_days_ago,
                          spam_rev_35_days_ago]
        # All of the spam_revs were published and then marked as spam
        for rev in spam_revs:
            rev.save()
            rev.akismet_submissions.add(RevisionAkismetSubmission(
                sender=self.admin, type="spam")
            )

        # Summary of self.testuser's ham submissions
        ham_weekly = revs[3:5]
        ham_monthly = revs[3:5] + revs[6:8]
        ham_quarterly = revs[3:5] + revs[6:8] + revs[9:11]

        # There were 2 correctly blocked spam attempts 3 days ago (within past week)
        true_blocked_spam_num = 2
        for i in range(0, true_blocked_spam_num):
            document_spam_rev_3_days_ago = DocumentSpamAttempt(
                user=self.testuser,
                title='A spam revision',
                slug='spam-revision-slug',
                document=self.document,
                review=DocumentSpamAttempt.SPAM
            )
            document_spam_rev_3_days_ago.save()
            document_spam_rev_3_days_ago.created = three_days_ago
            document_spam_rev_3_days_ago.save()

        # There was 1 incorrectly blocked spam attempt 3 days ago
        false_blocked_spam_num = 1
        for i in range(0, false_blocked_spam_num):
            document_ham_rev_3_days_ago = DocumentSpamAttempt(
                user=self.testuser,
                title='Not a spam revision',
                slug='ham-revision-slug',
                document=self.document,
                review=DocumentSpamAttempt.HAM
            )
            document_ham_rev_3_days_ago.save()
            document_ham_rev_3_days_ago.created = three_days_ago
            document_ham_rev_3_days_ago.save()

        page_views = {}
        # The spam from 3 days ago was seen 3 times, from 10 days ago see 10 times,
        # and from 35 days ago seen 35 times
        page_views[spam_rev_3_days_ago.id] = 3
        page_views[spam_rev_10_days_ago.id] = 10
        page_views[spam_rev_35_days_ago.id] = 35
        # The mock Google Analytics return values for page views
        mock_analytics_upageviews.return_value = page_views

        self.client.login(username='******', password='******')
        # The first response will say that the report is being processed
        response = self.client.get(reverse('dashboards.spam', locale='en-US'))
        eq_(200, response.status_code)

        response2 = self.client.get(reverse('dashboards.spam', locale='en-US'))
        page = pq(response2.content)

        row_daily = page.find('.spam-trends-table tbody tr')[0].text_content().replace(' ', '').strip('\n').split('\n')
        row_weekly = page.find('.spam-trends-table tbody tr')[1].text_content().replace(' ', '').strip('\n').split('\n')
        row_monthly = page.find('.spam-trends-table tbody tr')[2].text_content().replace(' ', '').strip('\n').split('\n')
        row_quarterly = page.find('.spam-trends-table tbody tr')[3].text_content().replace(' ', '').strip('\n').split('\n')

        # These are the columns in the spam dashboard spam trends table
        period = 0
        start_date = 1
        spam_viewers_change_percent = 2
        spam_viewers = 3
        daily_average_viewers = 4
        published_spam = 5
        blocked_spam = 6
        blocked_ham = 7
        true_positive_rate = 8
        true_negative_rate = 9

        # The periods are identified as 'Daily', 'Weekly', 'Monthly', 'Quarterly'
        eq_(row_daily[period], 'Daily')
        eq_(row_weekly[period], 'Weekly')
        eq_(row_monthly[period], 'Monthly')
        eq_(row_quarterly[period], 'Quarterly')
        # The start dates for each period are correct
        eq_(row_daily[start_date], yesterday.strftime('%Y-%m-%d'))
        eq_(row_weekly[start_date], weekly_start_date.strftime('%Y-%m-%d'))
        eq_(row_monthly[start_date], monthly_start_date.strftime('%Y-%m-%d'))
        eq_(row_quarterly[start_date], quarterly_start_date.strftime('%Y-%m-%d'))
        # The page views during the week, month, quarter
        spam_views_week = page_views[spam_rev_3_days_ago.id]
        spam_views_month = spam_views_week + page_views[spam_rev_10_days_ago.id]
        spam_views_month_exclude_week = page_views[spam_rev_10_days_ago.id]
        spam_views_quarter = spam_views_month + page_views[spam_rev_35_days_ago.id]
        spam_views_quarter_exclude_month = page_views[spam_rev_35_days_ago.id]
        # The percentage change in spam viewers
        weekly_spam_change_percent = '{:.1%}'.format(
            float(spam_views_week - spam_views_month_exclude_week) / spam_views_month_exclude_week
        )
        monthly_spam_change_percent = '{:.1%}'.format(
            float(spam_views_month - spam_views_quarter_exclude_month) / spam_views_quarter_exclude_month
        )
        eq_(row_daily[spam_viewers_change_percent], '0.0%')
        eq_(row_weekly[spam_viewers_change_percent], weekly_spam_change_percent)
        eq_(row_monthly[spam_viewers_change_percent], monthly_spam_change_percent)
        eq_(row_quarterly[spam_viewers_change_percent], '0.0%')
        # The spam viewers
        eq_(int(row_daily[spam_viewers]), 0)
        eq_(int(row_weekly[spam_viewers]), spam_views_week)
        eq_(int(row_monthly[spam_viewers]), spam_views_month)
        eq_(int(row_quarterly[spam_viewers]), spam_views_quarter)
        # The daily average of spam viewers
        eq_(float(row_daily[daily_average_viewers]), 0.0)
        eq_(row_weekly[daily_average_viewers],
            '{:.1f}'.format(float(spam_views_week) / days_in_week))
        eq_(row_monthly[daily_average_viewers],
            '{:.1f}'.format(float(spam_views_month) / days_in_month))
        eq_(row_quarterly[daily_average_viewers],
            '{:.1f}'.format(float(spam_views_quarter) / days_in_quarter))
        # The published spam: 1 this week, 2 this month, 3 this quarter
        eq_(int(row_daily[published_spam]), len([]))
        eq_(int(row_weekly[published_spam]), len(spam_weekly))
        eq_(int(row_monthly[published_spam]), len(spam_monthly))
        eq_(int(row_quarterly[published_spam]), len(spam_quarterly))
        # The blocked spam: there were 2 correctly blocked spam attempts 3 days ago
        eq_(int(row_daily[blocked_spam]), 0)
        eq_(int(row_weekly[blocked_spam]), true_blocked_spam_num)
        eq_(int(row_monthly[blocked_spam]), true_blocked_spam_num)
        eq_(int(row_quarterly[blocked_spam]), true_blocked_spam_num)
        # The blocked ham: there was 1 incorrectly blocked spam attempt 3 days ago
        eq_(int(row_daily[blocked_ham]), 0)
        eq_(int(row_weekly[blocked_ham]), false_blocked_spam_num)
        eq_(int(row_monthly[blocked_ham]), false_blocked_spam_num)
        eq_(int(row_quarterly[blocked_ham]), false_blocked_spam_num)
        # The true positive rate == blocked_spam / total spam
        tpr_weekly = '{:.1%}'.format(
            true_blocked_spam_num / float(true_blocked_spam_num + len(spam_weekly))
        )
        tpr_monthly = '{:.1%}'.format(
            true_blocked_spam_num / float(true_blocked_spam_num + len(spam_monthly))
        )
        tpr_quarterly = '{:.1%}'.format(
            true_blocked_spam_num / float(true_blocked_spam_num + len(spam_quarterly))
        )
        eq_(row_daily[true_positive_rate], '100.0%')
        eq_(row_weekly[true_positive_rate], tpr_weekly)
        eq_(row_monthly[true_positive_rate], tpr_monthly)
        eq_(row_quarterly[true_positive_rate], tpr_quarterly)
        # The true negative rate == published ham / total ham
        tnr_weekly = '{:.1%}'.format(
            len(ham_weekly) / float(false_blocked_spam_num + len(ham_weekly))
        )
        tnr_monthly = '{:.1%}'.format(
            len(ham_monthly) / float(false_blocked_spam_num + len(ham_monthly))
        )
        tnr_quarterly = '{:.1%}'.format(
            len(ham_quarterly) / float(false_blocked_spam_num + len(ham_quarterly))
        )
        eq_(row_daily[true_negative_rate], '100.0%')
        eq_(row_weekly[true_negative_rate], tnr_weekly)
        eq_(row_monthly[true_negative_rate], tnr_monthly)
        eq_(row_quarterly[true_negative_rate], tnr_quarterly)
Beispiel #15
0
 def test_submitted_data(self):
     dsa = DocumentSpamAttempt(data=None)
     assert self.admin.submitted_data(dsa) == SUBMISSION_NOT_AVAILABLE
     data = '{"foo": "bar"}'
     dsa.data = data
     assert self.admin.submitted_data(dsa) == data
Beispiel #16
0
 def test_submitted_data(self):
     dsa = DocumentSpamAttempt(data=None)
     assert self.admin.submitted_data(dsa) == SUBMISSION_NOT_AVAILABLE
     data = '{"foo": "bar"}'
     dsa.data = data
     assert self.admin.submitted_data(dsa) == data
Beispiel #17
0
 def test_doc_short_without_document(self):
     dsa = DocumentSpamAttempt(slug='Slug')
     assert self.admin.doc_short(dsa) == '<em>new document</em>'
Beispiel #18
0
 def test_slug_short(self):
     dsa = DocumentSpamAttempt(slug='Web/CSS')
     assert self.admin.slug_short(dsa) == 'Web/CSS'
     dsa.slug = 'Web/A_long_slug_that_will_be_truncated'
     assert self.admin.slug_short(dsa) == 'Web/A_long_slug_that_w...' ''
Beispiel #19
0
 def test_slug_short(self):
     dsa = DocumentSpamAttempt(slug='Web/CSS')
     assert self.admin.slug_short(dsa) == 'Web/CSS'
     dsa.slug = 'Web/A_long_slug_that_will_be_truncated'
     assert self.admin.slug_short(dsa) == 'Web/A_long_slug_that_w...'''
Beispiel #20
0
 def test_title_short(self):
     dsa = DocumentSpamAttempt(title='A short title')
     assert self.admin.title_short(dsa) == 'A short title'
     dsa.title = 'A long title that will need to be truncated.'
     assert self.admin.title_short(dsa) == 'A long title that will...'
Beispiel #21
0
    def test_spam_trends_stats(self, mock_analytics_upageviews):
        """Test that the correct stats show up on the spam trends dashboard."""
        # Period length
        days_in_week = 7
        days_in_month = 28
        days_in_quarter = 91
        # Dates
        today = datetime.datetime.today()
        yesterday = today - datetime.timedelta(days=1)
        three_days_ago = today - datetime.timedelta(days=3)
        weekly_start_date = today - datetime.timedelta(days=days_in_week)
        ten_days_ago = today - datetime.timedelta(days=10)
        monthly_start_date = today - datetime.timedelta(days=days_in_month)
        thirtyfive_days_ago = today - datetime.timedelta(days=35)
        quarterly_start_date = today - datetime.timedelta(days=days_in_quarter)
        hundred_days_ago = today - datetime.timedelta(days=100)

        # Revisions made by self.testuser: 3 made today, 3 made 3 days ago,
        # 3 made 10 days ago, 3 made 35 days ago, 3 made 100 days ago
        revs = self.create_revisions(num=15,
                                     creator=self.testuser,
                                     document=self.document)
        for i in range(0, 3):
            revs[i].created = today
        for i in range(3, 6):
            revs[i].created = three_days_ago
        for i in range(6, 9):
            revs[i].created = ten_days_ago
        for i in range(9, 12):
            revs[i].created = thirtyfive_days_ago
        for i in range(12, 15):
            revs[i].created = hundred_days_ago
        for rev in revs:
            rev.save()

        # Published spam by self.testuser
        spam_rev_today = revs[2]
        spam_rev_3_days_ago = revs[5]
        spam_rev_10_days_ago = revs[8]
        spam_rev_35_days_ago = revs[11]
        spam_rev_100_days_ago = revs[14]
        spam_revs = [
            spam_rev_today,
            spam_rev_3_days_ago,
            spam_rev_10_days_ago,
            spam_rev_35_days_ago,
            spam_rev_100_days_ago,
        ]
        # Summary of spam submissions
        spam_weekly = [spam_rev_3_days_ago]
        spam_monthly = [spam_rev_3_days_ago, spam_rev_10_days_ago]
        spam_quarterly = [
            spam_rev_3_days_ago,
            spam_rev_10_days_ago,
            spam_rev_35_days_ago,
        ]
        # All of the spam_revs were published and then marked as spam
        for rev in spam_revs:
            rev.save()
            rev.akismet_submissions.create(sender=self.admin, type="spam")

        # Summary of self.testuser's ham submissions
        ham_weekly = revs[3:5]
        ham_monthly = revs[3:5] + revs[6:8]
        ham_quarterly = revs[3:5] + revs[6:8] + revs[9:11]

        # There were 2 correctly blocked spam attempts 3 days ago (within past week)
        true_blocked_spam_num = 2
        for i in range(0, true_blocked_spam_num):
            document_spam_rev_3_days_ago = DocumentSpamAttempt(
                user=self.testuser,
                title="A spam revision",
                slug="spam-revision-slug",
                document=self.document,
                review=DocumentSpamAttempt.SPAM,
            )
            document_spam_rev_3_days_ago.save()
            document_spam_rev_3_days_ago.created = three_days_ago
            document_spam_rev_3_days_ago.save()

        # There was 1 incorrectly blocked spam attempt 3 days ago
        false_blocked_spam_num = 1
        for i in range(0, false_blocked_spam_num):
            document_ham_rev_3_days_ago = DocumentSpamAttempt(
                user=self.testuser,
                title="Not a spam revision",
                slug="ham-revision-slug",
                document=self.document,
                review=DocumentSpamAttempt.HAM,
            )
            document_ham_rev_3_days_ago.save()
            document_ham_rev_3_days_ago.created = three_days_ago
            document_ham_rev_3_days_ago.save()

        page_views = {}
        # The spam from 3 days ago was seen 3 times, from 10 days ago see 10 times,
        # and from 35 days ago seen 35 times
        page_views[spam_rev_3_days_ago.id] = 3
        page_views[spam_rev_10_days_ago.id] = 10
        page_views[spam_rev_35_days_ago.id] = 35
        # The mock Google Analytics return values for page views
        mock_analytics_upageviews.return_value = page_views

        self.client.login(username="******", password="******")
        # The first response will say that the report is being processed
        response = self.client.get(reverse("dashboards.spam"),
                                   HTTP_HOST=settings.WIKI_HOST)
        assert 200 == response.status_code

        response2 = self.client.get(reverse("dashboards.spam"),
                                    HTTP_HOST=settings.WIKI_HOST)
        page = pq(response2.content)

        row_daily = (
            page.find(".spam-trends-table tbody tr")[0].text_content().replace(
                " ", "").strip("\n").split("\n"))
        row_weekly = (
            page.find(".spam-trends-table tbody tr")[1].text_content().replace(
                " ", "").strip("\n").split("\n"))
        row_monthly = (
            page.find(".spam-trends-table tbody tr")[2].text_content().replace(
                " ", "").strip("\n").split("\n"))
        row_quarterly = (
            page.find(".spam-trends-table tbody tr")[3].text_content().replace(
                " ", "").strip("\n").split("\n"))

        # These are the columns in the spam dashboard spam trends table
        period = 0
        start_date = 1
        spam_viewers_change_percent = 2
        spam_viewers = 3
        daily_average_viewers = 4
        published_spam = 5
        blocked_spam = 6
        blocked_ham = 7
        true_positive_rate = 8
        true_negative_rate = 9

        # The periods are identified as 'Daily', 'Weekly', 'Monthly', 'Quarterly'
        assert "Daily" == row_daily[period]
        assert "Weekly" == row_weekly[period]
        assert "Monthly" == row_monthly[period]
        assert "Quarterly" == row_quarterly[period]
        # The start dates for each period are correct
        assert yesterday.strftime("%Y-%m-%d") == row_daily[start_date]
        assert weekly_start_date.strftime("%Y-%m-%d") == row_weekly[start_date]
        assert monthly_start_date.strftime(
            "%Y-%m-%d") == row_monthly[start_date]
        assert quarterly_start_date.strftime(
            "%Y-%m-%d") == row_quarterly[start_date]
        # The page views during the week, month, quarter
        spam_views_week = page_views[spam_rev_3_days_ago.id]
        spam_views_month = spam_views_week + page_views[
            spam_rev_10_days_ago.id]
        spam_views_month_exclude_week = page_views[spam_rev_10_days_ago.id]
        spam_views_quarter = spam_views_month + page_views[
            spam_rev_35_days_ago.id]
        spam_views_quarter_exclude_month = page_views[spam_rev_35_days_ago.id]
        # The percentage change in spam viewers
        weekly_spam_change_percent = "{:.1%}".format(
            float(spam_views_week - spam_views_month_exclude_week) /
            spam_views_month_exclude_week)
        monthly_spam_change_percent = "{:.1%}".format(
            float(spam_views_month - spam_views_quarter_exclude_month) /
            spam_views_quarter_exclude_month)
        assert "0.0%" == row_daily[spam_viewers_change_percent]
        assert weekly_spam_change_percent == row_weekly[
            spam_viewers_change_percent]
        assert monthly_spam_change_percent == row_monthly[
            spam_viewers_change_percent]
        assert "0.0%" == row_quarterly[spam_viewers_change_percent]
        # The spam viewers
        assert 0 == int(row_daily[spam_viewers])
        assert spam_views_week == int(row_weekly[spam_viewers])
        assert spam_views_month == int(row_monthly[spam_viewers])
        assert spam_views_quarter == int(row_quarterly[spam_viewers])
        # The daily average of spam viewers
        assert float(row_daily[daily_average_viewers]) == 0.0
        assert row_weekly[daily_average_viewers] == "{:.1f}".format(
            float(spam_views_week) / days_in_week)
        assert row_monthly[daily_average_viewers] == "{:.1f}".format(
            float(spam_views_month) / days_in_month)
        assert row_quarterly[daily_average_viewers] == "{:.1f}".format(
            float(spam_views_quarter) / days_in_quarter)
        # The published spam: 1 this week, 2 this month, 3 this quarter
        assert not int(row_daily[published_spam])
        assert len(spam_weekly) == int(row_weekly[published_spam])
        assert len(spam_monthly) == int(row_monthly[published_spam])
        assert len(spam_quarterly) == int(row_quarterly[published_spam])
        # The blocked spam: there were 2 correctly blocked spam attempts 3 days ago
        assert 0 == int(row_daily[blocked_spam])
        assert true_blocked_spam_num == int(row_weekly[blocked_spam])
        assert true_blocked_spam_num == int(row_monthly[blocked_spam])
        assert true_blocked_spam_num == int(row_quarterly[blocked_spam])
        # The blocked ham: there was 1 incorrectly blocked spam attempt 3 days ago
        assert 0 == int(row_daily[blocked_ham])
        assert false_blocked_spam_num == int(row_weekly[blocked_ham])
        assert false_blocked_spam_num == int(row_monthly[blocked_ham])
        assert false_blocked_spam_num == int(row_quarterly[blocked_ham])
        # The true positive rate == blocked_spam / total spam
        tpr_weekly = "{:.1%}".format(
            true_blocked_spam_num /
            float(true_blocked_spam_num + len(spam_weekly)))
        tpr_monthly = "{:.1%}".format(
            true_blocked_spam_num /
            float(true_blocked_spam_num + len(spam_monthly)))
        tpr_quarterly = "{:.1%}".format(
            true_blocked_spam_num /
            float(true_blocked_spam_num + len(spam_quarterly)))
        assert "100.0%" == row_daily[true_positive_rate]
        assert tpr_weekly == row_weekly[true_positive_rate]
        assert tpr_monthly == row_monthly[true_positive_rate]
        assert tpr_quarterly == row_quarterly[true_positive_rate]
        # The true negative rate == published ham / total ham
        tnr_weekly = "{:.1%}".format(
            len(ham_weekly) / float(false_blocked_spam_num + len(ham_weekly)))
        tnr_monthly = "{:.1%}".format(
            len(ham_monthly) /
            float(false_blocked_spam_num + len(ham_monthly)))
        tnr_quarterly = "{:.1%}".format(
            len(ham_quarterly) /
            float(false_blocked_spam_num + len(ham_quarterly)))
        assert "100.0%" == row_daily[true_negative_rate]
        assert tnr_weekly == row_weekly[true_negative_rate]
        assert tnr_monthly == row_monthly[true_negative_rate]
        assert tnr_quarterly == row_quarterly[true_negative_rate]