jenkins-bot has submitted this change and it was merged.

Change subject: Prune old bounce records
......................................................................


Prune old bounce records

Bounce records needs to be occassionaly removed because:
* User might update their faulty email address in between
* The table will grow large.
* A maximum of 100 rows will get deleted at a time.
* Made getOldRecrods() private

Bug: T75876
Change-Id: I3f743f0166b4ac59e853e2fed4b9e05c7c44c196
---
M BounceHandler.php
M includes/ProcessBounceEmails.php
A includes/PruneOldBounceRecords.php
A tests/PruneOldBounceRecordsTest.php
4 files changed, 249 insertions(+), 3 deletions(-)

Approvals:
  Legoktm: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/BounceHandler.php b/BounceHandler.php
index 6189e96..cdd9a99 100644
--- a/BounceHandler.php
+++ b/BounceHandler.php
@@ -34,6 +34,7 @@
 $wgAutoloadClasses['ProcessBounceWithPlancake'] = $dir. 
'/includes/ProcessBounceWithPlancake.php';
 $wgAutoloadClasses['ProcessBounceWithRegex'] = $dir. 
'/includes/ProcessBounceWithRegex.php';
 $wgAutoloadClasses['VerpAddressGenerator'] = $dir. 
'/includes/VerpAddressGenerator.php';
+$wgAutoloadClasses['PruneOldBounceRecords'] = $dir. 
'/includes/PruneOldBounceRecords.php';
 
 $wgJobClasses['BounceHandlerJob'] = 'BounceHandlerJob';
 
@@ -84,7 +85,10 @@
 # Central DB name to use if the bounce table is to be shared
 $wgBounceHandlerSharedDB = false;
 
