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