1+ <?php
2+
3+ declare (strict_types=1 );
4+
5+ namespace GlobalPayments \Api \Tests \Integration \Gateways \PorticoConnector ;
6+
7+ use GlobalPayments \Api \ServiceConfigs \Gateways \PorticoConfig ;
8+ use GlobalPayments \Api \Entities \Enums \ServiceEndpoints ;
9+ use GlobalPayments \Api \ServicesContainer ;
10+ use GlobalPayments \Api \PaymentMethods \CreditCardData ;
11+ use GlobalPayments \Api \Entities \Address ;
12+ use PHPUnit \Framework \TestCase ;
13+
14+ class PorticoEndpointConfigTest extends TestCase
15+ {
16+ private object $ requestLogger ;
17+
18+ protected function setUp (): void
19+ {
20+ parent ::setUp ();
21+
22+ // Create a mock request logger that captures URLs
23+ $ this ->requestLogger = new class implements \GlobalPayments \Api \Entities \IRequestLogger {
24+ public static array $ urls = [];
25+
26+ public function requestSent ($ verb , $ endpoint , $ headers , $ queryStringParams , $ data ): void {
27+ self ::$ urls [] = $ endpoint ;
28+ error_log ("REQUEST CAPTURED: $ verb $ endpoint " );
29+ }
30+
31+ public function responseReceived (\GlobalPayments \Api \Gateways \GatewayResponse $ response ): void {}
32+
33+ public function responseError (\Exception $ e , $ headers = '' ): void {}
34+ };
35+
36+ // Clear previous URLs for this test
37+ $ this ->requestLogger ::$ urls = [];
38+ }
39+
40+ /**
41+ * CRITICAL: Verify production credentials with explicit CERT endpoint route to CERT
42+ */
43+ public function testProdKeyWithCertEndpoint (): void
44+ {
45+ $ config = new PorticoConfig ();
46+ $ config ->secretApiKey = 'skapi_prod_9UnjAQz7gI5Bnl6MQq ' ; #gitleaks:allow
47+ $ config ->serviceUrl = ServiceEndpoints::PORTICO_TEST ;
48+ $ config ->requestLogger = $ this ->requestLogger ;
49+
50+ ServicesContainer::configureService ($ config , 'cert_test ' );
51+
52+ try {
53+ $ this ->createTestCard ()->charge (10.00 )
54+ ->withCurrency ('USD ' )
55+ ->withAddress ($ this ->createTestAddress ())
56+ ->execute ('cert_test ' );
57+ } catch (\Exception ) {
58+ // Expected to fail - we're testing URL routing
59+ }
60+
61+ $ capturedUrl = $ this ->requestLogger ::$ urls [0 ] ?? '' ;
62+ $ this ->assertStringContainsString ('cert.api2.heartlandportico.com ' , $ capturedUrl );
63+ $ this ->assertStringNotContainsString ('https://api2.heartlandportico.com/ ' , $ capturedUrl );
64+ }
65+
66+ /**
67+ * Verify that production credentials without explicit URL go to production
68+ */
69+ public function testProdKeyAutoConfig (): void
70+ {
71+ $ config = new PorticoConfig ();
72+ $ config ->secretApiKey = 'skapi_prod_9UnjAQz7gI5Bnl6MQq ' ; #gitleaks:allow
73+ $ config ->requestLogger = $ this ->requestLogger ;
74+
75+ ServicesContainer::configureService ($ config , 'prod_auto ' );
76+
77+ try {
78+ $ this ->createTestCard ()
79+ ->charge (10.00 )
80+ ->withCurrency ('USD ' )
81+ ->execute ('prod_auto ' );
82+ } catch (\Exception ) {
83+ // Expected to fail - we're testing URL routing
84+ }
85+
86+ $ capturedUrl = $ this ->requestLogger ::$ urls [0 ] ?? '' ;
87+ $ this ->assertStringNotContainsString ('cert. ' , $ capturedUrl );
88+ $ this ->assertStringContainsString ('api2.heartlandportico.com ' , $ capturedUrl );
89+ }
90+
91+ /**
92+ * Critical bug scenario: Production credentials + explicit CERT must NOT hit production
93+ */
94+ public function testBugFix (): void
95+ {
96+ $ config = new PorticoConfig ();
97+ $ config ->secretApiKey = 'skapi_prod_9UnjAQz7gI5Bnl6MQq ' ; #gitleaks:allow
98+ $ config ->serviceUrl = ServiceEndpoints::PORTICO_TEST ;
99+ $ config ->requestLogger = $ this ->requestLogger ;
100+
101+ ServicesContainer::configureService ($ config , 'bug_scenario ' );
102+
103+ try {
104+ $ this ->createTestCard ()->charge (1.00 )
105+ ->withCurrency ('USD ' )
106+ ->withAddress ($ this ->createTestAddress ())
107+ ->execute ('bug_scenario ' );
108+ } catch (\Exception ) {
109+ // Expected to fail - we're testing routing, not success
110+ }
111+
112+ $ actualUrl = $ this ->requestLogger ::$ urls [0 ] ?? '' ;
113+
114+ $ this ->assertStringContainsString ('cert.api2.heartlandportico.com ' , $ actualUrl );
115+ $ this ->assertStringNotContainsString ('https://api2.heartlandportico.com/ ' , $ actualUrl );
116+ $ this ->assertNotEquals (
117+ ServiceEndpoints::PORTICO_PRODUCTION . '/Hps.Exchange.PosGateway/PosGatewayService.asmx ' ,
118+ $ actualUrl
119+ );
120+ }
121+
122+ private function createTestCard (): CreditCardData
123+ {
124+ $ card = new CreditCardData ();
125+ $ card ->number = '4111111111111111 ' ;
126+ $ card ->expMonth = 12 ;
127+ $ card ->expYear = 2025 ;
128+ $ card ->cvn = '123 ' ;
129+
130+ return $ card ;
131+ }
132+
133+ private function createTestAddress (): Address
134+ {
135+ $ address = new Address ();
136+ $ address ->streetAddress1 = '123 Main St ' ;
137+ $ address ->city = 'Downtown ' ;
138+ $ address ->province = 'NJ ' ;
139+ $ address ->postalCode = '12345 ' ;
140+ $ address ->country = 'USA ' ;
141+
142+ return $ address ;
143+ }
144+
145+ protected function tearDown (): void
146+ {
147+ $ configurations = ['cert_test ' , 'prod_auto ' , 'bug_scenario ' ];
148+
149+ foreach ($ configurations as $ config ) {
150+ ServicesContainer::removeConfiguration ($ config );
151+ }
152+
153+ parent ::tearDown ();
154+ }
155+ }
0 commit comments