SampleRepositoryTest.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Downloadable\Api;
  7. use Magento\Catalog\Model\Product;
  8. use Magento\Downloadable\Model\Sample;
  9. use Magento\TestFramework\Helper\Bootstrap;
  10. use Magento\TestFramework\TestCase\WebapiAbstract;
  11. class SampleRepositoryTest extends WebapiAbstract
  12. {
  13. /**
  14. * @var array
  15. */
  16. protected $createServiceInfo;
  17. /**
  18. * @var string
  19. */
  20. protected $testImagePath;
  21. /**
  22. * @var array
  23. */
  24. protected $updateServiceInfo;
  25. /**
  26. * @var array
  27. */
  28. protected $deleteServiceInfo;
  29. protected function setUp()
  30. {
  31. $this->createServiceInfo = [
  32. 'rest' => [
  33. 'resourcePath' => '/V1/products/downloadable-product/downloadable-links/samples',
  34. 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
  35. ],
  36. 'soap' => [
  37. 'service' => 'downloadableSampleRepositoryV1',
  38. 'serviceVersion' => 'V1',
  39. 'operation' => 'downloadableSampleRepositoryV1Save',
  40. ],
  41. ];
  42. $this->updateServiceInfo = [
  43. 'rest' => [
  44. 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
  45. ],
  46. 'soap' => [
  47. 'service' => 'downloadableSampleRepositoryV1',
  48. 'serviceVersion' => 'V1',
  49. 'operation' => 'downloadableSampleRepositoryV1Save',
  50. ],
  51. ];
  52. $this->deleteServiceInfo = [
  53. 'rest' => [
  54. 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE,
  55. ],
  56. 'soap' => [
  57. 'service' => 'downloadableSampleRepositoryV1',
  58. 'serviceVersion' => 'V1',
  59. 'operation' => 'downloadableSampleRepositoryV1Delete',
  60. ],
  61. ];
  62. $this->testImagePath = __DIR__ . str_replace('/', DIRECTORY_SEPARATOR, '/_files/test_image.jpg');
  63. }
  64. /**
  65. * Retrieve product that was updated by test
  66. *
  67. * @param bool $isScopeGlobal if true product store ID will be set to 0
  68. * @return Product
  69. */
  70. protected function getTargetProduct($isScopeGlobal = false)
  71. {
  72. if ($isScopeGlobal) {
  73. $product = Bootstrap::getObjectManager()->get(\Magento\Catalog\Model\ProductFactory::class)
  74. ->create()->setStoreId(0)->load(1);
  75. } else {
  76. $product = Bootstrap::getObjectManager()->get(\Magento\Catalog\Model\ProductFactory::class)
  77. ->create()
  78. ->load(1);
  79. }
  80. return $product;
  81. }
  82. /**
  83. * Retrieve product sample by its ID (or first sample if ID is not specified)
  84. *
  85. * @param Product $product
  86. * @param int|null $sampleId
  87. * @return Sample|null
  88. */
  89. protected function getTargetSample(Product $product, $sampleId = null)
  90. {
  91. $samples = $product->getExtensionAttributes()->getDownloadableProductSamples();
  92. if ($sampleId) {
  93. /* @var $sample \Magento\Downloadable\Model\Sample */
  94. if ($samples) {
  95. foreach ($samples as $sample) {
  96. if ($sample->getId() == $sampleId) {
  97. return $sample;
  98. }
  99. }
  100. }
  101. return null;
  102. }
  103. // return first sample
  104. return $samples[0];
  105. }
  106. /**
  107. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  108. */
  109. public function testCreateUploadsProvidedFileContent()
  110. {
  111. $requestData = [
  112. 'isGlobalScopeContent' => true,
  113. 'sku' => 'downloadable-product',
  114. 'sample' => [
  115. 'title' => 'Title',
  116. 'sort_order' => 1,
  117. 'sample_file_content' => [
  118. 'file_data' => base64_encode(file_get_contents($this->testImagePath)),
  119. 'name' => 'image.jpg',
  120. ],
  121. 'sample_type' => 'file',
  122. ],
  123. ];
  124. $newSampleId = $this->_webApiCall($this->createServiceInfo, $requestData);
  125. $globalScopeSample = $this->getTargetSample($this->getTargetProduct(true), $newSampleId);
  126. $sample = $this->getTargetSample($this->getTargetProduct(), $newSampleId);
  127. $this->assertNotNull($sample);
  128. $this->assertNotNull($sample->getId());
  129. $this->assertEquals($requestData['sample']['title'], $sample->getTitle());
  130. $this->assertEquals($requestData['sample']['title'], $globalScopeSample->getTitle());
  131. $this->assertEquals($requestData['sample']['sort_order'], $sample->getSortOrder());
  132. $this->assertEquals($requestData['sample']['sample_type'], $sample->getSampleType());
  133. $this->assertStringEndsWith('.jpg', $sample->getSampleFile());
  134. $this->assertNull($sample->getSampleUrl());
  135. }
  136. /**
  137. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  138. */
  139. public function testCreateSavesTitleInStoreViewScope()
  140. {
  141. $requestData = [
  142. 'isGlobalScopeContent' => false,
  143. 'sku' => 'downloadable-product',
  144. 'sample' => [
  145. 'title' => 'Store View Title',
  146. 'sort_order' => 1,
  147. 'sample_url' => 'http://www.sample.example.com/',
  148. 'sample_type' => 'url',
  149. ],
  150. ];
  151. $newSampleId = $this->_webApiCall($this->createServiceInfo, $requestData);
  152. $sample = $this->getTargetSample($this->getTargetProduct(), $newSampleId);
  153. $globalScopeSample = $this->getTargetSample($this->getTargetProduct(true), $newSampleId);
  154. $this->assertNotNull($sample);
  155. $this->assertEquals($requestData['sample']['title'], $sample->getTitle());
  156. $this->assertEquals($requestData['sample']['sort_order'], $sample->getSortOrder());
  157. $this->assertEquals($requestData['sample']['sample_url'], $sample->getSampleUrl());
  158. $this->assertEquals($requestData['sample']['sample_type'], $sample->getSampleType());
  159. $this->assertEmpty($globalScopeSample->getTitle());
  160. }
  161. /**
  162. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  163. */
  164. public function testCreateSavesProvidedUrls()
  165. {
  166. $requestData = [
  167. 'isGlobalScopeContent' => false,
  168. 'sku' => 'downloadable-product',
  169. 'sample' => [
  170. 'title' => 'Sample with URL resource',
  171. 'sort_order' => 1,
  172. 'sample_url' => 'http://www.sample.example.com/',
  173. 'sample_type' => 'url',
  174. ],
  175. ];
  176. $newSampleId = $this->_webApiCall($this->createServiceInfo, $requestData);
  177. $sample = $this->getTargetSample($this->getTargetProduct(), $newSampleId);
  178. $this->assertNotNull($sample);
  179. $this->assertEquals($requestData['sample']['title'], $sample->getTitle());
  180. $this->assertEquals($requestData['sample']['sort_order'], $sample->getSortOrder());
  181. $this->assertEquals($requestData['sample']['sample_type'], $sample->getSampleType());
  182. $this->assertEquals($requestData['sample']['sample_url'], $sample->getSampleUrl());
  183. }
  184. /**
  185. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  186. * @expectedException \Exception
  187. * @expectedExceptionMessage The sample type is invalid. Verify the sample type and try again.
  188. */
  189. public function testCreateThrowsExceptionIfSampleTypeIsInvalid()
  190. {
  191. $requestData = [
  192. 'isGlobalScopeContent' => false,
  193. 'sku' => 'downloadable-product',
  194. 'sample' => [
  195. 'title' => 'Sample with URL resource',
  196. 'sort_order' => 1,
  197. 'sample_type' => 'invalid',
  198. ],
  199. ];
  200. $this->_webApiCall($this->createServiceInfo, $requestData);
  201. }
  202. /**
  203. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  204. * @expectedException \Exception
  205. * @expectedExceptionMessage Provided content must be valid base64 encoded data.
  206. */
  207. public function testCreateThrowsExceptionIfSampleFileContentIsNotAValidBase64EncodedString()
  208. {
  209. $requestData = [
  210. 'isGlobalScopeContent' => false,
  211. 'sku' => 'downloadable-product',
  212. 'sample' => [
  213. 'title' => 'Sample Title',
  214. 'sort_order' => 1,
  215. 'sample_type' => 'file',
  216. 'sample_file_content' => [
  217. 'file_data' => 'not_a_base64_encoded_content',
  218. 'name' => 'image.jpg',
  219. ],
  220. ],
  221. ];
  222. $this->_webApiCall($this->createServiceInfo, $requestData);
  223. }
  224. /**
  225. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  226. * @expectedException \Exception
  227. * @expectedExceptionMessage Provided file name contains forbidden characters.
  228. */
  229. public function testCreateThrowsExceptionIfSampleFileNameContainsForbiddenCharacters()
  230. {
  231. $requestData = [
  232. 'isGlobalScopeContent' => false,
  233. 'sku' => 'downloadable-product',
  234. 'sample' => [
  235. 'title' => 'Title',
  236. 'sort_order' => 15,
  237. 'sample_type' => 'file',
  238. 'sample_file_content' => [
  239. 'file_data' => base64_encode(file_get_contents($this->testImagePath)),
  240. 'name' => 'name/with|forbidden{characters',
  241. ],
  242. ],
  243. ];
  244. $this->_webApiCall($this->createServiceInfo, $requestData);
  245. }
  246. /**
  247. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  248. * @expectedException \Exception
  249. * @expectedExceptionMessage Sample URL must have valid format.
  250. */
  251. public function testCreateThrowsExceptionIfSampleUrlHasWrongFormat()
  252. {
  253. $requestData = [
  254. 'isGlobalScopeContent' => false,
  255. 'sku' => 'downloadable-product',
  256. 'sample' => [
  257. 'title' => 'Sample Title',
  258. 'sort_order' => 1,
  259. 'sample_type' => 'url',
  260. 'sample_url' => 'http://example<.>com/',
  261. ],
  262. ];
  263. $this->_webApiCall($this->createServiceInfo, $requestData);
  264. }
  265. /**
  266. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  267. * @expectedException \Exception
  268. * @expectedExceptionMessage Sort order must be a positive integer.
  269. * @dataProvider getInvalidSortOrder
  270. */
  271. public function testCreateThrowsExceptionIfSortOrderIsInvalid($sortOrder)
  272. {
  273. $requestData = [
  274. 'isGlobalScopeContent' => false,
  275. 'sku' => 'downloadable-product',
  276. 'sample' => [
  277. 'title' => 'Sample Title',
  278. 'sort_order' => $sortOrder,
  279. 'sample_type' => 'url',
  280. 'sample_url' => 'http://example.com/',
  281. ],
  282. ];
  283. $this->_webApiCall($this->createServiceInfo, $requestData);
  284. }
  285. /**
  286. * @return array
  287. */
  288. public function getInvalidSortOrder()
  289. {
  290. return [
  291. [-1],
  292. ];
  293. }
  294. /**
  295. * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
  296. * @expectedException \Exception
  297. * @expectedExceptionMessage The product needs to be the downloadable type. Verify the product and try again.
  298. */
  299. public function testCreateThrowsExceptionIfTargetProductTypeIsNotDownloadable()
  300. {
  301. $this->createServiceInfo['rest']['resourcePath'] = '/V1/products/simple/downloadable-links/samples';
  302. $requestData = [
  303. 'isGlobalScopeContent' => false,
  304. 'sku' => 'simple',
  305. 'sample' => [
  306. 'title' => 'Sample Title',
  307. 'sort_order' => 50,
  308. 'sample_type' => 'url',
  309. 'sample_url' => 'http://example.com/',
  310. ],
  311. ];
  312. $this->_webApiCall($this->createServiceInfo, $requestData);
  313. }
  314. /**
  315. * @expectedException \Exception
  316. * @expectedExceptionMessage The product that was requested doesn't exist. Verify the product and try again.
  317. */
  318. public function testCreateThrowsExceptionIfTargetProductDoesNotExist()
  319. {
  320. $this->createServiceInfo['rest']['resourcePath'] = '/V1/products/wrong-sku/downloadable-links/samples';
  321. $requestData = [
  322. 'isGlobalScopeContent' => false,
  323. 'sku' => 'wrong-sku',
  324. 'sample' => [
  325. 'title' => 'Title',
  326. 'sort_order' => 15,
  327. 'sample_type' => 'url',
  328. 'sample_url' => 'http://example.com/',
  329. ],
  330. ];
  331. $this->_webApiCall($this->createServiceInfo, $requestData);
  332. }
  333. /**
  334. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php
  335. */
  336. public function testUpdate()
  337. {
  338. $sampleId = $this->getTargetSample($this->getTargetProduct())->getId();
  339. $this->updateServiceInfo['rest']['resourcePath']
  340. = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}";
  341. $requestData = [
  342. 'isGlobalScopeContent' => false,
  343. 'sku' => 'downloadable-product',
  344. 'sample' => [
  345. 'id' => $sampleId,
  346. 'title' => 'Updated Title',
  347. 'sort_order' => 2,
  348. 'sample_type' => 'url',
  349. ],
  350. ];
  351. $this->assertEquals($sampleId, $this->_webApiCall($this->updateServiceInfo, $requestData));
  352. $sample = $this->getTargetSample($this->getTargetProduct(), $sampleId);
  353. $this->assertNotNull($sample);
  354. $this->assertEquals($requestData['sample']['id'], $sample->getId());
  355. $this->assertEquals($requestData['sample']['title'], $sample->getTitle());
  356. $this->assertEquals($requestData['sample']['sort_order'], $sample->getSortOrder());
  357. }
  358. /**
  359. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php
  360. */
  361. public function testUpdateSavesDataInGlobalScopeAndDoesNotAffectValuesStoredInStoreViewScope()
  362. {
  363. $originalSample = $this->getTargetSample($this->getTargetProduct());
  364. $sampleId = $originalSample->getId();
  365. $this->updateServiceInfo['rest']['resourcePath']
  366. = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}";
  367. $requestData = [
  368. 'isGlobalScopeContent' => true,
  369. 'sku' => 'downloadable-product',
  370. 'sample' => [
  371. 'id' => $sampleId,
  372. 'title' => 'Updated Title',
  373. 'sort_order' => 2,
  374. 'sample_type' => 'url',
  375. ],
  376. ];
  377. $this->assertEquals($sampleId, $this->_webApiCall($this->updateServiceInfo, $requestData));
  378. $sample = $this->getTargetSample($this->getTargetProduct(), $sampleId);
  379. $globalScopeSample = $this->getTargetSample($this->getTargetProduct(true), $sampleId);
  380. $this->assertNotNull($sample);
  381. // Title was set on store view level in fixture so it must be the same
  382. $this->assertEquals($originalSample->getTitle(), $sample->getTitle());
  383. $this->assertEquals($requestData['sample']['title'], $globalScopeSample->getTitle());
  384. $this->assertEquals($requestData['sample']['sort_order'], $sample->getSortOrder());
  385. }
  386. /**
  387. * @expectedException \Exception
  388. * @expectedExceptionMessage The product that was requested doesn't exist. Verify the product and try again.
  389. */
  390. public function testUpdateThrowsExceptionIfTargetProductDoesNotExist()
  391. {
  392. $this->updateServiceInfo['rest']['resourcePath'] = '/V1/products/wrong-sku/downloadable-links/samples/1';
  393. $requestData = [
  394. 'isGlobalScopeContent' => true,
  395. 'sku' => 'wrong-sku',
  396. 'sample' => [
  397. 'id' => 1,
  398. 'title' => 'Updated Title',
  399. 'sort_order' => 2,
  400. 'sample_type' => 'url',
  401. ],
  402. ];
  403. $this->_webApiCall($this->updateServiceInfo, $requestData);
  404. }
  405. /**
  406. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php
  407. * @expectedException \Exception
  408. * @expectedExceptionMessage No downloadable sample with the provided ID was found. Verify the ID and try again.
  409. */
  410. public function testUpdateThrowsExceptionIfThereIsNoDownloadableSampleWithGivenId()
  411. {
  412. $sampleId = 9999;
  413. $this->updateServiceInfo['rest']['resourcePath']
  414. = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}";
  415. $requestData = [
  416. 'isGlobalScopeContent' => true,
  417. 'sku' => 'downloadable-product',
  418. 'sample' => [
  419. 'id' => $sampleId,
  420. 'title' => 'Title',
  421. 'sort_order' => 2,
  422. 'sample_type' => 'url',
  423. ],
  424. ];
  425. $this->_webApiCall($this->updateServiceInfo, $requestData);
  426. }
  427. /**
  428. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php
  429. * @expectedException \Exception
  430. * @expectedExceptionMessage Sort order must be a positive integer.
  431. * @dataProvider getInvalidSortOrder
  432. */
  433. public function testUpdateThrowsExceptionIfSortOrderIsInvalid($sortOrder)
  434. {
  435. $sampleId = $this->getTargetSample($this->getTargetProduct())->getId();
  436. $this->updateServiceInfo['rest']['resourcePath']
  437. = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}";
  438. $requestData = [
  439. 'isGlobalScopeContent' => false,
  440. 'sku' => 'downloadable-product',
  441. 'sample' => [
  442. 'id' => $sampleId,
  443. 'title' => 'Updated Sample Title',
  444. 'sort_order' => $sortOrder,
  445. 'sample_type' => 'url',
  446. ],
  447. ];
  448. $this->_webApiCall($this->updateServiceInfo, $requestData);
  449. }
  450. /**
  451. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php
  452. */
  453. public function testDelete()
  454. {
  455. $sampleId = $this->getTargetSample($this->getTargetProduct())->getId();
  456. $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/samples/{$sampleId}";
  457. $requestData = [
  458. 'id' => $sampleId,
  459. ];
  460. $this->assertTrue($this->_webApiCall($this->deleteServiceInfo, $requestData));
  461. $sample = $this->getTargetSample($this->getTargetProduct(), $sampleId);
  462. $this->assertNull($sample);
  463. }
  464. /**
  465. * @expectedException \Exception
  466. * @expectedExceptionMessage No downloadable sample with the provided ID was found. Verify the ID and try again.
  467. */
  468. public function testDeleteThrowsExceptionIfThereIsNoDownloadableSampleWithGivenId()
  469. {
  470. $sampleId = 9999;
  471. $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/samples/{$sampleId}";
  472. $requestData = [
  473. 'id' => $sampleId,
  474. ];
  475. $this->_webApiCall($this->deleteServiceInfo, $requestData);
  476. }
  477. /**
  478. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php
  479. * @dataProvider getListForAbsentProductProvider
  480. */
  481. public function testGetList($urlTail, $method, $expectations)
  482. {
  483. $sku = 'downloadable-product';
  484. $serviceInfo = [
  485. 'rest' => [
  486. 'resourcePath' => '/V1/products/' . $sku . $urlTail,
  487. 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
  488. ],
  489. 'soap' => [
  490. 'service' => 'downloadableSampleRepositoryV1',
  491. 'serviceVersion' => 'V1',
  492. 'operation' => 'downloadableSampleRepositoryV1' . $method,
  493. ],
  494. ];
  495. $requestData = ['sku' => $sku];
  496. $list = $this->_webApiCall($serviceInfo, $requestData);
  497. $this->assertEquals(1, count($list));
  498. $link = reset($list);
  499. foreach ($expectations['fields'] as $index => $value) {
  500. $this->assertEquals($value, $link[$index]);
  501. }
  502. $this->assertNotEmpty($link['sample_file']);
  503. }
  504. public function getListForAbsentProductProvider()
  505. {
  506. $sampleExpectation = [
  507. 'fields' => [
  508. 'title' => 'Downloadable Product Sample Title',
  509. 'sort_order' => 0,
  510. 'sample_type' => 'file'
  511. ]
  512. ];
  513. return [
  514. 'samples' => [
  515. '/downloadable-links/samples',
  516. 'GetList',
  517. $sampleExpectation,
  518. ],
  519. ];
  520. }
  521. }