+# Maximum time in seconds until which a bounce record should be stored in the 
table
+$wgBounceRecordMaxAge = 5184000; //60 * 24 * 60 *60  ( 60 Days time in seconds 
)
+
 // Local composer install during development
 if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) {
        require_once __DIR__ . '/vendor/autoload.php';
-}
+}
\ No newline at end of file
diff --git a/includes/ProcessBounceEmails.php b/includes/ProcessBounceEmails.php
index 13609de..f6ecc1b 100644
--- a/includes/ProcessBounceEmails.php
+++ b/includes/ProcessBounceEmails.php
@@ -44,13 +44,13 @@
         * @return bool
         */
        public function processBounceHeaders( $emailHeaders ) {
-               global $wgBounceRecordPeriod, $wgBounceRecordLimit, 
$wgBounceHandlerUnconfirmUsers;
+               global $wgBounceRecordPeriod, $wgBounceRecordLimit, 
$wgBounceHandlerUnconfirmUsers, $wgBounceRecordMaxAge;
                $to = $emailHeaders['to'];
                $subject = $emailHeaders['subject'];
 
                // Get original failed user email and wiki details
                $failedUser = $this->getUserDetails( $to );
-               if( is_array( $failedUser ) && isset( $failedUser['wikiId'] ) 
&& isset( $failedUser['rawEmail'] )
+               if ( is_array( $failedUser ) && isset( $failedUser['wikiId'] ) 
&& isset( $failedUser['rawEmail'] )
                        && isset( $failedUser[ 'bounceTime' ] )
                ) {
                        $wikiId = $failedUser['wikiId'];
@@ -65,6 +65,11 @@
                        );
                        $dbw->insert( 'bounce_records', $rowData, __METHOD__ );
 
+                       if ( $wgBounceRecordMaxAge ) {
+                               $pruneOldRecords = new PruneOldBounceRecords( 
$wgBounceRecordMaxAge );
+                               $pruneOldRecords->pruneOldRecords( $wikiId );
+                       }
+
                        $takeBounceActions = new BounceHandlerActions( $wikiId,
                                $wgBounceRecordPeriod, $wgBounceRecordLimit, 
$wgBounceHandlerUnconfirmUsers );
                        $takeBounceActions->handleFailingRecipient( $failedUser 
);
diff --git a/includes/PruneOldBounceRecords.php 
b/includes/PruneOldBounceRecords.php
new file mode 100644
index 0000000..0c70b60
--- /dev/null
+++ b/includes/PruneOldBounceRecords.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Class PruneOldBounceRecords
+ *
+ * Prune old bounce records from the 'bounce_records' table
+ *
+ * Copyright (c) 2014, Tony Thomas <[email protected]>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author Tony Thomas <[email protected]>
+ * @license GPL-2.0
+ * @ingroup Extensions
+ */
+class PruneOldBounceRecords {
+
+       /**
+        * @var int
+        */
+       private $bounceRecordMaxAge;
+
+       /**
+        * @param int $bounceRecordMaxAge
+        */
+       public function __construct( $bounceRecordMaxAge ) {
+               $this->bounceRecordMaxAge = $bounceRecordMaxAge;
+       }
+
+       /**
+        * Prune old bounce records
+        *
+        * @param string $wikiId
+        *
+        */
+       public function pruneOldRecords( $wikiId ) {
+               $idArray = $this->getOldRecords( $wikiId );
+               $idArrayCount = count( $idArray );
+               if ( $idArrayCount  > 0 ) {
+                       $dbw = ProcessBounceEmails::getBounceRecordDB( 
DB_MASTER, $wikiId );
+                       $dbw->delete(
+                               'bounce_records',
+                               array (
+                                       'br_id' => $idArray
+                               ),
+                               __METHOD__
+                       );
+                       wfDebugLog( 'BounceHandler', "Pruned $idArrayCount 
bounce records from $wikiId wiki." );
+               }
+
+       }
+
+       /**
+        * Get Old bounce records from DB
+        *
+        * @param string $wikiId
+        * @return int[]
+        */
+       private function getOldRecords( $wikiId ) {
+               $idArray = array();
+               $maximumRecordAge = time() - $this->bounceRecordMaxAge;
+               $dbr = ProcessBounceEmails::getBounceRecordDB( DB_SLAVE, 
$wikiId );
+               $res = $dbr->select(
+                       'bounce_records',
+                       array( 'br_id' ),
+                       'br_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( 
$maximumRecordAge ) ),
+                       __METHOD__,
+                       array( 'LIMIT' => 100 )
+               );
+
+               foreach( $res as $row ) {
+                       $idArray[] = (int)$row->br_id;
+               }
+
+               return $idArray;
+       }
+
+}
\ No newline at end of file
diff --git a/tests/PruneOldBounceRecordsTest.php 
b/tests/PruneOldBounceRecordsTest.php
new file mode 100644
index 0000000..43605fe
--- /dev/null
+++ b/tests/PruneOldBounceRecordsTest.php
@@ -0,0 +1,147 @@
+<?php
+
+/**
+ * Class PruneOldBounceRecordsTest
+ *
+ * @group Database
+ * @group medium
+ * @covers PruneOldBounceRecords
+ */
+class PruneOldBounceRecordsTest extends MediaWikiTestCase {
+
+       protected $encodedAddress;
+       protected $emailHeaders;
+       protected $wikiId;
+       protected $userId;
+       protected $originalEmail;
+       protected $subject = "Bounce Email";
+
+       protected function setUp() {
+               parent::setUp();
+
+               $user = User::newFromName( 'OldUser' );
+               $user->setEmail( '[email protected]' );
+               $user->addToDatabase();
+
+               $user->confirmEmail();
+               $user->saveSettings();
+
+
+               $bounceRecordPeriod = 604800;
+               $bounceRecordLimit = 4;
+               $bounceHandlerSharedDB = false;
+               $bounceHandlerCluster = false;
+               $bounceHandlerUnconfirmUsers = false;
+
+               $prefix = 'wiki';
+               $algorithm = 'md5';
+               $secretKey = 'mySecret';
+               $domain = 'testwiki.org';
+
+               $this->setMwGlobals(
+                       array(
+                               'wgBounceHandlerUnconfirmUsers' => 
$bounceHandlerUnconfirmUsers,
+                               'wgBounceRecordPeriod' => $bounceRecordPeriod,
+                               'wgBounceRecordLimit' => $bounceRecordLimit,
+                               'wgBounceHandlerSharedDB' => 
$bounceHandlerSharedDB,
+                               'wgBounceHandlerCluster' => 
$bounceHandlerCluster,
+                               'wgVERPAcceptTime' => 259200,
+                               'wgVERPprefix' => $prefix,
+                               'wgVERPalgorithm' => $algorithm,
+                               'wgVERPsecret' => $secretKey,
+                               'wgVERPdomainPart' => $domain,
+                       )
+               );
+
+               $this->originalEmail = $user->getEmail();
+               $this->wikiId = wfWikiID();
+               $this->tablesUsed = array( 'bounce_records' );
+       }
+
+       public function testPruneDeleteOldSingleRow() {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbr = wfGetDB( DB_SLAVE );
+               //Delete old rows
+               $bounceRecordMaxAge = -1; // To get all the bounces in the 
Database
+               $pruneOldRecordsTester = new PruneOldBounceRecords( 
$bounceRecordMaxAge );
+               $pruneOldRecordsTester->pruneOldRecords( $this->wikiId ); // 
Delete all rows
+               $res = $this->getOldRecordsCount( $bounceRecordMaxAge, $dbr );
+               $this->assertEquals( $res, 0 ); // We will have 0 elements 
after pruning
+
+
+               $bounceRecordMaxAge = 3;
+               $this->insertDelayedBounce( 4, $dbw );
+               $pruneOldRecordsTester = new PruneOldBounceRecords( 
$bounceRecordMaxAge );
+               $res = $this->getOldRecordsCount( $bounceRecordMaxAge, $dbr );
+
+               $this->assertEquals( $res, 1 ); // We have one bounce from 
above in the DB
+               $pruneOldRecordsTester->pruneOldRecords( $this->wikiId ); // 2 
should get deleted
+
+               //reset
+               $bounceRecordMaxAge = -1;
+               $res = $this->getOldRecordsCount( $bounceRecordMaxAge, $dbr );
+               $this->assertEquals( 0,  $res ); // We will have 0 elements 
after pruning
+       }
+
+       public function testMultipleOldRows() {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbr = wfGetDB( DB_SLAVE );
+               $bounceRecordMaxAge = -1; // To get all the bounces in the 
Database
+               $pruneOldRecordsTester = new PruneOldBounceRecords( 
$bounceRecordMaxAge );
+               $pruneOldRecordsTester->pruneOldRecords( $this->wikiId ); // 
Delete all rows
+               $res = $this->getOldRecordsCount( $bounceRecordMaxAge, $dbr );
+               $this->assertEquals( 0 , $res ); // We will have 0 elements
+
+               //Insert First bounce
+               $this->insertDelayedBounce( 4, $dbw ); // Insert with 4 seconds 
delay
+               $res = $this->getOldRecordsCount( $bounceRecordMaxAge, $dbr );
+               $this->assertEquals( $res, 1 ); // We will have only one bounce 
in the record
+
+               //Insert Second Bounce
+               $this->insertDelayedBounce( 0, $dbw ); // Insert with 0 delay
+               $res = $this->getOldRecordsCount( $bounceRecordMaxAge, $dbr );
+               $this->assertEquals( $res, 2 ); // We will have two bounces in 
the bounce record as of now
+
+               //Insert Third Bounce
+               $this->insertDelayedBounce( 0, $dbw ); //Insert with 0 delay
+               $res = $this->getOldRecordsCount( $bounceRecordMaxAge, $dbr );
+               $this->assertEquals( $res, 3 ); // We will have three bounces 
in the bounce record as of now
+
+               $bounceRecordMaxAge = 3;
+               $pruneOldRecordsTester = new PruneOldBounceRecords( 
$bounceRecordMaxAge );
+               $res = $this->getOldRecordsCount( $bounceRecordMaxAge, $dbr );
+               $this->assertEquals( $res, 1 ); // Only one among the three 
would be that old.
+
+               $pruneOldRecordsTester->pruneOldRecords( $this->wikiId ); // 2 
should get deleted
+
+               $bounceRecordMaxAge = -1; // To get all the bounces in the 
Database
+               $res = $this->getOldRecordsCount( $bounceRecordMaxAge, $dbr );
+               $this->assertEquals( $res, 2 );
+
+       }
+
+       protected function insertDelayedBounce( $delayTime, $dbw ) {
+               $bounceTimestamp = wfTimestamp( TS_MW, time() - $delayTime );
+               $rowData = array(
+                       'br_user_email' => $this->originalEmail,
+                       'br_timestamp' => $dbw->timestamp( $bounceTimestamp ),
+                       'br_reason' => $this->subject
+               );
+
+               $dbw->insert( 'bounce_records', $rowData, __METHOD__ );
+       }
+
+       protected function getOldRecordsCount( $bounceRecordMaxAge, $dbr ) {
+               $maximumRecordAge = time() - $bounceRecordMaxAge;
+               $res = $dbr->selectRowCount(
+                       'bounce_records',
+                       array( '*' ),
+                       'br_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( 
$maximumRecordAge ) ),
+                       __METHOD__,
+                       array( 'LIMIT' => 100 )
+               );
+
+               return $res;
+       }
+
+}
\ No newline at end of file

-- 
To view, visit https://gerrit.wikimedia.org/r/176366
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I3f743f0166b4ac59e853e2fed4b9e05c7c44c196
Gerrit-PatchSet: 25
Gerrit-Project: mediawiki/extensions/BounceHandler
Gerrit-Branch: master
Gerrit-Owner: 01tonythomas <[email protected]>
Gerrit-Reviewer: 01tonythomas <[email protected]>
Gerrit-Reviewer: Anomie <[email protected]>
Gerrit-Reviewer: Hoo man <[email protected]>
Gerrit-Reviewer: Jgreen <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Reedy <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to