LinkRepositoryTest.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  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\Api\ProductRepositoryInterface;
  8. use Magento\Catalog\Model\Product;
  9. use Magento\Downloadable\Model\Link;
  10. use Magento\TestFramework\Helper\Bootstrap;
  11. use Magento\TestFramework\TestCase\WebapiAbstract;
  12. class LinkRepositoryTest extends WebapiAbstract
  13. {
  14. /**
  15. * @var array
  16. */
  17. protected $createServiceInfo;
  18. /**
  19. * @var array
  20. */
  21. protected $updateServiceInfo;
  22. /**
  23. * @var array
  24. */
  25. protected $deleteServiceInfo;
  26. /**
  27. * @var string
  28. */
  29. protected $testImagePath;
  30. protected function setUp()
  31. {
  32. $this->createServiceInfo = [
  33. 'rest' => [
  34. 'resourcePath' => '/V1/products/downloadable-product/downloadable-links',
  35. 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
  36. ],
  37. 'soap' => [
  38. 'service' => 'downloadableLinkRepositoryV1',
  39. 'serviceVersion' => 'V1',
  40. 'operation' => 'downloadableLinkRepositoryV1Save',
  41. ],
  42. ];
  43. $this->updateServiceInfo = [
  44. 'rest' => [
  45. 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
  46. ],
  47. 'soap' => [
  48. 'service' => 'downloadableLinkRepositoryV1',
  49. 'serviceVersion' => 'V1',
  50. 'operation' => 'downloadableLinkRepositoryV1Save',
  51. ],
  52. ];
  53. $this->deleteServiceInfo = [
  54. 'rest' => [
  55. 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE,
  56. ],
  57. 'soap' => [
  58. 'service' => 'downloadableLinkRepositoryV1',
  59. 'serviceVersion' => 'V1',
  60. 'operation' => 'downloadableLinkRepositoryV1Delete',
  61. ],
  62. ];
  63. $this->testImagePath = __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'test_image.jpg';
  64. }
  65. /**
  66. * Retrieve product that was updated by test
  67. *
  68. * @param bool $isScopeGlobal if true product store ID will be set to 0
  69. * @return Product
  70. */
  71. protected function getTargetProduct($isScopeGlobal = false)
  72. {
  73. $objectManager = Bootstrap::getObjectManager();
  74. if ($isScopeGlobal) {
  75. $product = $objectManager->get(\Magento\Catalog\Model\ProductFactory::class)
  76. ->create()
  77. ->setStoreId(0)
  78. ->load(1);
  79. } else {
  80. $product = $objectManager->get(\Magento\Catalog\Model\ProductFactory::class)->create()->load(1);
  81. }
  82. return $product;
  83. }
  84. /**
  85. * Retrieve product link by its ID (or first link if ID is not specified)
  86. *
  87. * @param Product $product
  88. * @param int|null $linkId
  89. * @return Link|null
  90. */
  91. protected function getTargetLink(Product $product, $linkId = null)
  92. {
  93. $links = $product->getExtensionAttributes()->getDownloadableProductLinks();
  94. if ($linkId !== null) {
  95. if (!empty($links)) {
  96. foreach ($links as $link) {
  97. if ($link->getId() == $linkId) {
  98. return $link;
  99. }
  100. }
  101. }
  102. return null;
  103. }
  104. // return first link
  105. return reset($links);
  106. }
  107. /**
  108. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  109. */
  110. public function testCreateUploadsProvidedFileContent()
  111. {
  112. $requestData = [
  113. 'isGlobalScopeContent' => true,
  114. 'sku' => 'downloadable-product',
  115. 'link' => [
  116. 'title' => 'Title',
  117. 'sort_order' => 1,
  118. 'price' => 10.1,
  119. 'is_shareable' => 1,
  120. 'number_of_downloads' => 100,
  121. 'link_type' => 'file',
  122. 'link_file_content' => [
  123. 'file_data' => base64_encode(file_get_contents($this->testImagePath)),
  124. 'name' => 'image.jpg',
  125. ],
  126. 'sample_file_content' => [
  127. 'file_data' => base64_encode(file_get_contents($this->testImagePath)),
  128. 'name' => 'image.jpg',
  129. ],
  130. 'sample_type' => 'file',
  131. ],
  132. ];
  133. $newLinkId = $this->_webApiCall($this->createServiceInfo, $requestData);
  134. $globalScopeLink = $this->getTargetLink($this->getTargetProduct(true), $newLinkId);
  135. $link = $this->getTargetLink($this->getTargetProduct(), $newLinkId);
  136. $this->assertNotNull($link);
  137. $this->assertEquals($requestData['link']['title'], $link->getTitle());
  138. $this->assertEquals($requestData['link']['title'], $globalScopeLink->getTitle());
  139. $this->assertEquals($requestData['link']['sort_order'], $link->getSortOrder());
  140. $this->assertEquals($requestData['link']['price'], $link->getPrice());
  141. $this->assertEquals($requestData['link']['price'], $globalScopeLink->getPrice());
  142. $this->assertEquals($requestData['link']['is_shareable'], (int)$link->getIsShareable());
  143. $this->assertEquals($requestData['link']['number_of_downloads'], $link->getNumberOfDownloads());
  144. $this->assertEquals($requestData['link']['link_type'], $link->getLinkType());
  145. $this->assertEquals($requestData['link']['sample_type'], $link->getSampleType());
  146. $this->assertStringEndsWith('.jpg', $link->getSampleFile());
  147. $this->assertStringEndsWith('.jpg', $link->getLinkFile());
  148. $this->assertNull($link->getLinkUrl());
  149. $this->assertNull($link->getSampleUrl());
  150. }
  151. /**
  152. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  153. */
  154. public function testCreateSavesPriceAndTitleInStoreViewScope()
  155. {
  156. $requestData = [
  157. 'isGlobalScopeContent' => false,
  158. 'sku' => 'downloadable-product',
  159. 'link' => [
  160. 'title' => 'Store View Title',
  161. 'sort_order' => 1,
  162. 'price' => 150,
  163. 'is_shareable' => 1,
  164. 'number_of_downloads' => 100,
  165. 'link_url' => 'http://www.example.com/',
  166. 'link_type' => 'url',
  167. 'sample_url' => 'http://www.sample.example.com/',
  168. 'sample_type' => 'url',
  169. ],
  170. ];
  171. $newLinkId = $this->_webApiCall($this->createServiceInfo, $requestData);
  172. $link = $this->getTargetLink($this->getTargetProduct(), $newLinkId);
  173. $globalScopeLink = $this->getTargetLink($this->getTargetProduct(true), $newLinkId);
  174. $this->assertNotNull($link);
  175. $this->assertEquals($requestData['link']['title'], $link->getTitle());
  176. $this->assertEquals($requestData['link']['sort_order'], $link->getSortOrder());
  177. $this->assertEquals($requestData['link']['price'], $link->getPrice());
  178. $this->assertEquals($requestData['link']['is_shareable'], (int)$link->getIsShareable());
  179. $this->assertEquals($requestData['link']['number_of_downloads'], $link->getNumberOfDownloads());
  180. $this->assertEquals($requestData['link']['link_url'], $link->getLinkUrl());
  181. $this->assertEquals($requestData['link']['link_type'], $link->getLinkType());
  182. $this->assertEquals($requestData['link']['sample_url'], $link->getSampleUrl());
  183. $this->assertEquals($requestData['link']['sample_type'], $link->getSampleType());
  184. $this->assertEmpty($globalScopeLink->getTitle());
  185. $this->assertEmpty($globalScopeLink->getPrice());
  186. }
  187. /**
  188. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  189. */
  190. public function testCreateSavesProvidedUrls()
  191. {
  192. $requestData = [
  193. 'isGlobalScopeContent' => false,
  194. 'sku' => 'downloadable-product',
  195. 'link' => [
  196. 'title' => 'Link with URL resources',
  197. 'sort_order' => 1,
  198. 'price' => 10.1,
  199. 'is_shareable' => 1,
  200. 'number_of_downloads' => 100,
  201. 'link_url' => 'http://www.example.com/',
  202. 'link_type' => 'url',
  203. 'sample_url' => 'http://www.sample.example.com/',
  204. 'sample_type' => 'url',
  205. ],
  206. ];
  207. $newLinkId = $this->_webApiCall($this->createServiceInfo, $requestData);
  208. $link = $this->getTargetLink($this->getTargetProduct(), $newLinkId);
  209. $this->assertNotNull($link);
  210. $this->assertEquals($requestData['link']['title'], $link->getTitle());
  211. $this->assertEquals($requestData['link']['sort_order'], $link->getSortOrder());
  212. $this->assertEquals($requestData['link']['price'], $link->getPrice());
  213. $this->assertEquals($requestData['link']['is_shareable'], (int)$link->getIsShareable());
  214. $this->assertEquals($requestData['link']['number_of_downloads'], $link->getNumberOfDownloads());
  215. $this->assertEquals($requestData['link']['link_url'], $link->getLinkUrl());
  216. $this->assertEquals($requestData['link']['link_type'], $link->getLinkType());
  217. $this->assertEquals($requestData['link']['sample_type'], $link->getSampleType());
  218. $this->assertEquals($requestData['link']['sample_url'], $link->getSampleUrl());
  219. }
  220. /**
  221. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  222. * @expectedException \Exception
  223. * @expectedExceptionMessage The link type is invalid. Verify and try again.
  224. */
  225. public function testCreateThrowsExceptionIfLinkTypeIsNotSpecified()
  226. {
  227. $requestData = [
  228. 'isGlobalScopeContent' => false,
  229. 'sku' => 'downloadable-product',
  230. 'link' => [
  231. 'title' => 'Link with URL resources',
  232. 'sort_order' => 1,
  233. 'price' => 10.1,
  234. 'is_shareable' => 1,
  235. 'number_of_downloads' => 100,
  236. 'link_type' => 'invalid',
  237. 'sample_type' => 'url',
  238. 'sample_url' => 'http://www.example.com',
  239. ],
  240. ];
  241. $this->_webApiCall($this->createServiceInfo, $requestData);
  242. }
  243. /**
  244. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  245. * @expectedException \Exception
  246. * @expectedExceptionMessage Provided content must be valid base64 encoded data.
  247. */
  248. public function testCreateThrowsExceptionIfLinkFileContentIsNotAValidBase64EncodedString()
  249. {
  250. $requestData = [
  251. 'isGlobalScopeContent' => false,
  252. 'sku' => 'downloadable-product',
  253. 'link' => [
  254. 'title' => 'Link Title',
  255. 'sort_order' => 1,
  256. 'price' => 10,
  257. 'is_shareable' => 1,
  258. 'number_of_downloads' => 100,
  259. 'link_type' => 'url',
  260. 'link_url' => 'http://www.example.com/',
  261. 'sample_type' => 'file',
  262. 'sample_file_content' => [
  263. 'file_data' => 'not_a_base64_encoded_content',
  264. 'name' => 'image.jpg',
  265. ],
  266. ],
  267. ];
  268. $this->_webApiCall($this->createServiceInfo, $requestData);
  269. }
  270. /**
  271. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  272. * @expectedException \Exception
  273. * @expectedExceptionMessage Provided content must be valid base64 encoded data.
  274. */
  275. public function testCreateThrowsExceptionIfSampleFileContentIsNotAValidBase64EncodedString()
  276. {
  277. $requestData = [
  278. 'isGlobalScopeContent' => false,
  279. 'sku' => 'downloadable-product',
  280. 'link' => [
  281. 'title' => 'Link Title',
  282. 'sort_order' => 1,
  283. 'price' => 10,
  284. 'is_shareable' => 1,
  285. 'number_of_downloads' => 100,
  286. 'link_type' => 'file',
  287. 'link_file_content' => [
  288. 'file_data' => 'not_a_base64_encoded_content',
  289. 'name' => 'image.jpg',
  290. ],
  291. 'sample_type' => 'url',
  292. 'sample_url' => 'http://www.example.com/',
  293. ],
  294. ];
  295. $this->_webApiCall($this->createServiceInfo, $requestData);
  296. }
  297. /**
  298. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  299. * @expectedException \Exception
  300. * @expectedExceptionMessage Provided file name contains forbidden characters.
  301. */
  302. public function testCreateThrowsExceptionIfLinkFileNameContainsForbiddenCharacters()
  303. {
  304. $requestData = [
  305. 'isGlobalScopeContent' => false,
  306. 'sku' => 'downloadable-product',
  307. 'link' => [
  308. 'title' => 'Title',
  309. 'sort_order' => 15,
  310. 'price' => 10,
  311. 'is_shareable' => 1,
  312. 'number_of_downloads' => 100,
  313. 'link_type' => 'file',
  314. 'link_file_content' => [
  315. 'file_data' => base64_encode(file_get_contents($this->testImagePath)),
  316. 'name' => 'name/with|forbidden{characters',
  317. ],
  318. 'sample_type' => 'url',
  319. 'sample_url' => 'http://www.example.com/',
  320. ],
  321. ];
  322. $this->_webApiCall($this->createServiceInfo, $requestData);
  323. }
  324. /**
  325. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  326. * @expectedException \Exception
  327. * @expectedExceptionMessage Provided file name contains forbidden characters.
  328. */
  329. public function testCreateThrowsExceptionIfSampleFileNameContainsForbiddenCharacters()
  330. {
  331. $requestData = [
  332. 'isGlobalScopeContent' => false,
  333. 'sku' => 'downloadable-product',
  334. 'link' => [
  335. 'title' => 'Link Title',
  336. 'sort_order' => 1,
  337. 'price' => 10,
  338. 'is_shareable' => 1,
  339. 'number_of_downloads' => 100,
  340. 'link_type' => 'url',
  341. 'link_url' => 'http://www.example.com/',
  342. 'sample_type' => 'file',
  343. 'sample_file_content' => [
  344. 'file_data' => base64_encode(file_get_contents($this->testImagePath)),
  345. 'name' => 'name/with|forbidden{characters',
  346. ],
  347. ],
  348. ];
  349. $this->_webApiCall($this->createServiceInfo, $requestData);
  350. }
  351. /**
  352. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  353. * @expectedException \Exception
  354. * @expectedExceptionMessage Link URL must have valid format.
  355. */
  356. public function testCreateThrowsExceptionIfLinkUrlHasWrongFormat()
  357. {
  358. $requestData = [
  359. 'isGlobalScopeContent' => false,
  360. 'sku' => 'downloadable-product',
  361. 'link' => [
  362. 'title' => 'Link Title',
  363. 'sort_order' => 1,
  364. 'price' => 10,
  365. 'is_shareable' => 1,
  366. 'number_of_downloads' => 100,
  367. 'link_type' => 'url',
  368. 'link_url' => 'http://example<.>com/',
  369. 'sample_type' => 'url',
  370. 'sample_url' => 'http://www.example.com/',
  371. ],
  372. ];
  373. $this->_webApiCall($this->createServiceInfo, $requestData);
  374. }
  375. /**
  376. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  377. * @expectedException \Exception
  378. * @expectedExceptionMessage Sample URL must have valid format.
  379. */
  380. public function testCreateThrowsExceptionIfSampleUrlHasWrongFormat()
  381. {
  382. $requestData = [
  383. 'isGlobalScopeContent' => false,
  384. 'sku' => 'downloadable-product',
  385. 'link' => [
  386. 'title' => 'Link Title',
  387. 'sort_order' => 1,
  388. 'price' => 150,
  389. 'is_shareable' => 1,
  390. 'number_of_downloads' => 0,
  391. 'sample_type' => 'url',
  392. 'sample_url' => 'http://example<.>com/',
  393. 'link_type' => 'url',
  394. 'link_url' => 'http://example.com/',
  395. ],
  396. ];
  397. $this->_webApiCall($this->createServiceInfo, $requestData);
  398. }
  399. /**
  400. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  401. * @expectedException \Exception
  402. * @expectedExceptionMessage Link price must have numeric positive value.
  403. * @dataProvider getInvalidLinkPrice
  404. */
  405. public function testCreateThrowsExceptionIfLinkPriceIsInvalid($linkPrice)
  406. {
  407. $requestData = [
  408. 'isGlobalScopeContent' => false,
  409. 'sku' => 'downloadable-product',
  410. 'link' => [
  411. 'title' => 'Link Title',
  412. 'sort_order' => 1,
  413. 'price' => $linkPrice,
  414. 'is_shareable' => 1,
  415. 'number_of_downloads' => 0,
  416. 'sample_type' => 'url',
  417. 'sample_url' => 'http://example.com/',
  418. 'link_type' => 'url',
  419. 'link_url' => 'http://example.com/',
  420. ],
  421. ];
  422. $this->_webApiCall($this->createServiceInfo, $requestData);
  423. }
  424. /**
  425. * @return array
  426. */
  427. public function getInvalidLinkPrice()
  428. {
  429. return [
  430. [-1.5],
  431. ];
  432. }
  433. /**
  434. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  435. * @expectedException \Exception
  436. * @expectedExceptionMessage Sort order must be a positive integer.
  437. * @dataProvider getInvalidSortOrder
  438. */
  439. public function testCreateThrowsExceptionIfSortOrderIsInvalid($sortOrder)
  440. {
  441. $requestData = [
  442. 'isGlobalScopeContent' => false,
  443. 'sku' => 'downloadable-product',
  444. 'link' => [
  445. 'title' => 'Link Title',
  446. 'sort_order' => $sortOrder,
  447. 'price' => 10,
  448. 'is_shareable' => 0,
  449. 'number_of_downloads' => 0,
  450. 'sample_type' => 'url',
  451. 'sample_url' => 'http://example.com/',
  452. 'link_type' => 'url',
  453. 'link_url' => 'http://example.com/',
  454. ],
  455. ];
  456. $this->_webApiCall($this->createServiceInfo, $requestData);
  457. }
  458. /**
  459. * @return array
  460. */
  461. public function getInvalidSortOrder()
  462. {
  463. return [
  464. [-1],
  465. ];
  466. }
  467. /**
  468. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  469. * @expectedException \Exception
  470. * @expectedExceptionMessage Number of downloads must be a positive integer.
  471. * @dataProvider getInvalidNumberOfDownloads
  472. */
  473. public function testCreateThrowsExceptionIfNumberOfDownloadsIsInvalid($numberOfDownloads)
  474. {
  475. $requestData = [
  476. 'isGlobalScopeContent' => false,
  477. 'sku' => 'downloadable-product',
  478. 'link' => [
  479. 'title' => 'Link Title',
  480. 'sort_order' => 0,
  481. 'price' => 10,
  482. 'is_shareable' => 0,
  483. 'number_of_downloads' => $numberOfDownloads,
  484. 'sample_type' => 'url',
  485. 'sample_url' => 'http://example.com/',
  486. 'link_type' => 'url',
  487. 'link_url' => 'http://example.com/',
  488. ],
  489. ];
  490. $this->_webApiCall($this->createServiceInfo, $requestData);
  491. }
  492. /**
  493. * @return array
  494. */
  495. public function getInvalidNumberOfDownloads()
  496. {
  497. return [
  498. [-1],
  499. ];
  500. }
  501. /**
  502. * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
  503. * @expectedException \Exception
  504. * @expectedExceptionMessage The product needs to be the downloadable type. Verify the product and try again.
  505. */
  506. public function testCreateThrowsExceptionIfTargetProductTypeIsNotDownloadable()
  507. {
  508. $this->createServiceInfo['rest']['resourcePath'] = '/V1/products/simple/downloadable-links';
  509. $requestData = [
  510. 'isGlobalScopeContent' => false,
  511. 'sku' => 'simple',
  512. 'link' => [
  513. 'title' => 'Link Title',
  514. 'sort_order' => 50,
  515. 'price' => 200,
  516. 'is_shareable' => 0,
  517. 'number_of_downloads' => 10,
  518. 'sample_type' => 'url',
  519. 'sample_url' => 'http://example.com/',
  520. 'link_type' => 'url',
  521. 'link_url' => 'http://example.com/',
  522. ],
  523. ];
  524. $this->_webApiCall($this->createServiceInfo, $requestData);
  525. }
  526. /**
  527. * @expectedException \Exception
  528. * @expectedExceptionMessage The product that was requested doesn't exist. Verify the product and try again.
  529. */
  530. public function testCreateThrowsExceptionIfTargetProductDoesNotExist()
  531. {
  532. $this->createServiceInfo['rest']['resourcePath'] = '/V1/products/wrong-sku/downloadable-links';
  533. $requestData = [
  534. 'isGlobalScopeContent' => false,
  535. 'sku' => 'wrong-sku',
  536. 'link' => [
  537. 'title' => 'Link Title',
  538. 'sort_order' => 15,
  539. 'price' => 200,
  540. 'is_shareable' => 1,
  541. 'number_of_downloads' => 100,
  542. 'sample_type' => 'url',
  543. 'sample_url' => 'http://example.com/',
  544. 'link_type' => 'url',
  545. 'link_url' => 'http://example.com/',
  546. ],
  547. ];
  548. $this->_webApiCall($this->createServiceInfo, $requestData);
  549. }
  550. /**
  551. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  552. */
  553. public function testUpdate()
  554. {
  555. $linkId = $this->getTargetLink($this->getTargetProduct())->getId();
  556. $this->updateServiceInfo['rest']['resourcePath']
  557. = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
  558. $requestData = [
  559. 'isGlobalScopeContent' => false,
  560. 'sku' => 'downloadable-product',
  561. 'link' => [
  562. 'id' => $linkId,
  563. 'title' => 'Updated Title',
  564. 'sort_order' => 2,
  565. 'price' => 100.10,
  566. 'is_shareable' => 0,
  567. 'number_of_downloads' => 50,
  568. 'link_type' => 'url',
  569. 'sample_type' => 'url',
  570. ],
  571. ];
  572. $this->assertEquals($linkId, $this->_webApiCall($this->updateServiceInfo, $requestData));
  573. $link = $this->getTargetLink($this->getTargetProduct(), $linkId);
  574. $this->assertNotNull($link);
  575. $this->assertEquals($requestData['link']['title'], $link->getTitle());
  576. $this->assertEquals($requestData['link']['sort_order'], $link->getSortOrder());
  577. $this->assertEquals($requestData['link']['price'], $link->getPrice());
  578. $this->assertEquals($requestData['link']['is_shareable'], (int)$link->getIsShareable());
  579. $this->assertEquals($requestData['link']['number_of_downloads'], $link->getNumberOfDownloads());
  580. }
  581. /**
  582. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  583. */
  584. public function testUpdateSavesDataInGlobalScopeAndDoesNotAffectValuesStoredInStoreViewScope()
  585. {
  586. $originalLink = $this->getTargetLink($this->getTargetProduct());
  587. $linkId = $originalLink->getId();
  588. $this->updateServiceInfo['rest']['resourcePath']
  589. = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
  590. $requestData = [
  591. 'isGlobalScopeContent' => true,
  592. 'sku' => 'downloadable-product',
  593. 'link' => [
  594. 'id' => $linkId,
  595. 'title' => 'Updated Title',
  596. 'sort_order' => 2,
  597. 'price' => 100.10,
  598. 'is_shareable' => 0,
  599. 'number_of_downloads' => 50,
  600. 'link_type' => 'url',
  601. 'sample_type' => 'url',
  602. ],
  603. ];
  604. $this->assertEquals($linkId, $this->_webApiCall($this->updateServiceInfo, $requestData));
  605. $link = $this->getTargetLink($this->getTargetProduct(), $linkId);
  606. $globalScopeLink = $this->getTargetLink($this->getTargetProduct(true), $linkId);
  607. $this->assertNotNull($link);
  608. // Title and price were set on store view level in fixture so they must be the same
  609. $this->assertEquals($originalLink->getTitle(), $link->getTitle());
  610. $this->assertEquals($originalLink->getPrice(), $link->getPrice());
  611. $this->assertEquals($requestData['link']['title'], $globalScopeLink->getTitle());
  612. $this->assertEquals($requestData['link']['price'], $globalScopeLink->getPrice());
  613. $this->assertEquals($requestData['link']['sort_order'], $link->getSortOrder());
  614. $this->assertEquals($requestData['link']['is_shareable'], (int)$link->getIsShareable());
  615. $this->assertEquals($requestData['link']['number_of_downloads'], $link->getNumberOfDownloads());
  616. }
  617. /**
  618. * @expectedException \Exception
  619. * @expectedExceptionMessage The product that was requested doesn't exist. Verify the product and try again.
  620. */
  621. public function testUpdateThrowsExceptionIfTargetProductDoesNotExist()
  622. {
  623. $this->updateServiceInfo['rest']['resourcePath'] = '/V1/products/wrong-sku/downloadable-links/1';
  624. $requestData = [
  625. 'isGlobalScopeContent' => true,
  626. 'sku' => 'wrong-sku',
  627. 'link' => [
  628. 'id' => 1,
  629. 'title' => 'Updated Title',
  630. 'sort_order' => 2,
  631. 'price' => 100.10,
  632. 'is_shareable' => 0,
  633. 'number_of_downloads' => 50,
  634. 'link_type' => 'url',
  635. 'sample_type' => 'url',
  636. ],
  637. ];
  638. $this->_webApiCall($this->updateServiceInfo, $requestData);
  639. }
  640. /**
  641. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  642. * @expectedException \Exception
  643. * @expectedExceptionMessage No downloadable link with the provided ID was found. Verify the ID and try again.
  644. */
  645. public function testUpdateThrowsExceptionIfThereIsNoDownloadableLinkWithGivenId()
  646. {
  647. $linkId = 9999;
  648. $this->updateServiceInfo['rest']['resourcePath']
  649. = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
  650. $requestData = [
  651. 'isGlobalScopeContent' => true,
  652. 'sku' => 'downloadable-product',
  653. 'link' => [
  654. 'id' => $linkId,
  655. 'title' => 'Title',
  656. 'sort_order' => 2,
  657. 'price' => 100.10,
  658. 'is_shareable' => 0,
  659. 'number_of_downloads' => 50,
  660. 'link_type' => 'url',
  661. 'sample_type' => 'url',
  662. ],
  663. ];
  664. $this->_webApiCall($this->updateServiceInfo, $requestData);
  665. }
  666. /**
  667. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  668. * @expectedException \Exception
  669. * @expectedExceptionMessage Link price must have numeric positive value.
  670. * @dataProvider getInvalidLinkPrice
  671. */
  672. public function testUpdateThrowsExceptionIfLinkPriceIsInvalid($linkPrice)
  673. {
  674. $linkId = $this->getTargetLink($this->getTargetProduct())->getId();
  675. $this->updateServiceInfo['rest']['resourcePath']
  676. = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
  677. $requestData = [
  678. 'isGlobalScopeContent' => false,
  679. 'sku' => 'downloadable-product',
  680. 'link' => [
  681. 'id' => $linkId,
  682. 'title' => 'Updated Link Title',
  683. 'sort_order' => 2,
  684. 'price' => $linkPrice,
  685. 'is_shareable' => 0,
  686. 'number_of_downloads' => 50,
  687. 'link_type' => 'url',
  688. 'sample_type' => 'url',
  689. ],
  690. ];
  691. $this->_webApiCall($this->updateServiceInfo, $requestData);
  692. }
  693. /**
  694. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  695. * @expectedException \Exception
  696. * @expectedExceptionMessage Sort order must be a positive integer.
  697. * @dataProvider getInvalidSortOrder
  698. */
  699. public function testUpdateThrowsExceptionIfSortOrderIsInvalid($sortOrder)
  700. {
  701. $linkId = $this->getTargetLink($this->getTargetProduct())->getId();
  702. $this->updateServiceInfo['rest']['resourcePath']
  703. = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
  704. $requestData = [
  705. 'isGlobalScopeContent' => false,
  706. 'sku' => 'downloadable-product',
  707. 'link' => [
  708. 'id' => $linkId,
  709. 'title' => 'Updated Link Title',
  710. 'sort_order' => $sortOrder,
  711. 'price' => 100.50,
  712. 'is_shareable' => 0,
  713. 'number_of_downloads' => 50,
  714. 'link_type' => 'url',
  715. 'sample_type' => 'url',
  716. ],
  717. ];
  718. $this->_webApiCall($this->updateServiceInfo, $requestData);
  719. }
  720. /**
  721. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  722. * @expectedException \Exception
  723. * @expectedExceptionMessage Number of downloads must be a positive integer.
  724. * @dataProvider getInvalidNumberOfDownloads
  725. */
  726. public function testUpdateThrowsExceptionIfNumberOfDownloadsIsInvalid($numberOfDownloads)
  727. {
  728. $linkId = $this->getTargetLink($this->getTargetProduct())->getId();
  729. $this->updateServiceInfo['rest']['resourcePath']
  730. = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
  731. $requestData = [
  732. 'isGlobalScopeContent' => false,
  733. 'sku' => 'downloadable-product',
  734. 'link' => [
  735. 'id' => $linkId,
  736. 'title' => 'Updated Link Title',
  737. 'sort_order' => 200,
  738. 'price' => 100.50,
  739. 'is_shareable' => 0,
  740. 'number_of_downloads' => $numberOfDownloads,
  741. 'link_type' => 'url',
  742. 'sample_type' => 'url',
  743. ],
  744. ];
  745. $this->_webApiCall($this->updateServiceInfo, $requestData);
  746. }
  747. /**
  748. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php
  749. */
  750. public function testDelete()
  751. {
  752. $linkId = $this->getTargetLink($this->getTargetProduct())->getId();
  753. $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/{$linkId}";
  754. $requestData = [
  755. 'id' => $linkId,
  756. ];
  757. $this->assertTrue($this->_webApiCall($this->deleteServiceInfo, $requestData));
  758. $link = $this->getTargetLink($this->getTargetProduct(), $linkId);
  759. $this->assertNull($link);
  760. }
  761. /**
  762. * @expectedException \Exception
  763. * @expectedExceptionMessage No downloadable link with the provided ID was found. Verify the ID and try again.
  764. */
  765. public function testDeleteThrowsExceptionIfThereIsNoDownloadableLinkWithGivenId()
  766. {
  767. $linkId = 9999;
  768. $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/{$linkId}";
  769. $requestData = [
  770. 'id' => $linkId,
  771. ];
  772. $this->_webApiCall($this->deleteServiceInfo, $requestData);
  773. }
  774. /**
  775. * @dataProvider getListForAbsentProductProvider()
  776. */
  777. public function testGetListForAbsentProduct($urlTail, $method)
  778. {
  779. $sku = 'absent-product' . time();
  780. $serviceInfo = [
  781. 'rest' => [
  782. 'resourcePath' => '/V1/products/' . $sku . $urlTail,
  783. 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
  784. ],
  785. 'soap' => [
  786. 'service' => 'downloadableLinkRepositoryV1',
  787. 'serviceVersion' => 'V1',
  788. 'operation' => 'downloadableLinkRepositoryV1' . $method,
  789. ],
  790. ];
  791. $requestData = ['sku' => $sku];
  792. $expectedMessage = "The product that was requested doesn't exist. Verify the product and try again.";
  793. try {
  794. $this->_webApiCall($serviceInfo, $requestData);
  795. } catch (\SoapFault $e) {
  796. $this->assertEquals($expectedMessage, $e->getMessage());
  797. } catch (\Exception $e) {
  798. $this->assertContains($expectedMessage, $e->getMessage());
  799. }
  800. }
  801. /**
  802. * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
  803. * @dataProvider getListForAbsentProductProvider
  804. */
  805. public function testGetListForSimpleProduct($urlTail, $method)
  806. {
  807. $sku = 'simple';
  808. $serviceInfo = [
  809. 'rest' => [
  810. 'resourcePath' => '/V1/products/' . $sku . $urlTail,
  811. 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
  812. ],
  813. 'soap' => [
  814. 'service' => 'downloadableLinkRepositoryV1',
  815. 'serviceVersion' => 'V1',
  816. 'operation' => 'downloadableLinkRepositoryV1' . $method,
  817. ],
  818. ];
  819. $requestData = ['sku' => $sku];
  820. $list = $this->_webApiCall($serviceInfo, $requestData);
  821. $this->assertEmpty($list);
  822. }
  823. /**
  824. * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php
  825. * @dataProvider getListForAbsentProductProvider
  826. */
  827. public function testGetList($urlTail, $method, $expectations)
  828. {
  829. $sku = 'downloadable-product';
  830. $serviceInfo = [
  831. 'rest' => [
  832. 'resourcePath' => '/V1/products/' . $sku . $urlTail,
  833. 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
  834. ],
  835. 'soap' => [
  836. 'service' => 'downloadableLinkRepositoryV1',
  837. 'serviceVersion' => 'V1',
  838. 'operation' => 'downloadableLinkRepositoryV1' . $method,
  839. ],
  840. ];
  841. $requestData = ['sku' => $sku];
  842. $list = $this->_webApiCall($serviceInfo, $requestData);
  843. $this->assertEquals(1, count($list));
  844. $link = reset($list);
  845. foreach ($expectations['fields'] as $index => $value) {
  846. $this->assertEquals($value, $link[$index]);
  847. }
  848. $this->assertContains('jellyfish_1_3.jpg', $link['sample_file']);
  849. }
  850. public function getListForAbsentProductProvider()
  851. {
  852. $linkExpectation = [
  853. 'fields' => [
  854. 'is_shareable' => 2,
  855. 'price' => 15,
  856. 'number_of_downloads' => 15,
  857. 'sample_type' => 'file',
  858. 'link_file' => '/j/e/jellyfish_2_4.jpg',
  859. 'link_type' => 'file'
  860. ]
  861. ];
  862. return [
  863. 'links' => [
  864. '/downloadable-links',
  865. 'GetList',
  866. $linkExpectation,
  867. ],
  868. ];
  869. }
  870. }