jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/364143 )
Change subject: Add Ingenico Connect gateway based on GlobalCollect
......................................................................
Add Ingenico Connect gateway based on GlobalCollect
Swaps out curl_transaction for API calls and does json response parsing.
Shows an Ingenico Connect hosted checkout form!
TODO: parse errors, remove debug code added to verifyFormOutput
Bug: T163946
Change-Id: I4c02abd190b1ea27c1921f37196481d87cd0162a
---
M DonationInterface.class.php
M extension.json
M gateway_common/donation.api.php
A ingenico_gateway/IngenicoOrphanRectifier.php
A ingenico_gateway/config/country_fields.yaml
A ingenico_gateway/config/currencies.yaml
A ingenico_gateway/config/data_constraints.yaml
A ingenico_gateway/config/error_map.yaml
A ingenico_gateway/config/payment_methods.yaml
A ingenico_gateway/config/payment_submethods.yaml
A ingenico_gateway/config/transformers.yaml
A ingenico_gateway/config/var_map.yaml
A ingenico_gateway/ingenico.adapter.php
A ingenico_gateway/ingenico_gateway.alias.php
A ingenico_gateway/ingenico_gateway.body.php
A ingenico_gateway/ingenico_resultswitcher.body.php
A ingenico_gateway/orphan.adapter.php
A tests/phpunit/Adapter/Ingenico/IngenicoApiTest.php
A tests/phpunit/Adapter/Ingenico/IngenicoFormLoadTest.php
A tests/phpunit/Adapter/Ingenico/IngenicoOrphanAdapterTest.php
A tests/phpunit/Adapter/Ingenico/IngenicoOrphanRectifierTest.php
A tests/phpunit/Adapter/Ingenico/IngenicoTest.php
A tests/phpunit/Adapter/Ingenico/RealTimeBankTransferIdealTest.php
A tests/phpunit/Adapter/Ingenico/RecurringTest.php
A tests/phpunit/Adapter/Ingenico/ResultSwitcherTest.php
A tests/phpunit/BaseIngenicoTestCase.php
M tests/phpunit/DonationInterfaceTestCase.php
M tests/phpunit/TestConfiguration.php
28 files changed, 2,287 insertions(+), 16 deletions(-)
Approvals:
Mepps: Looks good to me, approved
jenkins-bot: Verified
diff --git a/DonationInterface.class.php b/DonationInterface.class.php
index 8f014e6..4282c2b 100644
--- a/DonationInterface.class.php
+++ b/DonationInterface.class.php
@@ -69,6 +69,7 @@
$wgAutoloadClasses['DonationInterfaceTestCase'] = $testDir .
'DonationInterfaceTestCase.php';
$wgAutoloadClasses['DonationInterfaceApiTestCase'] = $testDir .
'DonationInterfaceApiTestCase.php';
+ $wgAutoloadClasses['BaseIngenicoTestCase'] = $testDir .
'BaseIngenicoTestCase.php';
$wgAutoloadClasses['MockAmazonClient'] = $testDir .
'includes/MockAmazonClient.php';
$wgAutoloadClasses['MockAmazonResponse'] = $testDir .
'includes/MockAmazonResponse.php';
$wgAutoloadClasses['TestingAdyenAdapter'] = $testDir .
'includes/test_gateway/TestingAdyenAdapter.php';
diff --git a/extension.json b/extension.json
index 39afef2..9c0058a 100644
--- a/extension.json
+++ b/extension.json
@@ -26,6 +26,8 @@
"SystemStatus": "SystemStatus",
"GlobalCollectGateway": "GlobalCollectGateway",
"GlobalCollectGatewayResult": "GlobalCollectGatewayResult",
+ "IngenicoGateway": "IngenicoGateway",
+ "IngenicoGatewayResult": "IngenicoGatewayResult",
"AmazonGateway": "AmazonGateway",
"AdyenGateway": "AdyenGateway",
"AdyenGatewayResult": "AdyenGatewayResult",
@@ -57,6 +59,7 @@
"GatewayAliases": "DonationInterface.alias.php",
"AmazonGatewayAlias": "amazon_gateway/amazon_gateway.alias.php",
"GlobalCollectGatewayAlias":
"globalcollect_gateway/globalcollect_gateway.alias.php",
+ "IngenicoGatewayAlias":
"ingenico_gateway/ingenico_gateway.alias.php",
"AdyenGatewayAlias": "adyen_gateway/adyen_gateway.alias.php",
"AstroPayGatewayAlias":
"astropay_gateway/astropay_gateway.alias.php",
"PaypalGatewayAlias": "paypal_gateway/paypal_gateway.alias.php"
@@ -115,8 +118,13 @@
"GlobalCollectGateway":
"globalcollect_gateway/globalcollect_gateway.body.php",
"GlobalCollectGatewayResult":
"globalcollect_gateway/globalcollect_resultswitcher.body.php",
"GlobalCollectAdapter":
"globalcollect_gateway/globalcollect.adapter.php",
+ "IngenicoGateway": "ingenico_gateway/ingenico_gateway.body.php",
+ "IngenicoGatewayResult":
"ingenico_gateway/ingenico_resultswitcher.body.php",
+ "IngenicoAdapter": "ingenico_gateway/ingenico.adapter.php",
"GlobalCollectOrphanAdapter":
"globalcollect_gateway/orphan.adapter.php",
"GlobalCollectOrphanRectifier":
"globalcollect_gateway/GlobalCollectOrphanRectifier.php",
+ "IngenicoOrphanAdapter": "ingenico_gateway/orphan.adapter.php",
+ "IngenicoOrphanRectifier":
"ingenico_gateway/IngenicoOrphanRectifier.php",
"IngenicoFinancialNumber":
"globalcollect_gateway/IngenicoFinancialNumber.php",
"IngenicoLanguage":
"globalcollect_gateway/IngenicoLanguage.php",
"IngenicoMethodCodec":
"globalcollect_gateway/IngenicoMethodCodec.php",
@@ -424,6 +432,7 @@
"DonationInterfaceMinfraudErrorScore": 50,
"DonationInterfaceEnableBannerHistoryLog": false,
"GlobalCollectGatewayEnabled": false,
+ "IngenicoGatewayEnabled": false,
"AmazonGatewayEnabled": false,
"AdyenGatewayEnabled": false,
"AstroPayGatewayEnabled": false,
@@ -440,6 +449,8 @@
"DonationInterfaceGatewayAdapters": {
"globalcollect": "GlobalCollectAdapter",
"globalcollect_orphan": "GlobalCollectOrphanAdapter",
+ "ingenico": "IngenicoAdapter",
+ "ingenico_orphan": "IngenicoOrphanAdapter",
"amazon": "AmazonAdapter",
"adyen": "AdyenAdapter",
"astropay": "AstroPayAdapter",
diff --git a/gateway_common/donation.api.php b/gateway_common/donation.api.php
index 107f62c..16a6e7a 100644
--- a/gateway_common/donation.api.php
+++ b/gateway_common/donation.api.php
@@ -37,20 +37,27 @@
return;
}
- if ( $this->gateway == 'globalcollect' ) {
- switch ( $method ) {
- // TODO: add other iframe payment methods
- case 'cc':
- $result = $gatewayObj->do_transaction(
'INSERT_ORDERWITHPAYMENT' );
- break;
- default:
- $result = $gatewayObj->do_transaction(
'TEST_CONNECTION' );
- }
- } elseif ( $this->gateway == 'adyen' ) {
- $result = $gatewayObj->do_transaction( 'donate' );
- } elseif ( $this->gateway === 'paypal_ec' ) {
- $gatewayObj->doPayment();
- $result = $gatewayObj->getTransactionResponse();
+ switch( $this->gateway ) {
+ case 'globalcollect':
+ switch ( $method ) {
+ // TODO: add other iframe payment
methods
+ case 'cc':
+ $result =
$gatewayObj->do_transaction( 'INSERT_ORDERWITHPAYMENT' );
+ break;
+ default:
+ $result =
$gatewayObj->do_transaction( 'TEST_CONNECTION' );
+ }
+ break;
+ case 'ingenico':
+ $result = $gatewayObj->do_transaction(
'createHostedCheckout' );
+ break;
+ case 'adyen':
+ $result = $gatewayObj->do_transaction( 'donate'
);
+ break;
+ case 'paypal_ec':
+ $gatewayObj->doPayment();
+ $result = $gatewayObj->getTransactionResponse();
+ break;
}
// $normalizedData = $gatewayObj->getData_Unstaged_Escaped();
diff --git a/ingenico_gateway/IngenicoOrphanRectifier.php
b/ingenico_gateway/IngenicoOrphanRectifier.php
new file mode 100644
index 0000000..47273d7
--- /dev/null
+++ b/ingenico_gateway/IngenicoOrphanRectifier.php
@@ -0,0 +1,5 @@
+<?php
+
+class IngenicoOrphanRectifier extends GlobalCollectOrphanRectifier {
+
+}
\ No newline at end of file
diff --git a/ingenico_gateway/config/country_fields.yaml
b/ingenico_gateway/config/country_fields.yaml
new file mode 120000
index 0000000..b45ff73
--- /dev/null
+++ b/ingenico_gateway/config/country_fields.yaml
@@ -0,0 +1 @@
+../../globalcollect_gateway/config/country_fields.yaml
\ No newline at end of file
diff --git a/ingenico_gateway/config/currencies.yaml
b/ingenico_gateway/config/currencies.yaml
new file mode 120000
index 0000000..8234aeb
--- /dev/null
+++ b/ingenico_gateway/config/currencies.yaml
@@ -0,0 +1 @@
+../../globalcollect_gateway/config/currencies.yaml
\ No newline at end of file
diff --git a/ingenico_gateway/config/data_constraints.yaml
b/ingenico_gateway/config/data_constraints.yaml
new file mode 100644
index 0000000..166021f
--- /dev/null
+++ b/ingenico_gateway/config/data_constraints.yaml
@@ -0,0 +1,62 @@
+# General fields
+# AMOUNT: N12
+amount:
+ type: numeric
+ length: 12
+# city: AN40
+city:
+ type: alphanumeric
+ length: 40
+# countryCode: AN2
+country:
+ type: alphanumeric
+ length: 2
+# currency: AN3
+currency:
+ type: alphanumeric
+ length: 3
+# emailAddress: AN70
+email:
+ type: alphanumeric
+ length: 70
+# firstName: AN15
+first_name:
+ type: alphanumeric
+ length: 15
+# IPADDRESS: AN32
+user_ip:
+ type: alphanumeric
+ length: 32
+# locale: AN5
+language:
+ type: alphanumeric
+ length: 5
+# merchantReference: N10
+order_id:
+ type: numeric
+ length: 10
+# paymentProductId
+payment_product:
+ type: numeric
+ length: 5
+# returnUrl: AN512
+returnto:
+ type: alphanumeric
+ length: 512
+# state: AN35
+state_province:
+ type: alphanumeric
+ length: 35
+# street: AN50
+street_address:
+ type: alphanumeric
+ length: 50
+# surname: AN35
+last_name:
+ type: alphanumeric
+ length: 35
+# zip: AN10
+postal_code:
+ type: alphanumeric
+ length: 10
+
diff --git a/ingenico_gateway/config/error_map.yaml
b/ingenico_gateway/config/error_map.yaml
new file mode 120000
index 0000000..a5ef117
--- /dev/null
+++ b/ingenico_gateway/config/error_map.yaml
@@ -0,0 +1 @@
+../../globalcollect_gateway/config/error_map.yaml
\ No newline at end of file
diff --git a/ingenico_gateway/config/payment_methods.yaml
b/ingenico_gateway/config/payment_methods.yaml
new file mode 120000
index 0000000..ef8aeeb
--- /dev/null
+++ b/ingenico_gateway/config/payment_methods.yaml
@@ -0,0 +1 @@
+../../globalcollect_gateway/config/payment_methods.yaml
\ No newline at end of file
diff --git a/ingenico_gateway/config/payment_submethods.yaml
b/ingenico_gateway/config/payment_submethods.yaml
new file mode 120000
index 0000000..40198da
--- /dev/null
+++ b/ingenico_gateway/config/payment_submethods.yaml
@@ -0,0 +1 @@
+../../globalcollect_gateway/config/payment_submethods.yaml
\ No newline at end of file
diff --git a/ingenico_gateway/config/transformers.yaml
b/ingenico_gateway/config/transformers.yaml
new file mode 100644
index 0000000..f8d14c7
--- /dev/null
+++ b/ingenico_gateway/config/transformers.yaml
@@ -0,0 +1,14 @@
+# Core
+- Amount
+- DonorEmail
+- DonorFullName
+- AmountInCents
+- StreetAddress
+
+# Ingenico
+- FiscalNumber
+- ContributionTrackingPlusUnique
+- IngenicoFinancialNumber
+- DonorLocale
+- IngenicoMethodCodec
+- IngenicoReturntoHelper
diff --git a/ingenico_gateway/config/var_map.yaml
b/ingenico_gateway/config/var_map.yaml
new file mode 100644
index 0000000..79c88d8
--- /dev/null
+++ b/ingenico_gateway/config/var_map.yaml
@@ -0,0 +1,16 @@
+# TODO: move this all into SmashPig
+isRecurring: recurring
+locale: language
+amount: amount
+currencyCode: currency
+paymentProductId: payment_product
+city: city
+countryCode: country
+state: state_province
+street: street_address
+zip: postal_code
+emailAddress: email
+firstName: first_name
+surname: last_name
+merchantReference: order_id
+hostedCheckoutId: gateway_session_id
diff --git a/ingenico_gateway/ingenico.adapter.php
b/ingenico_gateway/ingenico.adapter.php
new file mode 100644
index 0000000..bc4bd45
--- /dev/null
+++ b/ingenico_gateway/ingenico.adapter.php
@@ -0,0 +1,172 @@
+<?php
+
+use SmashPig\PaymentProviders\PaymentProviderFactory;
+
+class IngenicoAdapter extends GlobalCollectAdapter {
+ const GATEWAY_NAME = 'Ingenico';
+ const IDENTIFIER = 'ingenico';
+ const GLOBAL_PREFIX = 'wgIngenicoGateway';
+
+ public function getCommunicationType() {
+ return 'array';
+ }
+
+ public function getResponseType() {
+ return 'json';
+ }
+
+ public function defineTransactions() {
+ parent::defineTransactions();
+ $this->transactions['createHostedCheckout'] = array(
+ 'request' => array(
+ 'hostedCheckoutSpecificInput' => array(
+ 'isRecurring',
+ 'locale',
+ 'paymentProductFilters' => array(
+ 'restrictTo' => array(
+ 'products' => array(
+ // HACK! this
array should be a simple
+ // list of
payment ids, not an associative array
+ // so... use
'null' to flag that?
+
'paymentProductId' => null
+ )
+ )
+ ),
+ 'returnUrl',
+ 'showResultPage',
+ // 'tokens', // we don't store user
accounts or tokens here
+ // 'variant', // For a/b testing of
iframe
+ ),
+ 'order' => array(
+ 'amountOfMoney' => array(
+ 'amount',
+ 'currencyCode',
+ ),
+ 'customer' => array(
+ 'billingAddress' => array(
+ 'city',
+ 'countryCode',
+ // 'houseNumber' //
hmm, hope this isn't used for fraud detection!
+ 'state',
+ // 'stateCode', //
should we use this instead?
+ 'street',
+ 'zip',
+ ),
+ 'contactDetails' => array(
+ 'emailAddress'
+ ),
+ // 'fiscalNumber' // only
required for boletos & Brazil paypal
+ 'locale', // used for
redirection to 3rd parties
+ 'personalInformation' => array(
+ 'name' => array(
+ 'firstName',
+ 'surname',
+ )
+ )
+ ),
+ /*'items' => array(
+ array(
+ 'amountOfMoney' =>
array(
+ 'amount',
+ 'currencyCode',
+ ),
+ 'invoiceData' => array(
+ 'description'
+ )
+ )
+ ),*/
+ 'references' => array(
+ 'descriptor', // First 22+
chars appear on card statement
+ 'merchantReference', // unique,
string(30)
+ )
+ )
+ ),
+ 'values' => array(
+ 'returnUrl' => $returnTitle =
Title::newFromText( 'Special:IngenicoGatewayResult' )
+ ->getFullURL( false, false,
PROTO_CURRENT ),
+ 'showResultPage' => 'false',
+ 'descriptor' => WmfFramework::formatMessage(
'donate_interface-donation-description' ),
+ ),
+ 'response' => array(
+ 'hostedCheckoutId'
+ )
+ );
+ }
+
+ /**
+ * Sets up the $order_id_meta array.
+ * Should contain the following keys/values:
+ * 'alt_locations' => array( $dataset_name, $dataset_key ) //ordered
+ * 'type' => numeric, or alphanumeric
+ * 'length' => $max_charlen
+ */
+ public function defineOrderIDMeta() {
+ $this->order_id_meta = array (
+ 'alt_locations' => array (),
+ 'ct_id' => TRUE,
+ 'generate' => TRUE,
+ );
+ }
+
+ public function curl_transaction( $data ) {
+ $email = $this->getData_Unstaged_Escaped( 'email' );
+ $this->logger->info( "Making API call for donor $email" );
+
+ $filterResult = $this->runSessionVelocityFilter();
+ if ( $filterResult === false ) {
+ return false;
+ }
+
+ $provider = $this->getPaymentProvider();
+ switch( $this->getCurrentTransaction() ) {
+ case 'createHostedCheckout':
+ $result = $provider->createHostedPayment( $data
);
+ $this->transaction_response->setRawResponse(
json_encode( $result ) );
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public function getBasedir() {
+ return __DIR__;
+ }
+
+ public function do_transaction( $transaction ) {
+ // If this is not our first call, get a fresh order ID
+ // FIXME: This is repeated in four places. Maybe always
regenerate in incrementSequenceNumber?
+ if ( $this->session_getData( 'sequence' ) ) {
+ $this->regenerateOrderID();
+ }
+ if ( $transaction === 'createHostedCheckout' ) {
+ $this->incrementSequenceNumber();
+ }
+ $result = parent::do_transaction( $transaction );
+ // Add things to session which may have been retrieved from API
+ $this->session_addDonorData();
+ return $result;
+ }
+
+ protected function getPaymentProvider() {
+ $method = $this->getData_Unstaged_Escaped( 'payment_method' );
+ return PaymentProviderFactory::getProviderForMethod( $method );
+ }
+
+ public function parseResponseCommunicationStatus( $response ) {
+ return true;
+ }
+
+ public function parseResponseErrors( $response ) {
+ return array();
+ }
+
+ public function parseResponseData( $response ) {
+ if ( isset( $response['partialRedirectUrl'] ) ) {
+ $provider = $this->getPaymentProvider();
+ $response['FORMACTION'] =
$provider->getHostedPaymentUrl(
+ $response['partialRedirectUrl']
+ );
+ }
+ return $response;
+ }
+}
diff --git a/ingenico_gateway/ingenico_gateway.alias.php
b/ingenico_gateway/ingenico_gateway.alias.php
new file mode 100644
index 0000000..cf74199
--- /dev/null
+++ b/ingenico_gateway/ingenico_gateway.alias.php
@@ -0,0 +1,9 @@
+<?php
+
+$specialPageAliases = array();
+
+/** English */
+$specialPageAliases['en'] = array(
+ 'IngenicoGateway' => array( 'IngenicoGateway' ),
+ 'IngenicoGatewayResult' => array( 'IngenicoGatewayResult' ),
+);
diff --git a/ingenico_gateway/ingenico_gateway.body.php
b/ingenico_gateway/ingenico_gateway.body.php
new file mode 100644
index 0000000..7f85f25
--- /dev/null
+++ b/ingenico_gateway/ingenico_gateway.body.php
@@ -0,0 +1,27 @@
+<?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.
+ *
+ */
+
+/**
+ * IngenicoGateway
+ *
+ */
+class IngenicoGateway extends GlobalCollectGateway {
+
+ protected $gatewayIdentifier = IngenicoAdapter::IDENTIFIER;
+
+}
diff --git a/ingenico_gateway/ingenico_resultswitcher.body.php
b/ingenico_gateway/ingenico_resultswitcher.body.php
new file mode 100644
index 0000000..38c901d
--- /dev/null
+++ b/ingenico_gateway/ingenico_resultswitcher.body.php
@@ -0,0 +1,7 @@
+<?php
+
+class IngenicoGatewayResult extends GlobalCollectGatewayResult {
+
+ protected $gatewayIdentifier = IngenicoAdapter::IDENTIFIER;
+
+}
diff --git a/ingenico_gateway/orphan.adapter.php
b/ingenico_gateway/orphan.adapter.php
new file mode 100644
index 0000000..07c5989
--- /dev/null
+++ b/ingenico_gateway/orphan.adapter.php
@@ -0,0 +1,5 @@
+<?php
+
+class IngenicoOrphanAdapter extends IngenicoAdapter {
+
+}
diff --git a/tests/phpunit/Adapter/Ingenico/IngenicoApiTest.php
b/tests/phpunit/Adapter/Ingenico/IngenicoApiTest.php
new file mode 100644
index 0000000..8a89e1e
--- /dev/null
+++ b/tests/phpunit/Adapter/Ingenico/IngenicoApiTest.php
@@ -0,0 +1,148 @@
+<?php
+
+use SmashPig\Core\DataStores\QueueWrapper;
+use SmashPig\CrmLink\Messages\SourceFields;
+use SmashPig\Tests\TestingContext;
+use SmashPig\Tests\TestingProviderConfiguration;
+
+/**
+ * @group Fundraising
+ * @group DonationInterface
+ * @group Ingenico
+ * @group IngenicoApi
+ * @group DonationInterfaceApi
+ * @group medium
+ */
+
+class IngenicoApiTest extends DonationInterfaceApiTestCase {
+
+ protected $hostedCheckoutProvider;
+
+ protected $partialUrl;
+
+ public function setUp() {
+ parent::setUp();
+ $ctx = TestingContext::get();
+ $globalConfig = $ctx->getGlobalConfiguration();
+
+ $providerConfig =
TestingProviderConfiguration::createForProvider(
+ 'ingenico', $globalConfig
+ );
+ $ctx->providerConfigurationOverride = $providerConfig;
+
+ $this->hostedCheckoutProvider = $this->getMockBuilder(
+
'SmashPig\PaymentProviders\Ingenico\HostedCheckoutProvider'
+ )->disableOriginalConstructor()->getMock();
+
+ $providerConfig->overrideObjectInstance( 'payment-provider/cc',
$this->hostedCheckoutProvider );
+ $this->partialUrl =
'poweredbyglobalcollect.com/pay8915-53ebca407e6b4a1dbd086aad4f10354d:' .
+
'8915-28e5b79c889641c8ba770f1ba576c1fe:9798f4c44ac6406e8288494332d1daa0';
+ }
+
+ public function testGoodSubmit() {
+ $init = DonationInterfaceTestCase::getDonorTestData();
+ $init['email'] = '[email protected]';
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['gateway'] = 'ingenico';
+ $init['action'] = 'donate';
+
+ $this->hostedCheckoutProvider->expects( $this->once() )
+ ->method( 'createHostedPayment' )->with(
+ $this->callback( function( $actual ) {
+ $hcsi = array(
+ 'locale' => 'en_US',
+ 'paymentProductFilters' =>
array(
+ 'restrictTo' => array(
+ 'products' =>
array(
+ 1
+ )
+ )
+ ),
+ 'showResultPage' => 'false'
+ );
+ $this->assertArraySubset( $hcsi,
$actual['hostedCheckoutSpecificInput'] );
+ $this->assertRegExp(
+
'/Special:IngenicoGatewayResult/',
+
$actual['hostedCheckoutSpecificInput']['returnUrl']
+ );
+ $order = array(
+ 'amountOfMoney' => array(
+ 'currencyCode' => 'USD',
+ 'amount' => 155
+ ),
+ 'customer' => array(
+ 'billingAddress' =>
array(
+ 'countryCode'
=> 'US',
+ 'city' => 'San
Francisco',
+ 'state' => 'CA',
+ 'zip' =>
'94105',
+ 'street' =>
'123 Fake Street'
+ ),
+ 'contactDetails' =>
array(
+ 'emailAddress'
=> '[email protected]'
+ ),
+ 'locale' => 'en_US',
+ 'personalInformation'
=> array(
+ 'name' => array(
+
'firstName' => 'Firstname',
+
'surname' => 'Surname'
+ )
+ )
+ )
+ );
+ $this->assertArraySubset( $order,
$actual['order'] );
+ $this->assertTrue( is_numeric(
$actual['order']['references']['merchantReference'] ) );
+ return true;
+ } )
+ )
+ ->willReturn(
+ array(
+ 'partialRedirectUrl' =>
$this->partialUrl,
+ 'hostedCheckoutId' =>
'8915-28e5b79c889641c8ba770f1ba576c1fe',
+ 'RETURNMAC' =>
'f5b66cf9-c64c-4c8d-8171-b47205c89a56'
+ )
+ );
+
+ $this->hostedCheckoutProvider->expects( $this->once() )
+ ->method( 'getHostedPaymentUrl' )->with(
+ $this->equalTo( $this->partialUrl )
+ )->willReturn( 'https://wmf-pay.' . $this->partialUrl );
+
+ $apiResult = $this->doApiRequest( $init );
+ $result = $apiResult[0]['result'];
+
+ $this->assertEquals(
+ 'https://wmf-pay.' . $this->partialUrl,
+ $result['formaction'],
+ 'Ingenico API not setting formaction'
+ );
+ $this->assertTrue( $result['status'], 'Ingenico API result
status should be true' );
+
+ $message = QueueWrapper::getQueue( 'pending' )->pop();
+ $this->assertNotNull( $message, 'Not sending a message to the
pending queue' );
+ SourceFields::removeFromMessage( $message );
+ $expected = array(
+ 'fee' => 0,
+ 'utm_source' => '..cc',
+ 'language' => 'en',
+ 'email' => '[email protected]',
+ 'first_name' => 'Firstname',
+ 'last_name' => 'Surname',
+ 'country' => 'US',
+ 'gateway' => 'ingenico',
+ 'recurring' => '',
+ 'payment_method' => 'cc',
+ 'payment_submethod' => 'visa',
+ 'currency' => 'USD',
+ 'gross' => 1.55,
+ 'user_ip' => '127.0.0.1',
+ 'street_address' => '123 Fake Street',
+ 'city' => 'San Francisco',
+ 'state_province' => 'CA',
+ 'postal_code' => '94105',
+ 'gateway_session_id' =>
'8915-28e5b79c889641c8ba770f1ba576c1fe'
+ );
+ $this->assertArraySubset( $expected, $message );
+ }
+}
diff --git a/tests/phpunit/Adapter/Ingenico/IngenicoFormLoadTest.php
b/tests/phpunit/Adapter/Ingenico/IngenicoFormLoadTest.php
new file mode 100644
index 0000000..b73e122
--- /dev/null
+++ b/tests/phpunit/Adapter/Ingenico/IngenicoFormLoadTest.php
@@ -0,0 +1,218 @@
+<?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 Ingenico
+ */
+class IngenicoFormLoadTest extends BaseIngenicoTestCase {
+
+ public function testIngenicoFormLoad() {
+ $init = $this->getDonorTestData( 'US' );
+ unset( $init['order_id'] );
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['ffname'] = 'cc-vmad';
+ $init['gateway'] = 'ingenico';
+
+ $assertNodes = array (
+ 'submethod-mc' => array (
+ 'nodename' => 'input'
+ ),
+ 'selected-amount' => array (
+ 'nodename' => 'span',
+ 'innerhtmlmatches' => '/^\s*' .
+ str_replace( '$', '\$',
+ Amount::format( 1.55, 'USD',
$init['language'] . '_' . $init['country'] )
+ ).
+ '\s*$/',
+ ),
+ 'state_province' => array (
+ 'nodename' => 'select',
+ 'selected' => 'CA',
+ ),
+ );
+
+ $this->verifyFormOutput( 'IngenicoGateway', $init,
$assertNodes, true );
+ }
+
+ function testIngenicoFormLoad_FR() {
+ $init = $this->getDonorTestData( 'FR' );
+ unset( $init['order_id'] );
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['ffname'] = 'cc-vmaj';
+ $init['gateway'] = 'ingenico';
+
+ $assertNodes = array (
+ 'selected-amount' => array (
+ 'nodename' => 'span',
+ 'innerhtmlmatches' => '/^\s*' .
+ Amount::format( 1.55, 'EUR',
$init['language'] . '_' . $init['country'] ) .
+ '\s*$/',
+ ),
+ 'first_name' => array (
+ 'nodename' => 'input',
+ 'value' => 'Prénom',
+ ),
+ 'last_name' => array (
+ 'nodename' => 'input',
+ 'value' => 'Nom',
+ ),
+ 'country' => array (
+ 'nodename' => 'input',
+ 'value' => 'FR',
+ ),
+ );
+
+ $this->verifyFormOutput( 'IngenicoGateway', $init,
$assertNodes, true );
+ }
+
+ /**
+ * Ensure that form loads for Italy
+ */
+ public function testIngenicoFormLoad_IT() {
+ $init = $this->getDonorTestData( 'IT' );
+ unset( $init['order_id'] );
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['ffname'] = 'cc-vmaj';
+ $init['gateway'] = 'ingenico';
+
+ $assertNodes = array (
+ 'selected-amount' => array (
+ 'nodename' => 'span',
+ 'innerhtmlmatches' => '/^\s*' .
+ Amount::format( 1.55, 'EUR',
$init['language'] . '_' . $init['country'] ) .
+ '\s*$/',
+ ),
+ 'first_name' => array (
+ 'nodename' => 'input',
+ 'placeholder' => wfMessage(
'donate_interface-donor-first_name')->inLanguage( 'it' )->text(),
+ ),
+ 'last_name' => array (
+ 'nodename' => 'input',
+ 'placeholder' => wfMessage(
'donate_interface-donor-last_name')->inLanguage( 'it' )->text(),
+ ),
+ 'informationsharing' => array (
+ 'nodename' => 'p',
+ 'innerhtml' => wfMessage(
'donate_interface-informationsharing', '.*' )->inLanguage( 'it' )->text(),
+ ),
+ 'country' => array (
+ 'nodename' => 'input',
+ 'value' => 'IT',
+ ),
+ );
+
+ $this->verifyFormOutput( 'IngenicoGateway', $init,
$assertNodes, true );
+ }
+
+ /**
+ * Make sure Belgian form loads in all of that country's supported
languages
+ * @dataProvider belgiumLanguageProvider
+ */
+ public function testIngenicoFormLoad_BE( $language ) {
+ $init = $this->getDonorTestData( 'BE' );
+ unset( $init['order_id'] );
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['ffname'] = 'cc-vmaj';
+ $init['language'] = $language;
+ $init['gateway'] = 'ingenico';
+
+ $assertNodes = array (
+ 'selected-amount' => array (
+ 'nodename' => 'span',
+ 'innerhtmlmatches' => '/^\s*' .
+ Amount::format( 1.55, 'EUR',
$init['language'] . '_' . $init['country'] ) .
+ '\s*$/',
+ ),
+ 'first_name' => array (
+ 'nodename' => 'input',
+ 'placeholder' => wfMessage(
'donate_interface-donor-first_name')->inLanguage( $language )->text(),
+ ),
+ 'last_name' => array (
+ 'nodename' => 'input',
+ 'placeholder' => wfMessage(
'donate_interface-donor-last_name')->inLanguage( $language )->text(),
+ ),
+ 'informationsharing' => array (
+ 'nodename' => 'p',
+ 'innerhtml' => wfMessage(
'donate_interface-informationsharing', '.*' )->inLanguage( $language )->text(),
+ ),
+ 'country' => array (
+ 'nodename' => 'input',
+ 'value' => 'BE',
+ ),
+ );
+
+ $this->verifyFormOutput( 'IngenicoGateway', $init,
$assertNodes, true );
+ }
+
+ /**
+ * Make sure Canadian CC form loads in English and French
+ * @dataProvider canadaLanguageProvider
+ */
+ public function testIngenicoFormLoad_CA( $language ) {
+ $init = $this->getDonorTestData( 'CA' );
+ unset( $init['order_id'] );
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['ffname'] = 'cc-vma';
+ $init['language'] = $language;
+ $init['gateway'] = 'ingenico';
+
+ $assertNodes = array (
+ 'selected-amount' => array (
+ 'nodename' => 'span',
+ 'innerhtmlmatches' => '/^\s*' .
+ str_replace( '$', '\$',
+ Amount::format( 1.55, 'CAD',
$init['language'] . '_' . $init['country'] )
+ ) .
+ '\s*$/',
+ ),
+ 'first_name' => array (
+ 'nodename' => 'input',
+ 'placeholder' => wfMessage(
'donate_interface-donor-first_name')->inLanguage( $language )->text(),
+ ),
+ 'last_name' => array (
+ 'nodename' => 'input',
+ 'placeholder' => wfMessage(
'donate_interface-donor-last_name')->inLanguage( $language )->text(),
+ ),
+ 'informationsharing' => array (
+ 'nodename' => 'p',
+ 'innerhtml' => wfMessage(
'donate_interface-informationsharing', '.*' )->inLanguage( $language )->text(),
+ ),
+ 'state_province' => array (
+ 'nodename' => 'select',
+ 'selected' => 'SK',
+ ),
+ 'postal_code' => array (
+ 'nodename' => 'input',
+ 'value' => $init['postal_code'],
+ ),
+ 'country' => array (
+ 'nodename' => 'input',
+ 'value' => 'CA',
+ ),
+ );
+
+ $this->verifyFormOutput( 'IngenicoGateway', $init,
$assertNodes, true );
+ }
+}
diff --git a/tests/phpunit/Adapter/Ingenico/IngenicoOrphanAdapterTest.php
b/tests/phpunit/Adapter/Ingenico/IngenicoOrphanAdapterTest.php
new file mode 100644
index 0000000..10042f7
--- /dev/null
+++ b/tests/phpunit/Adapter/Ingenico/IngenicoOrphanAdapterTest.php
@@ -0,0 +1,212 @@
+<?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;
+use SmashPig\Core\DataStores\QueueWrapper;
+use SmashPig\CrmLink\Messages\SourceFields;
+use SmashPig\Tests\TestingContext;
+use SmashPig\Tests\TestingProviderConfiguration;
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ *
+ * @group Fundraising
+ * @group DonationInterface
+ * @group Ingenico
+ * @group OrphanSlayer
+ */
+class DonationInterface_Adapter_Ingenico_Orphans_IngenicoTest extends
DonationInterfaceTestCase {
+ public function setUp() {
+ parent::setUp();
+ $this->markTestSkipped( 'Orphan adapter not yet implemented' );
+
+ TestingContext::get()->providerConfigurationOverride =
+ TestingProviderConfiguration::createForProvider(
+ 'ingenico',
+ $this->smashPigGlobalConfig
+ );
+
+ $this->setMwGlobals( array(
+ 'wgIngenicoGatewayEnabled' => true,
+ 'wgDonationInterfaceAllowedHtmlForms' => array(
+ 'cc-vmad' => array(
+ 'gateway' => 'ingenico',
+ 'payment_methods' => array('cc' =>
array( 'visa', 'mc', 'amex', 'discover' )),
+ 'countries' => array(
+ '+' => array( 'US', ),
+ ),
+ ),
+ ),
+ ) );
+ }
+
+ /**
+ * @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->dummy_utm_data = array (
+ 'utm_source' => 'dummy_source',
+ 'utm_campaign' => 'dummy_campaign',
+ 'utm_medium' => 'dummy_medium',
+ 'date' => time(),
+ );
+ }
+
+ public function testConstructor() {
+
+ $class = $this->testAdapterClass;
+
+ $gateway = $this->getFreshGatewayObject();
+
+ $this->assertInstanceOf( $class, $gateway );
+
+ $this->verifyNoLogErrors();
+ }
+
+
+ public function testBatchOrderID_generate() {
+
+ //no data on construct, generate Order IDs
+ $gateway = $this->getFreshGatewayObject( null, array (
'order_id_meta' => array ( 'generate' => TRUE ) ) );
+ $this->assertTrue( $gateway->getOrderIDMeta( 'generate' ), 'The
order_id meta generate setting override is not working properly. Order_id
generation may be broken.' );
+ $this->assertNotNull( $gateway->getData_Unstaged_Escaped(
'order_id' ), 'Failed asserting that an absent order id is not left as null,
when generating our own' );
+
+ $data = array_merge( $this->getDonorTestData(),
$this->dummy_utm_data );
+ $data['order_id'] = '55555';
+
+ //now, add data and check that we didn't kill the oid. Still
generating.
+ $gateway->loadDataAndReInit( $data );
+ $this->assertEquals( $gateway->getData_Unstaged_Escaped(
'order_id' ), '55555', 'loadDataAndReInit failed to stick OrderID' );
+
+ $data['order_id'] = '444444';
+ $gateway->loadDataAndReInit( $data );
+ $this->assertEquals( $gateway->getData_Unstaged_Escaped(
'order_id' ), '444444', 'loadDataAndReInit failed to stick OrderID' );
+
+ $this->verifyNoLogErrors();
+ }
+
+ public function testBatchOrderID_no_generate() {
+
+ //no data on construct, do not generate Order IDs
+ $gateway = $this->getFreshGatewayObject( null, array (
'order_id_meta' => array ( 'generate' => FALSE ) ) );
+ $this->assertFalse( $gateway->getOrderIDMeta( 'generate' ),
'The order_id meta generate setting override is not working properly. Deferred
order_id generation may be broken.' );
+ $this->assertEmpty( $gateway->getData_Unstaged_Escaped(
'order_id' ), 'Failed asserting that an absent order id is left as null, when
not generating our own' );
+
+ $data = array_merge( $this->getDonorTestData(),
$this->dummy_utm_data );
+ $data['order_id'] = '66666';
+
+ //now, add data and check that we didn't kill the oid. Still
not generating
+ $gateway->loadDataAndReInit( $data );
+ $this->assertEquals( $gateway->getData_Unstaged_Escaped(
'order_id' ), '66666', 'loadDataAndReInit failed to stick OrderID' );
+
+ $data['order_id'] = '777777';
+ $gateway->loadDataAndReInit( $data );
+ $this->assertEquals( $gateway->getData_Unstaged_Escaped(
'order_id' ), '777777', 'loadDataAndReInit failed to stick OrderID on second
batch item' );
+
+ $this->verifyNoLogErrors();
+ }
+
+ /**
+ * Tests to make sure that certain error codes returned from GC will
+ * trigger order cancellation, even if retryable errors also exist.
+ * @dataProvider mcNoRetryCodeProvider
+ */
+ public function testNoMastercardFinesForRepeatOnBadCodes( $code ) {
+ $gateway = $this->getFreshGatewayObject( null, array (
'order_id_meta' => array ( 'generate' => FALSE ) ) );
+
+ //Toxic card should not retry, even if there's an order id
collision
+ $init = array_merge( $this->getDonorTestData(),
$this->dummy_utm_data );
+ $init['ffname'] = 'cc-vmad';
+ $init['order_id'] = '55555';
+ $init['email'] = '[email protected]';
+ $init['contribution_tracking_id'] = mt_rand();
+ $gateway->loadDataAndReInit( $init );
+
+ $gateway->setDummyGatewayResponseCode( $code );
+ $result = $gateway->do_transaction( 'Confirm_CreditCard' );
+ $this->assertEquals( 1, count( $gateway->curled ), "Gateway
kept trying even with response code $code! MasterCard could fine us a thousand
bucks for that!" );
+ $this->assertEquals( false, $result->getCommunicationStatus(),
"Error code $code should mean status of do_transaction is false" );
+ $errors = $result->getErrors();
+ $this->assertFalse( empty( $errors ), 'Orphan adapter needs to
see the errors to consider it rectified' );
+ $finder = function( $error ) {
+ return $error->getErrorCode() == '1000001';
+ };
+ $this->assertNotEmpty( array_filter( $errors, $finder ),
'Orphan adapter needs error 1000001 to consider it rectified' );
+ $loglines = $this->getLogMatches( LogLevel::INFO, "/Got error
code $code, not retrying to avoid MasterCard fines./" );
+ $this->assertNotEmpty( $loglines, "GC Error $code is not
generating the expected payments log error" );
+ }
+
+ /**
+ * Make sure we're incorporating GET_ORDERSTATUS AVS and CVV responses
into
+ * fraud scores.
+ */
+ function testGetOrderstatusPostProcessFraud() {
+ $this->markTestSkipped( 'OrderStatus not yet implemented' );
+ $this->setMwGlobals( array(
+ 'wgDonationInterfaceEnableCustomFilters' => true,
+ 'wgIngenicoGatewayCustomFiltersFunctions' => array(
+ 'getCVVResult' => 10,
+ 'getAVSResult' => 30,
+ ),
+ ) );
+ $gateway = $this->getFreshGatewayObject( null, array (
'order_id_meta' => array ( 'generate' => FALSE ) ) );
+
+ $init = array_merge( $this->getDonorTestData(),
$this->dummy_utm_data );
+ $init['ffname'] = 'cc-vmad';
+ $init['order_id'] = '55555';
+ $init['email'] = '[email protected]';
+ $init['contribution_tracking_id'] = mt_rand();
+ $init['payment_method'] = 'cc';
+
+ $gateway->loadDataAndReInit( $init );
+ $gateway->setDummyGatewayResponseCode( '600_badCvv' );
+
+ $gateway->do_transaction( 'Confirm_CreditCard' );
+ $action = $gateway->getValidationAction();
+ $this->assertEquals( 'review', $action,
+ 'Orphan gateway should fraud fail on bad CVV and AVS' );
+
+ $exposed = TestingAccessWrapper::newFromObject( $gateway );
+ $this->assertEquals( 40, $exposed->risk_score,
+ 'Risk score was incremented correctly.' );
+ $message = QueueWrapper::getQueue( 'payments-antifraud'
)->pop();
+ SourceFields::removeFromMessage( $message );
+ $expected = array(
+ 'validation_action' => 'review',
+ 'risk_score' => 40,
+ 'score_breakdown' => array(
+ // FIXME: need to enable utm / email / country
checks ???
+ 'initial' => 0,
+ 'getCVVResult' => 10,
+ 'getAVSResult' => 30,
+ ),
+ 'user_ip' => null, // FIXME
+ 'gateway_txn_id' => '55555',
+ 'date' => $message['date'],
+ 'server' => gethostname(),
+ 'gateway' => 'ingenico',
+ 'contribution_tracking_id' =>
$gateway->getData_Unstaged_Escaped( 'contribution_tracking_id' ),
+ 'order_id' => $gateway->getData_Unstaged_Escaped(
'order_id' ),
+ 'payment_method' => 'cc',
+ );
+ $this->assertEquals( $expected, $message );
+ }
+}
diff --git a/tests/phpunit/Adapter/Ingenico/IngenicoOrphanRectifierTest.php
b/tests/phpunit/Adapter/Ingenico/IngenicoOrphanRectifierTest.php
new file mode 100644
index 0000000..4926c49
--- /dev/null
+++ b/tests/phpunit/Adapter/Ingenico/IngenicoOrphanRectifierTest.php
@@ -0,0 +1,215 @@
+<?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 SmashPig\Core\DataStores\PendingDatabase;
+
+/**
+ * @covers IngenicoOrphanRectifier
+ *
+ * @group Fundraising
+ * @group DonationInterface
+ * @group Ingenico
+ * @group OrphanSlayer
+ */
+class DonationInterface_Adapter_Ingenico_Orphan_Rectifier_Test
+ extends DonationInterfaceTestCase
+{
+ // TODO: Give vulgar names.
+ // FIXME: Is 25 the normal unauthorized status? Use the common one,
whatever that is.
+ const STATUS_PENDING = 25;
+ const STATUS_PENDING_POKE = 600;
+ const STATUS_COMPLETE = 800;
+
+ // Arbitrary configuration for testing time logic.
+ const TIME_BUFFER = 60;
+ const TARGET_EXECUTE_TIME = 1200;
+
+ public $pendingDb;
+
+ public function setUp() {
+ parent::setUp();
+ $this->markTestSkipped( 'Orphan rectifier not yet implemented'
);
+
+ $this->setMwGlobals( array(
+ 'wgDonationInterfaceOrphanCron' => array(
+ 'enable' => true,
+ 'target_execute_time' =>
self::TARGET_EXECUTE_TIME,
+ 'time_buffer' => self::TIME_BUFFER,
+ ),
+ 'wgIngenicoGatewayEnabled' => true,
+ 'wgDonationInterfaceGatewayAdapters' => array(
+ // We include the regular adapter in order to
pass gateway validation D:
+ 'ingenico' => 'IngenicoOrphanAdapter',
+ 'ingenico_orphan' => 'IngenicoOrphanAdapter',
+ ),
+ ) );
+
+
+ $this->pendingDb = PendingDatabase::get();
+
+ // Create the schema.
+ $this->pendingDb->createTable();
+ }
+
+ /**
+ * When leaving a message unprocessed and pending, don't try to process
it
+ * again.
+ */
+ public function testProcessOrphansStatusPending() {
+ $orphan_pending = $this->createOrphan();
+
+ $rectifier = new IngenicoOrphanRectifier();
+ $this->gateway = $rectifier->getAdapter();
+ $this->gateway->setDummyGatewayResponseCode(
self::STATUS_PENDING );
+ $rectifier->processOrphans();
+
+ $fetched = $this->pendingDb->fetchMessageByGatewayOrderId(
+ 'ingenico', $orphan_pending['order_id'] );
+ $this->assertNull( $fetched,
+ 'Message was popped.' );
+
+ $this->assertGatewayCallsExactly( array(
+ 'GET_ORDERSTATUS'
+ ) );
+ }
+
+ /**
+ * If a message is waiting for the API kiss of death, perform it.
+ */
+ public function testProcessOrphansStatusPendingPoke() {
+ $orphan_pending_poke = $this->createOrphan();
+
+ $rectifier = new IngenicoOrphanRectifier();
+ $this->gateway = $rectifier->getAdapter();
+ $this->gateway->setDummyGatewayResponseCode(
self::STATUS_PENDING_POKE );
+ $rectifier->processOrphans();
+
+ $fetched = $this->pendingDb->fetchMessageByGatewayOrderId(
+ 'ingenico', $orphan_pending_poke['order_id'] );
+ $this->assertNull( $fetched,
+ 'Message was popped' );
+
+ $this->assertGatewayCallsExactly( array(
+ 'GET_ORDERSTATUS',
+ 'SET_PAYMENT',
+ ) );
+
+ // TODO: test that we sent a completion message
+ }
+
+ /**
+ * Report a completed transaction.
+ */
+ public function testProcessOrphansStatusComplete() {
+
+ $orphan_complete = $this->createOrphan();
+
+ $rectifier = new IngenicoOrphanRectifier();
+ $this->gateway = $rectifier->getAdapter();
+ $this->gateway->setDummyGatewayResponseCode(
self::STATUS_COMPLETE );
+ $rectifier->processOrphans();
+
+ $fetched = $this->pendingDb->fetchMessageByGatewayOrderId(
+ 'ingenico', $orphan_complete['order_id'] );
+ $this->assertNull( $fetched,
+ 'Message was popped' );
+
+ $this->assertGatewayCallsExactly( array(
+ 'GET_ORDERSTATUS',
+ ) );
+
+ // TODO: test that we sent a completion message
+ }
+
+ /**
+ * Don't process recent messages.
+ */
+ public function testTooRecentMessage() {
+ $orphan_complete = $this->createOrphan( array(
+ 'date' => time() - self::TIME_BUFFER + 30,
+ ) );
+
+ $rectifier = new IngenicoOrphanRectifier();
+ $this->gateway = $rectifier->getAdapter();
+ $rectifier->processOrphans();
+
+ $fetched = $this->pendingDb->fetchMessageByGatewayOrderId(
+ 'ingenico', $orphan_complete['order_id'] );
+ $this->assertNotNull( $fetched,
+ 'Message was not popped' );
+
+ $this->assertGatewayCallsExactly( array() );
+
+ // TODO: Test that we:
+ // * Logged the "done with old messages" line.
+ }
+
+ /**
+ * Create an orphaned tranaction and store it to the pending database.
+ *
+ * TODO: Reuse SmashPigBaseTest#createMessage
+ */
+ public function createOrphan( $overrides = array() ) {
+ $uniq = mt_rand();
+ $message = $overrides + array(
+ 'contribution_tracking_id' => $uniq,
+ 'first_name' => 'Flighty',
+ 'last_name' => 'Dono',
+ 'email' => '[email protected]',
+ 'gateway' => 'ingenico',
+ 'gateway_txn_id' => "txn-{$uniq}",
+ 'order_id' => "order-{$uniq}",
+ 'gateway_account' => 'default',
+ 'payment_method' => 'cc',
+ 'payment_submethod' => 'mc',
+ // Defaults to a magic 25 minutes ago, within the
process window.
+ 'date' => time() - 25 * 60,
+ 'amount' => 123,
+ 'currency' => 'EUR',
+ );
+ $this->pendingDb->storeMessage( $message );
+ return $message;
+ }
+
+ /**
+ * Assert whether we made exactly the expected gateway calls
+ *
+ * @param array $expected List of API action names, in the form they
appear
+ * in the <ACTION> tag.
+ */
+ protected function assertGatewayCallsExactly( $expected ) {
+ $expected_num_calls = count( $expected );
+ $this->assertEquals( $expected_num_calls, count(
$this->gateway->curled ),
+ "Ran exactly {$expected_num_calls} API calls" );
+ foreach ( $expected as $index => $action ) {
+ $this->assertRegExp( '/\b' . $action . '\b/',
$this->gateway->curled[$index],
+ "Call #" . ( $index + 1 ) . " was {$action}." );
+ }
+ }
+
+ /**
+ * Dump the entire database state, for debugging.
+ */
+ protected function debugDbContents() {
+ $result = $this->pendingDb->getDatabase()->query(
+ "select * from pending" );
+ $rows = $result->fetchAll( PDO::FETCH_ASSOC );
+ var_export($rows);
+ }
+}
diff --git a/tests/phpunit/Adapter/Ingenico/IngenicoTest.php
b/tests/phpunit/Adapter/Ingenico/IngenicoTest.php
new file mode 100644
index 0000000..38fbf27
--- /dev/null
+++ b/tests/phpunit/Adapter/Ingenico/IngenicoTest.php
@@ -0,0 +1,477 @@
+<?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;
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ *
+ * @group Fundraising
+ * @group DonationInterface
+ * @group Ingenico
+ */
+class DonationInterface_Adapter_Ingenico_IngenicoTest extends
BaseIngenicoTestCase {
+
+ protected $partialUrl;
+
+ protected $hostedCheckoutCreateResponse;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->partialUrl =
'poweredbyglobalcollect.com/pay8915-53ebca407e6b4a1dbd086aad4f10354d:' .
+
'8915-28e5b79c889641c8ba770f1ba576c1fe:9798f4c44ac6406e8288494332d1daa0';
+
+ $this->hostedCheckoutCreateResponse = array(
+ 'partialRedirectUrl' => $this->partialUrl,
+ 'hostedCheckoutId' =>
'8915-28e5b79c889641c8ba770f1ba576c1fe',
+ 'RETURNMAC' => 'f5b66cf9-c64c-4c8d-8171-b47205c89a56'
+ );
+ }
+
+ /**
+ * Non-exhaustive integration tests to verify that order_id, when in
+ * self-generation mode, won't regenerate until it is told to.
+ * @covers GatewayAdapter::normalizeOrderID
+ * @covers GatewayAdapter::regenerateOrderID
+ */
+ function testStickyGeneratedOrderID() {
+ $init = self::$initial_vars;
+ unset( $init['order_id'] );
+
+ //no order_id from anywhere, explicit generate
+ $gateway = $this->getFreshGatewayObject( $init, array (
'order_id_meta' => array ( 'generate' => TRUE ) ) );
+ $this->assertNotNull( $gateway->getData_Unstaged_Escaped(
'order_id' ), 'Generated order_id is null. The rest of this test is broken.' );
+ $original_order_id = $gateway->getData_Unstaged_Escaped(
'order_id' );
+
+ $gateway->normalizeOrderID();
+ $this->assertEquals( $original_order_id,
$gateway->getData_Unstaged_Escaped( 'order_id' ), 'Re-normalized order_id has
changed without explicit regeneration.' );
+
+ //this might look a bit strange, but we need to be able to
generate valid order_ids without making them stick to anything.
+ $gateway->generateOrderID();
+ $this->assertEquals( $original_order_id,
$gateway->getData_Unstaged_Escaped( 'order_id' ), 'function generateOrderID
auto-changed the selected order ID. Not cool.' );
+
+ $gateway->regenerateOrderID();
+ $this->assertNotEquals( $original_order_id,
$gateway->getData_Unstaged_Escaped( 'order_id' ), 'Re-normalized order_id has
not changed, after explicit regeneration.' );
+ }
+
+ /**
+ * Integration test to verify that order_id can be retrieved from
+ * performing an createHostedCheckout.
+ */
+ function testGatewaySessionRetrieval() {
+ $init = $this->getDonorTestData();
+ unset( $init['order_id'] );
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $this->hostedCheckoutProvider->expects( $this->once() )
+ ->method( 'createHostedPayment' )
+ ->willReturn(
+ $this->hostedCheckoutCreateResponse
+ );
+ //no order_id from anywhere, explicit generate
+ $gateway = $this->getFreshGatewayObject( $init );
+ $gateway->do_transaction( 'createHostedCheckout' );
+
+ $this->assertNotNull(
+ $gateway->getData_Unstaged_Escaped(
'gateway_session_id' ),
+ 'No gateway_session_id was retrieved from
createHostedCheckout'
+ );
+ }
+
+ /**
+ * Just run the GET_ORDERSTATUS transaction and make sure we load the
data
+ */
+ function testGetOrderStatus() {
+ $this->markTestSkipped( 'OrderStatus not implemented' );
+ $init = $this->getDonorTestData();
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['email'] = '[email protected]';
+
+ $gateway = $this->getFreshGatewayObject( $init );
+
+ $gateway->do_transaction( 'GET_ORDERSTATUS' );
+
+ $data = $gateway->getTransactionData();
+
+ $this->assertEquals( 'N', $data['CVVRESULT'], 'CVV Result not
loaded from XML response' );
+ }
+
+ /**
+ * Don't fraud-fail someone for bad CVV if GET_ORDERSTATUS
+ * comes back with STATUSID 25 and no CVVRESULT
+ * @group CvvResult
+ */
+ function testConfirmCreditCardStatus25() {
+ $this->markTestSkipped( 'OrderStatus not implemented' );
+ $init = $this->getDonorTestData();
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['email'] = '[email protected]';
+
+ $this->setUpRequest( array( 'CVVRESULT' => 'M' ) );
+
+ $gateway = $this->getFreshGatewayObject( $init );
+ $gateway->setDummyGatewayResponseCode( '25' );
+
+ $gateway->do_transaction( 'Confirm_CreditCard' );
+ $action = $gateway->getValidationAction();
+ $this->assertEquals( 'process', $action, 'Gateway should not
fraud fail on STATUSID 25' );
+ }
+
+ /**
+ * Make sure we're incorporating GET_ORDERSTATUS AVS and CVV responses
into
+ * fraud scores.
+ */
+ function testGetOrderstatusPostProcessFraud() {
+ $this->markTestSkipped( 'OrderStatus not implemented' );
+ $this->setMwGlobals( array(
+ 'wgDonationInterfaceEnableCustomFilters' => true,
+ 'wgIngenicoGatewayCustomFiltersFunctions' => array(
+ 'getCVVResult' => 10,
+ 'getAVSResult' => 30,
+ ),
+ ) );
+
+ $init = $this->getDonorTestData();
+ $init['ffname'] = 'cc-vmad';
+ $init['order_id'] = '55555';
+ $init['email'] = '[email protected]';
+ $init['contribution_tracking_id'] = mt_rand();
+ $init['payment_method'] = 'cc';
+ $gateway = $this->getFreshGatewayObject( $init );
+
+ $gateway->setDummyGatewayResponseCode( '600_badCvv' );
+
+ $gateway->do_transaction( 'Confirm_CreditCard' );
+ $action = $gateway->getValidationAction();
+ $this->assertEquals( 'review', $action,
+ 'Orphan gateway should fraud fail on bad CVV and AVS' );
+
+ $exposed = TestingAccessWrapper::newFromObject( $gateway );
+ $this->assertEquals( 40, $exposed->risk_score,
+ 'Risk score was incremented correctly.' );
+ }
+
+ /**
+ * Ensure the Confirm_CreditCard transaction prefers CVVRESULT from the
XML
+ * over any value from the querystring
+ */
+ function testConfirmCreditCardPrefersApiCvv() {
+ $this->markTestSkipped( 'OrderStatus not implemented' );
+ $init = $this->getDonorTestData();
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['email'] = '[email protected]';
+
+ $this->setUpRequest( array( 'CVVRESULT' => 'M' ) );
+
+ $gateway = $this->getFreshGatewayObject( $init );
+
+ $gateway->do_transaction( 'Confirm_CreditCard' );
+
+ $this->assertEquals( 'N',
$gateway->getData_Unstaged_Escaped('cvv_result'), 'CVV Result not taken from
XML response' );
+ }
+
+ /**
+ * Make sure we record the actual amount charged, even if the donor has
+ * opened a new window and screwed up their session data.
+ */
+ function testConfirmCreditCardUpdatesAmount() {
+ $this->markTestSkipped( 'OrderStatus not implemented' );
+ $init = $this->getDonorTestData();
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['email'] = '[email protected]';
+ // The values in session are not the values we originally used
+ // for createHostedCheckout
+ $init['amount'] = '12.50';
+ $init['currency'] = 'USD';
+
+ $gateway = $this->getFreshGatewayObject( $init );
+
+ $amount = $gateway->getData_Unstaged_Escaped( 'amount' );
+ $currency = $gateway->getData_Unstaged_Escaped( 'currency' );
+ $this->assertEquals( '12.50', $amount );
+ $this->assertEquals( 'USD', $currency );
+
+ $gateway->do_transaction( 'Confirm_CreditCard' );
+
+ $amount = $gateway->getData_Unstaged_Escaped( 'amount' );
+ $currency = $gateway->getData_Unstaged_Escaped( 'currency' );
+ $this->assertEquals( '23.45', $amount, 'Not recording correct
amount' );
+ $this->assertEquals( 'EUR', $currency, 'Not recording correct
currency' );
+ }
+
+ public function testLanguageStaging() {
+ $options = $this->getDonorTestData( 'NO' );
+ $options['payment_method'] = 'cc';
+ $options['payment_submethod'] = 'visa';
+ $gateway = $this->getFreshGatewayObject( $options );
+
+ $exposed = TestingAccessWrapper::newFromObject( $gateway );
+ $exposed->stageData();
+
+ $this->assertEquals( $exposed->getData_Staged( 'language' ),
'no_NO', "'NO' donor's language was improperly set. Should be 'no_NO'" );
+ }
+
+ public function testLanguageFallbackStaging() {
+ $this->markTestSkipped( 'Do we have to fall back with Connect?'
);
+ $options = $this->getDonorTestData( 'Catalonia' );
+ $options['payment_method'] = 'cc';
+ $options['payment_submethod'] = 'visa';
+ $gateway = $this->getFreshGatewayObject( $options );
+
+ $exposed = TestingAccessWrapper::newFromObject( $gateway );
+ $exposed->stageData();
+
+ // Requesting the fallback language from the gateway.
+ $this->assertEquals( 'en', $exposed->getData_Staged( 'language'
) );
+ }
+
+ /**
+ * Make sure unstaging functions don't overwrite core donor data.
+ */
+ public function testAddResponseData_underzealous() {
+ $options = $this->getDonorTestData( 'Catalonia' );
+ $options['payment_method'] = 'cc';
+ $options['payment_submethod'] = 'visa';
+ $gateway = $this->getFreshGatewayObject( $options );
+
+ // This will set staged_data['language'] = 'en'.
+ $exposed = TestingAccessWrapper::newFromObject( $gateway );
+ $exposed->stageData();
+
+ $ctid = mt_rand();
+
+ $gateway->addResponseData( array(
+ 'contribution_tracking_id' => $ctid . '.1',
+ ) );
+
+ $exposed = TestingAccessWrapper::newFromObject( $gateway );
+ // Desired vars were written into normalized data.
+ $this->assertEquals( $ctid, $exposed->dataObj->getVal(
'contribution_tracking_id' ) );
+
+ // Language was not overwritten.
+ $this->assertEquals( 'ca', $exposed->dataObj->getVal(
'language' ) );
+ }
+
+ /**
+ * Tests to make sure that certain error codes returned from GC will or
+ * will not create payments error loglines.
+ */
+ function testCCLogsOnGatewayError() {
+ $this->markTestSkipped( 'order status not implemented' );
+ $init = $this->getDonorTestData( 'US' );
+ unset( $init['order_id'] );
+ $init['ffname'] = 'cc-vmad';
+
+ //this should not throw any payments errors: Just an invalid
card.
+ $gateway = $this->getFreshGatewayObject( $init );
+ $gateway->setDummyGatewayResponseCode( '430285' );
+ $gateway->do_transaction( 'GET_ORDERSTATUS' );
+ $this->verifyNoLogErrors();
+
+ //Now test one we want to throw a payments error
+ $gateway = $this->getFreshGatewayObject( $init );
+ $gateway->setDummyGatewayResponseCode( '21000050' );
+ $gateway->do_transaction( 'GET_ORDERSTATUS' );
+ $loglines = $this->getLogMatches( LogLevel::ERROR,
'/Investigation required!/' );
+ $this->assertNotEmpty( $loglines, 'GC Error 21000050 is not
generating the expected payments log error' );
+
+ //Reset logs
+ $this->testLogger->messages = array();
+
+ //Most irritating version of 20001000 - They failed to enter an
expiration date on GC's form. This should log some specific info, but not an
error.
+ $gateway = $this->getFreshGatewayObject( $init );
+ $gateway->setDummyGatewayResponseCode( '20001000-expiry' );
+ $gateway->do_transaction( 'GET_ORDERSTATUS' );
+ $this->verifyNoLogErrors();
+ $loglines = $this->getLogMatches( LogLevel::INFO,
'/processResponse:.*EXPIRYDATE/' );
+ $this->assertNotEmpty( $loglines, 'GC Error 20001000-expiry is
not generating the expected payments log line' );
+ }
+
+ /**
+ * Tests to make sure that certain error codes returned from GC will
+ * trigger order cancellation, even if retryable errors also exist.
+ * @dataProvider mcNoRetryCodeProvider
+ */
+ public function testNoMastercardFinesForRepeatOnBadCodes( $code ) {
+ $this->markTestSkipped( 'OrderStatus not implemented' );
+ $init = $this->getDonorTestData( 'US' );
+ unset( $init['order_id'] );
+ $init['ffname'] = 'cc-vmad';
+ //Make it not look like an orphan
+ $this->setUpRequest( array(
+ 'CVVRESULT' => 'M',
+ 'AVSRESULT' => '0'
+ ) );
+
+ //Toxic card should not retry, even if there's an order id
collision
+ $gateway = $this->getFreshGatewayObject( $init );
+ $gateway->setDummyGatewayResponseCode( $code );
+ $gateway->do_transaction( 'Confirm_CreditCard' );
+ $this->assertEquals( 1, count( $gateway->curled ), "Gateway
kept trying even with response code $code! MasterCard could fine us a thousand
bucks for that!" );
+ }
+
+ /**
+ * Tests that two API requests don't send the same order ID and merchant
+ * reference. This was the case when users doubleclicked and we were
+ * using the last 5 digits of time in seconds as a suffix. We want to
see
+ * what happens when a 2nd request comes in while the 1st is still
waiting
+ * for a CURL response, so here we fake that situation by having CURL
throw
+ * an exception during the 1st response.
+ */
+ public function testNoDupeOrderId( ) {
+ $this->setUpRequest( array(
+ 'action'=>'donate',
+ 'amount'=>'3.00',
+ 'card_type'=>'amex',
+ 'city'=>'Hollywood',
+ 'contribution_tracking_id'=>'22901382',
+ 'country'=>'US',
+ 'currency'=>'USD',
+ 'email'=>'[email protected]',
+ 'first_name'=>'Fakety',
+ 'format'=>'json',
+ 'gateway'=>'ingenico',
+ 'language'=>'en',
+ 'last_name'=>'Fake',
+ 'payment_method'=>'cc',
+ 'referrer'=>'http://en.wikipedia.org/wiki/Main_Page',
+ 'state_province'=>'MA',
+ 'street_address'=>'99 Fake St',
+ 'utm_campaign'=>'C14_en5C_dec_dsk_FR',
+ 'utm_medium'=>'sitenotice',
+ 'utm_source'=>'B14_120921_5C_lg_fnt_sans.no-LP.cc',
+ 'postal_code'=>'90210'
+ ) );
+
+ $gateway = new IngenicoAdapter();
+ $calls = [];
+ $this->hostedCheckoutProvider->expects( $this->exactly( 2 ) )
+ ->method( 'createHostedPayment' )
+ ->with( $this->callback( function( $arg ) use ( &$calls
) {
+ $calls[] = $arg;
+ if ( count( $calls ) === 2 ) {
+ $this->assertFalse( $calls[0] ===
$calls[1], 'Two calls to the api did the same thing' );
+ }
+ return true;
+ } ) )
+ ->will( $this->onConsecutiveCalls(
+ $this->throwException( new Exception( 'test' )
),
+ $this->returnValue(
$this->hostedCheckoutCreateResponse )
+ ) );
+ try {
+ $gateway->do_transaction( 'createHostedCheckout' );
+ }
+ catch ( Exception $e ) {
+ // totally expected this
+ }
+
+ //simulate another request coming in before we get anything
back from GC
+ $anotherGateway = new IngenicoAdapter();
+ $anotherGateway->do_transaction( 'createHostedCheckout' );
+
+ }
+
+ /**
+ * Tests to see that we don't claim we're going to retry when we aren't
+ * going to. For GC, we really only want to retry on code 300620
+ * @dataProvider benignNoRetryCodeProvider
+ */
+ public function testNoClaimRetryOnBoringCodes( $code ) {
+ $this->markTestSkipped( 'OrderStatus not implemented' );
+ $init = $this->getDonorTestData( 'US' );
+ unset( $init['order_id'] );
+ $init['ffname'] = 'cc-vmad';
+ //Make it not look like an orphan
+ $this->setUpRequest( array(
+ 'CVVRESULT' => 'M',
+ 'AVSRESULT' => '0'
+ ) );
+
+ $gateway = $this->getFreshGatewayObject( $init );
+ $gateway->setDummyGatewayResponseCode( $code );
+ $exposed = TestingAccessWrapper::newFromObject( $gateway );
+ $start_id = $exposed->getData_Staged( 'order_id' );
+ $gateway->do_transaction( 'Confirm_CreditCard' );
+ $finish_id = $exposed->getData_Staged( 'order_id' );
+ $loglines = $this->getLogMatches( LogLevel::INFO, '/Repeating
transaction on request for vars:/' );
+ $this->assertEmpty( $loglines, "Log says we are going to repeat
the transaction for code $code, but that is not true" );
+ $this->assertEquals( $start_id, $finish_id, "Needlessly
regenerated order id for code $code ");
+ }
+
+ /**
+ * doPayment should recover from Ingenico-side timeouts.
+ */
+ function testTimeoutRecover() {
+ $this->markTestSkipped( 'SetPayment not implemented' );
+ $init = $this->getDonorTestData();
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['email'] = '[email protected]';
+ $init['ffname'] = 'cc-vmad';
+
+ $gateway = $this->getFreshGatewayObject( $init );
+
+ $gateway->do_transaction( 'SET_PAYMENT' );
+ $loglines = $this->getLogMatches( LogLevel::INFO, '/Repeating
transaction for timeout/' );
+ $this->assertNotEmpty( $loglines, "Log does not say we retried
for timeout." );
+ }
+
+ public function testDonorReturnSuccess() {
+ $this->markTestSkipped( 'SetPayment not implemented' );
+ $init = $this->getDonorTestData( 'FR' );
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['email'] = '[email protected]';
+ $init['order_id'] = mt_rand();
+ $session['Donor'] = $init;
+ $this->setUpRequest( $init, $session );
+ $gateway = $this->getFreshGatewayObject( array() );
+ $result = $gateway->processDonorReturn( array(
+ 'REF' => $init['order_id'],
+ 'CVVRESULT' => 'M',
+ 'AVSRESULT' => '0'
+ ) );
+ $this->assertFalse( $result->isFailed() );
+ $this->assertEmpty( $result->getErrors() );
+ // TODO inspect the queue message
+ }
+
+ public function testDonorReturnFailure() {
+ $this->markTestSkipped( 'OrderStatus not implemented' );
+ $init = $this->getDonorTestData();
+ $init['payment_method'] = 'cc';
+ $init['payment_submethod'] = 'visa';
+ $init['email'] = '[email protected]';
+ $init['order_id'] = mt_rand();
+ $session['Donor'] = $init;
+ $this->setUpRequest( $init, $session );
+ $gateway = $this->getFreshGatewayObject( array() );
+ $gateway->setDummyGatewayResponseCode( '430285' ); // invalid
card
+ $result = $gateway->processDonorReturn( array(
+ 'REF' => $init['order_id'],
+ 'CVVRESULT' => 'M',
+ 'AVSRESULT' => '0'
+ ) );
+ $this->assertTrue( $result->isFailed() );
+ }
+}
diff --git a/tests/phpunit/Adapter/Ingenico/RealTimeBankTransferIdealTest.php
b/tests/phpunit/Adapter/Ingenico/RealTimeBankTransferIdealTest.php
new file mode 100644
index 0000000..8caf7ac
--- /dev/null
+++ b/tests/phpunit/Adapter/Ingenico/RealTimeBankTransferIdealTest.php
@@ -0,0 +1,378 @@
+<?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 SmashPig\Tests\TestingContext;
+use SmashPig\Tests\TestingProviderConfiguration;
+
+/**
+ *
+ * @group Fundraising
+ * @group DonationInterface
+ * @group Ingenico
+ * @group RealTimeBankTransfer
+ */
+class DonationInterface_Adapter_Ingenico_RealTimeBankTransferIdealTest extends
BaseIngenicoTestCase {
+ /**
+ * @var PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $bankPaymentProvider;
+
+ public function setUp() {
+ parent::setUp();
+ $this->markTestSkipped( 'RTBT not implemented' );
+ $config = TestingProviderConfiguration::createForProvider(
+ 'ingenico',
+ $this->smashPigGlobalConfig
+ );
+ TestingContext::get()->providerConfigurationOverride = $config;
+
+ $this->bankPaymentProvider = $this->getMockBuilder(
+
'\SmashPig\PaymentProviders\Ingenico\BankPaymentProvider'
+ )->disableOriginalConstructor()->getMock();
+
+ $config->overrideObjectInstance( 'payment-provider/rtbt',
$this->bankPaymentProvider );
+
+ $this->bankPaymentProvider->method( 'getBankList' )
+ ->willReturn(
+ array(
+ 'Test1234' => 'Test Bank 1234',
+ 'Test5678' => 'Test Bank 5678',
+ )
+ );
+
+ $this->setMwGlobals(
+ array(
+ 'wgIngenicoGatewayEnabled' => true,
+ 'wgDonationInterfaceAllowedHtmlForms' => array(
+ 'rtbt-ideal' => array(
+ 'gateway' => 'ingenico',
+ 'payment_methods' => array(
'rtbt' => 'rtbt_ideal' ),
+ 'countries' => array( '+' =>
'NL' ),
+ 'currencies' => array( '+' =>
'EUR' ),
+ ),
+ ),
+ )
+ );
+ }
+
+ /**
+ * Test for ideal form loading
+ */
+ public function testIngenicoFormLoad_rtbt_Ideal() {
+ $init = $this->getDonorTestData( 'NL' );
+ unset( $init['order_id'] );
+ $init['payment_method'] = 'rtbt';
+ $init['ffname'] = 'rtbt-ideal';
+
+ $assertNodes = array(
+ 'amount' => array(
+ 'nodename' => 'input',
+ 'value' => '1.55',
+ ),
+ 'currency' => array(
+ 'nodename' => 'select',
+ 'selected' => 'EUR',
+ ),
+ 'country' => array(
+ 'nodename' => 'input',
+ 'value' => 'NL',
+ ),
+ 'issuer_id' => array(
+ 'innerhtmlmatches' => '/Test Bank 1234/'
+ )
+ );
+
+ $this->verifyFormOutput( 'IngenicoGateway', $init,
$assertNodes, true );
+ }
+
+ /**
+ * testBuildRequestXmlWithIssuerId21
+ *
+ * Rabobank: 21
+ *
+ * @covers GatewayAdapter::__construct
+ * @covers GatewayAdapter::setCurrentTransaction
+ * @covers GatewayAdapter::buildRequestXML
+ * @covers GatewayAdapter::getData_Unstaged_Escaped
+ */
+ public function testBuildRequestXmlWithIssuerId21() {
+
+ $optionsForTestData = array(
+ 'form_name' => 'TwoStepAmount',
+ 'payment_method' => 'rtbt',
+ 'payment_submethod' => 'rtbt_ideal',
+ 'payment_product_id' => 809,
+ 'issuer_id' => 21,
+ );
+
+ //somewhere else?
+ $options = $this->getDonorTestData( 'ES' );
+ $options = array_merge( $options, $optionsForTestData );
+ unset( $options['payment_product_id'] );
+
+ $this->buildRequestXmlForIngenico( $optionsForTestData,
$options );
+ }
+
+ /**
+ * testBuildRequestXmlWithIssuerId31
+ *
+ * ABN AMRO: 31
+ *
+ * @covers GatewayAdapter::__construct
+ * @covers GatewayAdapter::setCurrentTransaction
+ * @covers GatewayAdapter::buildRequestXML
+ * @covers GatewayAdapter::getData_Unstaged_Escaped
+ */
+ public function testBuildRequestXmlWithIssuerId31() {
+
+ $optionsForTestData = array(
+ 'form_name' => 'TwoStepAmount',
+ 'payment_method' => 'rtbt',
+ 'payment_submethod' => 'rtbt_ideal',
+ 'payment_product_id' => 809,
+ 'issuer_id' => 31,
+ );
+
+ //somewhere else?
+ $options = $this->getDonorTestData( 'ES' );
+ $options = array_merge( $options, $optionsForTestData );
+ unset( $options['payment_product_id'] );
+
+ $this->buildRequestXmlForIngenico( $optionsForTestData,
$options );
+ }
+
+ /**
+ * testBuildRequestXmlWithIssuerId91
+ *
+ * Rabobank: 21
+ *
+ * @covers GatewayAdapter::__construct
+ * @covers GatewayAdapter::setCurrentTransaction
+ * @covers GatewayAdapter::buildRequestXML
+ * @covers GatewayAdapter::getData_Unstaged_Escaped
+ */
+ public function testBuildRequestXmlWithIssuerId91() {
+
+ $optionsForTestData = array(
+ 'form_name' => 'TwoStepAmount',
+ 'payment_method' => 'rtbt',
+ 'payment_submethod' => 'rtbt_ideal',
+ 'payment_product_id' => 809,
+ 'issuer_id' => 21,
+ );
+
+ //somewhere else?
+ $options = $this->getDonorTestData( 'ES' );
+ $options = array_merge( $options, $optionsForTestData );
+ unset( $options['payment_product_id'] );
+
+ $this->buildRequestXmlForIngenico( $optionsForTestData,
$options );
+ }
+
+ /**
+ * testBuildRequestXmlWithIssuerId161
+ *
+ * Van Lanschot Bankiers: 161
+ *
+ * @covers GatewayAdapter::__construct
+ * @covers GatewayAdapter::setCurrentTransaction
+ * @covers GatewayAdapter::buildRequestXML
+ * @covers GatewayAdapter::getData_Unstaged_Escaped
+ */
+ public function testBuildRequestXmlWithIssuerId161() {
+
+ $optionsForTestData = array(
+ 'form_name' => 'TwoStepAmount',
+ 'payment_method' => 'rtbt',
+ 'payment_submethod' => 'rtbt_ideal',
+ 'payment_product_id' => 809,
+ 'issuer_id' => 161,
+ );
+
+ //somewhere else?
+ $options = $this->getDonorTestData( 'ES' );
+ $options = array_merge( $options, $optionsForTestData );
+ unset( $options['payment_product_id'] );
+
+ $this->buildRequestXmlForIngenico( $optionsForTestData,
$options );
+ }
+
+ /**
+ * testBuildRequestXmlWithIssuerId511
+ *
+ * Triodos Bank: 511
+ *
+ * @covers GatewayAdapter::__construct
+ * @covers GatewayAdapter::setCurrentTransaction
+ * @covers GatewayAdapter::buildRequestXML
+ * @covers GatewayAdapter::getData_Unstaged_Escaped
+ */
+ public function testBuildRequestXmlWithIssuerId511() {
+
+ $optionsForTestData = array(
+ 'form_name' => 'TwoStepAmount',
+ 'payment_method' => 'rtbt',
+ 'payment_submethod' => 'rtbt_ideal',
+ 'payment_product_id' => 809,
+ 'issuer_id' => 511,
+ );
+
+ //somewhere else?
+ $options = $this->getDonorTestData( 'ES' );
+ $options = array_merge( $options, $optionsForTestData );
+ unset( $options['payment_product_id'] );
+
+ $this->buildRequestXmlForIngenico( $optionsForTestData,
$options );
+ }
+
+ /**
+ * testBuildRequestXmlWithIssuerId721
+ *
+ * ING: 721
+ *
+ * @covers GatewayAdapter::__construct
+ * @covers GatewayAdapter::setCurrentTransaction
+ * @covers GatewayAdapter::buildRequestXML
+ * @covers GatewayAdapter::getData_Unstaged_Escaped
+ */
+ public function testBuildRequestXmlWithIssuerId721() {
+
+ $optionsForTestData = array(
+ 'form_name' => 'TwoStepAmount',
+ 'payment_method' => 'rtbt',
+ 'payment_submethod' => 'rtbt_ideal',
+ 'payment_product_id' => 809,
+ 'issuer_id' => 721,
+ );
+
+ //somewhere else?
+ $options = $this->getDonorTestData( 'ES' );
+ $options = array_merge( $options, $optionsForTestData );
+ unset( $options['payment_product_id'] );
+
+ $this->buildRequestXmlForIngenico( $optionsForTestData,
$options );
+ }
+
+ /**
+ * testBuildRequestXmlWithIssuerId751
+ *
+ * SNS Bank: 751
+ *
+ * @covers GatewayAdapter::__construct
+ * @covers GatewayAdapter::setCurrentTransaction
+ * @covers GatewayAdapter::buildRequestXML
+ * @covers GatewayAdapter::getData_Unstaged_Escaped
+ */
+ public function testBuildRequestXmlWithIssuerId751() {
+
+ $optionsForTestData = array(
+ 'form_name' => 'TwoStepAmount',
+ 'payment_method' => 'rtbt',
+ 'payment_submethod' => 'rtbt_ideal',
+ 'payment_product_id' => 809,
+ 'issuer_id' => 751,
+ );
+
+ //somewhere else?
+ $options = $this->getDonorTestData( 'ES' );
+ $options = array_merge( $options, $optionsForTestData );
+ unset( $options['payment_product_id'] );
+
+ $this->buildRequestXmlForIngenico( $optionsForTestData,
$options );
+ }
+
+ /**
+ * testBuildRequestXmlWithIssuerId761
+ *
+ * ASN Bank: 761
+ *
+ * @covers GatewayAdapter::__construct
+ * @covers GatewayAdapter::setCurrentTransaction
+ * @covers GatewayAdapter::buildRequestXML
+ * @covers GatewayAdapter::getData_Unstaged_Escaped
+ */
+ public function testBuildRequestXmlWithIssuerId761() {
+
+ $optionsForTestData = array(
+ 'form_name' => 'TwoStepAmount',
+ 'payment_method' => 'rtbt',
+ 'payment_submethod' => 'rtbt_ideal',
+ 'payment_product_id' => 809,
+ 'issuer_id' => 761,
+ );
+
+ //somewhere else?
+ $options = $this->getDonorTestData( 'ES' );
+ $options = array_merge( $options, $optionsForTestData );
+ unset( $options['payment_product_id'] );
+
+ $this->buildRequestXmlForIngenico( $optionsForTestData,
$options );
+ }
+
+ /**
+ * testBuildRequestXmlWithIssuerId771
+ *
+ * RegioBank: 771
+ *
+ * @covers GatewayAdapter::__construct
+ * @covers GatewayAdapter::setCurrentTransaction
+ * @covers GatewayAdapter::buildRequestXML
+ * @covers GatewayAdapter::getData_Unstaged_Escaped
+ */
+ public function testBuildRequestXmlWithIssuerId771() {
+
+ $optionsForTestData = array(
+ 'form_name' => 'TwoStepAmount',
+ 'payment_method' => 'rtbt',
+ 'payment_submethod' => 'rtbt_ideal',
+ 'payment_product_id' => 809,
+ 'issuer_id' => 771,
+ );
+
+ //somewhere else?
+ $options = $this->getDonorTestData( 'ES' );
+ $options = array_merge( $options, $optionsForTestData );
+ unset( $options['payment_product_id'] );
+
+ $this->buildRequestXmlForIngenico( $optionsForTestData,
$options );
+ }
+
+ public function testFormAction() {
+
+ $optionsForTestData = array(
+ 'payment_method' => 'rtbt',
+ 'payment_submethod' => 'rtbt_ideal',
+ 'issuer_id' => 771,
+ // Email is required for RTBT.
+ 'email' => '[email protected]',
+ );
+
+ //somewhere else?
+ $options = $this->getDonorTestData( 'ES' );
+ $options = array_merge( $options, $optionsForTestData );
+
+ $this->gatewayAdapter = $this->getFreshGatewayObject( $options
);
+
+ $this->assertTrue( $this->gatewayAdapter->validatedOK() );
+
+ $this->gatewayAdapter->do_transaction(
"INSERT_ORDERWITHPAYMENT" );
+ $action = $this->gatewayAdapter->getTransactionDataFormAction();
+ $this->assertEquals( "url_placeholder", $action, "The
formaction was not populated as expected (ideal)." );
+ }
+
+}
+
diff --git a/tests/phpunit/Adapter/Ingenico/RecurringTest.php
b/tests/phpunit/Adapter/Ingenico/RecurringTest.php
new file mode 100644
index 0000000..20e2bf5
--- /dev/null
+++ b/tests/phpunit/Adapter/Ingenico/RecurringTest.php
@@ -0,0 +1,135 @@
+<?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 Ingenico
+ * @group Recurring
+ */
+class DonationInterface_Adapter_Ingenico_RecurringTest extends
BaseIngenicoTestCase {
+
+ public function setUp() {
+ parent::setUp();
+ $this->markTestSkipped( 'Recurring not implemented' );
+ }
+
+ /**
+ * Can make a recurring payment
+ *
+ * @covers IngenicoAdapter::transactionRecurring_Charge
+ */
+ public function testRecurringCharge() {
+ $init = array(
+ 'amount' => '2345',
+ 'effort_id' => 2,
+ 'order_id' => '9998890004',
+ 'currency' => 'EUR',
+ 'payment_product' => '',
+ );
+ $gateway = $this->getFreshGatewayObject( $init );
+
+ $gateway->setDummyGatewayResponseCode( 'recurring-OK' );
+
+ $result = $gateway->do_transaction( 'Recurring_Charge' );
+
+ $this->assertTrue( $result->getCommunicationStatus() );
+ $this->assertRegExp( '/SET_PAYMENT/', $result->getRawResponse()
);
+ }
+
+ /**
+ * Can make a recurring payment
+ *
+ * @covers IngenicoAdapter::transactionRecurring_Charge
+ */
+ public function testDeclinedRecurringCharge() {
+ $init = array(
+ 'amount' => '2345',
+ 'effort_id' => 2,
+ 'order_id' => '9998890004',
+ 'currency' => 'EUR',
+ 'payment_product' => '',
+ );
+ $gateway = $this->getFreshGatewayObject( $init );
+
+ $gateway->setDummyGatewayResponseCode( 'recurring-declined' );
+
+ $result = $gateway->do_transaction( 'Recurring_Charge' );
+
+ $this->assertRegExp(
+ '/GET_ORDERSTATUS/',
+ $result->getRawResponse(),
+ 'Stopped after GET_ORDERSTATUS.'
+ );
+ $this->assertEquals(
+ 2,
+ count( $gateway->curled ),
+ 'Expected 2 API calls'
+ );
+ $this->assertEquals( FinalStatus::FAILED,
$gateway->getFinalStatus() );
+ }
+
+ /**
+ * Throw errors if the payment is incomplete
+ *
+ * @covers IngenicoAdapter::transactionRecurring_Charge
+ */
+ public function testRecurringTimeout() {
+ $init = array(
+ 'amount' => '2345',
+ 'effort_id' => 2,
+ 'order_id' => '9998890004',
+ 'currency' => 'EUR',
+ 'payment_product' => '',
+ );
+ $gateway = $this->getFreshGatewayObject( $init );
+
+ $gateway->setDummyGatewayResponseCode( 'recurring-timeout' );
+
+ $result = $gateway->do_transaction( 'Recurring_Charge' );
+
+ $this->assertFalse( $result->getCommunicationStatus() );
+ $this->assertRegExp( '/GET_ORDERSTATUS/',
$result->getRawResponse() );
+ // FIXME: This is a little funky--the transaction is actually
pending-poke.
+ $this->assertEquals( FinalStatus::FAILED,
$gateway->getFinalStatus() );
+ }
+
+ /**
+ * Can resume a recurring payment
+ *
+ * @covers IngenicoAdapter::transactionRecurring_Charge
+ */
+ public function testRecurringResume() {
+ $init = array(
+ 'amount' => '2345',
+ 'effort_id' => 2,
+ 'order_id' => '9998890004',
+ 'currency' => 'EUR',
+ 'payment_product' => '',
+ );
+ $gateway = $this->getFreshGatewayObject( $init );
+
+ $gateway->setDummyGatewayResponseCode( 'recurring-resume' );
+
+ $result = $gateway->do_transaction( 'Recurring_Charge' );
+
+ $this->assertTrue( $result->getCommunicationStatus() );
+ $this->assertRegExp( '/SET_PAYMENT/', $result->getRawResponse()
);
+ }
+}
diff --git a/tests/phpunit/Adapter/Ingenico/ResultSwitcherTest.php
b/tests/phpunit/Adapter/Ingenico/ResultSwitcherTest.php
new file mode 100644
index 0000000..71072fd
--- /dev/null
+++ b/tests/phpunit/Adapter/Ingenico/ResultSwitcherTest.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * @group Fundraising
+ * @group DonationInterface
+ * @group Ingenico
+ */
+class DonationInterface_Adapter_Ingenico_ResultSwitcherTest extends
BaseIngenicoTestCase {
+
+ /**
+ * Assuming we've popped out of the frame, does processing succeed?
+ */
+ public function testResultSwitcherLiberatedSuccess() {
+ $this->markTestSkipped( 'ResultSwitcher not implemented' );
+ $donorTestData = $this->getDonorTestData( 'FR' );
+ $donorTestData['payment_method'] = 'cc';
+ $donorTestData['payment_submethod'] = 'visa';
+ $donorTestData['email'] = '[email protected]';
+ $donorTestData['order_id'] = mt_rand();
+ $session['Donor'] = $donorTestData;
+ // Mark the order as already popped out of the iframe
+ $session['order_status'][$donorTestData['order_id']] =
'liberated';
+ $request = array(
+ 'REF' => $donorTestData['order_id'],
+ 'CVVRESULT' => 'M',
+ 'AVSRESULT' => '0',
+ 'language' => 'fr', // FIXME: verifyFormOutput
conflates request with other stuff
+ );
+ $assertNodes = array(
+ 'headers' => array(
+ 'Location' => function( $location ) use (
$donorTestData ) {
+ // Do this after the real processing to
avoid side effects
+ $gateway =
$this->getFreshGatewayObject( $donorTestData );
+ $url = ResultPages::getThankYouPage(
$gateway );
+ $this->assertEquals( $url, $location );
+ }
+ )
+ );
+
+ $this->verifyFormOutput( 'IngenicoGatewayResult', $request,
$assertNodes, false, $session );
+ // Make sure we logged the expected cURL attempts
+ $messages = $this->getLogMatches( 'info', '/Preparing to send
GET_ORDERSTATUS transaction to Global Collect/' );
+ $this->assertNotEmpty( $messages );
+ $messages = $this->getLogMatches( 'info', '/Preparing to send
SET_PAYMENT transaction to Global Collect/' );
+ $this->assertNotEmpty( $messages );
+ }
+}
diff --git a/tests/phpunit/BaseIngenicoTestCase.php
b/tests/phpunit/BaseIngenicoTestCase.php
new file mode 100644
index 0000000..53b0618
--- /dev/null
+++ b/tests/phpunit/BaseIngenicoTestCase.php
@@ -0,0 +1,84 @@
+<?php
+
+use SmashPig\Core\Context;
+use SmashPig\PaymentProviders\Ingenico\HostedCheckoutProvider;
+use SmashPig\Tests\TestingContext;
+use SmashPig\Tests\TestingProviderConfiguration;
+
+class BaseIngenicoTestCase extends DonationInterfaceTestCase {
+
+ /**
+ * @var HostedCheckoutProvider
+ */
+ protected $hostedCheckoutProvider;
+
+ protected $testAdapterClass = 'IngenicoAdapter';
+
+ protected function setUp() {
+ parent::setUp();
+ $providerConfig = $this->setSmashPigProvider( 'ingenico' );
+
+ $this->hostedCheckoutProvider = $this->getMockBuilder(
+
'SmashPig\PaymentProviders\Ingenico\HostedCheckoutProvider'
+ )->disableOriginalConstructor()->getMock();
+
+ $providerConfig->overrideObjectInstance(
+ 'payment-provider/cc',
+ $this->hostedCheckoutProvider
+ );
+
+ $vmad_countries = array( 'US', );
+ $vmaj_countries = array(
+ 'AD', 'AT', 'AU', 'BE', 'BH', 'DE', 'EC', 'ES', 'FI',
'FR', 'GB',
+ 'GF', 'GR', 'HK', 'IE', 'IT', 'JP', 'KR', 'LU', 'MY',
'NL', 'PR',
+ 'PT', 'SG', 'SI', 'SK', 'TH', 'TW',
+ );
+ $vma_countries = array(
+ 'AE', 'AL', 'AN', 'AR', 'BG', 'CA', 'CH', 'CN', 'CR',
'CY', 'CZ', 'DK',
+ 'DZ', 'EE', 'EG', 'JO', 'KE', 'HR', 'HU', 'IL', 'KW',
'KZ', 'LB', 'LI',
+ 'LK', 'LT', 'LV', 'MA', 'MT', 'NO', 'NZ', 'OM', 'PK',
'PL', 'QA', 'RO',
+ 'RU', 'SA', 'SE', 'TN', 'TR', 'UA',
+ );
+ $this->setMwGlobals( array(
+ 'wgIngenicoGatewayEnabled' => true,
+ 'wgDonationInterfaceAllowedHtmlForms' => array(
+ 'cc-vmad' => array(
+ 'gateway' => 'ingenico',
+ 'payment_methods' => array('cc' =>
array( 'visa', 'mc', 'amex', 'discover' )),
+ 'countries' => array(
+ '+' => $vmad_countries,
+ ),
+ ),
+ 'cc-vmaj' => array(
+ 'gateway' => 'ingenico',
+ 'payment_methods' => array('cc' =>
array( 'visa', 'mc', 'amex', 'jcb' )),
+ 'countries' => array(
+ '+' => $vmaj_countries,
+ ),
+ ),
+ 'cc-vma' => array(
+ 'gateway' => 'ingenico',
+ 'payment_methods' => array('cc' =>
array( 'visa', 'mc', 'amex' )),
+ 'countries' => array(
+ // Array merge with cc-vmaj as
fallback in case 'j' goes down
+ // Array merge with cc-vmad as
fallback in case 'd' goes down
+ '+' => array_merge(
+ $vmaj_countries,
+ $vmad_countries,
+ $vma_countries
+ ),
+ ),
+ ),
+ 'rtbt-sofo' => array(
+ 'gateway' => 'ingenico',
+ 'countries' => array(
+ '+' => array( 'AT', 'BE', 'CH',
'DE' ),
+ '-' => 'GB'
+ ),
+ 'currencies' => array( '+' => 'EUR' ),
+ 'payment_methods' => array('rtbt' =>
'rtbt_sofortuberweisung'),
+ ),
+ ),
+ ) );
+ }
+}
diff --git a/tests/phpunit/DonationInterfaceTestCase.php
b/tests/phpunit/DonationInterfaceTestCase.php
index 12ea84b..145c63e 100644
--- a/tests/phpunit/DonationInterfaceTestCase.php
+++ b/tests/phpunit/DonationInterfaceTestCase.php
@@ -19,6 +19,7 @@
use SmashPig\Core\Context;
use SmashPig\Tests\TestingContext;
use SmashPig\Tests\TestingGlobalConfiguration;
+use SmashPig\Tests\TestingProviderConfiguration;
use Wikimedia\TestingAccessWrapper;
/**
@@ -107,6 +108,18 @@
RequestContext::getMain()->setLanguage( $language );
// BackCompat
$this->setMwGlobals( 'wgLang',
RequestContext::getMain()->getLanguage() );
+ }
+
+ /**
+ * @param string $provider
+ * @return TestingProviderConfiguration
+ */
+ protected function setSmashPigProvider( $provider ) {
+ $providerConfig =
TestingProviderConfiguration::createForProvider(
+ $provider, $this->smashPigGlobalConfig
+ );
+ TestingContext::get()->providerConfigurationOverride =
$providerConfig;
+ return $providerConfig;
}
/**
@@ -584,7 +597,8 @@
unset( $perform_these_checks['headers'] );
$input_node = $dom_thingy->getElementById( $id );
- $this->assertNotNull( $input_node, "Couldn't find the
'$id' element" );
+ $this->assertNotNull( $input_node, "Couldn't find the
'$id' element in html. Log entries: \n" .
+ print_r(
DonationLoggerFactory::$overrideLogger->messages, true ) .
"\n\nHTML:\n$form_html" );
foreach ( $checks as $name => $expected ) {
switch ( $name ) {
case 'nodename':
diff --git a/tests/phpunit/TestConfiguration.php
b/tests/phpunit/TestConfiguration.php
index 8763cbf..8a0bd95 100644
--- a/tests/phpunit/TestConfiguration.php
+++ b/tests/phpunit/TestConfiguration.php
@@ -84,6 +84,7 @@
$wgDonationInterfaceCustomFiltersSrcRules,
$wgDonationInterfaceCustomFiltersFunctions,
$wgGlobalCollectGatewayCustomFiltersFunctions,
+ $wgIngenicoGatewayCustomFiltersFunctions,
$wgDonationInterfaceCountryMap,
$wgDonationInterfaceUtmCampaignMap,
$wgDonationInterfaceUtmSourceMap,
@@ -95,6 +96,7 @@
$wgDonationInterfaceGatewayAdapters = array(
'globalcollect'=> 'TestingGlobalCollectAdapter',
+ 'ingenico' => 'IngenicoAdapter',
'amazon'=> 'TestingAmazonAdapter',
'adyen'=> 'TestingAdyenAdapter',
'astropay'=> 'TestingAstroPayAdapter',
@@ -116,7 +118,6 @@
$wgGlobalCollectGatewayAccountInfo['test'] = array(
'MerchantID' => 'test',
);
-
/** Paypal **/
$wgPaypalGatewayAccountInfo = array();
@@ -222,6 +223,8 @@
'getAVSResult' => 25,
) + $customFilters;
+$wgIngenicoGatewayCustomFiltersFunctions =
$wgGlobalCollectGatewayCustomFiltersFunctions;
+
$wgDonationInterfaceCountryMap = array (
'US' => 40,
'CA' => 15,
--
To view, visit https://gerrit.wikimedia.org/r/364143
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I4c02abd190b1ea27c1921f37196481d87cd0162a
Gerrit-PatchSet: 35
Gerrit-Project: mediawiki/extensions/DonationInterface
Gerrit-Branch: master
Gerrit-Owner: Ejegg <[email protected]>
Gerrit-Reviewer: AndyRussG <[email protected]>
Gerrit-Reviewer: Cdentinger <[email protected]>
Gerrit-Reviewer: Eileen <[email protected]>
Gerrit-Reviewer: Ejegg <[email protected]>
Gerrit-Reviewer: Katie Horn <[email protected]>
Gerrit-Reviewer: Mepps <[email protected]>
Gerrit-Reviewer: XenoRyet <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits