~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/scripts/tests/test_garbo.py

[r=gmb][bug=424156] Provide a new daily garbo job to remove answer
        contacts which are deactivated (after 1 day) or suspended
        (after 7 days).

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
from canonical.config import config
34
34
from canonical.database import sqlbase
35
35
from canonical.database.constants import (
 
36
    ONE_DAY_AGO,
 
37
    SEVEN_DAYS_AGO,
36
38
    THIRTY_DAYS_AGO,
37
39
    UTC_NOW,
38
40
    )
43
45
    OAuthNonce,
44
46
    )
45
47
from canonical.launchpad.database.openidconsumer import OpenIDConsumerNonce
 
48
from canonical.launchpad.interfaces.account import AccountStatus
46
49
from canonical.launchpad.interfaces.emailaddress import EmailAddressStatus
47
50
from canonical.launchpad.interfaces.lpstorm import IMasterStore
48
51
from canonical.launchpad.scripts.tests import run_script
57
60
    LaunchpadZopelessLayer,
58
61
    ZopelessDatabaseLayer,
59
62
    )
 
63
from lp.answers.model.answercontact import AnswerContact
60
64
from lp.bugs.model.bugmessage import BugMessage
61
65
from lp.bugs.model.bugnotification import (
62
66
    BugNotification,
93
97
    SessionData,
94
98
    SessionPkgData,
95
99
    )
 
100
from lp.services.worlddata.interfaces.language import ILanguageSet
96
101
from lp.testing import (
 
102
    person_logged_in,
97
103
    TestCase,
98
104
    TestCaseWithFactory,
99
105
    )
100
 
from lp.translations.model.potemplate import POTemplate
101
106
from lp.translations.model.potmsgset import POTMsgSet
102
107
from lp.translations.model.translationtemplateitem import (
103
108
    TranslationTemplateItem,
392
397
    def test_OAuthNoncePruner(self):
393
398
        now = datetime.now(UTC)
394
399
        timestamps = [
395
 
            now - timedelta(days=2), # Garbage
396
 
            now - timedelta(days=1) - timedelta(seconds=60), # Garbage
397
 
            now - timedelta(days=1) + timedelta(seconds=60), # Not garbage
398
 
            now, # Not garbage
 
400
            now - timedelta(days=2),  # Garbage
 
401
            now - timedelta(days=1) - timedelta(seconds=60),  # Garbage
 
402
            now - timedelta(days=1) + timedelta(seconds=60),  # Not garbage
 
403
            now,  # Not garbage
399
404
            ]
400
405
        LaunchpadZopelessLayer.switchDbUser('testadmin')
401
406
        store = IMasterStore(OAuthNonce)
406
411
        for timestamp in timestamps:
407
412
            store.add(OAuthNonce(
408
413
                access_token=OAuthAccessToken.get(1),
409
 
                request_timestamp = timestamp,
410
 
                nonce = str(timestamp)))
 
414
                request_timestamp=timestamp,
 
415
                nonce=str(timestamp)))
411
416
        transaction.commit()
412
417
 
413
418
        # Make sure we have 4 nonces now.
414
419
        self.failUnlessEqual(store.find(OAuthNonce).count(), 4)
415
420
 
416
 
        self.runHourly(maximum_chunk_size=60) # 1 minute maximum chunk size
 
421
        self.runHourly(maximum_chunk_size=60)  # 1 minute maximum chunk size
417
422
 
418
423
        store = IMasterStore(OAuthNonce)
419
424
 
435
440
        HOURS = 60 * 60
436
441
        DAYS = 24 * HOURS
437
442
        timestamps = [
438
 
            now - 2 * DAYS, # Garbage
439
 
            now - 1 * DAYS - 1 * MINUTES, # Garbage
440
 
            now - 1 * DAYS + 1 * MINUTES, # Not garbage
441
 
            now, # Not garbage
 
443
            now - 2 * DAYS,  # Garbage
 
444
            now - 1 * DAYS - 1 * MINUTES,  # Garbage
 
445
            now - 1 * DAYS + 1 * MINUTES,  # Not garbage
 
446
            now,  # Not garbage
442
447
            ]
443
448
        LaunchpadZopelessLayer.switchDbUser('testadmin')
444
449
 
456
461
        self.failUnlessEqual(store.find(OpenIDConsumerNonce).count(), 4)
457
462
 
458
463
        # Run the garbage collector.
459
 
        self.runHourly(maximum_chunk_size=60) # 1 minute maximum chunks.
 
464
        self.runHourly(maximum_chunk_size=60)  # 1 minute maximum chunks.
460
465
 
461
466
        store = IMasterStore(OpenIDConsumerNonce)
