Ejegg has uploaded a new change for review. https://gerrit.wikimedia.org/r/273018
Change subject: Merge master into deployment ...................................................................... Merge master into deployment 1d346e4 Localisation updates from https://translatewiki.net. 1fbdd75 Localisation updates from https://translatewiki.net. 9d37cf9 Compress PNGs with zopflipng b1ef8ce Compress PNGs with zopflipng 6aed862 Localisation updates from https://translatewiki.net. ebe90a0 Delete unused images a874eea Add country to thank you URL 9f09ff3 Expand list of penalized fraudy error codes Removed tests Change-Id: Id5925b985236553dd21667ea0addc6b0fa692491 --- D tests/Adapter/PayPal/PayPalResultSwitcherTest.php D tests/Adapter/Worldpay/WorldpayTest.php D tests/DonationInterfaceTestCase.php 3 files changed, 0 insertions(+), 1,262 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DonationInterface refs/changes/18/273018/1 diff --git a/tests/Adapter/PayPal/PayPalResultSwitcherTest.php b/tests/Adapter/PayPal/PayPalResultSwitcherTest.php deleted file mode 100644 index 4610b02..0000000 --- a/tests/Adapter/PayPal/PayPalResultSwitcherTest.php +++ /dev/null @@ -1,49 +0,0 @@ -<<<<<<< HEAD (c8e1e4 Merge master into deployment) -======= -<?php -/** - * Wikimedia Foundation - * - * LICENSE - * - * 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. - */ - -/** - * @group Fundraising - * @group DonationInterface - * @group PayPal - */ -class PayPalResultSwitcherTest extends DonationInterfaceTestCase { - public function setUp() { - parent::setUp(); - - $this->setMwGlobals( array( - 'wgPaypalGatewayEnabled' => true, - ) ); - } - - function testSuccessfulRedirect() { - $init = $this->getDonorTestData( 'FR' ); - $init['OTT'] = 'SALT123456789'; - $session = array( 'Donor' => $init ); - - $assertNodes = array( - 'headers' => array( - 'Location' => 'https://wikimediafoundation.org/wiki/Thank_You/fr?country=FR', - ), - ); - - $this->verifyFormOutput( 'PaypalGatewayResult', $init, $assertNodes, false, $session ); - } - -} ->>>>>>> BRANCH (9f09ff Expand list of penalized fraudy error codes) diff --git a/tests/Adapter/Worldpay/WorldpayTest.php b/tests/Adapter/Worldpay/WorldpayTest.php deleted file mode 100644 index 14c19f1..0000000 --- a/tests/Adapter/Worldpay/WorldpayTest.php +++ /dev/null @@ -1,520 +0,0 @@ -<<<<<<< HEAD (c8e1e4 Merge master into deployment) -======= -<?php -/** - * Wikimedia Foundation - * - * LICENSE - * - * 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. - * - */ -use Psr\Log\LogLevel; - -/** - * - * @group Fundraising - * @group DonationInterface - * @group Worldpay - */ -class DonationInterface_Adapter_Worldpay_WorldpayTest extends DonationInterfaceTestCase { - - /** - * @param $name string The name of the test case - * @param $data array Any parameters read from a dataProvider - * @param $dataName string|int The name or index of the data set - */ - function __construct( $name = null, array $data = array(), $dataName = '' ) { - parent::__construct( $name, $data, $dataName ); - $this->testAdapterClass = 'TestingWorldpayAdapter'; - } - - public function setUp() { - global $wgWorldpayGatewayHtmlFormDir; - parent::setUp(); - - $this->setMwGlobals( array( - 'wgWorldpayGatewayEnabled' => true, - 'wgDonationInterfaceAllowedHtmlForms' => array( - 'testytest' => array( - 'gateway' => 'worldpay', - ), - 'worldpay' => array( - 'file' => $wgWorldpayGatewayHtmlFormDir . '/worldpay.html', - 'gateway' => 'worldpay', - 'countries' => array( '+' => array( 'AU', 'BE', 'CA', 'FR', 'GB', 'IL', 'NZ', 'US' ) ), - 'currencies' => array( '+' => 'ALL' ), - 'payment_methods' => array( 'cc' => 'ALL' ), - 'selection_weight' => 10 - ), - ), - ) ); - } - - /** - * Just making sure we can instantiate the thing without blowing up completely - */ - function testConstruct() { - $options = $this->getDonorTestData(); - $class = $this->testAdapterClass; - - $_SERVER['REQUEST_URI'] = GatewayFormChooser::buildPaymentsFormURL( 'testytest', array ( 'gateway' => $class::getIdentifier() ) ); - $gateway = $this->getFreshGatewayObject( $options ); - - $this->assertInstanceOf( 'TestingWorldpayAdapter', $gateway ); - } - - /** - * Test the AntiFraud hooks - */ - function testAntiFraudHooks() { - $options = $this->getDonorTestData( 'US' ); - $options['utm_source'] = "somethingmedia"; - $options['email'] = "[email protected]"; - - $gateway = $this->getFreshGatewayObject( $options ); - - $gateway->runAntifraudHooks(); - - $this->assertEquals( 'reject', $gateway->getValidationAction(), 'Validation action is not as expected' ); - $exposed = TestingAccessWrapper::newFromObject( $gateway ); - $this->assertEquals( 113, $exposed->risk_score, 'RiskScore is not as expected' ); - } - - /** - * Just making sure we can instantiate the thing without blowing up completely - */ - function testNeverLog() { - $options = $this->getDonorTestData(); - $options['cvv'] = '123'; - $class = $this->testAdapterClass; - - $_SERVER['REQUEST_URI'] = GatewayFormChooser::buildPaymentsFormURL( 'testytest', array ( 'gateway' => $class::getIdentifier() ) ); - $gateway = $this->getFreshGatewayObject( $options ); - - $this->assertInstanceOf( 'TestingWorldpayAdapter', $gateway ); - $gateway->do_transaction( 'AuthorizePaymentForFraud' ); - - $loglines = $this->getLogMatches( LogLevel::INFO, '/Request XML/' ); - - $this->assertEquals( 1, count( $loglines ), "We did not receive exactly one logline back that contains request XML" ); - $this->assertEquals( 1, preg_match( '/Cleaned/', $loglines[0] ), 'The logline did not come back marked as "Cleaned".' ); - $this->assertEquals( 0, preg_match( '/CNV/', $loglines[0] ), 'The "Cleaned" logline contained CVN data!' ); - } - - function testWorldpayFormLoad() { - $init = $this->getDonorTestData(); - unset( $init['order_id'] ); - $init['payment_method'] = 'cc'; - $init['email'] = '[email protected]'; - $init['payment_submethod'] = 'visa'; - $init['ffname'] = 'worldpay'; - $init['currency_code'] = 'EUR'; - - $assertNodes = array ( - 'selected-amount' => array ( - 'nodename' => 'span', - 'innerhtml' => '€1.55', - ), - 'fname' => array( - 'nodename' => 'input', - 'value' => 'Firstname', - ), - 'lname' => array( - 'nodename' => 'input', - 'value' => 'Surname', - ), - 'street' => array( - 'nodename' => 'input', - 'value' => '123 Fake Street', - ), - 'city' => array( - 'nodename' => 'input', - 'value' => 'San Francisco', - ), - 'zip' => array( - 'nodename' => 'input', - 'value' => '94105', - ), - 'country' => array( - 'nodename' => 'input', - 'value' => 'US', - ), - 'emailAdd' => array( - 'nodename' => 'input', - 'value' => '[email protected]', - ), - 'language' => array( - 'nodename' => 'input', - 'value' => 'en', - ), - 'state' => array( - 'nodename' => 'select', - 'selected' => 'CA', - ), - 'informationsharing' => array ( - 'nodename' => 'p', - 'innerhtml' => "By donating, you agree to share your personal information with the Wikimedia Foundation, the nonprofit organization that hosts Wikipedia and other Wikimedia projects, and its service providers pursuant to our <a href=\"//wikimediafoundation.org/wiki/Donor_policy\">donor policy</a>. Wikimedia Foundation and its service providers are located in the United States and in other countries whose privacy laws may not be equivalent to your own. We do not sell or trade your information to anyone. For more information please read our <a href=\"//wikimediafoundation.org/wiki/Donor_policy\">donor policy</a>." - ), - ); - - $this->verifyFormOutput( 'TestingWorldpayGateway', $init, $assertNodes, true ); - } - - function testPaymentFormSubmit() { - $init = $this->getDonorTestData( 'FR' ); - unset( $init['order_id'] ); - $init['payment_method'] = 'cc'; - $init['payment_submethod'] = 'visa'; - $init['ffname'] = 'worldpay'; - $init['currency_code'] = 'EUR'; - $init['email'] = '[email protected]'; - - $init['OTT'] = 'SALT123456789'; - - $assertNodes = array( - 'headers' => array( - 'Location' => 'https://wikimediafoundation.org/wiki/Thank_You/fr?country=FR', - ), - ); - - $this->verifyFormOutput( 'TestingWorldpayGateway', $init, $assertNodes, true ); - } - - function testWorldpayFormLoad_FR() { - $init = $this->getDonorTestData( 'FR' ); - unset( $init['order_id'] ); - $init['payment_method'] = 'cc'; - $init['payment_submethod'] = 'visa'; - $init['ffname'] = 'worldpay'; - - $assertNodes = array ( - 'selected-amount' => array ( - 'nodename' => 'span', - 'innerhtml' => '€1.55', - ), - 'fname' => array ( - 'nodename' => 'input', - 'value' => 'Prénom', - ), - 'lname' => array ( - 'nodename' => 'input', - 'value' => 'Nom', - ), - 'country' => array ( - 'nodename' => 'input', - 'value' => 'FR', - ), - ); - - $this->verifyFormOutput( 'TestingWorldpayGateway', $init, $assertNodes, true ); - } - - /** - * Make sure Belgian form loads in all of that country's supported languages - * @dataProvider belgiumLanguageProvider - */ - public function testWorldpayFormLoad_BE( $language ) { - $init = $this->getDonorTestData( 'BE' ); - unset( $init['order_id'] ); - $init['payment_method'] = 'cc'; - $init['payment_submethod'] = 'visa'; - $init['ffname'] = 'worldpay'; - $init['language'] = $language; - - $assertNodes = array ( - 'selected-amount' => array ( - 'nodename' => 'span', - 'innerhtml' => '€1.55', - ), - 'fname-label' => array ( - 'nodename' => 'label', - 'innerhtml' => wfMessage( 'donate_interface-donor-fname' )->inLanguage( $language )->text(), - ), - 'lname-label' => array ( - 'nodename' => 'label', - 'innerhtml' => wfMessage( 'donate_interface-donor-lname' )->inLanguage( $language )->text(), - ), - 'emailAdd-label' => array ( - 'nodename' => 'label', - 'innerhtml' => wfMessage( 'donate_interface-donor-email' )->inLanguage( $language )->text(), - ), - 'informationsharing' => array ( - 'nodename' => 'p', - 'innerhtml' => wfMessage( 'donate_interface-informationsharing', '.*' )->inLanguage( $language )->text(), - ), - ); - - $this->verifyFormOutput( 'TestingWorldpayGateway', $init, $assertNodes, true ); - } - - /** - * Testing that we can retrieve the cvv_match value and run antifraud on it correctly - */ - function testAntifraudCVVMatch() { - $options = $this->getDonorTestData(); //don't really care: We'll be using the dummy response directly. - - $gateway = $this->getFreshGatewayObject( $options ); - $gateway->do_transaction( 'AuthorizePaymentForFraud' ); - - $this->assertEquals( '1', $gateway->getData_Unstaged_Escaped( 'cvv_result' ), 'cvv_result was not set after AuthorizePaymentForFraud' ); - $this->assertTrue( $gateway->getCVVResult(), 'getCVVResult not passing somebody with a match.' ); - - //and now, for fun, test a wrong code. - $gateway->addResponseData( array ( 'cvv_result' => '2' ) ); - $this->assertFalse( $gateway->getCVVResult(), 'getCVVResult not failing somebody with garbage.' ); - } - - /** - * Ensure we don't give too high a risk score when AVS address / zip match was not performed - */ - function testAntifraudAllowsAvsNotPerformed() { - $options = $this->getDonorTestData('FR'); //don't really care: We'll be using the dummy response directly. - - $gateway = $this->getFreshGatewayObject( $options ); - $gateway->setDummyGatewayResponseCode( 9000 ); - $gateway->do_transaction( 'AuthorizePaymentForFraud' ); - - $this->assertEquals( '9', $gateway->getData_Unstaged_Escaped( 'avs_address' ), 'avs_address was not set after AuthorizePaymentForFraud' ); - $this->assertEquals( '9', $gateway->getData_Unstaged_Escaped( 'avs_zip' ), 'avs_zip was not set after AuthorizePaymentForFraud' ); - $this->assertTrue( $gateway->getAVSResult() < 25, 'getAVSResult returning too high a score for AVS not performed.' ); - } - - /** - * Check to make sure we don't run antifraud filters (and burn a minfraud query) when we know the transaction has already failed - */ - function testAntifraudNotPerformedOnGatewayError() { - $options = $this->getDonorTestData( 'FR' ); //don't really care: We'll be using the dummy response directly. - - $gateway = $this->getFreshGatewayObject( $options ); - $gateway->setDummyGatewayResponseCode( 2208 ); //account problems - $gateway->do_transaction( 'AuthorizePaymentForFraud' ); - - //assert that: - //#1 - the gateway object has an appropriate transaction error set - //#2 - antifraud checks were not performed. - - //check for the error code that corresponds to the transaction coming back with a failure, rather than the one that we use for fraud fail. - $errors = $gateway->getTransactionErrors(); - $this->assertTrue( !empty( $errors ), 'No errors in getTransactionErrors after a bad "AuthorizePaymentForFraud"' ); - $this->assertTrue( array_key_exists( 'internal-0001', $errors ), 'Unexpected error code' ); - - //check more things to make sure we didn't run any fraud filters - $loglines = $this->getLogMatches( LogLevel::INFO, '/Preparing to run custom filters/' ); - $this->assertEmpty( $loglines, 'According to the logs, we ran antifraud filters and should not have' ); - $this->assertEquals( 'process', $gateway->getValidationAction(), 'Validation action is not as expected' ); - $exposed = TestingAccessWrapper::newFromObject( $gateway ); - $this->assertEquals( 0, $exposed->risk_score, 'RiskScore is not as expected' ); - - } - - /** - * Check to make sure we do run antifraud filters when we know the transaction is okay to go - */ - function testAntifraudPerformedOnGatewayNoError() { - $options = $this->getDonorTestData( 'FR' ); //don't really care: We'll be using the dummy response directly. - $options['email'] = '[email protected]'; - - $gateway = $this->getFreshGatewayObject( $options ); -// $gateway->setDummyGatewayResponseCode( 2208 ); //account problems - $gateway->do_transaction( 'AuthorizePaymentForFraud' ); - - //assert that: - //#1 - the gateway object has no errors set - //#2 - antifraud checks were performed. - $errors = $gateway->getTransactionErrors(); - $this->assertTrue( empty( $errors ), 'Errors assigned in getTransactionErrors after a good "AuthorizePaymentForFraud"' ); - //check more things to make sure we did run the fraud filters - $loglines = $this->getLogMatches( LogLevel::INFO, '/CustomFiltersScores/' ); - $this->assertNotEmpty( $loglines, 'No antifraud filters were run, according to the logs' ); - $this->assertEquals( 'process', $gateway->getValidationAction(), 'Validation action is not as expected' ); - $exposed = TestingAccessWrapper::newFromObject( $gateway ); - $this->assertEquals( 0, $exposed->risk_score, 'RiskScore is not as expected' ); - } - - /** - * Ensure we're staging a punctuation-stripped version of the email address in merchant_reference_2 - */ - function testMerchantReference2() { - $options = $this->getDonorTestData(); - $options['email'] = '[email protected]'; - $gateway = $this->getFreshGatewayObject( $options ); - $exposed = TestingAccessWrapper::newFromObject( $gateway ); - $exposed->stageData(); - $staged = $exposed->getData_Staged( 'merchant_reference_2' ); - $this->assertEquals( 'little teapot short stout com', $staged ); - } - - function testTransliterateUtf8forEurocentricProcessor() { - $options = $this->getDonorTestData(); - $options['fname'] = 'Barnabáš'; - $options['lname'] = 'Voříšek'; - $options['street'] = 'Truhlářská 320/62'; - $options['city'] = 'České Budějovice'; - $class = $this->testAdapterClass; - - $_SERVER['REQUEST_URI'] = GatewayFormChooser::buildPaymentsFormURL( 'testytest', array ( 'gateway' => $class::getIdentifier() ) ); - $gateway = $this->getFreshGatewayObject( $options ); - - $exposed = TestingAccessWrapper::newFromObject( $gateway ); - $exposed->stageData(); - $gateway->do_transaction( 'AuthorizeAndDepositPayment' ); - $xml = new SimpleXMLElement( preg_replace( '/StringIn=/', '', $gateway->curled ) ); - $this->assertEquals( 'Barnabás', $xml->FirstName ); - $this->assertEquals( 'Vorísek', $xml->LastName ); - $this->assertEquals( 'Truhlárská 320/62', $xml->Address1 ); - $this->assertEquals( 'Ceské Budejovice', $xml->City ); - } - - /** - * Check that whacky #.# format orderid is unmolested by order_id_meta validation. - */ - function testWackyOrderIdPassedValidation() { - $externalData = self::$initial_vars; - $externalData['order_id'] = '2143.0'; - $options = array( - 'external_data' => $externalData, - 'batch_mode' => true, - ); - - $gateway = new TestingWorldpayAdapter( $options ); - $this->assertEquals( $externalData['order_id'], $gateway->getData_Unstaged_Escaped( 'order_id' ), - 'Decimal Order ID should be allowed by orderIdMeta validation' ); - } - - /** - * Check that order_id is built from contribution_tracking id. - */ - function testWackyOrderIdBasedOnContributionTracking() { - $externalData = self::$initial_vars; - $externalData['contribution_tracking_id'] = mt_rand(); - $session = array( 'sequence' => 2 ); - - $this->setUpRequest( array(), $session ); - $gateway = $this->getFreshGatewayObject( $externalData, array( 'batch_mode' => TRUE, ) ); - $expected_order_id = "{$externalData['contribution_tracking_id']}.{$session['sequence']}"; - $this->assertEquals( $expected_order_id, $gateway->getData_Unstaged_Escaped( 'order_id' ), - 'Decimal Order ID is not correctly built from Contribution Tracking ID.' ); - } - - /** - * Ensure processResponse doesn't fail trxn for special accounts when AVS - * nodes are missing. - */ - function testProcessResponseAllowsSnowflakeAVSMissing() { - $options = $this->getDonorTestData( 'FJ' ); // 'FJ' store ID is set up as a special exception - - $gateway = $this->getFreshGatewayObject( $options ); - $gateway->setDummyGatewayResponseCode( 'snowflake' ); - $results = $gateway->do_transaction( 'AuthorizePaymentForFraud' ); - - // internal-0001 is the error code processRespose adds for missing nodes - $this->assertFalse( array_key_exists( 'internal-0001', $results->getErrors() ), - 'processResponse is failing a special snowflake account with a response missing AVS nodes' ); - } - - /** - * Ensure we don't give too high a risk score for special accounts when - * AVS address / zip match was not performed and CVV reports failure - */ - function testAntifraudAllowsSnowflakeAVSMissingAndCVVMismatch() { - $options = $this->getDonorTestData( 'FJ' ); // 'FJ' store ID is set up as a special exception - - $gateway = $this->getFreshGatewayObject( $options ); - $gateway->setDummyGatewayResponseCode( 'snowflake' ); - $gateway->do_transaction( 'AuthorizePaymentForFraud' ); - - $this->assertTrue( $gateway->getCVVResult(), 'getCVVResult failing snowflake account' ); - - $this->assertTrue( $gateway->getAVSResult() < 25, 'getAVSResult giving snowflake account too high a risk score' ); - } - - function testNarrativeStatement1() { - $class = $this->testAdapterClass; - $_SERVER['REQUEST_URI'] = GatewayFormChooser::buildPaymentsFormURL( 'testytest', array ( 'gateway' => $class::getIdentifier() ) ); - $options = $this->getDonorTestData(); - $options['contribution_tracking_id'] = mt_rand(); - $gateway = $this->getFreshGatewayObject( $options ); - - $exposed = TestingAccessWrapper::newFromObject( $gateway ); - $exposed->stageData(); - $gateway->do_transaction( 'AuthorizeAndDepositPayment' ); - $xml = new SimpleXMLElement( preg_replace( '/StringIn=/', '', $gateway->curled ) ); - $this->assertEquals( "Wikimedia {$options['contribution_tracking_id']}", $xml->NarrativeStatement1 ); - } - - /** - * Check that we send different OrderNumbers for each transaction in a donation. - */ - function testDistinctOrderNumberForEachTxn() { - $options = $this->getDonorTestData(); - $gateway = $this->getFreshGatewayObject( $options ); - - $getOrderNumber = function() use ( $gateway ) { - $xml = new SimpleXMLElement( preg_replace( '/StringIn=/', '', $gateway->curled ) ); - return $xml->OrderNumber; - }; - - $gateway->do_transaction( 'AuthorizePaymentForFraud' ); - $fraudOrderNumber = $getOrderNumber(); - $gateway->do_transaction( 'AuthorizeAndDepositPayment' ); - $saleOrderNumber = $getOrderNumber(); - - $this->assertNotEquals( $fraudOrderNumber, $saleOrderNumber, - 'Sending same OrderNumber for both fraud auth and sale.' ); - } - - /** - * doPayment should return an empty result with normal data - */ - function testDoPaymentSuccess() { - $init = $this->getDonorTestData(); - $init['payment_method'] = 'cc'; - $init['payment_submethod'] = 'visa'; - $init['email'] = '[email protected]'; - $init['ffname'] = 'worldpay'; - $init['currency_code'] = 'EUR'; - $init['OTT'] = 'SALT123456789'; - unset( $init['order_id'] ); - - $gateway = $this->getFreshGatewayObject( $init ); - $result = $gateway->doPayment(); - $this->assertEmpty( $result->isFailed(), 'PaymentResult should not be failed' ); - $this->assertEmpty( $result->getErrors(), 'PaymentResult should have no errors' ); - } - - /** - * doPayment should return a failed result with data that triggers the fraud - * filter - */ - function testDoPaymentFailed() { - $init = $this->getDonorTestData(); - $init['payment_method'] = 'cc'; - $init['payment_submethod'] = 'visa'; - $init['email'] = '[email protected]'; //configured as fraudy - $init['ffname'] = 'worldpay'; - $init['currency_code'] = 'EUR'; - $init['OTT'] = 'SALT123456789'; - unset( $init['order_id'] ); - - $gateway = $this->getFreshGatewayObject( $init ); - $result = $gateway->doPayment(); - $this->assertTrue( $result->isFailed(), 'PaymentResult should be failed' ); - $errors = $result->getErrors(); - - $this->assertEquals( - 'Failed post-process checks for transaction type AuthorizePaymentForFraud.', - $errors['internal-0000']['debugInfo'], - 'PaymentResult errors should include fraud check failure' - ); - } -} ->>>>>>> BRANCH (9f09ff Expand list of penalized fraudy error codes) diff --git a/tests/DonationInterfaceTestCase.php b/tests/DonationInterfaceTestCase.php deleted file mode 100644 index c734fa9..0000000 --- a/tests/DonationInterfaceTestCase.php +++ /dev/null @@ -1,693 +0,0 @@ -<<<<<<< HEAD (c8e1e4 Merge master into deployment) -======= -<?php -/** - * Wikimedia Foundation - * - * LICENSE - * - * 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. - * - */ -use Psr\Log\LogLevel; - -/** - * @group Fundraising - * @group QueueHandling - * @group ClassMethod - * @group ListenerAdapter - * - * @category UnitTesting - * @package Fundraising_QueueHandling - */ -abstract class DonationInterfaceTestCase extends MediaWikiTestCase { - protected $backupGlobalsBlacklist = array( - 'wgHooks', - ); - - /** - * An array of the vars we expect to be set before people hit payments. - * @var array - */ - public static $initial_vars = array ( - 'ffname' => 'testytest', - 'referrer' => 'www.yourmom.com', //please don't go there. - 'currency_code' => 'USD', - ); - - /** - * This will be set by a test method with the adapter object. - * - * @var GatewayAdapter $gatewayAdapter - */ - protected $gatewayAdapter; - - /** - * @var TestingDonationLogger - */ - protected $testLogger; - - /** - * @param $name string The name of the test case - * @param $data array Any parameters read from a dataProvider - * @param $dataName string|int The name or index of the data set - */ - public function __construct( $name = null, array $data = array(), $dataName = '' ) { - - //Just in case you got here without running the configuration... - global $wgDonationInterfaceTestMode; - $wgDonationInterfaceTestMode = true; - - $adapterclass = TESTS_ADAPTER_DEFAULT; - $this->testAdapterClass = $adapterclass; - - parent::__construct( $name, $data, $dataName ); - } - - protected function setUp() { - $this->testLogger = new TestingDonationLogger(); - DonationLoggerFactory::$overrideLogger = $this->testLogger; - parent::setUp(); - } - - protected function tearDown() { - $this->resetAllEnv(); - DonationLoggerFactory::$overrideLogger = null; - parent::tearDown(); - } - - /** - * Set up a fake request with the given data. Returns the fake request. - * @param array $data - * @param array $session - * @return FauxRequest - */ - protected function setUpRequest( $data, $session = null ) { - RequestContext::resetMain(); - $request = new FauxRequest( $data, false, $session ); - RequestContext::getMain()->setRequest( $request ); - return $request; - } - - /** - * buildRequestXmlForGlobalCollect - * - * @todo - * - there are many cases to this that need to be developed. - * - Do not consider this a complete test! - * - * @covers GatewayAdapter::__construct - * @covers GatewayAdapter::setCurrentTransaction - * @covers GatewayAdapter::buildRequestXML - */ - public function buildRequestXmlForGlobalCollect( $optionsForTestData, $options ) { - - global $wgDonationInterfaceTest; - - $wgDonationInterfaceTest = true; - - $this->setUpRequest( $options ); - $this->gatewayAdapter = new TestingGlobalCollectAdapter(); - - $this->gatewayAdapter->setCurrentTransaction('INSERT_ORDERWITHPAYMENT'); - - $exposed = TestingAccessWrapper::newFromObject( $this->gatewayAdapter ); - $request = trim( $exposed->buildRequestXML() ); - - $this->setUpRequest( $options ); - $expected = $this->getExpectedXmlRequestForGlobalCollect( $optionsForTestData, $options ); - - $this->assertEquals( $expected, $request, 'The constructed XML for payment_method [' . $optionsForTestData['payment_method'] . '] and payment_submethod [' . $optionsForTestData['payment_submethod'] . '] does not match our expected request.' ); - } - - /** - * - * @param string $country The country we want the test user to be from. - * @return array Donor data to use - * @throws OutOfBoundsException when there is no data available for the requested country - */ - public static function getDonorTestData( $country = '' ) { - $donortestdata = array ( - 'US' => array ( //default - 'city' => 'San Francisco', - 'state' => 'CA', - 'zip' => '94105', - 'currency_code' => 'USD', - 'street' => '123 Fake Street', - 'fname' => 'Firstname', - 'lname' => 'Surname', - 'amount' => '1.55', - 'language' => 'en', - 'email' => '[email protected]', - ), - 'ES' => array ( - 'city' => 'Barcelona', - 'state' => 'XX', - 'zip' => '0', - 'currency_code' => 'EUR', - 'street' => '123 Calle Fake', - 'fname' => 'Nombre', - 'lname' => 'Apellido', - 'amount' => '1.55', - 'language' => 'es', - ), - 'Catalonia' => array ( - 'city' => 'Barcelona', - 'state' => 'XX', - 'zip' => '0', - 'currency_code' => 'EUR', - 'street' => '123 Calle Fake', - 'fname' => 'Nombre', - 'lname' => 'Apellido', - 'amount' => '1.55', - 'language' => 'ca', - ), - 'NO' => array ( - 'city' => 'Oslo', - 'state' => 'XX', - 'zip' => '0', - 'currency_code' => 'EUR', - 'street' => '123 Fake Gate', - 'fname' => 'Fornavn', - 'lname' => 'Etternavn', - 'amount' => '1.55', - 'language' => 'no', - ), - 'FR' => array ( - 'city' => 'Versailles', - 'state' => 'XX', - 'zip' => '0', - 'currency_code' => 'EUR', - 'street' => '123 Rue Faux', - 'fname' => 'Prénom', - 'lname' => 'Nom', - 'amount' => '1.55', - 'language' => 'fr', - ), - // Fiji is configured as a snowflake to test special treatment for certain store IDs - 'FJ' => array ( - 'city' => 'Suva', - 'state' => 'XX', - 'zip' => '0', - 'currency_code' => 'EUR', - 'street' => '123 Fake Street', - 'fname' => 'FirstName', - 'lname' => 'LastName', - 'amount' => '1.55', - 'language' => 'en', - ), - 'NL' => array ( - 'city' => 'Amsterdam', - 'state' => 'XX', - 'zip' => '0', - 'currency_code' => 'EUR', - 'street' => '123 nep straat', - 'fname' => 'Voornaam', - 'lname' => 'Achternaam', - 'amount' => '1.55', - 'language' => 'nl', - ), - 'BE' => array ( - 'city' => 'Antwerp', - 'state' => 'XX', - 'zip' => '0', - 'currency_code' => 'EUR', - 'street' => '123 nep straat', - 'fname' => 'Voornaam', - 'lname' => 'Achternaam', - 'amount' => '1.55', - 'language' => 'nl', - ), - 'IT' => array ( - 'city' => 'Torino', - 'state' => 'TO', - 'zip' => '10123', - 'currency_code' => 'EUR', - 'street' => 'Via Falso 123', - 'fname' => 'Nome', - 'lname' => 'Cognome', - 'amount' => '1.55', - 'language' => 'it', - ), - 'CA' => array ( - 'city' => 'Saskatoon', - 'state' => 'SK', - 'zip' => 'S7K 0J5', - 'currency_code' => 'CAD', - 'street' => '123 Fake Street', - 'fname' => 'Firstname', - 'lname' => 'Surname', - 'amount' => '1.55', - 'language' => 'en', - ), - 'BR' => array ( - 'currency_code' => 'BRL', - 'fiscal_number' => '00003456789', - 'payment_submethod' => 'test_bank', - 'fname' => 'Nome', - 'lname' => 'Apelido', - 'amount' => '100', - 'language' => 'pt', - 'email' => '[email protected]' - ), - ); - //default to US - if ( $country === '' ) { - $country = 'US'; - } - - if ( array_key_exists( $country, $donortestdata ) ) { - $donortestdata = array_merge( self::$initial_vars, $donortestdata[$country] ); - $donortestdata['country'] = $country; - return $donortestdata; - } - throw new OutOfBoundsException( __FUNCTION__ . ": No donor data for country '$country'" ); - } - - /** - * Supported languages for Belgium - */ - public function belgiumLanguageProvider() { - return array( - array( 'nl' ), - array( 'de' ), - array( 'fr' ), - ); - } - - /** - * Supported languages for Canada - */ - public function canadaLanguageProvider() { - return array( - array( 'en' ), - array( 'fr' ), - ); - } - - /** - * Transaction codes for GC and GC orphan adapters not to be retried - * on pain of $1000+ fines by MasterCard - */ - public function mcNoRetryCodeProvider() { - return array( - array( '430260' ), - array( '430306' ), - array( '430330' ), - array( '430354' ), - array( '430357' ), - ); - } - - public function benignNoRetryCodeProvider() { - return array( - array( '430285' ), - ); - } - - /** - * Get the expected XML request from GlobalCollect - * - * @param $optionsForTestData - * @param array $options - * @return string The expected XML request - */ - public function getExpectedXmlRequestForGlobalCollect( $optionsForTestData, $options = array() ) { - global $wgDonationInterfaceThankYouPage; - $request = RequestContext::getMain()->getRequest(); - - $orderId = $this->gatewayAdapter->getData_Unstaged_Escaped( 'order_id' ); - $exposed = TestingAccessWrapper::newFromObject( $this->gatewayAdapter ); - $merchantref = $exposed->getData_Staged( 'contribution_tracking_id' ); - //@TODO: WHY IN THE NAME OF ZARQUON are we building XML in a STRING format here?!?!?!!!1one1!?. Great galloping galumphing giraffes. - $expected = '<?xml version="1.0" encoding="UTF-8"?' . ">\n"; - $expected .= '<XML>'; - $expected .= '<REQUEST>'; - $expected .= '<ACTION>INSERT_ORDERWITHPAYMENT</ACTION>'; - $expected .= '<META><MERCHANTID>' . $exposed->account_config[ 'MerchantID' ] . '</MERCHANTID>'; - - if ( isset( $request ) ) { - $expected .= '<IPADDRESS>' . $request->getIP() . '</IPADDRESS>'; - } - - $expected .= '<VERSION>1.0</VERSION>'; - $expected .= '</META>'; - $expected .= '<PARAMS>'; - $expected .= '<ORDER>'; - $expected .= '<ORDERID>' . $orderId . '</ORDERID>'; - $expected .= '<AMOUNT>' . $options['amount'] * 100 . '</AMOUNT>'; - $expected .= '<CURRENCYCODE>' . $options['currency_code'] . '</CURRENCYCODE>'; - $expected .= '<LANGUAGECODE>' . $options['language'] . '</LANGUAGECODE>'; - $expected .= '<COUNTRYCODE>' . $options['country'] . '</COUNTRYCODE>'; - $expected .= '<MERCHANTREFERENCE>' . $merchantref . '</MERCHANTREFERENCE>'; - - if ( isset( $request ) ) { - $expected .= '<IPADDRESSCUSTOMER>' . $request->getIP() . '</IPADDRESSCUSTOMER>'; - } - - $expected .= '<EMAIL>' . TESTS_EMAIL . '</EMAIL>'; - $expected .= '</ORDER>'; - $expected .= '<PAYMENT>'; - $expected .= '<PAYMENTPRODUCTID>' . $optionsForTestData['payment_product_id'] . '</PAYMENTPRODUCTID>'; - $expected .= '<AMOUNT>' . $options['amount'] * 100 . '</AMOUNT>'; - $expected .= '<CURRENCYCODE>' . $options['currency_code'] . '</CURRENCYCODE>'; - $expected .= '<LANGUAGECODE>' . $options['language'] . '</LANGUAGECODE>'; - $expected .= '<COUNTRYCODE>' . $options['country'] . '</COUNTRYCODE>'; - $expected .= '<HOSTEDINDICATOR>1</HOSTEDINDICATOR>'; - $expected .= "<RETURNURL>{$wgDonationInterfaceThankYouPage}/{$options['language']}?country={$options['country']}</RETURNURL>"; - $expected .= '<AUTHENTICATIONINDICATOR>0</AUTHENTICATIONINDICATOR>'; - $expected .= '<FIRSTNAME>' . $options['fname'] . '</FIRSTNAME>'; - $expected .= '<SURNAME>' . $options['lname'] . '</SURNAME>'; - $expected .= '<STREET>' . $options['street'] . '</STREET>'; - $expected .= '<CITY>' . $options['city'] . '</CITY>'; - $expected .= '<STATE>' . $options['state'] . '</STATE>'; - $expected .= '<ZIP>' . $options['zip'] . '</ZIP>'; - $expected .= '<EMAIL>' . TESTS_EMAIL . '</EMAIL>'; - - // Set the issuer id if it is passed. - if ( isset( $optionsForTestData['descriptor'] ) ) { - $expected .= '<DESCRIPTOR>' . $optionsForTestData['descriptor'] . '</DESCRIPTOR>'; - } - - // Set the issuer id if it is passed. - if ( isset( $optionsForTestData['issuer_id'] ) ) { - $expected .= '<ISSUERID>' . $optionsForTestData['issuer_id'] . '</ISSUERID>'; - } - - - // If we're doing Direct Debit... - //@TODO: go ahead and split this out into a "Get the direct debit I_OWP XML block function" the second this gets even slightly annoying. - if ( $optionsForTestData['payment_method'] === 'dd' ) { - $expected .= '<DATECOLLECT>' . gmdate( 'Ymd' ) . '</DATECOLLECT>'; //is this cheating? Probably. - $expected .= '<ACCOUNTNAME>' . $optionsForTestData['account_name'] . '</ACCOUNTNAME>'; - $expected .= '<ACCOUNTNUMBER>' . $optionsForTestData['account_number'] . '</ACCOUNTNUMBER>'; - $expected .= '<BANKCODE>' . $optionsForTestData['bank_code'] . '</BANKCODE>'; - $expected .= '<BRANCHCODE>' . $optionsForTestData['branch_code'] . '</BRANCHCODE>'; - $expected .= '<BANKCHECKDIGIT>' . $optionsForTestData['bank_check_digit'] . '</BANKCHECKDIGIT>'; - $expected .= '<DIRECTDEBITTEXT>' . $optionsForTestData['direct_debit_text'] . '</DIRECTDEBITTEXT>'; - } - - $expected .= '</PAYMENT>'; - $expected .= '</PARAMS>'; - $expected .= '</REQUEST>'; - $expected .= '</XML>'; - - return $expected; - - } - - /** - * Get a fresh gateway object of the type specified in the variable - * $this->testAdapterClass. - * @param array $external_data If you want to shoehorn in some external - * data, do that here. - * @param array $setup_hacks An array of things that override stuff in - * the constructor of the gateway object that I can't get to without - * refactoring the whole thing. @TODO: Refactor the gateway adapter - * constructor. - * @return GatewayAdapter The new relevant gateway adapter object. - */ - function getFreshGatewayObject( $external_data = null, $setup_hacks = array() ) { - $p1 = null; - if ( !is_null( $external_data ) ) { - $p1 = array ( - 'external_data' => $external_data, - ); - } - - if ( $setup_hacks ) { - if ( !is_null( $p1 ) ) { - $p1 = array_merge( $p1, $setup_hacks ); - } else { - $p1 = $setup_hacks; - } - } - - $class = $this->testAdapterClass; - $gateway = new $class( $p1 ); - - // FIXME: Find a more elegant way to hackity hacken hack. - // We want to override any define- functions with hacky values. - foreach ( $setup_hacks as $field => $value ) { - $gateway->$field = $value; - } - - return $gateway; - } - - function resetAllEnv() { - $_SESSION = array ( ); - $_GET = array ( ); - $_POST = array ( ); - - $_SERVER = array ( ); - $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; - $_SERVER['HTTP_HOST'] = TESTS_HOSTNAME; - $_SERVER['SERVER_NAME'] = TESTS_HOSTNAME; - $_SERVER['SCRIPT_NAME'] = __FILE__; - - RequestContext::resetMain(); - // The following is only needed until 1.27, as the above reset only - // sets the request back to $wgRequest - $request = RequestContext::getMain()->getRequest(); - if ( $request instanceof FauxRequest ) { - $session = $request->getSessionArray(); - if ( is_array( $session ) ) { - foreach( $session as $key => $value ) { - $request->setSessionData( $key, null ); - } - } - } - - // Wipe out the $instance of these classes to make sure they're - // re-created with fresh gateway instances for the next test - $singleton_classes = array( - 'Gateway_Extras_ConversionLog', - 'Gateway_Extras_CustomFilters', - 'Gateway_Extras_CustomFilters_Functions', - 'Gateway_Extras_CustomFilters_IP_Velocity', - 'Gateway_Extras_CustomFilters_MinFraud', - 'Gateway_Extras_CustomFilters_Referrer', - 'Gateway_Extras_CustomFilters_Source', - 'Gateway_Extras_SessionVelocityFilter', - ); - foreach( $singleton_classes as $singleton_class ) { - $singleton_class::$instance = null; - } - } - - /** - * Instantiates the $special_page_class with supplied $initial_vars, - * yoinks the html output from the output buffer, loads that into a - * DomDocument and performs asserts on the results per the checks - * supplied in $perform_these_checks. - * Optional: Asserts that the gateway has logged nothing at ERROR level. - * - * @param class $special_page_class A testing descendant of GatewayPage - * @param array $initial_vars Array that will be loaded straight into a - * test version of the http request. - * @param array $perform_these_checks Array of checks to perform in the - * following format: - * $perform_these_checks[$element_id][$check_to_perform][$expected_result] - * So far, $check_to_perform can be either 'nodename' or 'innerhtml' - * @param boolean $fail_on_log_errors When true, this will fail the - * current test if there are entries in the gateway's error log. - * @param array $session pre-existing session data. - */ - function verifyFormOutput( $special_page_class, $initial_vars, $perform_these_checks, $fail_on_log_errors = false, $session = null ) { - // Nasty hack to clear output from any previous tests. - $mainContext = RequestContext::getMain(); - $newOutput = new OutputPage( $mainContext ); - $newRequest = new TestingRequest( $initial_vars, false, $session ); - $newTitle = Title::newFromText( 'nonsense is apparently fine' ); - $mainContext->setRequest( $newRequest ); - $mainContext->setOutput( $newOutput ); - $mainContext->setTitle( $newTitle ); - - $globals = array ( - 'wgTitle' => $newTitle, - 'wgOut' => $newOutput, - ); - - $this->setMwGlobals( $globals ); - - $this->setLanguage( $initial_vars['language'] ); - - ob_start(); - $formpage = new $special_page_class(); - $formpage->execute( NULL ); - $formpage->getOutput()->output(); - $form_html = ob_get_contents(); - ob_end_clean(); - - // In the event that something goes crazy, uncomment the next line for much easier local debugging - // file_put_contents( '/tmp/xmlout.txt', $form_html ); - - if ( $fail_on_log_errors ) { - $this->verifyNoLogErrors(); - } - - $dom_thingy = new DomDocument(); - //// DEBUGGING, foo - // if (property_exists($this, 'FOO')) { - // error_log(var_export($formpage->getRequest()->response()->getheader('Location'), true)); - // error_log(var_export($form_html, true)); - // } - - if ( $form_html ) { - // p.s. i'm SERIOUS about the character encoding. - $dom_thingy->loadHTML( '<?xml encoding="UTF-8">' . $form_html ); - $dom_thingy->encoding = 'UTF-8'; - } - - foreach ( $perform_these_checks as $id => $checks ) { - if ( $id == 'headers' ) { - foreach ( $checks as $name => $expected ) { - $actual = $formpage->getRequest()->response()->getheader( $name ); - $this->performCheck( $actual, $expected, "header '$name'"); - break; - } - continue; - } - unset( $perform_these_checks['headers'] ); - - $input_node = $dom_thingy->getElementById( $id ); - $this->assertNotNull( $input_node, "Couldn't find the '$id' element" ); - foreach ( $checks as $name => $expected ) { - switch ( $name ) { - case 'nodename': - $this->performCheck( $input_node->nodeName, $expected, "name of node with id '$id'"); - break; - case 'innerhtml': - $actual_html = self::getInnerHTML( $input_node ); - // Strip comments - $actual_html = preg_replace( '/<!--[^>]*-->/', '', $actual_html ); - $this->performCheck( $actual_html, $expected, "innerHTML of node '$id'"); - break; - case 'innerhtmlmatches': - $this->assertEquals( 1, preg_match( $expected, self::getInnerHTML( $input_node ) ), "Value of the node with id '$id' does not match pattern '$expected'. It has value " . self::getInnerHTML( $input_node ) ); - break; - case 'value': - $this->performCheck( $input_node->getAttribute('value'), $expected, "value of node with id '$id'"); - break; - case 'selected': - $selected = null; - if ( $input_node->nodeName === 'select' ) { - $options = $input_node->getElementsByTagName( 'option' ); - foreach ( $options as $option ) { - if ( $option->hasAttribute( 'selected' ) ) { - $selected = $option->getAttribute( 'value' ); - break; - } - } - $this->performCheck( $selected, $expected, "selected option value of node with id '$id'"); - } else { - $this->fail( "Attempted to test for selected value on non-select node, id '$id'" ); - } - break; - } - } - } - - // Are there untranslated boogers? - if ( preg_match_all( '/<[^<]+(>|>)/', $form_html, $matches ) ) { - $this->fail( 'Untranslated messages present: ' . implode( ', ', $matches[0] ) ); - } - } - - /** - * Performs some sort of assertion on a value. - * - * @param string $value the value to test - * @param string|callable $check - * if $check is callable, it is called with argument $value - * otherwise, $value is asserted to be equal to $check - * @param string $label identifies the value in assertion failures - * @return void - */ - function performCheck( $value, $check, $label = 'Tested value' ) { - if ( is_callable( $check ) ) { - $check( $value ); - return; - } - $this->assertEquals( $check, $value, "Expected $label to be $check, found $value instead."); - } - /** - * Asserts that there are no log entries of LOG_ERR or worse. - */ - function verifyNoLogErrors( ) { - $log = $this->testLogger->messages; - - $this->assertTrue( is_array( $log ), "Missing the test log" ); - - //for our purposes, an "error" is LOG_ERR or less. - $checklogs = array ( - LogLevel::ERROR => "Oops: We've got LOG_ERRors.", - LogLevel::CRITICAL => "Critical errors!", - LogLevel::ALERT => "Log Alerts!", - LogLevel::EMERGENCY => "Logs says the servers are actually on fire.", - ); - - $message = false; - foreach ( $checklogs as $level => $levelmessage ) { - if ( array_key_exists( $level, $log ) ) { - $message = $levelmessage . ' ' . print_r( $log[$level], true ) . "\n"; - } - } - - $this->assertFalse( $message, $message ); //ha - } - - /** - * Finds a relevant line/lines in a gateway's log array - * @param string $log_level One of the constants in \Psr\Log\LogLevel - * @param string $match A regex to match against the log lines. - * @return array All log lines that match $match. - */ - public function getLogMatches( $log_level, $match ) { - $log = $this->testLogger->messages; - if ( !array_key_exists( $log_level, $log ) ) { - return false; - } - $return = array ( ); - foreach ( $log[$log_level] as $line ) { - if ( preg_match( $match, $line ) ) { - $return[] = $line; - } - } - return $return; - } - - /** - * Set global language for the duration of the test - * - * @param string $language language code to force - */ - protected function setLanguage( $language ) { - $newLang = new TestingLanguage(); - //this should be more robust, but... might have to work for now. - $newLang->forceLang( $language ); - - $this->setMwGlobals( array ( - 'wgLang' => $newLang, - ) ); - } - - static function getInnerHTML( $node ) { - $innerHTML = ''; - $children = $node->childNodes; - foreach ( $children as $child ) { - $innerHTML .= $child->ownerDocument->saveXML( $child ); - } - return $innerHTML; - } -} ->>>>>>> BRANCH (9f09ff Expand list of penalized fraudy error codes) -- To view, visit https://gerrit.wikimedia.org/r/273018 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id5925b985236553dd21667ea0addc6b0fa692491 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/DonationInterface Gerrit-Branch: deployment Gerrit-Owner: Ejegg <[email protected]> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
