22
22
use Magento \Framework \Exception \LocalizedException ;
23
23
use Magento \Framework \HTTP \Client \Curl ;
24
24
use Magento \Framework \HTTP \Client \CurlFactory ;
25
+ use Magento \Framework \HTTP \ClientInterface ;
25
26
use Magento \Framework \Pricing \PriceCurrencyInterface ;
26
27
use Magento \Framework \Serialize \Serializer \Json ;
27
28
use Magento \Framework \TestFramework \Unit \Helper \ObjectManager ;
49
50
use PHPUnit \Framework \TestCase ;
50
51
use Psr \Log \LoggerInterface ;
51
52
use Magento \Catalog \Api \Data \ProductInterface ;
53
+ use Magento \Framework \App \CacheInterface ;
52
54
53
55
/**
54
56
* CarrierTest contains units test for Fedex carrier methods
@@ -102,11 +104,6 @@ class CarrierTest extends TestCase
102
104
*/
103
105
private Json $ serializer ;
104
106
105
- /**
106
- * @var LoggerInterface|MockObject
107
- */
108
- private LoggerInterface $ logger ;
109
-
110
107
/**
111
108
* @var CurrencyFactory|MockObject
112
109
*/
@@ -132,6 +129,11 @@ class CarrierTest extends TestCase
132
129
*/
133
130
private DecoderInterface $ decoderInterface ;
134
131
132
+ /**
133
+ * @var CacheInterface|MockObject
134
+ */
135
+ private $ cacheMock ;
136
+
135
137
/**
136
138
* @return void
137
139
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
@@ -189,7 +191,7 @@ protected function setUp(): void
189
191
->disableOriginalConstructor ()
190
192
->getMock ();
191
193
192
- $ this -> logger = $ this ->getMockForAbstractClass (LoggerInterface::class);
194
+ $ logger = $ this ->getMockForAbstractClass (LoggerInterface::class);
193
195
194
196
$ this ->curlFactory = $ this ->getMockBuilder (CurlFactory::class)
195
197
->disableOriginalConstructor ()
@@ -206,13 +208,16 @@ protected function setUp(): void
206
208
->onlyMethods (['decode ' ])
207
209
->getMock ();
208
210
211
+ $ this ->cacheMock = $ this ->getMockBuilder (CacheInterface::class)
212
+ ->onlyMethods (['load ' , 'save ' ])
213
+ ->getMockForAbstractClass ();
209
214
$ this ->carrier = $ this ->getMockBuilder (Carrier::class)
210
215
->addMethods (['rateRequest ' ])
211
216
->setConstructorArgs (
212
217
[
213
218
'scopeConfig ' => $ this ->scope ,
214
219
'rateErrorFactory ' => $ this ->errorFactory ,
215
- 'logger ' => $ this -> logger ,
220
+ 'logger ' => $ logger ,
216
221
'xmlSecurity ' => new Security (),
217
222
'xmlElFactory ' => $ elementFactory ,
218
223
'rateFactory ' => $ rateFactory ,
@@ -229,6 +234,7 @@ protected function setUp(): void
229
234
'productCollectionFactory ' => $ this ->collectionFactory ,
230
235
'curlFactory ' => $ this ->curlFactory ,
231
236
'decoderInterface ' => $ this ->decoderInterface ,
237
+ 'cache ' => $ this ->cacheMock ,
232
238
'data ' => [],
233
239
'serializer ' => $ this ->serializer ,
234
240
]
@@ -1064,6 +1070,173 @@ public function testGetCodeWithDropoffTypeNoCode(): void
1064
1070
$ this ->assertEquals (__ ('Regular Pickup ' ), $ result ['REGULAR_PICKUP ' ]);
1065
1071
}
1066
1072
1073
+ /**
1074
+ * Test get access token from cache
1075
+ */
1076
+ public function testCollectRatesWithCachedAccessToken (): void
1077
+ {
1078
+ $ apiKey = 'TestApiKey ' ;
1079
+ $ secretKey = 'TestSecretKey ' ;
1080
+ $ accessToken = 'CachedTestAccessToken ' ;
1081
+ $ cacheKey = 'fedex_access_token_ ' . hash ('sha256 ' , $ apiKey . $ secretKey );
1082
+ $ expiresAt = time () + 3600 ;
1083
+ $ cachedData = json_encode ([
1084
+ 'access_token ' => $ accessToken ,
1085
+ 'expires_at ' => $ expiresAt
1086
+ ]);
1087
+ $ this ->scope ->expects ($ this ->any ())
1088
+ ->method ('getValue ' )
1089
+ ->willReturnCallback ([$ this , 'scopeConfigGetValue ' ]);
1090
+ $ this ->scope ->expects ($ this ->exactly (2 ))
1091
+ ->method ('isSetFlag ' )
1092
+ ->willReturn (true );
1093
+
1094
+ $ this ->cacheMock ->expects ($ this ->once ())
1095
+ ->method ('load ' )
1096
+ ->with ($ cacheKey )
1097
+ ->willReturn ($ cachedData );
1098
+
1099
+ $ rateResponseMock = [
1100
+ 'output ' => [
1101
+ 'rateReplyDetails ' => [
1102
+ [
1103
+ 'serviceType ' => 'FEDEX_GROUND ' ,
1104
+ 'ratedShipmentDetails ' => [
1105
+ [
1106
+ 'totalNetCharge ' => '28.75 ' ,
1107
+ 'currency ' => 'USD ' ,
1108
+ 'ratedPackages ' => [
1109
+ ['packageRateDetail ' => ['rateType ' => 'RATED_ACCOUNT_PACKAGE ' ]]
1110
+ ]
1111
+ ]
1112
+ ]
1113
+ ]
1114
+ ]
1115
+ ]
1116
+ ];
1117
+ $ this ->serializer ->expects ($ this ->once ())
1118
+ ->method ('serialize ' )
1119
+ ->willReturn (json_encode (['mocked_request ' => 'data ' ]));
1120
+ $ this ->serializer ->expects ($ this ->once ())
1121
+ ->method ('unserialize ' )
1122
+ ->willReturn ($ rateResponseMock );
1123
+ $ this ->curlFactory ->expects ($ this ->once ())
1124
+ ->method ('create ' )
1125
+ ->willReturn ($ this ->curlClient );
1126
+ $ this ->curlClient ->expects ($ this ->once ())
1127
+ ->method ('setHeaders ' )
1128
+ ->willReturnSelf ();
1129
+ $ this ->curlClient ->expects ($ this ->once ())
1130
+ ->method ('post ' )
1131
+ ->willReturnSelf ();
1132
+ $ this ->curlClient ->expects ($ this ->once ())
1133
+ ->method ('getBody ' )
1134
+ ->willReturn (json_encode ($ rateResponseMock ));
1135
+ $ request = $ this ->getMockBuilder (RateRequest::class)
1136
+ ->addMethods (['getBaseCurrency ' , 'getPackageWeight ' ])
1137
+ ->disableOriginalConstructor ()
1138
+ ->getMock ();
1139
+ $ request ->method ('getPackageWeight ' )
1140
+ ->willReturn (10.0 );
1141
+ $ result = $ this ->carrier ->collectRates ($ request );
1142
+ $ this ->assertInstanceOf (RateResult::class, $ result );
1143
+ $ rates = $ result ->getAllRates ();
1144
+ $ this ->assertNotEmpty ($ rates );
1145
+ }
1146
+
1147
+ /**
1148
+ * Test getTracking when a new access token is requested and saved to cache
1149
+ */
1150
+ public function testGetTrackingWithNewAccessTokenSavedToCache (): void
1151
+ {
1152
+ $ apiKey = 'TestApiKey ' ;
1153
+ $ secretKey = 'TestSecretKey ' ;
1154
+ $ accessToken = 'NewTrackingTestAccessToken ' ;
1155
+ $ cacheKey = 'fedex_access_token_ ' . hash ('sha256 ' , $ apiKey . $ secretKey );
1156
+ $ expiresIn = 3600 ;
1157
+ $ cacheType = 'fedex_api ' ;
1158
+ $ tokenResponse = [
1159
+ 'access_token ' => $ accessToken ,
1160
+ 'expires_in ' => $ expiresIn
1161
+ ];
1162
+ $ trackingNumber = '123456789012 ' ;
1163
+ $ this ->scope ->expects ($ this ->any ())
1164
+ ->method ('getValue ' )
1165
+ ->willReturnCallback ([$ this , 'scopeConfigGetValue ' ]);
1166
+ $ this ->cacheMock ->expects ($ this ->once ())
1167
+ ->method ('load ' )
1168
+ ->with ($ cacheKey )
1169
+ ->willReturn (false );
1170
+ $ this ->cacheMock ->expects ($ this ->once ())
1171
+ ->method ('save ' )
1172
+ ->with (
1173
+ $ this ->callback (function ($ data ) use ($ accessToken , $ expiresIn ) {
1174
+ $ decoded = json_decode ($ data , true );
1175
+ return $ decoded ['access_token ' ] === $ accessToken &&
1176
+ $ decoded ['expires_at ' ] <= (time () + $ expiresIn ) &&
1177
+ $ decoded ['expires_at ' ] > time ();
1178
+ }),
1179
+ $ cacheKey ,
1180
+ [$ cacheType ],
1181
+ $ expiresIn
1182
+ )
1183
+ ->willReturn (true );
1184
+ $ curlTokenClient = $ this ->createMock (ClientInterface::class);
1185
+ $ this ->curlFactory ->expects ($ this ->exactly (2 ))
1186
+ ->method ('create ' )
1187
+ ->willReturnOnConsecutiveCalls ($ curlTokenClient , $ this ->curlClient );
1188
+ $ curlTokenClient ->expects ($ this ->once ())
1189
+ ->method ('setHeaders ' )
1190
+ ->willReturnSelf ();
1191
+ $ curlTokenClient ->expects ($ this ->once ())
1192
+ ->method ('post ' )
1193
+ ->willReturnSelf ();
1194
+ $ curlTokenClient ->expects ($ this ->once ())
1195
+ ->method ('getBody ' )
1196
+ ->willReturn (json_encode ($ tokenResponse ));
1197
+ $ trackingResponse = $ this ->getTrackingResponse ();
1198
+ $ trackingStatusMock = $ this ->getMockBuilder (Status::class)
1199
+ ->addMethods (['setCarrier ' , 'setCarrierTitle ' , 'setTracking ' ])
1200
+ ->onlyMethods (['addData ' ])
1201
+ ->getMock ();
1202
+ $ this ->statusFactory ->expects ($ this ->once ())
1203
+ ->method ('create ' )
1204
+ ->willReturn ($ trackingStatusMock );
1205
+ $ trackingStatusMock ->expects ($ this ->once ())
1206
+ ->method ('setCarrier ' )
1207
+ ->with (Carrier::CODE )
1208
+ ->willReturnSelf ();
1209
+ $ trackingStatusMock ->expects ($ this ->once ())
1210
+ ->method ('setCarrierTitle ' )
1211
+ ->willReturnSelf ();
1212
+ $ trackingStatusMock ->expects ($ this ->once ())
1213
+ ->method ('setTracking ' )
1214
+ ->with ($ trackingNumber )
1215
+ ->willReturnSelf ();
1216
+ $ trackingStatusMock ->expects ($ this ->once ())
1217
+ ->method ('addData ' )
1218
+ ->willReturnSelf ();
1219
+ $ this ->serializer ->expects ($ this ->once ())
1220
+ ->method ('serialize ' )
1221
+ ->willReturn (json_encode ($ this ->getTrackRequest ($ trackingNumber )));
1222
+ $ this ->serializer ->expects ($ this ->exactly (2 ))
1223
+ ->method ('unserialize ' )
1224
+ ->willReturnOnConsecutiveCalls ($ tokenResponse , $ trackingResponse );
1225
+ $ this ->curlClient ->expects ($ this ->once ())
1226
+ ->method ('setHeaders ' )
1227
+ ->willReturnSelf ();
1228
+ $ this ->curlClient ->expects ($ this ->once ())
1229
+ ->method ('post ' )
1230
+ ->willReturnSelf ();
1231
+ $ this ->curlClient ->expects ($ this ->once ())
1232
+ ->method ('getBody ' )
1233
+ ->willReturn (json_encode ($ trackingResponse ));
1234
+ $ trackings = [$ trackingNumber ];
1235
+ $ result = $ this ->carrier ->getTracking ($ trackings );
1236
+ $ this ->assertInstanceOf (Result::class, $ result );
1237
+ $ trackingsResult = $ result ->getAllTrackings ();
1238
+ $ this ->assertNotEmpty ($ trackingsResult );
1239
+ }
1067
1240
/**
1068
1241
* Gets list of variations for testing ship date.
1069
1242
*
@@ -1314,4 +1487,29 @@ private function getShipmentRequestMock(): MockObject
1314
1487
])
1315
1488
->getMock ();
1316
1489
}
1490
+
1491
+ /**
1492
+ * @return array
1493
+ */
1494
+ private function getTrackingResponse (): array
1495
+ {
1496
+ return [
1497
+ 'output ' => [
1498
+ 'completeTrackResults ' => [
1499
+ [
1500
+ 'trackingNumber ' => '123456789012 ' ,
1501
+ 'trackResults ' => [
1502
+ [
1503
+ 'trackingNumberInfo ' => ['trackingNumber ' => '123456789012 ' ],
1504
+ 'statusDetail ' => ['description ' => 'Delivered ' ],
1505
+ 'dateAndTimes ' => [
1506
+ ['type ' => 'ACTUAL_DELIVERY ' , 'dateTime ' => '2025-05-20T10:00:00Z ' ]
1507
+ ]
1508
+ ]
1509
+ ]
1510
+ ]
1511
+ ]
1512
+ ]
1513
+ ];
1514
+ }
1317
1515
}
0 commit comments