ValidationTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. declare(strict_types=1);
  7. namespace Magento\InventoryApi\Test\Api\SourceItemsSave;
  8. use Magento\Framework\Webapi\Exception;
  9. use Magento\Framework\Webapi\Rest\Request;
  10. use Magento\InventoryApi\Api\Data\SourceItemInterface;
  11. use Magento\TestFramework\TestCase\WebapiAbstract;
  12. class ValidationTest extends WebapiAbstract
  13. {
  14. /**#@+
  15. * Service constants
  16. */
  17. const RESOURCE_PATH = '/V1/inventory/source-items';
  18. const SERVICE_NAME = 'inventoryApiSourceItemsSaveV1';
  19. /**#@-*/
  20. /**
  21. * @var array
  22. */
  23. private $validData = [
  24. SourceItemInterface::SKU => 'SKU-1',
  25. SourceItemInterface::QUANTITY => 1.5,
  26. SourceItemInterface::SOURCE_CODE => 'eu-1',
  27. SourceItemInterface::STATUS => SourceItemInterface::STATUS_IN_STOCK,
  28. ];
  29. /**
  30. * @param string $field
  31. * @param array $expectedErrorData
  32. * @throws \Exception
  33. * @magentoApiDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/products.php
  34. * @magentoApiDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/sources.php
  35. * @dataProvider dataProviderRequiredFields
  36. */
  37. public function testCreateWithMissedRequiredFields(string $field, array $expectedErrorData)
  38. {
  39. $data = $this->validData;
  40. unset($data[$field]);
  41. $serviceInfo = [
  42. 'rest' => [
  43. 'resourcePath' => self::RESOURCE_PATH,
  44. 'httpMethod' => Request::HTTP_METHOD_POST,
  45. ],
  46. 'soap' => [
  47. 'service' => self::SERVICE_NAME,
  48. 'operation' => self::SERVICE_NAME . 'Execute',
  49. ],
  50. ];
  51. $this->webApiCall($serviceInfo, [$data], $expectedErrorData);
  52. }
  53. /**
  54. * @return array
  55. */
  56. public function dataProviderRequiredFields(): array
  57. {
  58. return [
  59. 'without_' . SourceItemInterface::SKU => [
  60. SourceItemInterface::SKU,
  61. [
  62. 'message' => 'Validation Failed',
  63. 'errors' => [
  64. [
  65. 'message' => '"%field" can not be empty.',
  66. 'parameters' => [
  67. 'field' => SourceItemInterface::SKU,
  68. ],
  69. ],
  70. ],
  71. ],
  72. ],
  73. 'without_' . SourceItemInterface::SOURCE_CODE => [
  74. SourceItemInterface::SOURCE_CODE,
  75. [
  76. 'message' => 'Validation Failed',
  77. 'errors' => [
  78. [
  79. 'message' => '"%field" can not be empty.',
  80. 'parameters' => [
  81. 'field' => SourceItemInterface::SOURCE_CODE,
  82. ],
  83. ],
  84. ],
  85. ],
  86. ],
  87. 'without_' . SourceItemInterface::QUANTITY => [
  88. SourceItemInterface::QUANTITY,
  89. [
  90. 'message' => 'Validation Failed',
  91. 'errors' => [
  92. [
  93. 'message' => '"%field" should be numeric.',
  94. 'parameters' => [
  95. 'field' => SourceItemInterface::QUANTITY,
  96. ],
  97. ],
  98. ],
  99. ],
  100. ],
  101. 'without_' . SourceItemInterface::STATUS => [
  102. SourceItemInterface::STATUS,
  103. [
  104. 'message' => 'Validation Failed',
  105. 'errors' => [
  106. [
  107. 'message' => '"%field" should be numeric.',
  108. 'parameters' => [
  109. 'field' => SourceItemInterface::STATUS,
  110. ],
  111. ],
  112. ],
  113. ],
  114. ],
  115. ];
  116. }
  117. /**
  118. * @param string $field
  119. * @param string|null $value
  120. * @param array $expectedErrorData
  121. * @magentoApiDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/products.php
  122. * @magentoApiDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/sources.php
  123. * @dataProvider failedValidationDataProvider
  124. */
  125. public function testFailedValidationOnCreate(string $field, $value, array $expectedErrorData)
  126. {
  127. $data = $this->validData;
  128. $data[$field] = $value;
  129. $serviceInfo = [
  130. 'rest' => [
  131. 'resourcePath' => self::RESOURCE_PATH,
  132. 'httpMethod' => Request::HTTP_METHOD_POST,
  133. ],
  134. 'soap' => [
  135. 'service' => self::SERVICE_NAME,
  136. 'operation' => self::SERVICE_NAME . 'Execute',
  137. ],
  138. ];
  139. $this->webApiCall($serviceInfo, [$data], $expectedErrorData);
  140. }
  141. /**
  142. * @return array
  143. * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
  144. */
  145. public function failedValidationDataProvider(): array
  146. {
  147. if (TESTS_WEB_API_ADAPTER === self::ADAPTER_SOAP) {
  148. $nonExistedSourceCodeError = [
  149. 'message' => 'Could not save Source Item',
  150. 'errors' => [],
  151. ];
  152. } else {
  153. $nonExistedSourceCodeError = ['message' => 'Could not save Source Item'];
  154. }
  155. return [
  156. 'null_' . SourceItemInterface::SKU => [
  157. SourceItemInterface::SKU,
  158. null,
  159. [
  160. 'message' => 'Validation Failed',
  161. 'errors' => [
  162. [
  163. 'message' => '"%field" can not be empty.',
  164. 'parameters' => [
  165. 'field' => SourceItemInterface::SKU,
  166. ],
  167. ],
  168. ],
  169. ],
  170. ],
  171. 'empty_' . SourceItemInterface::SKU => [
  172. SourceItemInterface::SKU,
  173. '',
  174. [
  175. 'message' => 'Validation Failed',
  176. 'errors' => [
  177. [
  178. 'message' => '"%field" can not be empty.',
  179. 'parameters' => [
  180. 'field' => SourceItemInterface::SKU,
  181. ],
  182. ],
  183. ],
  184. ],
  185. ],
  186. 'whitespaces_' . SourceItemInterface::SKU => [
  187. SourceItemInterface::SKU,
  188. ' ',
  189. [
  190. 'message' => 'Validation Failed',
  191. 'errors' => [
  192. [
  193. 'message' => '"%field" can not be empty.',
  194. 'parameters' => [
  195. 'field' => SourceItemInterface::SKU,
  196. ],
  197. ],
  198. ],
  199. ],
  200. ],
  201. 'unknown_' . SourceItemInterface::STATUS => [
  202. SourceItemInterface::STATUS,
  203. '999999',
  204. [
  205. 'message' => 'Validation Failed',
  206. 'errors' => [
  207. [
  208. 'message' => '"%field" should a known status.',
  209. 'parameters' => [
  210. 'field' => SourceItemInterface::STATUS,
  211. ],
  212. ],
  213. ],
  214. ],
  215. ],
  216. 'null_' . SourceItemInterface::QUANTITY => [
  217. SourceItemInterface::QUANTITY,
  218. null,
  219. [
  220. 'message' => 'Validation Failed',
  221. 'errors' => [
  222. [
  223. 'message' => '"%field" should be numeric.',
  224. 'parameters' => [
  225. 'field' => SourceItemInterface::QUANTITY,
  226. ],
  227. ],
  228. ],
  229. ],
  230. ],
  231. 'null_' . SourceItemInterface::SOURCE_CODE => [
  232. SourceItemInterface::SOURCE_CODE,
  233. null,
  234. [
  235. 'message' => 'Validation Failed',
  236. 'errors' => [
  237. [
  238. 'message' => '"%field" can not be empty.',
  239. 'parameters' => [
  240. 'field' => SourceItemInterface::SOURCE_CODE,
  241. ],
  242. ],
  243. ],
  244. ],
  245. ],
  246. 'empty_' . SourceItemInterface::SOURCE_CODE => [
  247. SourceItemInterface::SOURCE_CODE,
  248. '',
  249. [
  250. 'message' => 'Validation Failed',
  251. 'errors' => [
  252. [
  253. 'message' => '"%field" can not be empty.',
  254. 'parameters' => [
  255. 'field' => SourceItemInterface::SOURCE_CODE,
  256. ],
  257. ],
  258. ],
  259. ],
  260. ],
  261. 'whitespaces_' . SourceItemInterface::SOURCE_CODE => [
  262. SourceItemInterface::SOURCE_CODE,
  263. ' ',
  264. [
  265. 'message' => 'Validation Failed',
  266. 'errors' => [
  267. [
  268. 'message' => '"%field" can not be empty.',
  269. 'parameters' => [
  270. 'field' => SourceItemInterface::SOURCE_CODE,
  271. ],
  272. ],
  273. ],
  274. ],
  275. ],
  276. 'not_exists_' . SourceItemInterface::SOURCE_CODE => [
  277. SourceItemInterface::SOURCE_CODE,
  278. 'not-existed-source-code',
  279. $nonExistedSourceCodeError,
  280. ],
  281. 'with_whitespaces_' . SourceItemInterface::SOURCE_CODE => [
  282. SourceItemInterface::SOURCE_CODE,
  283. 'source code',
  284. [
  285. 'message' => 'Validation Failed',
  286. 'errors' => [
  287. [
  288. 'message' => '"%field" can not contain whitespaces.',
  289. 'parameters' => [
  290. 'field' => SourceItemInterface::SOURCE_CODE,
  291. ],
  292. ],
  293. ],
  294. ],
  295. ],
  296. ];
  297. }
  298. /**
  299. * @param string $field
  300. * @param string|null $value
  301. * @param array $expectedErrorData
  302. * @magentoApiDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/products.php
  303. * @magentoApiDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/sources.php
  304. * @dataProvider failedValidationRelatedOnlyForRestDataProvider
  305. */
  306. public function testFailedValidationOnCreateRelatedOnlyForRest(string $field, $value, array $expectedErrorData)
  307. {
  308. if (TESTS_WEB_API_ADAPTER === self::ADAPTER_SOAP) {
  309. $this->markTestSkipped(
  310. 'Test works only for REST adapter because in SOAP one parameters would be converted'
  311. . ' into zero (zero is allowed input value)'
  312. );
  313. }
  314. $data = $this->validData;
  315. $data[$field] = $value;
  316. $serviceInfo = [
  317. 'rest' => [
  318. 'resourcePath' => self::RESOURCE_PATH,
  319. 'httpMethod' => Request::HTTP_METHOD_POST,
  320. ],
  321. 'soap' => [
  322. 'service' => self::SERVICE_NAME,
  323. 'operation' => self::SERVICE_NAME . 'Execute',
  324. ],
  325. ];
  326. $this->webApiCall($serviceInfo, [$data], $expectedErrorData);
  327. }
  328. /**
  329. * @return array
  330. */
  331. public function failedValidationRelatedOnlyForRestDataProvider(): array
  332. {
  333. return [
  334. 'empty_' . SourceItemInterface::QUANTITY => [
  335. SourceItemInterface::QUANTITY,
  336. '',
  337. [
  338. 'message' => 'Error occurred during "' . SourceItemInterface::QUANTITY
  339. . '" processing. The "" value\'s type is invalid. The "float" type was expected. '
  340. . 'Verify and try again.',
  341. ],
  342. ],
  343. 'string_' . SourceItemInterface::QUANTITY => [
  344. SourceItemInterface::QUANTITY,
  345. 'test',
  346. [
  347. 'message' => 'Error occurred during "' . SourceItemInterface::QUANTITY
  348. . '" processing. The "test" value\'s type is invalid. The "float" type was expected. '
  349. . 'Verify and try again.',
  350. ],
  351. ],
  352. 'array_' . SourceItemInterface::SOURCE_CODE => [
  353. SourceItemInterface::SOURCE_CODE,
  354. [],
  355. [
  356. 'message' => 'Error occurred during "' . SourceItemInterface::SOURCE_CODE
  357. . '" processing. The "array" value\'s type is invalid. The "string" type was expected. '
  358. . 'Verify and try again.',
  359. ],
  360. ],
  361. ];
  362. }
  363. /**
  364. * @magentoApiDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/products.php
  365. * @magentoApiDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/sources.php
  366. */
  367. public function testCreateWithEmptyData()
  368. {
  369. $sourceItems = [];
  370. if (TESTS_WEB_API_ADAPTER === self::ADAPTER_SOAP) {
  371. $expectedErrorData = [
  372. 'message' => 'Input data is empty',
  373. 'errors' => [],
  374. ];
  375. } else {
  376. $expectedErrorData = ['message' => 'Input data is empty'];
  377. }
  378. $serviceInfo = [
  379. 'rest' => [
  380. 'resourcePath' => self::RESOURCE_PATH,
  381. 'httpMethod' => Request::HTTP_METHOD_POST,
  382. ],
  383. 'soap' => [
  384. 'service' => self::SERVICE_NAME,
  385. 'operation' => self::SERVICE_NAME . 'Execute',
  386. ],
  387. ];
  388. $this->webApiCall($serviceInfo, $sourceItems, $expectedErrorData);
  389. }
  390. /**
  391. * @param array $serviceInfo
  392. * @param array $sourceItems
  393. * @param array $expectedErrorData
  394. * @return void
  395. * @throws \Exception
  396. */
  397. private function webApiCall(array $serviceInfo, array $sourceItems, array $expectedErrorData)
  398. {
  399. try {
  400. $this->_webApiCall($serviceInfo, ['sourceItems' => $sourceItems]);
  401. $this->fail('Expected throwing exception');
  402. } catch (\Exception $exception) {
  403. if (TESTS_WEB_API_ADAPTER === self::ADAPTER_REST) {
  404. self::assertEquals($expectedErrorData, $this->processRestExceptionResult($exception));
  405. self::assertEquals(Exception::HTTP_BAD_REQUEST, $exception->getCode());
  406. } elseif (TESTS_WEB_API_ADAPTER === self::ADAPTER_SOAP) {
  407. $this->assertInstanceOf('SoapFault', $exception);
  408. $expectedWrappedErrors = [];
  409. foreach ($expectedErrorData['errors'] as $error) {
  410. // @see \Magento\TestFramework\TestCase\WebapiAbstract::getActualWrappedErrors()
  411. $expectedWrappedErrors[] = [
  412. 'message' => $error['message'],
  413. 'params' => $error['parameters'],
  414. ];
  415. }
  416. $this->checkSoapFault(
  417. $exception,
  418. $expectedErrorData['message'],
  419. 'env:Sender',
  420. [],
  421. $expectedWrappedErrors
  422. );
  423. } else {
  424. throw $exception;
  425. }
  426. }
  427. }
  428. }