462
467
 
465
470
 
466
471
        # And none of them are older than 1 day
467
472
        earliest = store.find(Min(OpenIDConsumerNonce.timestamp)).one()
468
 
        self.failUnless(earliest >= now - 24*60*60, 'Still have old nonces')
 
473
        self.failUnless(
 
474
            earliest >= now - 24 * 60 * 60, 'Still have old nonces')
469
475
 
470
476
    def test_CodeImportResultPruner(self):
471
477
        now = datetime.now(UTC)
492
498
 
493
499
        new_code_import_result(now - timedelta(days=60))
494
500
        for i in range(results_to_keep_count - 1):
495
 
            new_code_import_result(now - timedelta(days=19+i))
 
501
            new_code_import_result(now - timedelta(days=19 + i))
496
502
 
497
503
        # Run the garbage collector
498
504
        self.runDaily()
565
571
            store.execute("""
566
572
                INSERT INTO %s (server_url, handle, issued, lifetime)
567
573
                VALUES (%s, %s, %d, %d)
568
 
                """ % (table_name, str(delta), str(delta), now-10, delta))
 
574
                """ % (table_name, str(delta), str(delta), now - 10, delta))
569
575
        transaction.commit()
570
576
 
571
577
        # Ensure that we created at least one expirable row (using the
779
785
                BugNotification.date_emailed < THIRTY_DAYS_AGO).count(),
780
786
            0)
781
787
 
 
788
    def _test_AnswerContactPruner(self, status, interval, expected_count=0):
 
789
        # Garbo should remove answer contacts for accounts with given 'status'
 
790
        # which was set more than 'interval' days ago.
 
791
        LaunchpadZopelessLayer.switchDbUser('testadmin')
 
792
        store = IMasterStore(AnswerContact)
 
793
 
 
794
        person = self.factory.makePerson()
 
795
        person.addLanguage(getUtility(ILanguageSet)['en'])
 
796
        question = self.factory.makeQuestion()
 
797
        with person_logged_in(question.owner):
 
798
            question.target.addAnswerContact(person, person)
 
799
        Store.of(question).flush()
 
800
        self.assertEqual(
 
801
            store.find(
 
802
                AnswerContact,
 
803
                AnswerContact.person == person.id).count(),
 
804
                1)
 
805
 
 
806
        account = person.account
 
807
        account.status = status
 
808
        # We flush because a trigger sets the date_status_set and we need to
 
809
        # modify it ourselves.
 
810
        Store.of(account).flush()
 
811
        if interval is not None:
 
812
            account.date_status_set = interval
 
813
 
 
814
        self.runDaily()
 
815
 
 
816
        LaunchpadZopelessLayer.switchDbUser('testadmin')
 
817
        self.assertEqual(
 
818
            store.find(
 
819
                AnswerContact,
 
820
                AnswerContact.person == person.id).count(),
 
821
                expected_count)
 
822
 
 
823
    def test_AnswerContactPruner_deactivated_accounts(self):
 
824
        # Answer contacts with an account deactivated at least one day ago
 
825
        # should be pruned.
 
826
        self._test_AnswerContactPruner(AccountStatus.DEACTIVATED, ONE_DAY_AGO)
 
827
 
 
828
    def test_AnswerContactPruner_suspended_accounts(self):
 
829
        # Answer contacts with an account suspended at least seven days ago
 
830
        # should be pruned.
 
831
        self._test_AnswerContactPruner(
 
832
            AccountStatus.SUSPENDED, SEVEN_DAYS_AGO)
 
833
 
 
834
    def test_AnswerContactPruner_doesnt_prune_recently_changed_accounts(self):
 
835
        # Answer contacts which are suspended or deactivated inside the
 
836
        # minimum time interval are not pruned.
 
837
        self._test_AnswerContactPruner(
 
838
            AccountStatus.DEACTIVATED, None, expected_count=1)
 
839
        self._test_AnswerContactPruner(
 
840
            AccountStatus.SUSPENDED, ONE_DAY_AGO, expected_count=1)
 
841
 
782
842
    def test_BranchJobPruner(self):
783
843
        # Garbo should remove jobs completed over 30 days ago.
784
844
        LaunchpadZopelessLayer.switchDbUser('testadmin')
900
960
        finally:
901
961
            con.close()
902
962
        store = IMasterStore(BugMessage)
903
 
        unmigrated = store.find(BugMessage, BugMessage.ownerID==None).count
 
963
        unmigrated = store.find(BugMessage, BugMessage.ownerID == None).count
904
964
        self.assertNotEqual(0, unmigrated())
905
965
        self.runHourly()
906
966
        self.assertEqual(0, unmigrated())