diff --git a/composer.json b/composer.json index b30cc8775b2c0c5ae99184c4842eaf789cab2ab5..e1e90a8395badb514578521b64a55f3d8cd938ac 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,8 @@ "ext-curl": "*", "ext-iconv": "*", "sjparkinson/static-review": "~4.1", - "fabpot/php-cs-fixer": "~1.2" + "fabpot/php-cs-fixer": "~1.2", + "lusitanian/oauth": "~0.3" }, "replace": { "magento/module-admin-notification": "self.version", diff --git a/composer.lock b/composer.lock index d2fc6da7fe7b83c465d55c071e449341f86e4cb2..990692a84d28d499a7b9a0b3c3e06b19eabecc7e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "d3a510fb8a6b17c084148509d02478d4", + "hash": "0c7573953aece5e5227468ebff4539da", "packages": [ { "name": "composer/composer", @@ -1923,6 +1923,68 @@ ], "time": "2014-11-08 02:33:31" }, + { + "name": "lusitanian/oauth", + "version": "v0.3.5", + "source": { + "type": "git", + "url": "https://github.com/Lusitanian/PHPoAuthLib.git", + "reference": "ac5a1cd5a4519143728dce2213936eea302edf8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/ac5a1cd5a4519143728dce2213936eea302edf8a", + "reference": "ac5a1cd5a4519143728dce2213936eea302edf8a", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*", + "predis/predis": "0.8.*@dev", + "symfony/http-foundation": "~2.1" + }, + "suggest": { + "ext-openssl": "Allows for usage of secure connections with the stream-based HTTP client.", + "predis/predis": "Allows using the Redis storage backend.", + "symfony/http-foundation": "Allows using the Symfony Session storage backend." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1-dev" + } + }, + "autoload": { + "psr-0": { + "OAuth": "src", + "OAuth\\Unit": "tests" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "David Desberg", + "email": "david@daviddesberg.com" + }, + { + "name": "Pieter Hordijk", + "email": "info@pieterhordijk.com" + } + ], + "description": "PHP 5.3+ oAuth 1/2 Library", + "keywords": [ + "Authentication", + "authorization", + "oauth", + "security" + ], + "time": "2014-09-05 15:19:58" + }, { "name": "pdepend/pdepend", "version": "2.0.4", @@ -2001,16 +2063,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "2.0.13", + "version": "2.0.14", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "0e7d2eec5554f869fa7a4ec2d21e4b37af943ea5" + "reference": "ca158276c1200cc27f5409a5e338486bc0b4fc94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e7d2eec5554f869fa7a4ec2d21e4b37af943ea5", - "reference": "0e7d2eec5554f869fa7a4ec2d21e4b37af943ea5", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca158276c1200cc27f5409a5e338486bc0b4fc94", + "reference": "ca158276c1200cc27f5409a5e338486bc0b4fc94", "shasum": "" }, "require": { @@ -2062,7 +2124,7 @@ "testing", "xunit" ], - "time": "2014-12-03 06:41:44" + "time": "2014-12-26 13:28:33" }, { "name": "phpunit/php-file-iterator", diff --git a/dev/tests/api-functional/.gitignore b/dev/tests/api-functional/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..77d5f53390c6c26ad0b8b00ad8dd577abedf89e8 --- /dev/null +++ b/dev/tests/api-functional/.gitignore @@ -0,0 +1,3 @@ +/*.xml +/var/ +/config/*.php diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester.php b/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester.php new file mode 100644 index 0000000000000000000000000000000000000000..e6bc716ff5529448ef5542c12cbe4ff0c93f05a8 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester.php @@ -0,0 +1,69 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Controller; + +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; +use Magento\Framework\Stdlib\Cookie\PhpCookieManager; + +/** + * Controller for testing the CookieManager. + * + */ +class CookieTester extends \Magento\Framework\App\Action\Action +{ + /** @var PhpCookieManager */ + protected $cookieManager; + + /** @var CookieMetadataFactory */ + protected $cookieMetadataFactory; + + /** + * @param \Magento\Framework\App\Action\Context $context + * @param PhpCookieManager $cookieManager + * @param CookieMetadataFactory $cookieMetadataFactory + */ + public function __construct( + \Magento\Framework\App\Action\Context $context, + PhpCookieManager $cookieManager, + CookieMetadataFactory $cookieMetadataFactory + ) { + $this->cookieManager = $cookieManager; + $this->cookieMetadataFacory = $cookieMetadataFactory; + parent::__construct($context); + } + + /** + * Retrieve cookie metadata factory + */ + protected function getCookieMetadataFactory() + { + return $this->cookieMetadataFacory; + } + + /** + * Retrieve cookie metadata factory + */ + protected function getCookieManager() + { + return $this->cookieManager; + } + + /** + * Dispatch request + * + * @param RequestInterface $request + * @return \Magento\Framework\App\ResponseInterface + */ + public function dispatch(RequestInterface $request) + { + if (!$this->getRequest()->isDispatched()) { + parent::dispatch($request); + } + + $result = parent::dispatch($request); + return $result; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester/DeleteCookie.php b/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester/DeleteCookie.php new file mode 100644 index 0000000000000000000000000000000000000000..f7ef99d6b520524f9a088367d6c46ab3df9e47b3 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester/DeleteCookie.php @@ -0,0 +1,21 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Controller\CookieTester; + +/** + * Controller to test deletion of a cookie + */ +class DeleteCookie extends \Magento\TestModule1\Controller\CookieTester +{ + /** + * + * @return void + */ + public function execute() + { + $cookieName = $this->getRequest()->getParam('cookie_name'); + $this->getCookieManager()->deleteCookie($cookieName); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester/SetPublicCookie.php b/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester/SetPublicCookie.php new file mode 100644 index 0000000000000000000000000000000000000000..c72395edf16c766a7db3a8306c389ea704072932 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester/SetPublicCookie.php @@ -0,0 +1,49 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Controller\CookieTester; + +/** + */ +class SetPublicCookie extends \Magento\TestModule1\Controller\CookieTester +{ + /** + * Sets a public cookie with data from url parameters + * + * @return void + */ + public function execute() + { + $publicCookieMetadata = $this->getCookieMetadataFactory()->createPublicCookieMetadata(); + + $cookieDomain = $this->getRequest()->getParam('cookie_domain'); + if ($cookieDomain !== null) { + $publicCookieMetadata->setDomain($cookieDomain); + } + + $cookiePath = $this->getRequest()->getParam('cookie_path'); + if ($cookiePath !== null) { + $publicCookieMetadata->setPath($cookiePath); + } + + $cookieDuration = $this->getRequest()->getParam('cookie_duration'); + if ($cookieDuration !== null) { + $publicCookieMetadata->setDuration($cookieDuration); + } + + $httpOnly = $this->getRequest()->getParam('cookie_httponly'); + if ($httpOnly !== null) { + $publicCookieMetadata->setHttpOnly($httpOnly); + } + + $secure = $this->getRequest()->getParam('cookie_secure'); + if ($secure !== null) { + $publicCookieMetadata->setSecure($secure); + } + + $cookieName = $this->getRequest()->getParam('cookie_name'); + $cookieValue = $this->getRequest()->getParam('cookie_value'); + $this->getCookieManager()->setPublicCookie($cookieName, $cookieValue, $publicCookieMetadata); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester/SetSensitiveCookie.php b/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester/SetSensitiveCookie.php new file mode 100644 index 0000000000000000000000000000000000000000..3cb0d47fae43535e7fdda6799e0a7aa4d037eb6f --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester/SetSensitiveCookie.php @@ -0,0 +1,33 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Controller\CookieTester; + +/** + */ +class SetSensitiveCookie extends \Magento\TestModule1\Controller\CookieTester +{ + /** + * Sets a sensitive cookie with data from url parameters + * + * @return void + */ + public function execute() + { + $sensitiveCookieMetadata = $this->getCookieMetadataFactory()->createSensitiveCookieMetadata(); + + $cookieDomain = $this->getRequest()->getParam('cookie_domain'); + if ($cookieDomain !== null) { + $sensitiveCookieMetadata->setDomain($cookieDomain); + } + $cookiePath = $this->getRequest()->getParam('cookie_domain'); + if ($cookiePath !== null) { + $sensitiveCookieMetadata->setPath($cookiePath); + } + + $cookieName = $this->getRequest()->getParam('cookie_name'); + $cookieValue = $this->getRequest()->getParam('cookie_value'); + $this->getCookieManager()->setSensitiveCookie($cookieName, $cookieValue, $sensitiveCookieMetadata); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/AllSoapAndRest.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/AllSoapAndRest.php new file mode 100644 index 0000000000000000000000000000000000000000..025d819004d0658f650faf8b0a1bcad6fbff4eb7 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/AllSoapAndRest.php @@ -0,0 +1,108 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V1; + +use Magento\TestModule1\Service\V1\Entity\CustomAttributeDataObjectBuilder; +use Magento\TestModule1\Service\V1\Entity\Item; +use Magento\TestModule1\Service\V1\Entity\ItemBuilder; + +class AllSoapAndRest implements \Magento\TestModule1\Service\V1\AllSoapAndRestInterface +{ + /** + * @var ItemBuilder + */ + protected $itemBuilder; + + /** + * @var CustomAttributeDataObjectBuilder + */ + protected $customAttributeDataObjectBuilder; + + /** + * @param ItemBuilder $itemBuilder + * @param CustomAttributeDataObjectBuilder $customAttributeNestedDataObjectBuilder + */ + public function __construct( + ItemBuilder $itemBuilder, + CustomAttributeDataObjectBuilder $customAttributeNestedDataObjectBuilder + ) { + $this->itemBuilder = $itemBuilder; + $this->customAttributeDataObjectBuilder = $customAttributeNestedDataObjectBuilder; + } + + /** + * {@inheritdoc} + */ + public function item($itemId) + { + return $this->itemBuilder->setItemId($itemId)->setName('testProduct1')->create(); + } + + /** + * {@inheritdoc} + */ + public function items() + { + $result1 = $this->itemBuilder->setItemId(1)->setName('testProduct1')->create(); + $result2 = $this->itemBuilder->setItemId(2)->setName('testProduct2')->create(); + + return [$result1, $result2]; + } + + /** + * {@inheritdoc} + */ + public function create($name) + { + return $this->itemBuilder->setItemId(rand())->setName($name)->create(); + } + + /** + * {@inheritdoc} + */ + public function update(Item $entityItem) + { + return $this->itemBuilder->setItemId($entityItem->getItemId()) + ->setName('Updated' . $entityItem->getName()) + ->create(); + } + + public function testOptionalParam($name = null) + { + if (is_null($name)) { + return $this->itemBuilder->setItemId(3)->setName('No Name')->create(); + } else { + return $this->itemBuilder->setItemId(3)->setName($name)->create(); + } + } + + /** + * {@inheritdoc} + */ + public function itemAnyType(Item $item) + { + return $item; + } + + /** + * {@inheritdoc} + */ + public function getPreconfiguredItem() + { + $customAttributeDataObject = $this->customAttributeDataObjectBuilder + ->setName('nameValue') + ->setCustomAttribute('custom_attribute_int', 1) + ->create(); + + $item = $this->itemBuilder + ->setItemId(1) + ->setName('testProductAnyType') + ->setCustomAttribute('custom_attribute_data_object', $customAttributeDataObject) + ->setCustomAttribute('custom_attribute_string', 'someStringValue') + ->create(); + + return $item; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/AllSoapAndRestInterface.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/AllSoapAndRestInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..d43d1553561de2d74d9fd4fcf6a271b124f02a1d --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/AllSoapAndRestInterface.php @@ -0,0 +1,50 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V1; + +use Magento\TestModule1\Service\V1\Entity\Item; + +interface AllSoapAndRestInterface +{ + /** + * @param int $itemId + * @return \Magento\TestModule1\Service\V1\Entity\Item + */ + public function item($itemId); + + /** + * @param string $name + * @return \Magento\TestModule1\Service\V1\Entity\Item + */ + public function create($name); + + /** + * @param \Magento\TestModule1\Service\V1\Entity\Item $entityItem + * @return \Magento\TestModule1\Service\V1\Entity\Item + */ + public function update(Item $entityItem); + + /** + * @return \Magento\TestModule1\Service\V1\Entity\Item[] + */ + public function items(); + + /** + * @param string $name + * @return \Magento\TestModule1\Service\V1\Entity\Item + */ + public function testOptionalParam($name = null); + + /** + * @param \Magento\TestModule1\Service\V1\Entity\Item $entityItem + * @return \Magento\TestModule1\Service\V1\Entity\Item + */ + public function itemAnyType(Item $entityItem); + + /** + * @return \Magento\TestModule1\Service\V1\Entity\Item + */ + public function getPreconfiguredItem(); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeDataObject.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeDataObject.php new file mode 100644 index 0000000000000000000000000000000000000000..b3cf77d44933f6d2811611705205d48117a61b94 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeDataObject.php @@ -0,0 +1,16 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V1\Entity; + +class CustomAttributeDataObject extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * @return string + */ + public function getName() + { + return $this->_data['name']; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeDataObjectBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeDataObjectBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..e128de99359f774aa1508e4b08252b1f179c678d --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeDataObjectBuilder.php @@ -0,0 +1,20 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestModule1\Service\V1\Entity; + +class CustomAttributeDataObjectBuilder extends \Magento\Framework\Api\ExtensibleObjectBuilder +{ + /** + * @param string $name + * + * @return $this + */ + public function setName($name) + { + $this->data['name'] = $name; + return $this; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeNestedDataObject.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeNestedDataObject.php new file mode 100644 index 0000000000000000000000000000000000000000..6b439713fafdcecd9bcb3e1fe3073b9381cda4fb --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeNestedDataObject.php @@ -0,0 +1,16 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V1\Entity; + +class CustomAttributeNestedDataObject extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * @return string + */ + public function getName() + { + return $this->_data['name']; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeNestedDataObjectBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeNestedDataObjectBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..4bf501ac727da54c801558326e1aa21254292b02 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/CustomAttributeNestedDataObjectBuilder.php @@ -0,0 +1,20 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestModule1\Service\V1\Entity; + +class CustomAttributeNestedDataObjectBuilder extends \Magento\Framework\Api\ExtensibleObjectBuilder +{ + /** + * @param string $name + * + * @return $this + */ + public function setName($name) + { + $this->data['name'] = $name; + return $this; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/Eav/AttributeMetadata.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/Eav/AttributeMetadata.php new file mode 100644 index 0000000000000000000000000000000000000000..134623a864f693e9d8a755b46808602970bd066c --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/Eav/AttributeMetadata.php @@ -0,0 +1,42 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V1\Entity\Eav; + +use Magento\Framework\Api\AbstractExtensibleObject; +use Magento\Framework\Api\MetadataObjectInterface; + +/** + * Class AttributeMetadata + */ +class AttributeMetadata extends AbstractExtensibleObject implements MetadataObjectInterface +{ + /**#@+ + * Constants used as keys into $_data + */ + const ATTRIBUTE_ID = 'attribute_id'; + + const ATTRIBUTE_CODE = 'attribute_code'; + /**#@-*/ + + /** + * Retrieve id of the attribute. + * + * @return string|null + */ + public function getAttributeId() + { + return $this->_get(self::ATTRIBUTE_ID); + } + + /** + * Retrieve code of the attribute. + * + * @return string|null + */ + public function getAttributeCode() + { + return $this->_get(self::ATTRIBUTE_CODE); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/Eav/AttributeMetadataBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/Eav/AttributeMetadataBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..b96ef2b4f5da204af0511149eea26edd36d4ec4f --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/Eav/AttributeMetadataBuilder.php @@ -0,0 +1,36 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V1\Entity\Eav; + +use Magento\Framework\Api\AttributeMetadataBuilderInterface; +use Magento\Framework\Api\ExtensibleObjectBuilder; + +/** + * Class AttributeMetadataBuilder + */ +class AttributeMetadataBuilder extends ExtensibleObjectBuilder implements AttributeMetadataBuilderInterface +{ + /** + * Set attribute id + * + * @param int $attributeId + * @return $this + */ + public function setAttributeId($attributeId) + { + return $this->_set(AttributeMetadata::ATTRIBUTE_ID, $attributeId); + } + + /** + * Set attribute code + * + * @param string $attributeCode + * @return $this + */ + public function setAttributeCode($attributeCode) + { + return $this->_set(AttributeMetadata::ATTRIBUTE_CODE, $attributeCode); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/Item.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/Item.php new file mode 100644 index 0000000000000000000000000000000000000000..d307ac8f6a8d1fe71a808b529e913df7d4f74cfe --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/Item.php @@ -0,0 +1,24 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V1\Entity; + +class Item extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * @return int + */ + public function getItemId() + { + return $this->_data['item_id']; + } + + /** + * @return string + */ + public function getName() + { + return $this->_data['name']; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/ItemBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/ItemBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..c13fd4b8e898074d2dade57b556e7e668ad92a03 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V1/Entity/ItemBuilder.php @@ -0,0 +1,51 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V1\Entity; + +class ItemBuilder extends \Magento\Framework\Api\ExtensibleObjectBuilder +{ + /**#@+ + * Custom attribute code constants + */ + const CUSTOM_ATTRIBUTE_1 = 'custom_attribute1'; + const CUSTOM_ATTRIBUTE_2 = 'custom_attribute2'; + const CUSTOM_ATTRIBUTE_3 = 'custom_attribute3'; + /**#@-*/ + + /** + * @param int $itemId + * + * @return \Magento\TestModule1\Service\V1\Entity\ItemBuilder + */ + public function setItemId($itemId) + { + $this->data['item_id'] = $itemId; + return $this; + } + + /** + * @param string $name + * + * @return \Magento\TestModule1\Service\V1\Entity\ItemBuilder + */ + public function setName($name) + { + $this->data['name'] = $name; + return $this; + } + + /** + * Template method used to configure the attribute codes for the custom attributes + * + * @return string[] + */ + public function getCustomAttributesCodes() + { + return array_merge( + parent::getCustomAttributesCodes(), + [self::CUSTOM_ATTRIBUTE_1, self::CUSTOM_ATTRIBUTE_2, self::CUSTOM_ATTRIBUTE_3] + ); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/AllSoapAndRest.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/AllSoapAndRest.php new file mode 100644 index 0000000000000000000000000000000000000000..ef17f0c5749bef4262d3e9c1f5acb09445f69c0b --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/AllSoapAndRest.php @@ -0,0 +1,85 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V2; + +use Magento\TestModule1\Service\V2\Entity\Item; +use Magento\TestModule1\Service\V2\Entity\ItemBuilder; + +class AllSoapAndRest implements \Magento\TestModule1\Service\V2\AllSoapAndRestInterface +{ + /** + * @var ItemBuilder + */ + protected $itemBuilder; + + /** + * @param ItemBuilder $itemBuilder + */ + public function __construct(ItemBuilder $itemBuilder) + { + $this->itemBuilder = $itemBuilder; + } + + /** + * {@inheritdoc} + */ + public function item($id) + { + return $this->itemBuilder->setId($id)->setName('testProduct1')->setPrice('1')->create(); + } + + /** + * {@inheritdoc} + */ + public function items($filters = [], $sortOrder = 'ASC') + { + $result = []; + $firstItem = $this->itemBuilder->setId(1)->setName('testProduct1')->setPrice('1')->create(); + $secondItem = $this->itemBuilder->setId(2)->setName('testProduct2')->setPrice('2')->create(); + + /** Simple filtration implementation */ + if (!empty($filters)) { + /** @var \Magento\Framework\Api\Filter $filter */ + foreach ($filters as $filter) { + if ('id' == $filter->getField() && $filter->getValue() == 1) { + $result[] = $firstItem; + } elseif ('id' == $filter->getField() && $filter->getValue() == 2) { + $result[] = $secondItem; + } + } + } else { + /** No filter is specified. */ + $result = [$firstItem, $secondItem]; + } + return $result; + } + + /** + * {@inheritdoc} + */ + public function create($name) + { + return $this->itemBuilder->setId(rand())->setName($name)->setPrice('10')->create(); + } + + /** + * {@inheritdoc} + */ + public function update(Item $entityItem) + { + return $this->itemBuilder + ->setId($entityItem->getId()) + ->setName('Updated' . $entityItem->getName()) + ->setPrice('5')->create(); + } + + /** + * {@inheritdoc} + */ + public function delete($id) + { + return $this->itemBuilder->setId($id)->setName('testProduct1')->setPrice('1')->create(); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/AllSoapAndRestInterface.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/AllSoapAndRestInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..0507a01422b72fbc9c0af63aaf1800c592a10dcf --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/AllSoapAndRestInterface.php @@ -0,0 +1,51 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V2; + +use Magento\TestModule1\Service\V2\Entity\Item; + +interface AllSoapAndRestInterface +{ + /** + * Get item. + * + * @param int $id + * @return \Magento\TestModule1\Service\V2\Entity\Item + */ + public function item($id); + + /** + * Create item. + * + * @param string $name + * @return \Magento\TestModule1\Service\V2\Entity\Item + */ + public function create($name); + + /** + * Update item. + * + * @param \Magento\TestModule1\Service\V2\Entity\Item $entityItem + * @return \Magento\TestModule1\Service\V2\Entity\Item + */ + public function update(Item $entityItem); + + /** + * Retrieve a list of items. + * + * @param \Magento\Framework\Api\Filter[] $filters + * @param string $sortOrder + * @return \Magento\TestModule1\Service\V2\Entity\Item[] + */ + public function items($filters = [], $sortOrder = 'ASC'); + + /** + * Delete an item. + * + * @param int $id + * @return \Magento\TestModule1\Service\V2\Entity\Item + */ + public function delete($id); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/Entity/Item.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/Entity/Item.php new file mode 100644 index 0000000000000000000000000000000000000000..79438931a5dd35aee7b9ac923dacfc14417189b8 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/Entity/Item.php @@ -0,0 +1,32 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V2\Entity; + +class Item extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * @return int + */ + public function getId() + { + return $this->_data['id']; + } + + /** + * @return string + */ + public function getName() + { + return $this->_data['name']; + } + + /** + * @return string + */ + public function getPrice() + { + return $this->_data['price']; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/Entity/ItemBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/Entity/ItemBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..d28d791b6b8fcf4a337000f01ff4db1ea7a7d5de --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Service/V2/Entity/ItemBuilder.php @@ -0,0 +1,41 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule1\Service\V2\Entity; + +class ItemBuilder extends \Magento\Framework\Api\ExtensibleObjectBuilder +{ + /** + * @param int $id + * + * @return \Magento\TestModule1\Service\V2\Entity\ItemBuilder + */ + public function setId($id) + { + $this->data['id'] = $id; + return $this; + } + + /** + * @param string $name + * + * @return \Magento\TestModule1\Service\V2\Entity\ItemBuilder + */ + public function setName($name) + { + $this->data['name'] = $name; + return $this; + } + + /** + * @param string $price + * + * @return \Magento\TestModule1\Service\V2\Entity\ItemBuilder + */ + public function setPrice($price) + { + $this->data['price'] = $price; + return $this; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/acl.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/acl.xml new file mode 100644 index 0000000000000000000000000000000000000000..e6fcca6add8e3a5f1cb6ba3dd094507e532f0573 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/acl.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Acl/etc/acl.xsd"> + <acl> + <resources> + <resource id="Magento_Adminhtml::admin"> + <resource id="Magento_TestModule1::all" title="TestModule1" sortOrder="1"> + <resource id="Magento_TestModule1::resource1" title="Resource1" sortOrder="20"/> + <resource id="Magento_TestModule1::resource2" title="Resource2" sortOrder="10"/> + <resource id="Magento_TestModule1::resource3" title="Resource3" sortOrder="30"/> + </resource> + </resource> + </resources> + </acl> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/data_object.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/data_object.xml new file mode 100644 index 0000000000000000000000000000000000000000..f30038e83f43424f97cd1da59114a062ec27db19 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/data_object.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd"> + <custom_attributes for="Magento\TestModule1\Service\V1\Entity\Item"> + <attribute code="custom_attribute_data_object" type="Magento\TestModule1\Service\V1\Entity\CustomAttributeDataObject" /> + <attribute code="custom_attribute_string" type="string" /> + </custom_attributes> + <custom_attributes for="Magento\TestModule1\Service\V1\Entity\CustomAttributeDataObject"> + <attribute code="custom_attribute_nested" type="Magento\TestModule1\Service\V1\Entity\CustomAttributeNestedDataObject" /> + <attribute code="custom_attribute_int" type="int" /> + </custom_attributes> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/di.xml new file mode 100644 index 0000000000000000000000000000000000000000..977ca625f28c51fc95cbef8906214c51c5b6e62f --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/di.xml @@ -0,0 +1,22 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd"> + <preference for="Magento\TestModule1\Service\V1\AllSoapAndRestInterface" type="Magento\TestModule1\Service\V1\AllSoapAndRest" /> + <preference for="Magento\TestModule1\Service\V2\AllSoapAndRestInterface" type="Magento\TestModule1\Service\V2\AllSoapAndRest" /> + + <virtualType name="Magento\TestModule1\Service\Config\TestModule1MetadataConfig" type="Magento\Framework\Api\Config\MetadataConfig"> + <arguments> + <argument name="attributeMetadataBuilder" xsi:type="object">Magento\TestModule1\Service\V1\Entity\Eav\AttributeMetadataBuilder</argument> + <argument name="dataObjectClassName" xsi:type="string">Magento\TestModule1\Service\V1\Entity\Item</argument> + </arguments> + </virtualType> + <type name="Magento\TestModule1\Service\V1\Entity\ItemBuilder"> + <arguments> + <argument name="metadataService" xsi:type="object">Magento\TestModule1\Service\Config\TestModule1MetadataConfig</argument> + </arguments> + </type> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/frontend/routes.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/frontend/routes.xml new file mode 100644 index 0000000000000000000000000000000000000000..f6984e2d6d74dcb50b9e77f2d348d94ca405ef63 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/frontend/routes.xml @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../lib/internal/Magento/Framework/App/etc/routes.xsd"> + <router id="standard"> + <route id="testmoduleone" frontName="testmoduleone"> + <module name="Magento_TestModule1" /> + </route> + </router> +</config> \ No newline at end of file diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml new file mode 100644 index 0000000000000000000000000000000000000000..ba0d441958811635aaa373abe641378deefe97e2 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd"> + <module name="Magento_TestModule1" schema_version="1.0"/> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml new file mode 100644 index 0000000000000000000000000000000000000000..874afa7713840d9a7ed9015a033b4e556dd19ef6 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml @@ -0,0 +1,99 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../app/code/Magento/Webapi/etc/webapi.xsd"> + + <route method="GET" url="/V1/testmodule1/overwritten"> + <service class="Magento\TestModule1\Service\V1\AllSoapAndRestInterface" method="item" /> + <resources> + <resource ref="Magento_TestModule1::resource1" /> + </resources> + <data> + <parameter name="itemId" force="true">-55</parameter> + </data> + </route> + + <route method="POST" url="/V1/testmodule1/testOptionalParam"> + <service class="Magento\TestModule1\Service\V1\AllSoapAndRestInterface" method="testOptionalParam" /> + <resources> + <resource ref="Magento_TestModule1::resource1" /> + </resources> + <data> + <parameter name="name">Default Name</parameter> + </data> + </route> + + <route method="GET" url="/V1/testmodule1/:itemId"> + <service class="Magento\TestModule1\Service\V1\AllSoapAndRestInterface" method="item" /> + <resources> + <resource ref="Magento_TestModule1::resource1" /> + </resources> + </route> + <route method="GET" url="/V1/testmodule1"> + <service class="Magento\TestModule1\Service\V1\AllSoapAndRestInterface" method="items" /> + <resources> + <resource ref="Magento_TestModule1::resource2" /> + </resources> + </route> + <route method="POST" url="/V1/testmodule1"> + <service class="Magento\TestModule1\Service\V1\AllSoapAndRestInterface" method="create" /> + <resources> + <resource ref="Magento_TestModule1::resource3" /> + </resources> + </route> + <route method="PUT" url="/V1/testmodule1/:itemId"> + <service class="Magento\TestModule1\Service\V1\AllSoapAndRestInterface" method="update" /> + <resources> + <resource ref="Magento_TestModule1::resource1" /> + <resource ref="Magento_TestModule1::resource2" /> + </resources> + </route> + <route method="POST" url="/V1/testmodule1/itemAnyType"> + <service class="Magento\TestModule1\Service\V1\AllSoapAndRestInterface" method="itemAnyType" /> + <resources> + <resource ref="Magento_TestModule1::resource1" /> + <resource ref="Magento_TestModule1::resource2" /> + </resources> + </route> + <route method="GET" url="/V1/testmodule1/itemPreconfigured"> + <service class="Magento\TestModule1\Service\V1\AllSoapAndRestInterface" method="getPreconfiguredItem" /> + <resources> + <resource ref="Magento_TestModule1::resource1" /> + <resource ref="Magento_TestModule1::resource2" /> + </resources> + </route> + <route method="GET" url="/V2/testmodule1/:id"> + <service class="Magento\TestModule1\Service\V2\AllSoapAndRestInterface" method="item" /> + <resources> + <resource ref="Magento_TestModule1::resource1" /> + </resources> + </route> + <route method="GET" url="/V2/testmodule1"> + <service class="Magento\TestModule1\Service\V2\AllSoapAndRestInterface" method="items" /> + <resources> + <resource ref="Magento_TestModule1::resource2" /> + </resources> + </route> + <route method="POST" url="/V2/testmodule1"> + <service class="Magento\TestModule1\Service\V2\AllSoapAndRestInterface" method="create" /> + <resources> + <resource ref="Magento_TestModule1::resource3" /> + </resources> + </route> + <route method="PUT" url="/V2/testmodule1/:id"> + <service class="Magento\TestModule1\Service\V2\AllSoapAndRestInterface" method="update" /> + <resources> + <resource ref="Magento_TestModule1::resource1" /> + <resource ref="Magento_TestModule1::resource2" /> + </resources> + </route> + <route method="DELETE" url="/V2/testmodule1/:id"> + <service class="Magento\TestModule1\Service\V2\AllSoapAndRestInterface" method="delete" /> + <resources> + <resource ref="Magento_TestModule1::resource1" /> + </resources> + </route> +</routes> diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/Entity/Item.php b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/Entity/Item.php new file mode 100644 index 0000000000000000000000000000000000000000..ac51c4663a5a779eb72741564a7533ab26a6a1d2 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/Entity/Item.php @@ -0,0 +1,24 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule2\Service\V1\Entity; + +class Item extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * @return int + */ + public function getId() + { + return $this->_data['id']; + } + + /** + * @return string + */ + public function getName() + { + return $this->_data['name']; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/Entity/ItemBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/Entity/ItemBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..79b57a34aec3e6f30bdb0cebb6bd7909d4c4095f --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/Entity/ItemBuilder.php @@ -0,0 +1,28 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule2\Service\V1\Entity; + +class ItemBuilder extends \Magento\Framework\Api\ExtensibleObjectBuilder +{ + /** + * @param int $id + * @return \Magento\TestModule2\Service\V1\Entity\ItemBuilder + */ + public function setId($id) + { + $this->data['id'] = $id; + return $this; + } + + /** + * @param string $name + * @return \Magento\TestModule2\Service\V1\Entity\ItemBuilder + */ + public function setName($name) + { + $this->data['name'] = $name; + return $this; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/NoWebApiXml.php b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/NoWebApiXml.php new file mode 100644 index 0000000000000000000000000000000000000000..9a1128502b8936b229283f756170b32ccb7cf6ca --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/NoWebApiXml.php @@ -0,0 +1,60 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule2\Service\V1; + +use Magento\TestModule2\Service\V1\Entity\Item; +use Magento\TestModule2\Service\V1\Entity\ItemBuilder; + +class NoWebApiXml implements \Magento\TestModule2\Service\V1\NoWebApiXmlInterface +{ + /** + * @var ItemBuilder + */ + protected $itemBuilder; + + /** + * @param ItemBuilder $itemBuilder + */ + public function __construct(ItemBuilder $itemBuilder) + { + $this->itemBuilder = $itemBuilder; + } + + /** + * {@inheritdoc} + */ + public function item($id) + { + return $this->itemBuilder->setId($id)->setName('testProduct1')->create(); + } + + /** + * {@inheritdoc} + */ + public function items() + { + $result1 = $this->itemBuilder->setId(1)->setName('testProduct1')->create(); + + $result2 = $this->itemBuilder->setId(2)->setName('testProduct2')->create(); + + return [$result1, $result2]; + } + + /** + * {@inheritdoc} + */ + public function create($name) + { + return $this->itemBuilder->setId(rand())->setName($name)->create(); + } + + /** + * {@inheritdoc} + */ + public function update(Item $item) + { + return $this->itemBuilder->setId($item->getId())->setName('Updated' . $item->getName())->create(); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/NoWebApiXmlInterface.php b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/NoWebApiXmlInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..474ef888d510ed92a3ee29430ef984d5cbe3db7d --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/NoWebApiXmlInterface.php @@ -0,0 +1,41 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule2\Service\V1; + +use Magento\TestModule2\Service\V1\Entity\Item; + +interface NoWebApiXmlInterface +{ + /** + * Get an item. + * + * @param int $id + * @return \Magento\TestModule2\Service\V1\Entity\Item + */ + public function item($id); + + /** + * Create an item. + * + * @param string $name + * @return \Magento\TestModule2\Service\V1\Entity\Item + */ + public function create($name); + + /** + * Update an item. + * + * @param \Magento\TestModule2\Service\V1\Entity\Item $item + * @return \Magento\TestModule2\Service\V1\Entity\Item + */ + public function update(Item $item); + + /** + * Retrieve a list of items. + * + * @return \Magento\TestModule2\Service\V1\Entity\Item[] + */ + public function items(); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/SubsetRest.php b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/SubsetRest.php new file mode 100644 index 0000000000000000000000000000000000000000..0f6d5e9670aa730d3cd0c7ae3e9a1b7be0efe4dc --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/SubsetRest.php @@ -0,0 +1,68 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule2\Service\V1; + +use Magento\TestModule2\Service\V1\Entity\Item; +use Magento\TestModule2\Service\V1\Entity\ItemBuilder; + +class SubsetRest implements \Magento\TestModule2\Service\V1\SubsetRestInterface +{ + /** + * @var ItemBuilder + */ + protected $itemBuilder; + + /** + * @param ItemBuilder $itemBuilder + */ + public function __construct(ItemBuilder $itemBuilder) + { + $this->itemBuilder = $itemBuilder; + } + + /** + * {@inheritdoc} + */ + public function item($id) + { + return $this->itemBuilder->setId($id)->setName('testItem' . $id)->create(); + } + + /** + * {@inheritdoc} + */ + public function items() + { + $result1 = $this->itemBuilder->setId(1)->setName('testItem1')->create(); + + $result2 = $this->itemBuilder->setId(2)->setName('testItem2')->create(); + + return [$result1, $result2]; + } + + /** + * {@inheritdoc} + */ + public function create($name) + { + return $this->itemBuilder->setId(rand())->setName($name)->create(); + } + + /** + * {@inheritdoc} + */ + public function update(Item $item) + { + return $this->itemBuilder->setId($item->getId())->setName('Updated' . $item->getName())->create(); + } + + /** + * {@inheritdoc} + */ + public function remove($id) + { + return $this->itemBuilder->setId(1)->create(); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/SubsetRestInterface.php b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/SubsetRestInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..c52fd18fb55b8f8d7b227dab223291eaab298eb2 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/Service/V1/SubsetRestInterface.php @@ -0,0 +1,49 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule2\Service\V1; + +use Magento\TestModule2\Service\V1\Entity\Item; + +interface SubsetRestInterface +{ + /** + * Return a single item. + * + * @param int $id + * @return \Magento\TestModule2\Service\V1\Entity\Item + */ + public function item($id); + + /** + * Return multiple items. + * + * @return \Magento\TestModule2\Service\V1\Entity\Item[] + */ + public function items(); + + /** + * Create an item. + * + * @param string $name + * @return \Magento\TestModule2\Service\V1\Entity\Item + */ + public function create($name); + + /** + * Update an item. + * + * @param \Magento\TestModule2\Service\V1\Entity\Item $item + * @return \Magento\TestModule2\Service\V1\Entity\Item + */ + public function update(Item $item); + + /** + * Delete an item. + * + * @param int $id + * @return \Magento\TestModule2\Service\V1\Entity\Item + */ + public function remove($id); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/acl.xml b/dev/tests/api-functional/_files/Magento/TestModule2/etc/acl.xml new file mode 100644 index 0000000000000000000000000000000000000000..d6b32a5bf83fb4ec80d8445d3a6688bd6b5d8ddc --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/acl.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Acl/etc/acl.xsd"> + <acl> + <resources> + <resource id="Magento_Adminhtml::admin"> + <resource id="Magento_TestModule2::all" title="TestModule2" sortOrder="1"> + <resource id="Magento_TestModule2::resource1" title="Resource1" sortOrder="20"/> + <resource id="Magento_TestModule2::resource2" title="Resource2" sortOrder="10"/> + <resource id="Magento_TestModule2::resource3" title="Resource3" sortOrder="30"/> + </resource> + </resource> + </resources> + </acl> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModule2/etc/di.xml new file mode 100644 index 0000000000000000000000000000000000000000..ffb7f082e52b06e8f7394958ef859f8f1fcb1a05 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/di.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd"> + <preference for="Magento\TestModule2\Service\V1\SubsetRestInterface" type="Magento\TestModule2\Service\V1\SubsetRest" /> + <preference for="Magento\TestModule2\Service\V1\NoWebApiXmlInterface" type="Magento\TestModule2\Service\V1\NoWebApiXml" /> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml new file mode 100644 index 0000000000000000000000000000000000000000..6f6c90cfd914f30c214eba82cf3d97126e42ea60 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd"> + <module name="Magento_TestModule2" schema_version="1.0"/> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/AllSoapNoRestV1.xsd b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/AllSoapNoRestV1.xsd new file mode 100644 index 0000000000000000000000000000000000000000..3e7caaa8d480048a83ea35018572ff62bf034ca9 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/AllSoapNoRestV1.xsd @@ -0,0 +1,239 @@ +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:complexType name="ItemRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:int"> + <xsd:annotation> + <xsd:documentation>Entity ID</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>Item</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ItemResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Item call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Item</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="ItemsResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Items call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" + type="ItemsArray"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Items</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + + <xsd:complexType name="ItemsArray"> + <xsd:annotation> + <xsd:documentation>Response container for the Items call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Items</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="name" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Item</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CreateRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Create</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CreateResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Create call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Create</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="name" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Create</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="UpdateRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:int"> + <xsd:annotation> + <xsd:documentation>Entity ID</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>Update</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="UpdateResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Update call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Update</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RemoveRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:int"> + <xsd:annotation> + <xsd:documentation>Entity ID</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>Remove</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RemoveResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Remove call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Remove</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> +</xsd:schema> diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/NoWebApiXmlV1.xsd b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/NoWebApiXmlV1.xsd new file mode 100644 index 0000000000000000000000000000000000000000..3e7caaa8d480048a83ea35018572ff62bf034ca9 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/NoWebApiXmlV1.xsd @@ -0,0 +1,239 @@ +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:complexType name="ItemRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:int"> + <xsd:annotation> + <xsd:documentation>Entity ID</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>Item</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ItemResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Item call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Item</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="ItemsResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Items call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" + type="ItemsArray"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Items</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + + <xsd:complexType name="ItemsArray"> + <xsd:annotation> + <xsd:documentation>Response container for the Items call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Items</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="name" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Item</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CreateRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Create</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CreateResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Create call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Create</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="name" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Create</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="UpdateRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:int"> + <xsd:annotation> + <xsd:documentation>Entity ID</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>Update</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="UpdateResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Update call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Update</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RemoveRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:int"> + <xsd:annotation> + <xsd:documentation>Entity ID</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>Remove</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RemoveResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Remove call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Remove</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> +</xsd:schema> diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/SubsetRestV1.xsd b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/SubsetRestV1.xsd new file mode 100644 index 0000000000000000000000000000000000000000..3e7caaa8d480048a83ea35018572ff62bf034ca9 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/SubsetRestV1.xsd @@ -0,0 +1,239 @@ +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:complexType name="ItemRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:int"> + <xsd:annotation> + <xsd:documentation>Entity ID</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>Item</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ItemResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Item call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Item</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="ItemsResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Items call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" + type="ItemsArray"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Items</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + + <xsd:complexType name="ItemsArray"> + <xsd:annotation> + <xsd:documentation>Response container for the Items call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Items</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="name" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Item</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CreateRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="name" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Create</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CreateResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Create call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Create</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="name" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Create</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="UpdateRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:int"> + <xsd:annotation> + <xsd:documentation>Entity ID</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>Update</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="UpdateResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Update call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Update</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RemoveRequest"> + <xsd:annotation> + <xsd:documentation/> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:int"> + <xsd:annotation> + <xsd:documentation>Entity ID</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>Remove</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="RemoveResponse"> + <xsd:annotation> + <xsd:documentation>Response container for the Remove call.</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Default label</xsd:documentation> + <xsd:appinfo xmlns:inf="http://magento.ll/webapi/soap"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>Remove</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + </xsd:complexType> +</xsd:schema> diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule2/etc/webapi.xml new file mode 100644 index 0000000000000000000000000000000000000000..fb4339826d5d1926d0947ab4ffa5b79556b763d3 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/webapi.xml @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../app/code/Magento/Webapi/etc/webapi.xsd"> + <route method="GET" url="/V1/testModule2SubsetRest/:id"> + <service class="Magento\TestModule2\Service\V1\SubsetRestInterface" method="item" /> + <resources> + <resource ref="Magento_TestModule2::resource1" /> + </resources> + </route> + <route method="GET" url="/V1/testModule2SubsetRest"> + <service class="Magento\TestModule2\Service\V1\SubsetRestInterface" method="items" /> + <resources> + <resource ref="Magento_TestModule2::resource2" /> + <resource ref="Magento_TestModule2::resource3" /> + </resources> + </route> +</routes> diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/Parameter.php b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/Parameter.php new file mode 100644 index 0000000000000000000000000000000000000000..a6f58178d0453ba3dab9ae658c8dbf3124b4d0d9 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/Parameter.php @@ -0,0 +1,28 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule3\Service\V1\Entity; + +class Parameter extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * Get Name. + * + * @return string $name + */ + public function getName() + { + return $this->_data['name']; + } + + /** + * Get value. + * + * @return string $value + */ + public function getValue() + { + return $this->_data['value']; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/ParameterBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/ParameterBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..31ec2076df461d2d6e2468b0b9a37449bda75b43 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/ParameterBuilder.php @@ -0,0 +1,32 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule3\Service\V1\Entity; + +class ParameterBuilder extends \Magento\Framework\Api\ExtensibleObjectBuilder +{ + /** + * Set Name. + * + * @param string $name + * @return \Magento\TestModule3\Service\V1\Entity\ParameterBuilder + */ + public function setName($name) + { + $this->data['name'] = $name; + return $this; + } + + /** + * Set value. + * + * @param string $value + * @return \Magento\TestModule3\Service\V1\Entity\ParameterBuilder + */ + public function setValue($value) + { + $this->data['value'] = $value; + return $this; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/WrappedErrorParameter.php b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/WrappedErrorParameter.php new file mode 100644 index 0000000000000000000000000000000000000000..775e04a2ce5ca2e3668069fbb4e7303b06a088a7 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/WrappedErrorParameter.php @@ -0,0 +1,29 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestModule3\Service\V1\Entity; + +class WrappedErrorParameter extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * Get field name. + * + * @return string $name + */ + public function getFieldName() + { + return $this->_data['field_name']; + } + + /** + * Get value. + * + * @return string $value + */ + public function getValue() + { + return $this->_data['value']; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/WrappedErrorParameterBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/WrappedErrorParameterBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..d6b3f9de2aec33064eec74f16014f2b59afd0bb8 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Entity/WrappedErrorParameterBuilder.php @@ -0,0 +1,33 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestModule3\Service\V1\Entity; + +class WrappedErrorParameterBuilder extends \Magento\Framework\Api\ExtensibleObjectBuilder +{ + /** + * Set field name. + * + * @param string $fieldName + * @return $this + */ + public function setFieldName($fieldName) + { + $this->data['field_name'] = $fieldName; + return $this; + } + + /** + * Set value. + * + * @param string $value + * @return $this + */ + public function setValue($value) + { + $this->data['value'] = $value; + return $this; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Error.php b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Error.php new file mode 100644 index 0000000000000000000000000000000000000000..6410845b0516d3dde2647155a87b6137a7cfd75e --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/Error.php @@ -0,0 +1,117 @@ +<?php +/** + * Implementation of a test service for error handling testing + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule3\Service\V1; + +use Magento\Framework\Exception\AuthorizationException; +use Magento\Framework\Exception\InputException; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\TestModule3\Service\V1\Entity\Parameter; +use Magento\TestModule3\Service\V1\Entity\ParameterBuilder; + +class Error implements \Magento\TestModule3\Service\V1\ErrorInterface +{ + /** + * @var ParameterBuilder + */ + protected $parameterBuilder; + + /** + * @param ParameterBuilder $parameterBuilder + */ + public function __construct(ParameterBuilder $parameterBuilder) + { + $this->parameterBuilder = $parameterBuilder; + } + + /** + * {@inheritdoc} + */ + public function success() + { + return $this->parameterBuilder->setName('id')->setValue('a good id')->create(); + } + + /** + * {@inheritdoc} + */ + public function resourceNotFoundException() + { + throw new NoSuchEntityException('Resource with ID "%resource_id" not found.', ['resource_id' => 'resourceY']); + } + + /** + * {@inheritdoc} + */ + public function serviceException() + { + throw new LocalizedException('Generic service exception %param', ['param' => 3456]); + } + + /** + * {@inheritdoc} + */ + public function parameterizedServiceException($parameters) + { + $details = []; + foreach ($parameters as $parameter) { + $details[$parameter->getName()] = $parameter->getValue(); + } + throw new LocalizedException('Parameterized service exception', $details); + } + + /** + * {@inheritdoc} + */ + public function authorizationException() + { + throw new AuthorizationException('Consumer is not authorized to access %resources', [ + 'resources' => 'resourceN' + ]); + } + + /** + * {@inheritdoc} + */ + public function webapiException() + { + throw new \Magento\Webapi\Exception('Service not found', 5555, \Magento\Webapi\Exception::HTTP_NOT_FOUND); + } + + /** + * {@inheritdoc} + */ + public function otherException() + { + throw new \Exception('Non service exception', 5678); + } + + /** + * {@inheritdoc} + */ + public function returnIncompatibleDataType() + { + return "incompatibleDataType"; + } + + /** + * {@inheritdoc} + */ + public function inputException($wrappedErrorParameters) + { + $exception = new InputException(); + if ($wrappedErrorParameters) { + foreach ($wrappedErrorParameters as $error) { + $exception->addError( + InputException::INVALID_FIELD_VALUE, + ['fieldName' => $error->getFieldName(), 'value' => $error->getValue()] + ); + } + } + throw $exception; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/ErrorInterface.php b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/ErrorInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..59612a9755b750bcf8e3974b206e323e87be4bac --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule3/Service/V1/ErrorInterface.php @@ -0,0 +1,59 @@ +<?php +/** + * Interface for a test service for error handling testing + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule3\Service\V1; + +use Magento\TestModule3\Service\V1\Entity\Parameter; + +interface ErrorInterface +{ + /** + * @return \Magento\TestModule3\Service\V1\Entity\Parameter + */ + public function success(); + + /** + * @return int Status + */ + public function resourceNotFoundException(); + + /** + * @return int Status + */ + public function serviceException(); + + /** + * @param \Magento\TestModule3\Service\V1\Entity\Parameter[] $parameters + * @return int Status + */ + public function parameterizedServiceException($parameters); + + /** + * @return int Status + */ + public function authorizationException(); + + /** + * @return int Status + */ + public function webapiException(); + + /** + * @return int Status + */ + public function otherException(); + + /** + * @return int Status + */ + public function returnIncompatibleDataType(); + + /** + * @param \Magento\TestModule3\Service\V1\Entity\WrappedErrorParameter[] $wrappedErrorParameters + * @return int Status + */ + public function inputException($wrappedErrorParameters); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/etc/acl.xml b/dev/tests/api-functional/_files/Magento/TestModule3/etc/acl.xml new file mode 100644 index 0000000000000000000000000000000000000000..556c098784384a38a6c7323e2b71731b959f407c --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule3/etc/acl.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Acl/etc/acl.xsd"> + <acl> + <resources> + <resource id="Magento_Adminhtml::admin"> + <resource id="Magento_TestModule3::all" title="TestModule3" sortOrder="1"> + <resource id="Magento_TestModule3::resource1" title="Resource1" sortOrder="20"/> + </resource> + </resource> + </resources> + </acl> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModule3/etc/di.xml new file mode 100644 index 0000000000000000000000000000000000000000..b26be009346343d0e43a5a7c29312d8e67e978d6 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule3/etc/di.xml @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd"> + <preference for="Magento\TestModule3\Service\V1\ErrorInterface" type="Magento\TestModule3\Service\V1\Error" /> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml new file mode 100644 index 0000000000000000000000000000000000000000..42ae9667a277150322d4c2a793a87c2882edeeab --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd"> + <module name="Magento_TestModule3" schema_version="1.0"/> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule3/etc/webapi.xml new file mode 100644 index 0000000000000000000000000000000000000000..ca7043e0c429cbcbf1b42a16e29bfdd4db6164eb --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule3/etc/webapi.xml @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../app/code/Magento/Webapi/etc/webapi.xsd"> + <route method="GET" url="/V1/errortest/success"> + <service class="Magento\TestModule3\Service\V1\ErrorInterface" method="success" /> + <resources> + <resource ref="Magento_TestModule3::resource1" /> + </resources> + </route> + <route method="GET" url="/V1/errortest/notfound"> + <service class="Magento\TestModule3\Service\V1\ErrorInterface" method="resourceNotFoundException" /> + <resources> + <resource ref="Magento_TestModule3::resource1" /> + </resources> + </route> + <route method="GET" url="/V1/errortest/serviceexception"> + <service class="Magento\TestModule3\Service\V1\ErrorInterface" method="serviceException" /> + <resources> + <resource ref="Magento_TestModule3::resource1" /> + </resources> + </route> + <route method="POST" url="/V1/errortest/parameterizedserviceexception"> + <service class="Magento\TestModule3\Service\V1\ErrorInterface" method="parameterizedServiceException" /> + <resources> + <resource ref="Magento_TestModule3::resource1" /> + </resources> + </route> + <route method="GET" url="/V1/errortest/unauthorized"> + <service class="Magento\TestModule3\Service\V1\ErrorInterface" method="authorizationException" /> + <resources> + <resource ref="Magento_TestModule3::resource1" /> + <resource ref="Magento_TestModule3::resource2" /> + </resources> + </route> + <route method="GET" url="/V1/errortest/otherException"> + <service class="Magento\TestModule3\Service\V1\ErrorInterface" method="otherException" /> + <resources> + <resource ref="Magento_TestModule3::resource1" /> + </resources> + </route> + <route method="GET" url="/V1/errortest/returnIncompatibleDataType"> + <service class="Magento\TestModule3\Service\V1\ErrorInterface" method="returnIncompatibleDataType" /> + <resources> + <resource ref="Magento_TestModule3::resource1" /> + </resources> + </route> + <route method="GET" url="/V1/errortest/webapiException"> + <service class="Magento\TestModule3\Service\V1\ErrorInterface" method="webapiException" /> + <resources> + <resource ref="Magento_TestModule3::resource1" /> + </resources> + </route> + <route method="POST" url="/V1/errortest/inputException"> + <service class="Magento\TestModule3\Service\V1\ErrorInterface" method="inputException" /> + <resources> + <resource ref="Magento_TestModule3::resource1" /> + </resources> + </route> +</routes> diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Model/Resource/Item.php b/dev/tests/api-functional/_files/Magento/TestModule4/Model/Resource/Item.php new file mode 100644 index 0000000000000000000000000000000000000000..346d39bdca4b16a57bc51aee9b23f99b67143b0f --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Model/Resource/Item.php @@ -0,0 +1,22 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestModule4\Model\Resource; + +/** + * Sample resource model + */ +class Item extends \Magento\Framework\Model\Resource\Db\AbstractDb +{ + /** + * Initialize connection and define main table + * + * @return void + */ + protected function _construct() + { + $this->_init('dummy_item', 'dummy_item_id'); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/DataObjectService.php b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/DataObjectService.php new file mode 100644 index 0000000000000000000000000000000000000000..9c960939015e0c93a992ce14957aa39d8d965d46 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/DataObjectService.php @@ -0,0 +1,69 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule4\Service\V1; + +use Magento\TestModule4\Service\V1\Entity\DataObjectRequest; +use Magento\TestModule4\Service\V1\Entity\DataObjectResponseBuilder; +use Magento\TestModule4\Service\V1\Entity\ExtensibleRequestInterface; +use Magento\TestModule4\Service\V1\Entity\NestedDataObjectRequest; + +class DataObjectService implements \Magento\TestModule4\Service\V1\DataObjectServiceInterface +{ + /** + * @var DataObjectResponseBuilder + */ + protected $responseBuilder; + + /** + * @param DataObjectResponseBuilder $responseBuilder + */ + public function __construct(DataObjectResponseBuilder $responseBuilder) + { + $this->responseBuilder = $responseBuilder; + } + + /** + * {@inheritdoc} + */ + public function getData($id) + { + return $this->responseBuilder->setEntityId($id)->setName("Test")->create(); + } + + /** + * {@inheritdoc} + */ + public function updateData($id, DataObjectRequest $request) + { + return $this->responseBuilder->setEntityId($id)->setName($request->getName())->create(); + } + + /** + * {@inheritdoc} + */ + public function nestedData($id, NestedDataObjectRequest $request) + { + return $this->responseBuilder->setEntityId($id)->setName($request->getDetails()->getName())->create(); + } + + /** + * Test return scalar value + * + * @param int $id + * @return int + */ + public function scalarResponse($id) + { + return $id; + } + + /** + * {@inheritdoc} + */ + public function extensibleDataObject($id, ExtensibleRequestInterface $request) + { + return $this->responseBuilder->setEntityId($id)->setName($request->getName())->create(); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/DataObjectServiceInterface.php b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/DataObjectServiceInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..f189b2c9ef42a3c4d2f478c44cf0aa06eadc2097 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/DataObjectServiceInterface.php @@ -0,0 +1,46 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule4\Service\V1; + +use Magento\TestModule4\Service\V1\Entity\DataObjectRequest; +use Magento\TestModule4\Service\V1\Entity\NestedDataObjectRequest; + +interface DataObjectServiceInterface +{ + /** + * @param int $id + * @return \Magento\TestModule4\Service\V1\Entity\DataObjectResponse + */ + public function getData($id); + + /** + * @param int $id + * @param \Magento\TestModule4\Service\V1\Entity\DataObjectRequest $request + * @return \Magento\TestModule4\Service\V1\Entity\DataObjectResponse + */ + public function updateData($id, DataObjectRequest $request); + + /** + * @param int $id + * @param \Magento\TestModule4\Service\V1\Entity\NestedDataObjectRequest $request + * @return \Magento\TestModule4\Service\V1\Entity\DataObjectResponse + */ + public function nestedData($id, NestedDataObjectRequest $request); + + /** + * Test return scalar value + * + * @param int $id + * @return int + */ + public function scalarResponse($id); + + /** + * @param int $id + * @param \Magento\TestModule4\Service\V1\Entity\ExtensibleRequestInterface $request + * @return \Magento\TestModule4\Service\V1\Entity\DataObjectResponse + */ + public function extensibleDataObject($id, \Magento\TestModule4\Service\V1\Entity\ExtensibleRequestInterface $request); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectRequest.php b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectRequest.php new file mode 100644 index 0000000000000000000000000000000000000000..1c3f3dff0f4fb6890b5b2ce65032c8ef25fa2957 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectRequest.php @@ -0,0 +1,24 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule4\Service\V1\Entity; + +class DataObjectRequest extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * @return string + */ + public function getName() + { + return $this->_get('name'); + } + + /** + * @return int|null + */ + public function getEntityId() + { + return $this->_get('entity_id'); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectRequestBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectRequestBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..d3d92a6d74a3c2baa2b386889aa69b913bd53678 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectRequestBuilder.php @@ -0,0 +1,26 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule4\Service\V1\Entity; + +class DataObjectRequestBuilder extends \Magento\Framework\Api\ExtensibleObjectBuilder +{ + /** + * @param string $name + * @return DataObjectRequest + */ + public function setName($name) + { + return $this->_set('name', $name); + } + + /** + * @param int $entityId + * @return DataObjectRequest + */ + public function setEntityId($entityId) + { + return $this->_set('entity_id', $entityId); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectResponse.php b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectResponse.php new file mode 100644 index 0000000000000000000000000000000000000000..0086eda109521c4f4894204e5694e478ac8050d6 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectResponse.php @@ -0,0 +1,24 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule4\Service\V1\Entity; + +class DataObjectResponse extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * @return int + */ + public function getEntityId() + { + return $this->_get('entity_id'); + } + + /** + * @return string + */ + public function getName() + { + return $this->_get('name'); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectResponseBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectResponseBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..288c72299852709e26e36906a75eda74e935634e --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/DataObjectResponseBuilder.php @@ -0,0 +1,26 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule4\Service\V1\Entity; + +class DataObjectResponseBuilder extends \Magento\Framework\Api\ExtensibleObjectBuilder +{ + /** + * @param int $entityId + * @return DataObjectResponseBuilder + */ + public function setEntityId($entityId) + { + return $this->_set('entity_id', $entityId); + } + + /** + * @param string $name + * @return DataObjectResponseBuilder + */ + public function setName($name) + { + return $this->_set('name', $name); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/ExtensibleRequest.php b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/ExtensibleRequest.php new file mode 100644 index 0000000000000000000000000000000000000000..41f78a2ed61cc9b620b2864cce32452651b1ab35 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/ExtensibleRequest.php @@ -0,0 +1,14 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule4\Service\V1\Entity; + +class ExtensibleRequest extends \Magento\Framework\Model\AbstractExtensibleModel + implements ExtensibleRequestInterface +{ + public function getName() + { + return $this->getData("name"); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/ExtensibleRequestInterface.php b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/ExtensibleRequestInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..fd258c7af99a2d8922a5e2b92d6f50c8a7cfad11 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/ExtensibleRequestInterface.php @@ -0,0 +1,18 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule4\Service\V1\Entity; + +interface ExtensibleRequestInterface extends \Magento\Framework\Api\ExtensibleDataInterface +{ + /** + * @return string + */ + public function getName(); + + /** + * @return int|null + */ + public function getEntityId(); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/NestedDataObjectRequest.php b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/NestedDataObjectRequest.php new file mode 100644 index 0000000000000000000000000000000000000000..6c2775f006da8222eaee4035575308cd128275b7 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/NestedDataObjectRequest.php @@ -0,0 +1,16 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule4\Service\V1\Entity; + +class NestedDataObjectRequest extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * @return \Magento\TestModule4\Service\V1\Entity\DataObjectRequest + */ + public function getDetails() + { + return $this->_get('details'); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/NestedDataObjectRequestBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/NestedDataObjectRequestBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..68e0123e75e279034a5dcdfbb1c126d048097c1d --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/Service/V1/Entity/NestedDataObjectRequestBuilder.php @@ -0,0 +1,17 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule4\Service\V1\Entity; + +class NestedDataObjectRequestBuilder extends \Magento\Framework\Api\ExtensibleObjectBuilder +{ + /** + * @param \Magento\TestModule4\Service\V1\Entity\DataObjectRequest $details + * @return \Magento\TestModule4\Service\V1\Entity\DataObjectRequest + */ + public function setDetails(DataObjectRequest $details) + { + return $this->_set('details', $details); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/etc/acl.xml b/dev/tests/api-functional/_files/Magento/TestModule4/etc/acl.xml new file mode 100644 index 0000000000000000000000000000000000000000..cb35e81b7750b58814484a7c3edb60e747d2db75 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/etc/acl.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Acl/etc/acl.xsd"> + <acl> + <resources> + <resource id="Magento_Adminhtml::admin"> + <resource id="Magento_TestModule4::all" title="TestModule4" sortOrder="1"> + <resource id="Magento_TestModule4::resource1" title="Resource1" sortOrder="20"/> + <resource id="Magento_TestModule4::resource2" title="Resource2" sortOrder="10"/> + <resource id="Magento_TestModule4::resource3" title="Resource3" sortOrder="30"/> + </resource> + </resource> + </resources> + </acl> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModule4/etc/di.xml new file mode 100644 index 0000000000000000000000000000000000000000..d41a2955c3398e375393522fd659a7c9286ebb95 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/etc/di.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd"> + <preference for="Magento\TestModule4\Service\V1\DataObjectServiceInterface" type="Magento\TestModule4\Service\V1\DataObjectService" /> + <preference for="Magento\TestModule4\Service\V1\Entity\ExtensibleRequestInterface" type="Magento\TestModule4\Service\V1\Entity\ExtensibleRequest" /> + <type name="Magento\TestModule4\Service\V1\Entity\ExtensibleRequest"> + <arguments> + <argument name="resource" xsi:type="object">Magento\TestModule4\Model\Resource\Item</argument> + </arguments> + </type> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml new file mode 100644 index 0000000000000000000000000000000000000000..f433c75e68f9ab915eae3aeea9eef076849a9c03 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd"> + <module name="Magento_TestModule4" schema_version="1.0"/> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule4/etc/webapi.xml new file mode 100644 index 0000000000000000000000000000000000000000..196aaf5ff2a06544f30372d3ccd7d597f051785a --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule4/etc/webapi.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../app/code/Magento/Webapi/etc/webapi.xsd"> + <route method="GET" url="/V1/testmodule4/:id"> + <service class="Magento\TestModule4\Service\V1\DataObjectServiceInterface" method="getData" /> + <resources> + <resource ref="Magento_TestModule4::resource1" /> + </resources> + </route> + <route method="GET" url="/V1/testmodule4/scalar/:id"> + <service class="Magento\TestModule4\Service\V1\DataObjectServiceInterface" method="scalarResponse" /> + <resources> + <resource ref="Magento_TestModule4::resource1" /> + </resources> + </route> + <route method="POST" url="/V1/testmodule4/:id"> + <service class="Magento\TestModule4\Service\V1\DataObjectServiceInterface" method="updateData" /> + <resources> + <resource ref="Magento_TestModule4::resource2" /> + </resources> + </route> + <route method="POST" url="/V1/testmodule4/:id/nested"> + <service class="Magento\TestModule4\Service\V1\DataObjectServiceInterface" method="nestedData" /> + <resources> + <resource ref="Magento_TestModule4::resource3" /> + </resources> + </route> + <route method="POST" url="/V1/testmodule4/extensibleDataObject/:id"> + <service class="Magento\TestModule4\Service\V1\DataObjectServiceInterface" method="extensibleDataObject" /> + <resources> + <resource ref="Magento_TestModule4::resource3" /> + </resources> + </route> +</routes> diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/AllSoapAndRest.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/AllSoapAndRest.php new file mode 100644 index 0000000000000000000000000000000000000000..6cf3942fe2d754f9119201e3e4d58503d13ff676 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/AllSoapAndRest.php @@ -0,0 +1,73 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule5\Service\V1; + +use Magento\TestModule5\Service\V1\Entity\AllSoapAndRestBuilder; + +class AllSoapAndRest implements \Magento\TestModule5\Service\V1\AllSoapAndRestInterface +{ + /** + * @var AllSoapAndRestBuilder + */ + protected $builder; + + /** + * @param AllSoapAndRestBuilder $builder + */ + public function __construct(AllSoapAndRestBuilder $builder) + { + $this->builder = $builder; + } + + /** + * {@inheritdoc} + */ + public function item($entityId) + { + return $this->builder + ->setEntityId($entityId) + ->setName('testItemName') + ->setIsEnabled(true) + ->setHasOrders(true) + ->create(); + } + + /** + * {@inheritdoc} + */ + public function items() + { + $allSoapAndRest1 = $this->builder->setEntityId(1)->setName('testProduct1')->create(); + $allSoapAndRest2 = $this->builder->setEntityId(2)->setName('testProduct2')->create(); + return [$allSoapAndRest1, $allSoapAndRest2]; + } + + /** + * {@inheritdoc} + */ + public function create(\Magento\TestModule5\Service\V1\Entity\AllSoapAndRest $item) + { + return $this->builder->populate($item)->create(); + } + + /** + * {@inheritdoc} + */ + public function update(\Magento\TestModule5\Service\V1\Entity\AllSoapAndRest $entityItem) + { + return $entityItem; + } + + /** + * {@inheritdoc} + */ + public function nestedUpdate( + $parentId, + $entityId, + \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest $entityItem + ) { + return $entityItem; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/AllSoapAndRestInterface.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/AllSoapAndRestInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..de1b4472479b98ef9b4dfbba4ac986709f8a0c2c --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/AllSoapAndRestInterface.php @@ -0,0 +1,54 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule5\Service\V1; + +interface AllSoapAndRestInterface +{ + /** + * Retrieve an item. + * + * @param int $entityId + * @return \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest + * @throws \Magento\Webapi\Exception + */ + public function item($entityId); + + /** + * Retrieve all items. + * + * @return \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest[] + */ + public function items(); + + /** + * Create a new item. + * + * @param \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest $item + * @return \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest + */ + public function create(\Magento\TestModule5\Service\V1\Entity\AllSoapAndRest $item); + + /** + * Update existing item. + * + * @param \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest $entityItem + * @return \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest + */ + public function update(\Magento\TestModule5\Service\V1\Entity\AllSoapAndRest $entityItem); + + /** + * Update existing item. + * + * @param string $parentId + * @param string $entityId + * @param \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest $entityItem + * @return \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest + */ + public function nestedUpdate( + $parentId, + $entityId, + \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest $entityItem + ); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/Entity/AllSoapAndRest.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/Entity/AllSoapAndRest.php new file mode 100644 index 0000000000000000000000000000000000000000..19e78efe69463cccaf0f21a64c5db0ab57d336ac --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/Entity/AllSoapAndRest.php @@ -0,0 +1,70 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule5\Service\V1\Entity; + +/** + * Some Data Object short description. + * + * Data Object long + * multi line description. + */ +class AllSoapAndRest extends \Magento\Framework\Api\AbstractExtensibleObject +{ + const ID = 'entity_id'; + const NAME = 'name'; + const ENABLED = 'enabled'; + const HAS_ORDERS = 'orders'; + + /** + * Retrieve item ID. + * + * @return int Item ID + */ + public function getEntityId() + { + return $this->_get(self::ID); + } + + /** + * Retrieve item Name. + * + * @return string|null Item name + */ + public function getName() + { + return $this->_get(self::NAME); + } + + /** + * Check if entity is enabled + * + * @return bool + */ + public function isEnabled() + { + return $this->_get(self::ENABLED); + } + + /** + * Check if current entity has a property defined + * + * @return bool + */ + public function hasOrders() + { + return $this->_get(self::HAS_ORDERS); + } + + /** + * Method which will not be used when adding complex type field to WSDL. + * + * @param string $value + * @return string + */ + public function getFieldExcludedFromWsdl($value) + { + return $value; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/Entity/AllSoapAndRestBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/Entity/AllSoapAndRestBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..70ed93fa515aa4a78d23a9697b719e63db533335 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/Entity/AllSoapAndRestBuilder.php @@ -0,0 +1,56 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule5\Service\V1\Entity; + +use Magento\Framework\Api\AbstractSimpleObjectBuilder; + +/** + * Some Data Object short description. + * + * Data Object long + * multi line description. + */ +class AllSoapAndRestBuilder extends AbstractSimpleObjectBuilder +{ + /** + * @param int $id + * @return AllSoapAndRestBuilder + */ + public function setEntityId($id) + { + return $this->_set(AllSoapAndRest::ID, $id); + } + + /** + * @param string $name + * @return AllSoapAndRestBuilder + */ + public function setName($name) + { + return $this->_set(AllSoapAndRest::NAME, $name); + } + + /** + * Set flag if entity is enabled + * + * @param bool $isEnabled + * @return AllSoapAndRestBuilder + */ + public function setIsEnabled($isEnabled) + { + return $this->_set(AllSoapAndRest::ENABLED, $isEnabled); + } + + /** + * Set flag if entity has orders + * + * @param bool $hasOrders + * @return AllSoapAndRestBuilder + */ + public function setHasOrders($hasOrders) + { + return $this->_set(AllSoapAndRest::HAS_ORDERS, $hasOrders); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/OverrideService.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/OverrideService.php new file mode 100644 index 0000000000000000000000000000000000000000..d5fb874d457bce5a61aac253687cee80e3099a91 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/OverrideService.php @@ -0,0 +1,35 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestModule5\Service\V1; + +use Magento\TestModule5\Service\V1\Entity\AllSoapAndRestBuilder; + +class OverrideService implements OverrideServiceInterface +{ + /** + * @var AllSoapAndRestBuilder + */ + protected $builder; + + /** + * @param AllSoapAndRestBuilder $builder + */ + public function __construct(AllSoapAndRestBuilder $builder) + { + $this->builder = $builder; + } + /** + * {@inheritdoc} + */ + public function scalarUpdate($entityId, $name, $hasOrders) + { + return $this->builder + ->setEntityId($entityId) + ->setName($name) + ->setHasOrders($hasOrders) + ->create(); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/OverrideServiceInterface.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/OverrideServiceInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..f8ce591980b5c2914d51e54f473882b6a589e404 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V1/OverrideServiceInterface.php @@ -0,0 +1,19 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestModule5\Service\V1; + +interface OverrideServiceInterface +{ + /** + * Update existing item. + * + * @param string $entityId + * @param string $name + * @param bool $orders + * @return \Magento\TestModule5\Service\V1\Entity\AllSoapAndRest + */ + public function scalarUpdate($entityId, $name, $orders); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/AllSoapAndRest.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/AllSoapAndRest.php new file mode 100644 index 0000000000000000000000000000000000000000..e4b006e8feadf62720ab0a0b950980b12909e40a --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/AllSoapAndRest.php @@ -0,0 +1,69 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule5\Service\V2; + +use Magento\TestModule5\Service\V2\Entity\AllSoapAndRest as AllSoapAndRestEntity; +use Magento\TestModule5\Service\V2\Entity\AllSoapAndRestBuilder; + +class AllSoapAndRest implements AllSoapAndRestInterface +{ + /** + * @var AllSoapAndRestBuilder + */ + protected $builder; + + /** + * @param AllSoapAndRestBuilder $builder + */ + public function __construct(AllSoapAndRestBuilder $builder) + { + $this->builder = $builder; + } + + /** + * @inheritdoc + */ + public function item($id) + { + return $this->builder->setPrice(1)->setId($id)->setName('testItemName')->create(); + } + + /** + * @inheritdoc + */ + public function items() + { + $allSoapAndRest1 = $this->builder->setPrice(1)->setId(1)->setName('testProduct1')->create(); + $allSoapAndRest2 = $this->builder->setPrice(1)->setId(2)->setName('testProduct2')->create(); + return [$allSoapAndRest1, $allSoapAndRest2]; + } + + /** + * @inheritdoc + */ + public function create(\Magento\TestModule5\Service\V2\Entity\AllSoapAndRest $item) + { + return $this->builder->populate($item)->create(); + } + + /** + * @inheritdoc + */ + public function update(\Magento\TestModule5\Service\V2\Entity\AllSoapAndRest $item) + { + $item->setName('Updated' . $item->getName()); + return $this->builder->populate($item)->create(); + } + + /** + * @param string $id + * @return AllSoapAndRestEntity + * @throws \Magento\Webapi\Exception + */ + public function delete($id) + { + return $this->builder->setPrice(1)->setId($id)->setName('testItemName')->create(); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/AllSoapAndRestInterface.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/AllSoapAndRestInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..dce9a15f0f5dc720e97996e8c470f98e19bddf8b --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/AllSoapAndRestInterface.php @@ -0,0 +1,48 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule5\Service\V2; + +interface AllSoapAndRestInterface +{ + /** + * Retrieve existing item. + * + * @param int $id + * @return \Magento\TestModule5\Service\V2\Entity\AllSoapAndRest + * @throws \Magento\Webapi\Exception + */ + public function item($id); + + /** + * Retrieve a list of all existing items. + * + * @return \Magento\TestModule5\Service\V2\Entity\AllSoapAndRest[] + */ + public function items(); + + /** + * Add new item. + * + * @param \Magento\TestModule5\Service\V2\Entity\AllSoapAndRest $item + * @return \Magento\TestModule5\Service\V2\Entity\AllSoapAndRest + */ + public function create(\Magento\TestModule5\Service\V2\Entity\AllSoapAndRest $item); + + /** + * Update one item. + * + * @param \Magento\TestModule5\Service\V2\Entity\AllSoapAndRest $item + * @return \Magento\TestModule5\Service\V2\Entity\AllSoapAndRest + */ + public function update(\Magento\TestModule5\Service\V2\Entity\AllSoapAndRest $item); + + /** + * Delete existing item. + * + * @param string $id + * @return \Magento\TestModule5\Service\V2\Entity\AllSoapAndRest + */ + public function delete($id); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/Entity/AllSoapAndRest.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/Entity/AllSoapAndRest.php new file mode 100644 index 0000000000000000000000000000000000000000..35e3674b679ab6623ed7f417738dd3010297b994 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/Entity/AllSoapAndRest.php @@ -0,0 +1,18 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule5\Service\V2\Entity; + +class AllSoapAndRest extends \Magento\TestModule5\Service\V2\AllSoapAndRest +{ + const PRICE = 'price'; + + /** + * @return int + */ + public function getPrice() + { + return $this->_get(self::PRICE); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/Entity/AllSoapAndRestBuilder.php b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/Entity/AllSoapAndRestBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..d68589484b322c64b7ddb3147e3519e8ab03646e --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/Service/V2/Entity/AllSoapAndRestBuilder.php @@ -0,0 +1,21 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModule5\Service\V2\Entity; + +use Magento\TestModule5\Service\V1\Entity; + +class AllSoapAndRestBuilder extends \Magento\TestModule5\Service\V1\Entity\AllSoapAndRestBuilder +{ + const PRICE = 'price'; + + /** + * @param int $price + * @return \Magento\TestModule5\Service\V2\Entity\AllSoapAndRestBuilder + */ + public function setPrice($price) + { + return $this->_set(self::PRICE, $price); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/etc/acl.xml b/dev/tests/api-functional/_files/Magento/TestModule5/etc/acl.xml new file mode 100644 index 0000000000000000000000000000000000000000..ebad51bd78d996e7fecd8ca070bacb434028a93b --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/etc/acl.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Acl/etc/acl.xsd"> + <acl> + <resources> + <resource id="Magento_Adminhtml::admin"> + <resource id="Magento_TestModule5::all" title="TestModule5" sortOrder="1"> + <resource id="Magento_TestModule5::resource1" title="Resource1" sortOrder="20"/> + <resource id="Magento_TestModule5::resource2" title="Resource2" sortOrder="10"/> + <resource id="Magento_TestModule5::resource3" title="Resource3" sortOrder="30"/> + </resource> + </resource> + </resources> + </acl> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModule5/etc/di.xml new file mode 100644 index 0000000000000000000000000000000000000000..13e121a2d7220be0c26b7785e033e496b0c47610 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/etc/di.xml @@ -0,0 +1,11 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd"> + <preference for="Magento\TestModule5\Service\V1\AllSoapAndRestInterface" type="Magento\TestModule5\Service\V1\AllSoapAndRest" /> + <preference for="Magento\TestModule5\Service\V2\AllSoapAndRestInterface" type="Magento\TestModule5\Service\V2\AllSoapAndRest" /> + <preference for="Magento\TestModule5\Service\V1\OverrideServiceInterface" type="Magento\TestModule5\Service\V1\OverrideService" /> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml new file mode 100644 index 0000000000000000000000000000000000000000..801468fd880a1697f3d4644135cf8dea87da8568 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd"> + <module name="Magento_TestModule5" schema_version="1.0"/> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule5/etc/webapi.xml new file mode 100644 index 0000000000000000000000000000000000000000..38cbd15afb17892b91493662cb015dce20c69937 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModule5/etc/webapi.xml @@ -0,0 +1,78 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../app/code/Magento/Webapi/etc/webapi.xsd"> + <route method="GET" url="/V1/TestModule5/:entityId"> + <service class="Magento\TestModule5\Service\V1\AllSoapAndRestInterface" method="item" /> + <resources> + <resource ref="Magento_TestModule5::resource1" /> + </resources> + </route> + <route method="GET" url="/V1/TestModule5"> + <service class="Magento\TestModule5\Service\V1\AllSoapAndRestInterface" method="items" /> + <resources> + <resource ref="Magento_TestModule5::resource2" /> + </resources> + </route> + <route method="POST" url="/V1/TestModule5"> + <service class="Magento\TestModule5\Service\V1\AllSoapAndRestInterface" method="create" /> + <resources> + <resource ref="Magento_TestModule5::resource3" /> + </resources> + </route> + <route method="PUT" url="/V1/TestModule5/:entityId"> + <service class="Magento\TestModule5\Service\V1\AllSoapAndRestInterface" method="update" /> + <resources> + <resource ref="Magento_TestModule5::resource1" /> + <resource ref="Magento_TestModule5::resource2" /> + </resources> + </route> + <route method="PUT" url="/V1/TestModule5/:parentId/nestedResource/:entityId"> + <service class="Magento\TestModule5\Service\V1\AllSoapAndRestInterface" method="nestedUpdate" /> + <resources> + <resource ref="Magento_TestModule5::resource1" /> + <resource ref="Magento_TestModule5::resource2" /> + </resources> + </route> + <route method="PUT" url="/V1/TestModule5/OverrideService/:parentId/nestedResource/:entityId"> + <service class="Magento\TestModule5\Service\V1\OverrideServiceInterface" method="scalarUpdate" /> + <resources> + <resource ref="Magento_TestModule5::resource1" /> + <resource ref="Magento_TestModule5::resource2" /> + </resources> + </route> + <route method="GET" url="/V2/TestModule5/:id"> + <service class="Magento\TestModule5\Service\V2\AllSoapAndRestInterface" method="item" /> + <resources> + <resource ref="Magento_TestModule5::resource1" /> + </resources> + </route> + <route method="GET" url="/V2/TestModule5"> + <service class="Magento\TestModule5\Service\V2\AllSoapAndRestInterface" method="items" /> + <resources> + <resource ref="Magento_TestModule5::resource2" /> + </resources> + </route> + <route method="POST" url="/V2/TestModule5"> + <service class="Magento\TestModule5\Service\V2\AllSoapAndRestInterface" method="create" /> + <resources> + <resource ref="Magento_TestModule5::resource3" /> + </resources> + </route> + <route method="PUT" url="/V2/TestModule5/:id"> + <service class="Magento\TestModule5\Service\V2\AllSoapAndRestInterface" method="update" /> + <resources> + <resource ref="Magento_TestModule5::resource1" /> + <resource ref="Magento_TestModule5::resource2" /> + </resources> + </route> + <route method="DELETE" url="/V2/TestModule5/:id"> + <service class="Magento\TestModule5\Service\V2\AllSoapAndRestInterface" method="delete" /> + <resources> + <resource ref="Magento_TestModule5::resource1" /> + </resources> + </route> +</routes> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/AllSoapAndRestInterface.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/AllSoapAndRestInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..baa4ab49f376be3b933997ec09a715be8a621992 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/AllSoapAndRestInterface.php @@ -0,0 +1,48 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModuleMSC\Api; + +interface AllSoapAndRestInterface +{ + /** + * @param int $itemId + * @return \Magento\TestModuleMSC\Api\Data\ItemInterface + */ + public function item($itemId); + + /** + * @param string $name + * @return \Magento\TestModuleMSC\Api\Data\ItemInterface + */ + public function create($name); + + /** + * @param \Magento\TestModuleMSC\Api\Data\ItemInterface $entityItem + * @return \Magento\TestModuleMSC\Api\Data\ItemInterface + */ + public function update(\Magento\TestModuleMSC\Api\Data\ItemInterface $entityItem); + + /** + * @return \Magento\TestModuleMSC\Api\Data\ItemInterface[] + */ + public function items(); + + /** + * @param string $name + * @return \Magento\TestModuleMSC\Api\Data\ItemInterface + */ + public function testOptionalParam($name = null); + + /** + * @param \Magento\TestModuleMSC\Api\Data\ItemInterface $entityItem + * @return \Magento\TestModuleMSC\Api\Data\ItemInterface + */ + public function itemAnyType(\Magento\TestModuleMSC\Api\Data\ItemInterface $entityItem); + + /** + * @return \Magento\TestModuleMSC\Api\Data\ItemInterface + */ + public function getPreconfiguredItem(); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/Data/CustomAttributeDataObjectInterface.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/Data/CustomAttributeDataObjectInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..0710ee62a85158a9494336ba209504860e513281 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/Data/CustomAttributeDataObjectInterface.php @@ -0,0 +1,15 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModuleMSC\Api\Data; + +interface CustomAttributeDataObjectInterface extends \Magento\Framework\Api\ExtensibleDataInterface +{ + const NAME = 'name'; + + /** + * @return string + */ + public function getName(); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/Data/CustomAttributeNestedDataObjectInterface.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/Data/CustomAttributeNestedDataObjectInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..5c5b634bd15e9b82dd078217f044c06b355add1a --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/Data/CustomAttributeNestedDataObjectInterface.php @@ -0,0 +1,13 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModuleMSC\Api\Data; + +interface CustomAttributeNestedDataObjectInterface extends \Magento\Framework\Api\ExtensibleDataInterface +{ + /** + * @return string + */ + public function getName(); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/Data/ItemInterface.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/Data/ItemInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..65595bafe836436811fb65b4bf8c1d9b14d8fe2b --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Api/Data/ItemInterface.php @@ -0,0 +1,18 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModuleMSC\Api\Data; + +interface ItemInterface extends \Magento\Framework\Api\ExtensibleDataInterface +{ + /** + * @return int + */ + public function getItemId(); + + /** + * @return string + */ + public function getName(); +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/AllSoapAndRest.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/AllSoapAndRest.php new file mode 100644 index 0000000000000000000000000000000000000000..cca810f6ca4d47b3e73bbae34e16b5d8c225a07a --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/AllSoapAndRest.php @@ -0,0 +1,107 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModuleMSC\Model; + +use Magento\TestModuleMSC\Api\Data\CustomAttributeDataObjectDataBuilder; +use Magento\TestModuleMSC\Api\Data\ItemDataBuilder; + +class AllSoapAndRest implements \Magento\TestModuleMSC\Api\AllSoapAndRestInterface +{ + /** + * @var ItemDataBuilder + */ + protected $itemDataBuilder; + + /** + * @var CustomAttributeDataObjectDataBuilder + */ + protected $customAttributeDataObjectDataBuilder; + + /** + * @param ItemDataBuilder $itemDataBuilder + * @param CustomAttributeDataObjectDataBuilder $customAttributeNestedDataObjectBuilder + */ + public function __construct( + ItemDataBuilder $itemDataBuilder, + CustomAttributeDataObjectDataBuilder $customAttributeNestedDataObjectBuilder + ) { + $this->itemDataBuilder = $itemDataBuilder; + $this->customAttributeDataObjectDataBuilder = $customAttributeNestedDataObjectBuilder; + } + + /** + * {@inheritdoc} + */ + public function item($itemId) + { + return $this->itemDataBuilder->setItemId($itemId)->setName('testProduct1')->create(); + } + + /** + * {@inheritdoc} + */ + public function items() + { + $result1 = $this->itemDataBuilder->setItemId(1)->setName('testProduct1')->create(); + $result2 = $this->itemDataBuilder->setItemId(2)->setName('testProduct2')->create(); + + return [$result1, $result2]; + } + + /** + * {@inheritdoc} + */ + public function create($name) + { + return $this->itemDataBuilder->setItemId(rand())->setName($name)->create(); + } + + /** + * {@inheritdoc} + */ + public function update(\Magento\TestModuleMSC\Api\Data\ItemInterface $entityItem) + { + return $this->itemDataBuilder->setItemId($entityItem->getItemId()) + ->setName('Updated' . $entityItem->getName()) + ->create(); + } + + public function testOptionalParam($name = null) + { + if (is_null($name)) { + return $this->itemDataBuilder->setItemId(3)->setName('No Name')->create(); + } else { + return $this->itemDataBuilder->setItemId(3)->setName($name)->create(); + } + } + + /** + * {@inheritdoc} + */ + public function itemAnyType(\Magento\TestModuleMSC\Api\Data\ItemInterface $entityItem) + { + return $entityItem; + } + + /** + * {@inheritdoc} + */ + public function getPreconfiguredItem() + { + $customAttributeDataObject = $this->customAttributeDataObjectDataBuilder + ->setName('nameValue') + ->setCustomAttribute('custom_attribute_int', 1) + ->create(); + + $item = $this->itemDataBuilder + ->setItemId(1) + ->setName('testProductAnyType') + ->setCustomAttribute('custom_attribute_data_object', $customAttributeDataObject) + ->setCustomAttribute('custom_attribute_string', 'someStringValue') + ->create(); + + return $item; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/CustomAttributeDataObject.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/CustomAttributeDataObject.php new file mode 100644 index 0000000000000000000000000000000000000000..dc3a1c1a17ece2d251d28e1fb18984174786bd41 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/CustomAttributeDataObject.php @@ -0,0 +1,19 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModuleMSC\Model\Data; + +use Magento\TestModuleMSC\Api\Data\CustomAttributeDataObjectInterface; + +class CustomAttributeDataObject extends \Magento\Framework\Api\AbstractExtensibleObject + implements CustomAttributeDataObjectInterface +{ + /** + * @return string + */ + public function getName() + { + return $this->_data['name']; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/CustomAttributeNestedDataObject.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/CustomAttributeNestedDataObject.php new file mode 100644 index 0000000000000000000000000000000000000000..9ea73d87acee50649757bb3622933b42aeefa1cd --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/CustomAttributeNestedDataObject.php @@ -0,0 +1,19 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModuleMSC\Model\Data; + +use Magento\TestModuleMSC\Api\Data\CustomAttributeNestedDataObjectInterface; + +class CustomAttributeNestedDataObject extends \Magento\Framework\Model\AbstractExtensibleModel + implements CustomAttributeNestedDataObjectInterface +{ + /** + * @return string + */ + public function getName() + { + return $this->_data['name']; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/Eav/AttributeMetadata.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/Eav/AttributeMetadata.php new file mode 100644 index 0000000000000000000000000000000000000000..2977a6e50691abf1b2c8f4f9996d0e1c340eef98 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/Eav/AttributeMetadata.php @@ -0,0 +1,42 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModuleMSC\Model\Data\Eav; + +use Magento\Framework\Api\AbstractExtensibleObject; +use Magento\Framework\Api\MetadataObjectInterface; + +/** + * Class AttributeMetadata + */ +class AttributeMetadata extends AbstractExtensibleObject implements MetadataObjectInterface +{ + /**#@+ + * Constants used as keys into $_data + */ + const ATTRIBUTE_ID = 'attribute_id'; + + const ATTRIBUTE_CODE = 'attribute_code'; + /**#@-*/ + + /** + * Retrieve id of the attribute. + * + * @return string|null + */ + public function getAttributeId() + { + return $this->_get(self::ATTRIBUTE_ID); + } + + /** + * Retrieve code of the attribute. + * + * @return string|null + */ + public function getAttributeCode() + { + return $this->_get(self::ATTRIBUTE_CODE); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/Eav/AttributeMetadataBuilder.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/Eav/AttributeMetadataBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..d037b299cd059cbf378598d17ecd0d31dd09c628 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/Eav/AttributeMetadataBuilder.php @@ -0,0 +1,36 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModuleMSC\Model\Data\Eav; + +use Magento\Framework\Api\AttributeMetadataBuilderInterface; +use Magento\Framework\Api\ExtensibleObjectBuilder; + +/** + * Class AttributeMetadataBuilder + */ +class AttributeMetadataBuilder extends ExtensibleObjectBuilder implements AttributeMetadataBuilderInterface +{ + /** + * Set attribute id + * + * @param int $attributeId + * @return $this + */ + public function setAttributeId($attributeId) + { + return $this->_set(AttributeMetadata::ATTRIBUTE_ID, $attributeId); + } + + /** + * Set attribute code + * + * @param string $attributeCode + * @return $this + */ + public function setAttributeCode($attributeCode) + { + return $this->_set(AttributeMetadata::ATTRIBUTE_CODE, $attributeCode); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/Item.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/Item.php new file mode 100644 index 0000000000000000000000000000000000000000..5593ffcffb412548e6b0796000e661fccd51c3b4 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Data/Item.php @@ -0,0 +1,27 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestModuleMSC\Model\Data; + +use Magento\TestModuleMSC\Api\Data\ItemInterface; + +class Item extends \Magento\Framework\Model\AbstractExtensibleModel + implements ItemInterface +{ + /** + * @return int + */ + public function getItemId() + { + return $this->_data['item_id']; + } + + /** + * @return string + */ + public function getName() + { + return $this->_data['name']; + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Resource/Item.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Resource/Item.php new file mode 100644 index 0000000000000000000000000000000000000000..b1236934e35a504bbb3a07d021d65492693eb6a1 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/Model/Resource/Item.php @@ -0,0 +1,22 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestModuleMSC\Model\Resource; + +/** + * Sample resource model + */ +class Item extends \Magento\Framework\Model\Resource\Db\AbstractDb +{ + /** + * Initialize connection and define main table + * + * @return void + */ + protected function _construct() + { + $this->_init('dummy_item', 'dummy_item_id'); + } +} diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/acl.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/acl.xml new file mode 100644 index 0000000000000000000000000000000000000000..923334c57ddd2347ccc53c4cb50db3ab5c1b77da --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/acl.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Acl/etc/acl.xsd"> + <acl> + <resources> + <resource id="Magento_Adminhtml::admin"> + <resource id="Magento_TestModuleMSC::all" title="TestModuleMSC" sortOrder="1"> + <resource id="Magento_TestModuleMSC::resource1" title="Resource1" sortOrder="20"/> + <resource id="Magento_TestModuleMSC::resource2" title="Resource2" sortOrder="10"/> + <resource id="Magento_TestModuleMSC::resource3" title="Resource3" sortOrder="30"/> + </resource> + </resource> + </resources> + </acl> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/data_object.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/data_object.xml new file mode 100644 index 0000000000000000000000000000000000000000..8fed3f6421cfb9030ebae2728c77e4bf1db5861e --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/data_object.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd"> + <custom_attributes for="Magento\TestModuleMSC\Api\Data\ItemInterface"> + <attribute code="custom_attribute_data_object" type="Magento\TestModuleMSC\Api\Data\CustomAttributeDataObjectInterface" /> + <attribute code="custom_attribute_string" type="string" /> + </custom_attributes> + <custom_attributes for="Magento\TestModuleMSC\Api\Data\CustomAttributeDataObjectInterface"> + <attribute code="custom_attribute_nested" type="Magento\TestModuleMSC\Api\Data\CustomAttributeNestedDataObjectInterface" /> + <attribute code="custom_attribute_int" type="int" /> + </custom_attributes> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/di.xml new file mode 100644 index 0000000000000000000000000000000000000000..62788df693dbe8215ad23ac2f8e698f0b3b6ef3a --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/di.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd"> + + <preference for="Magento\TestModuleMSC\Api\AllSoapAndRestInterface" type="Magento\TestModuleMSC\Model\AllSoapAndRest" /> + + <preference for="Magento\TestModuleMSC\Api\Data\ItemInterface" type="Magento\TestModuleMSC\Model\Data\Item" /> + <preference for="Magento\TestModuleMSC\Api\Data\CustomAttributeDataObjectInterface" type="Magento\TestModuleMSC\Model\Data\CustomAttributeDataObject" /> + <preference for="Magento\TestModuleMSC\Api\Data\CustomAttributeNestedDataObjectInterface" type="Magento\TestModuleMSC\Model\Data\CustomAttributeNestedDataObject" /> + + <virtualType name="Magento\TestModuleMSC\Service\Config\TestModuleMSCMetadataConfig" type="Magento\Framework\Api\Config\MetadataConfig"> + <arguments> + <argument name="attributeMetadataBuilder" xsi:type="object">Magento\TestModuleMSC\Model\Data\Eav\AttributeMetadataBuilder</argument> + <argument name="dataObjectClassName" xsi:type="string">Magento\TestModuleMSC\Model\Data\Item</argument> + </arguments> + </virtualType> + <type name="Magento\TestModuleMSC\Model\Data\Item"> + <arguments> + <argument name="resource" xsi:type="object">Magento\TestModuleMSC\Model\Resource\Item</argument> + <argument name="metadataService" xsi:type="object">Magento\TestModuleMSC\Service\Config\TestModuleMSCMetadataConfig</argument> + </arguments> + </type> + <type name="Magento\TestModuleMSC\Model\Data\CustomAttributeDataObject"> + <arguments> + <argument name="resource" xsi:type="object">Magento\TestModuleMSC\Model\Resource\Item</argument> + </arguments> + </type> + <type name="Magento\TestModuleMSC\Model\Data\CustomAttributeNestedDataObject"> + <arguments> + <argument name="resource" xsi:type="object">Magento\TestModuleMSC\Model\Resource\Item</argument> + </arguments> + </type> + +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml new file mode 100644 index 0000000000000000000000000000000000000000..554ab6d9d9143f03d394987815140ff52f9c8e11 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd"> + <module name="Magento_TestModuleMSC" schema_version="1.0"/> +</config> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/webapi.xml new file mode 100644 index 0000000000000000000000000000000000000000..ed721a73e8e884195f5c4aaba36b6118c3b91089 --- /dev/null +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/webapi.xml @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<!-- +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../app/code/Magento/Webapi/etc/webapi.xsd"> + + <route method="GET" url="/V1/testmoduleMSC/overwritten"> + <service class="Magento\TestModuleMSC\Api\AllSoapAndRestInterface" method="item" /> + <resources> + <resource ref="Magento_TestModuleMSC::resource1" /> + </resources> + <data> + <parameter name="itemId" force="true">-55</parameter> + </data> + </route> + + <route method="POST" url="/V1/testmoduleMSC/testOptionalParam"> + <service class="Magento\TestModuleMSC\Api\AllSoapAndRestInterface" method="testOptionalParam" /> + <resources> + <resource ref="Magento_TestModuleMSC::resource1" /> + </resources> + <data> + <parameter name="name">Default Name</parameter> + </data> + </route> + + <route method="GET" url="/V1/testmoduleMSC/:itemId"> + <service class="Magento\TestModuleMSC\Api\AllSoapAndRestInterface" method="item" /> + <resources> + <resource ref="Magento_TestModuleMSC::resource1" /> + </resources> + </route> + <route method="GET" url="/V1/testmoduleMSC"> + <service class="Magento\TestModuleMSC\Api\AllSoapAndRestInterface" method="items" /> + <resources> + <resource ref="Magento_TestModuleMSC::resource2" /> + </resources> + </route> + <route method="POST" url="/V1/testmoduleMSC"> + <service class="Magento\TestModuleMSC\Api\AllSoapAndRestInterface" method="create" /> + <resources> + <resource ref="Magento_TestModuleMSC::resource3" /> + </resources> + </route> + <route method="PUT" url="/V1/testmoduleMSC/:itemId"> + <service class="Magento\TestModuleMSC\Api\AllSoapAndRestInterface" method="update" /> + <resources> + <resource ref="Magento_TestModuleMSC::resource1" /> + <resource ref="Magento_TestModuleMSC::resource2" /> + </resources> + </route> + <route method="POST" url="/V1/testmoduleMSC/itemAnyType"> + <service class="Magento\TestModuleMSC\Api\AllSoapAndRestInterface" method="itemAnyType" /> + <resources> + <resource ref="Magento_TestModuleMSC::resource1" /> + <resource ref="Magento_TestModuleMSC::resource2" /> + </resources> + </route> + <route method="GET" url="/V1/testmoduleMSC/itemPreconfigured"> + <service class="Magento\TestModuleMSC\Api\AllSoapAndRestInterface" method="getPreconfiguredItem" /> + <resources> + <resource ref="Magento_TestModuleMSC::resource1" /> + <resource ref="Magento_TestModuleMSC::resource2" /> + </resources> + </route> +</routes> diff --git a/dev/tests/api-functional/config/install-config-mysql.php.dist b/dev/tests/api-functional/config/install-config-mysql.php.dist new file mode 100644 index 0000000000000000000000000000000000000000..85665d34d61615880847566e595d3dade4dafd3b --- /dev/null +++ b/dev/tests/api-functional/config/install-config-mysql.php.dist @@ -0,0 +1,29 @@ +<?php +/** + * Magento console installer options for Web API functional tests. Are used in functional tests bootstrap. + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +return [ + 'language' => 'en_US', + 'timezone' => 'America/Los_Angeles', + 'currency' => 'USD', + 'db_host' => 'localhost', + 'db_name' => 'magento_functional_tests', + 'db_user' => 'root', + 'db_pass' => '', + 'backend_frontname' => 'backend', + 'base_url' => 'http://localhost/', + 'use_secure' => '0', + 'use_rewrites' => '0', + 'admin_lastname' => 'Admin', + 'admin_firstname' => 'Admin', + 'admin_email' => 'admin@example.com', + 'admin_username' => 'admin', + 'admin_password' => '123123q', + 'admin_use_security_key' => '0', + /* PayPal has limitation for order number - 20 characters. 10 digits prefix + 8 digits number is good enough */ + 'sales_order_increment_prefix' => time(), + 'session_save' => 'db', + 'cleanup_database' => true, +]; diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php b/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php new file mode 100644 index 0000000000000000000000000000000000000000..6bc41d3a3f41e0e0e3fa1f35b87357d224236a54 --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php @@ -0,0 +1,152 @@ +<?php +/** + * Implementation of the magentoApiDataFixture DocBlock annotation. + * + * The difference of magentoApiDataFixture from magentoDataFixture is + * that no transactions should be used for API data fixtures. + * Otherwise fixture data will not be accessible to Web API functional tests. + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestFramework\Annotation; + +class ApiDataFixture +{ + /** + * @var string + */ + protected $_fixtureBaseDir; + + /** + * Fixtures that have been applied + * + * @var array + */ + private $_appliedFixtures = []; + + /** + * Constructor + * + * @param string $fixtureBaseDir + * @throws \Magento\Framework\Exception + */ + public function __construct($fixtureBaseDir) + { + if (!is_dir($fixtureBaseDir)) { + throw new \Magento\Framework\Exception("Fixture base directory '{$fixtureBaseDir}' does not exist."); + } + $this->_fixtureBaseDir = realpath($fixtureBaseDir); + } + + /** + * Handler for 'startTest' event + * + * @param \PHPUnit_Framework_TestCase $test + */ + public function startTest(\PHPUnit_Framework_TestCase $test) + { + /** Apply method level fixtures if thy are available, apply class level fixtures otherwise */ + $this->_applyFixtures($this->_getFixtures('method', $test) ?: $this->_getFixtures('class', $test)); + } + + /** + * Handler for 'endTest' event + */ + public function endTest() + { + $this->_revertFixtures(); + } + + /** + * Retrieve fixtures from annotation + * + * @param string $scope 'class' or 'method' + * @param \PHPUnit_Framework_TestCase $test + * @return array + * @throws \Magento\Framework\Exception + */ + protected function _getFixtures($scope, \PHPUnit_Framework_TestCase $test) + { + $annotations = $test->getAnnotations(); + $result = []; + if (!empty($annotations[$scope]['magentoApiDataFixture'])) { + foreach ($annotations[$scope]['magentoApiDataFixture'] as $fixture) { + if (strpos($fixture, '\\') !== false) { + // usage of a single directory separator symbol streamlines search across the source code + throw new \Magento\Framework\Exception('Directory separator "\\" is prohibited in fixture declaration.'); + } + $fixtureMethod = [get_class($test), $fixture]; + if (is_callable($fixtureMethod)) { + $result[] = $fixtureMethod; + } else { + $result[] = $this->_fixtureBaseDir . '/' . $fixture; + } + } + } + return $result; + } + + /** + * Execute single fixture script + * + * @param string|array $fixture + */ + protected function _applyOneFixture($fixture) + { + try { + if (is_callable($fixture)) { + call_user_func($fixture); + } else { + require $fixture; + } + } catch (\Exception $e) { + echo 'Exception occurred when running the ' + . (is_array($fixture) || is_scalar($fixture) ? json_encode($fixture) : 'callback') + . ' fixture: ', PHP_EOL, $e; + } + $this->_appliedFixtures[] = $fixture; + } + + /** + * Execute fixture scripts if any + * + * @param array $fixtures + * @throws \Magento\Framework\Exception + */ + protected function _applyFixtures(array $fixtures) + { + /* Execute fixture scripts */ + foreach ($fixtures as $oneFixture) { + /* Skip already applied fixtures */ + if (!in_array($oneFixture, $this->_appliedFixtures, true)) { + $this->_applyOneFixture($oneFixture); + } + } + } + + /** + * Revert changes done by fixtures + */ + protected function _revertFixtures() + { + foreach ($this->_appliedFixtures as $fixture) { + if (is_callable($fixture)) { + $fixture[1] .= 'Rollback'; + if (is_callable($fixture)) { + $this->_applyOneFixture($fixture); + } + } else { + $fileInfo = pathinfo($fixture); + $extension = ''; + if (isset($fileInfo['extension'])) { + $extension = '.' . $fileInfo['extension']; + } + $rollbackScript = $fileInfo['dirname'] . '/' . $fileInfo['filename'] . '_rollback' . $extension; + if (file_exists($rollbackScript)) { + $this->_applyOneFixture($rollbackScript); + } + } + } + $this->_appliedFixtures = []; + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/OauthHelper.php b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/OauthHelper.php new file mode 100644 index 0000000000000000000000000000000000000000..05d33b6bb9fb29ef25a68f63d898f3e6ab30d786 --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/OauthHelper.php @@ -0,0 +1,200 @@ +<?php +/** + * Helper class for generating OAuth related credentials + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestFramework\Authentication; + +use Magento\TestFramework\Authentication\Rest\OauthClient; +use Magento\TestFramework\Helper\Bootstrap; +use OAuth\Common\Consumer\Credentials; +use Zend\Stdlib\Exception\LogicException; + +class OauthHelper +{ + /** @var array */ + protected static $_apiCredentials; + + /** + * Generate authentication credentials + * @param string $date consumer creation date + * @return array + * <pre> + * array ( + * 'key' => 'ajdsjashgdkahsdlkjasldkjals', //consumer key + * 'secret' => 'alsjdlaskjdlaksjdlasjkdlas', //consumer secret + * 'verifier' => 'oiudioqueoiquweoiqwueoqwuii' + * 'consumer' => $consumer, // retrieved consumer Model + * 'token' => $token // retrieved token Model + * ); + * </pre> + */ + public static function getConsumerCredentials($date = null) + { + $integration = self::_createIntegration('all'); + $objectManager = Bootstrap::getObjectManager(); + /** @var $oauthService \Magento\Integration\Service\V1\Oauth */ + $oauthService = $objectManager->get('Magento\Integration\Service\V1\Oauth'); + $consumer = $oauthService->loadConsumer($integration->getConsumerId()); + $url = TESTS_BASE_URL; + $consumer->setCallbackUrl($url); + $consumer->setRejectedCallbackUrl($url); + if (!is_null($date)) { + $consumer->setCreatedAt($date); + } + $consumer->save(); + $token = $objectManager->create('Magento\Integration\Model\Oauth\Token'); + $verifier = $token->createVerifierToken($consumer->getId())->getVerifier(); + + return [ + 'key' => $consumer->getKey(), + 'secret' => $consumer->getSecret(), + 'verifier' => $verifier, + 'consumer' => $consumer, + 'token' => $token + ]; + } + + /** + * Create an access token to associated to a consumer to access APIs. No resources are available to this consumer. + * + * @return array comprising of token key and secret + * <pre> + * array ( + * 'key' => 'ajdsjashgdkahsdlkjasldkjals', //token key + * 'secret' => 'alsjdlaskjdlaksjdlasjkdlas', //token secret + * 'oauth_client' => $oauthClient // OauthClient instance used to fetch the access token + * ); + * </pre> + */ + public static function getAccessToken() + { + $consumerCredentials = self::getConsumerCredentials(); + $credentials = new Credentials($consumerCredentials['key'], $consumerCredentials['secret'], TESTS_BASE_URL); + $oAuthClient = new OauthClient($credentials); + $requestToken = $oAuthClient->requestRequestToken(); + $accessToken = $oAuthClient->requestAccessToken( + $requestToken->getRequestToken(), + $consumerCredentials['verifier'], + $requestToken->getRequestTokenSecret() + ); + + /** TODO: Reconsider return format. It is not aligned with method name. */ + return [ + 'key' => $accessToken->getAccessToken(), + 'secret' => $accessToken->getAccessTokenSecret(), + 'oauth_client' => $oAuthClient + ]; + } + + /** + * Create an access token, tied to integration which has permissions to all API resources in the system. + * + * @param array $resources list of resources to grant to the integration + * @return array + * <pre> + * array ( + * 'key' => 'ajdsjashgdkahsdlkjasldkjals', //token key + * 'secret' => 'alsjdlaskjdlaksjdlasjkdlas', //token secret + * 'oauth_client' => $oauthClient // OauthClient instance used to fetch the access token + * 'integration' => $integration // Integration instance associated with access token + * ); + * </pre> + * @throws LogicException + */ + public static function getApiAccessCredentials($resources = null) + { + if (!self::$_apiCredentials) { + $integration = self::_createIntegration($resources); + $objectManager = Bootstrap::getObjectManager(); + /** @var \Magento\Integration\Service\V1\Oauth $oauthService */ + $oauthService = $objectManager->get('Magento\Integration\Service\V1\Oauth'); + $oauthService->createAccessToken($integration->getConsumerId()); + $accessToken = $oauthService->getAccessToken($integration->getConsumerId()); + if (!$accessToken) { + throw new LogicException('Access token was not created.'); + } + $consumer = $oauthService->loadConsumer($integration->getConsumerId()); + $credentials = new Credentials($consumer->getKey(), $consumer->getSecret(), TESTS_BASE_URL); + /** @var $oAuthClient OauthClient */ + $oAuthClient = new OauthClient($credentials); + + self::$_apiCredentials = [ + 'key' => $accessToken->getToken(), + 'secret' => $accessToken->getSecret(), + 'oauth_client' => $oAuthClient, + 'integration' => $integration, + ]; + } + return self::$_apiCredentials; + } + + /** + * Forget API access credentials. + */ + public static function clearApiAccessCredentials() + { + self::$_apiCredentials = false; + } + + /** + * Remove fs element with nested elements. + * + * @param string $dir + * @param bool $doSaveRoot + */ + protected static function _rmRecursive($dir, $doSaveRoot = false) + { + if (is_dir($dir)) { + foreach (glob($dir . '/*') as $object) { + if (is_dir($object)) { + self::_rmRecursive($object); + } else { + unlink($object); + } + } + if (!$doSaveRoot) { + rmdir($dir); + } + } else { + unlink($dir); + } + } + + /** + * Create integration instance. + * + * @param array $resources + * @return \Magento\Integration\Model\Integration + * @throws \Zend\Stdlib\Exception\LogicException + */ + protected static function _createIntegration($resources) + { + $objectManager = Bootstrap::getObjectManager(); + /** @var $integrationService \Magento\Integration\Service\V1\IntegrationInterface */ + $integrationService = $objectManager->get('Magento\Integration\Service\V1\IntegrationInterface'); + + $params = ['name' => 'Integration' . microtime()]; + + if ($resources === null || $resources == 'all') { + $params['all_resources'] = true; + } else { + $params['resource'] = $resources; + } + $integration = $integrationService->create($params); + $integration->setStatus(\Magento\Integration\Model\Integration::STATUS_ACTIVE)->save(); + + /** Magento cache must be cleared to activate just created ACL role. */ + $varPath = realpath('../../../var'); + if (!$varPath) { + throw new LogicException("Magento cache cannot be cleared after new ACL role creation."); + } else { + $cachePath = $varPath . '/cache'; + if (is_dir($cachePath)) { + self::_rmRecursive($cachePath, true); + } + } + return $integration; + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient.php b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient.php new file mode 100644 index 0000000000000000000000000000000000000000..021e836e0f37ccef541c018673ee37d4e3f9ace9 --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient.php @@ -0,0 +1,271 @@ +<?php +/** + * oAuth client for Magento REST API. + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestFramework\Authentication\Rest; + +use Magento\TestFramework\Helper\Bootstrap; +use OAuth\Common\Consumer\Credentials; +use OAuth\Common\Http\Client\ClientInterface; +use OAuth\Common\Http\Exception\TokenResponseException; +use OAuth\Common\Http\Uri\Uri; +use OAuth\Common\Http\Uri\UriInterface; +use OAuth\Common\Storage\TokenStorageInterface; +use OAuth\OAuth1\Service\AbstractService; +use OAuth\OAuth1\Signature\SignatureInterface; +use OAuth\OAuth1\Token\StdOAuth1Token; +use OAuth\OAuth1\Token\TokenInterface; + +class OauthClient extends AbstractService +{ + /** @var string|null */ + protected $_oauthVerifier = null; + + public function __construct( + Credentials $credentials, + ClientInterface $httpClient = null, + TokenStorageInterface $storage = null, + SignatureInterface $signature = null, + UriInterface $baseApiUri = null + ) { + if (!isset($httpClient)) { + $httpClient = new \OAuth\Common\Http\Client\StreamClient(); + } + if (!isset($storage)) { + $storage = new \OAuth\Common\Storage\Session(); + } + if (!isset($signature)) { + $signature = new \Magento\TestFramework\Authentication\Rest\OauthClient\Signature($credentials); + } + parent::__construct($credentials, $httpClient, $storage, $signature, $baseApiUri); + } + + /** + * @return UriInterface + */ + public function getRequestTokenEndpoint() + { + return new Uri(TESTS_BASE_URL . '/oauth/token/request'); + } + + /** + * Returns the authorization API endpoint. + * + * @return UriInterface + */ + public function getAuthorizationEndpoint() + { + throw new \OAuth\Common\Exception\Exception( + 'Magento REST API is 2-legged. Current operation is not available.' + ); + } + + /** + * Returns the access token API endpoint. + * + * @return UriInterface + */ + public function getAccessTokenEndpoint() + { + return new Uri(TESTS_BASE_URL . '/oauth/token/access'); + } + + /** + * Returns the TestModule1 Rest API endpoint. + * + * @return UriInterface + */ + public function getTestApiEndpoint() + { + $defaultStoreCode = Bootstrap::getObjectManager()->get('Magento\Store\Model\StoreManagerInterface') + ->getStore()->getCode(); + return new Uri(TESTS_BASE_URL . '/rest/' . $defaultStoreCode . '/V1/testmodule1'); + } + + /** + * Parses the access token response and returns a TokenInterface. + * + * @return TokenInterface + * @param string $responseBody + */ + protected function parseAccessTokenResponse($responseBody) + { + return $this->_parseToken($responseBody); + } + + /** + * Parses the request token response and returns a TokenInterface. + * + * @return TokenInterface + * @param string $responseBody + * @throws TokenResponseException + */ + protected function parseRequestTokenResponse($responseBody) + { + $data = $this->_parseResponseBody($responseBody); + if (isset($data['oauth_verifier'])) { + $this->_oauthVerifier = $data['oauth_verifier']; + } + return $this->_parseToken($responseBody); + } + + /** + * Parse response body and create oAuth token object based on parameters provided. + * + * @param string $responseBody + * @return StdOAuth1Token + * @throws TokenResponseException + */ + protected function _parseToken($responseBody) + { + $data = $this->_parseResponseBody($responseBody); + $token = new StdOAuth1Token(); + $token->setRequestToken($data['oauth_token']); + $token->setRequestTokenSecret($data['oauth_token_secret']); + $token->setAccessToken($data['oauth_token']); + $token->setAccessTokenSecret($data['oauth_token_secret']); + $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES); + unset($data['oauth_token'], $data['oauth_token_secret']); + $token->setExtraParams($data); + return $token; + } + + /** + * Parse response body and return data in array. + * + * @param string $responseBody + * @return array + * @throws \OAuth\Common\Http\Exception\TokenResponseException + */ + protected function _parseResponseBody($responseBody) + { + if (!is_string($responseBody)) { + throw new TokenResponseException("Response body is expected to be a string."); + } + parse_str($responseBody, $data); + if (null === $data || !is_array($data)) { + throw new TokenResponseException('Unable to parse response.'); + } elseif (isset($data['error'])) { + throw new TokenResponseException("Error occurred: '{$data['error']}'"); + } + return $data; + } + + /** + * Retrieve oAuth verifier that was obtained during request token request. + * + * @return string + * @throws \OAuth\Common\Http\Exception\TokenResponseException + */ + public function getOauthVerifier() + { + if (!isset($this->_oauthVerifier) || isEmpty($this->_oauthVerifier)) { + throw new TokenResponseException("oAuth verifier must be obtained during request token request."); + } + return $this->_oauthVerifier; + } + + /** + * @override to fix since parent implementation from lib not sending the oauth_verifier when requesting access token + * Builds the authorization header for an authenticated API request + * @param string $method + * @param UriInterface $uri the uri the request is headed + * @param \OAuth\OAuth1\Token\TokenInterface $token + * @param $bodyParams array + * @return string + */ + protected function buildAuthorizationHeaderForAPIRequest( + $method, + UriInterface $uri, + TokenInterface $token, + $bodyParams = null + ) { + $this->signature->setTokenSecret($token->getAccessTokenSecret()); + $parameters = $this->getBasicAuthorizationHeaderInfo(); + if (isset($parameters['oauth_callback'])) { + unset($parameters['oauth_callback']); + } + + $parameters = array_merge($parameters, ['oauth_token' => $token->getAccessToken()]); + $parameters = array_merge($parameters, $bodyParams); + $parameters['oauth_signature'] = $this->signature->getSignature($uri, $parameters, $method); + + $authorizationHeader = 'OAuth '; + $delimiter = ''; + + foreach ($parameters as $key => $value) { + $authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"'; + $delimiter = ', '; + } + + return $authorizationHeader; + } + + /** + * Builds the oAuth authorization header for an authenticated API request + * + * @param UriInterface $uri the uri the request is headed + * @param \OAuth\OAuth1\Token\TokenInterface $token + * @param string $tokenSecret used to verify the passed token + * @param array $bodyParams + * @param string $method HTTP method to use + * @return array + */ + public function buildOauthAuthorizationHeader($uri, $token, $tokenSecret, $bodyParams, $method = 'GET') + { + $uri = new Uri($uri); + $tokenObj = new StdOAuth1Token(); + $tokenObj->setAccessToken($token); + $tokenObj->setAccessTokenSecret($tokenSecret); + $tokenObj->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES); + return [ + 'Authorization: ' . $this->buildAuthorizationHeaderForAPIRequest($method, $uri, $tokenObj, $bodyParams) + ]; + } + + /** + * Builds the bearer token authorization header + * + * @param string $token + * @return array + */ + public function buildBearerTokenAuthorizationHeader($token) + { + return [ + 'Authorization: Bearer ' . $token + ]; + } + + /** + * Validates a Test REST api call access using oauth access token + * + * @param TokenInterface $token The access token. + * @param string $method HTTP method. + * @return array + * @throws TokenResponseException + */ + public function validateAccessToken($token, $method = 'GET') + { + //Need to add Accept header else Magento errors out with 503 + $extraAuthenticationHeaders = ['Accept' => 'application/json']; + + $this->signature->setTokenSecret($token->getAccessTokenSecret()); + + $authorizationHeader = [ + 'Authorization' => $this->buildAuthorizationHeaderForAPIRequest( + $method, + $this->getTestApiEndpoint(), + $token, + [] + ), + ]; + + $headers = array_merge($authorizationHeader, $extraAuthenticationHeaders); + + $responseBody = $this->httpClient->retrieveResponse($this->getTestApiEndpoint(), [], $headers, $method); + + return json_decode($responseBody); + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient/Signature.php b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient/Signature.php new file mode 100644 index 0000000000000000000000000000000000000000..2a2a6c73692bf1c529cd05d23295022085778a32 --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient/Signature.php @@ -0,0 +1,53 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestFramework\Authentication\Rest\OauthClient; + +use OAuth\Common\Http\Uri\UriInterface; + +/** + * Signature class for Magento REST API. + */ +class Signature extends \OAuth\OAuth1\Signature\Signature +{ + /** + * {@inheritdoc} + * + * In addition to the original method, allows array parameters for filters. + */ + public function getSignature(UriInterface $uri, array $params, $method = 'POST') + { + $queryStringData = !$uri->getQuery() ? [] : array_reduce( + explode('&', $uri->getQuery()), + function ($carry, $item) { + list($key, $value) = explode('=', $item, 2); + $carry[rawurldecode($key)] = rawurldecode($value); + return $carry; + }, + [] + ); + + foreach (array_merge($queryStringData, $params) as $key => $value) { + $signatureData[rawurlencode($key)] = rawurlencode($value); + } + + ksort($signatureData); + + // determine base uri + $baseUri = $uri->getScheme() . '://' . $uri->getRawAuthority(); + + if ('/' == $uri->getPath()) { + $baseUri .= $uri->hasExplicitTrailingHostSlash() ? '/' : ''; + } else { + $baseUri .= $uri->getPath(); + } + + $baseString = strtoupper($method) . '&'; + $baseString .= rawurlencode($baseUri) . '&'; + $baseString .= rawurlencode($this->buildSignatureDataString($signatureData)); + + return base64_encode($this->hash($baseString)); + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Bootstrap/WebapiDocBlock.php b/dev/tests/api-functional/framework/Magento/TestFramework/Bootstrap/WebapiDocBlock.php new file mode 100644 index 0000000000000000000000000000000000000000..a764f9988864f3053ae6890605d4f54452a78b24 --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/Bootstrap/WebapiDocBlock.php @@ -0,0 +1,23 @@ +<?php +/** + * Bootstrap of the custom Web API DocBlock annotations. + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestFramework\Bootstrap; + +class WebapiDocBlock extends \Magento\TestFramework\Bootstrap\DocBlock +{ + /** + * Get list of subscribers. In addition, register <b>magentoApiDataFixture</b> annotation processing. + * + * @param \Magento\TestFramework\Application $application + * @return array + */ + protected function _getSubscribers(\Magento\TestFramework\Application $application) + { + $subscribers = parent::_getSubscribers($application); + array_unshift($subscribers, new \Magento\TestFramework\Annotation\ApiDataFixture($this->_fixturesBaseDir)); + return $subscribers; + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Helper/Customer.php b/dev/tests/api-functional/framework/Magento/TestFramework/Helper/Customer.php new file mode 100644 index 0000000000000000000000000000000000000000..77033575557430fc8b296893bc099b1b41d3152c --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/Helper/Customer.php @@ -0,0 +1,170 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestFramework\Helper; + +use Magento\Customer\Api\Data\AddressDataBuilder; +use Magento\Customer\Api\Data\CustomerDataBuilder; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Model\Data\Customer as CustomerData; +use Magento\Framework\Reflection\DataObjectProcessor; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class Customer extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/customers'; + const SERVICE_NAME = 'customerAccountManagementV1'; + const SERVICE_VERSION = 'V1'; + + const CONFIRMATION = 'a4fg7h893e39d'; + const CREATED_AT = '2013-11-05'; + const CREATED_IN = 'default'; + const STORE_NAME = 'Store Name'; + const DOB = '1970-01-01'; + const GENDER = 'Male'; + const GROUP_ID = 1; + const MIDDLENAME = 'A'; + const PREFIX = 'Mr.'; + const STORE_ID = 1; + const SUFFIX = 'Esq.'; + const TAXVAT = '12'; + const WEBSITE_ID = 1; + + /** Sample values for testing */ + const FIRSTNAME = 'Jane'; + const LASTNAME = 'Doe'; + const PASSWORD = 'test@123'; + + const ADDRESS_CITY1 = 'CityM'; + const ADDRESS_CITY2 = 'CityX'; + const ADDRESS_REGION_CODE1 = 'AL'; + const ADDRESS_REGION_CODE2 = 'AL'; + + /** @var AddressDataBuilder */ + private $addressBuilder; + + /** @var CustomerDataBuilder */ + private $customerBuilder; + + /** @var DataObjectProcessor */ + private $dataObjectProcessor; + + public function __construct($name = null, array $data = [], $dataName = '') + { + parent::__construct($name, $data, $dataName); + + $this->addressBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Customer\Api\Data\AddressDataBuilder' + ); + + $this->customerBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Customer\Api\Data\CustomerDataBuilder' + ); + + $this->dataObjectProcessor = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Reflection\DataObjectProcessor' + ); + } + + public function createSampleCustomer() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'CreateAccount', + ], + ]; + $customerDataArray = $this->dataObjectProcessor->buildOutputDataArray( + $this->createSampleCustomerDataObject(), + '\Magento\Customer\Api\Data\CustomerInterface' + ); + $requestData = ['customer' => $customerDataArray, 'password' => self::PASSWORD]; + $customerData = $this->_webApiCall($serviceInfo, $requestData); + return $customerData; + } + + /** + * Create customer using setters. + * + * @return CustomerInterface + */ + public function createSampleCustomerDataObject() + { + $this->addressBuilder + ->setCountryId('US') + ->setDefaultBilling(true) + ->setDefaultShipping(true) + ->setPostcode('75477') + ->setRegion( + Bootstrap::getObjectManager()->create('Magento\Customer\Api\Data\RegionDataBuilder') + ->setRegionCode(self::ADDRESS_REGION_CODE1) + ->setRegion('Alabama') + ->setRegionId(1) + ->create() + ) + ->setStreet(['Green str, 67']) + ->setTelephone('3468676') + ->setCity(self::ADDRESS_CITY1) + ->setFirstname('John') + ->setLastname('Smith'); + $address1 = $this->dataObjectProcessor->buildOutputDataArray( + $this->addressBuilder->create(), + 'Magento\Customer\Api\Data\AddressInterface' + ); + + $this->addressBuilder + ->setCountryId('US') + ->setDefaultBilling(false) + ->setDefaultShipping(false) + ->setPostcode('47676') + ->setRegion( + Bootstrap::getObjectManager()->create('Magento\Customer\Api\Data\RegionDataBuilder') + ->setRegionCode(self::ADDRESS_REGION_CODE2) + ->setRegion('Alabama') + ->setRegionId(1) + ->create() + ) + ->setStreet(['Black str, 48', 'Building D']) + ->setCity(self::ADDRESS_CITY2) + ->setTelephone('3234676') + ->setFirstname('John') + ->setLastname('Smith'); + $address2 = $this->dataObjectProcessor->buildOutputDataArray( + $this->addressBuilder->create(), + 'Magento\Customer\Api\Data\AddressInterface' + ); + + $customerData = [ + CustomerData::FIRSTNAME => self::FIRSTNAME, + CustomerData::LASTNAME => self::LASTNAME, + CustomerData::EMAIL => 'janedoe' . uniqid() . '@example.com', + CustomerData::CONFIRMATION => self::CONFIRMATION, + CustomerData::CREATED_AT => self::CREATED_AT, + CustomerData::CREATED_IN => self::STORE_NAME, + CustomerData::DOB => self::DOB, + CustomerData::GENDER => self::GENDER, + CustomerData::GROUP_ID => self::GROUP_ID, + CustomerData::MIDDLENAME => self::MIDDLENAME, + CustomerData::PREFIX => self::PREFIX, + CustomerData::STORE_ID => self::STORE_ID, + CustomerData::SUFFIX => self::SUFFIX, + CustomerData::TAXVAT => self::TAXVAT, + CustomerData::WEBSITE_ID => self::WEBSITE_ID, + CustomerData::KEY_ADDRESSES => [$address1, $address2], + 'custom_attributes' => [ + [ + 'attribute_code' => 'disable_auto_group_change', + 'value' => '0', + ], + ], + ]; + return $this->customerBuilder->populateWithArray($customerData)->create(); + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Rest.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Rest.php new file mode 100644 index 0000000000000000000000000000000000000000..91a12efba587b2d5a22bfccee576f1a875af0c3a --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Rest.php @@ -0,0 +1,145 @@ +<?php +/** + * Test client for REST API testing. + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestFramework\TestCase\Webapi\Adapter; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Webapi\Model\Rest\Config; + +class Rest implements \Magento\TestFramework\TestCase\Webapi\AdapterInterface +{ + /** @var \Magento\Webapi\Model\Config */ + protected $_config; + + /** @var \Magento\Integration\Model\Oauth\Consumer */ + protected static $_consumer; + + /** @var \Magento\Integration\Model\Oauth\Token */ + protected static $_token; + + /** @var string */ + protected static $_consumerKey; + + /** @var string */ + protected static $_consumerSecret; + + /** @var string */ + protected static $_verifier; + + /** @var \Magento\TestFramework\TestCase\Webapi\Adapter\Rest\CurlClient */ + protected $curlClient; + + /** @var \Magento\TestFramework\TestCase\Webapi\Adapter\Rest\DocumentationGenerator */ + protected $documentationGenerator; + + /** @var string */ + protected $defaultStoreCode; + + /** + * Initialize dependencies. + */ + public function __construct() + { + /** @var $objectManager \Magento\TestFramework\ObjectManager */ + $objectManager = Bootstrap::getObjectManager(); + $this->_config = $objectManager->get('Magento\Webapi\Model\Config'); + $this->curlClient = $objectManager->get('Magento\TestFramework\TestCase\Webapi\Adapter\Rest\CurlClient'); + $this->documentationGenerator = $objectManager->get( + 'Magento\TestFramework\TestCase\Webapi\Adapter\Rest\DocumentationGenerator' + ); + $this->defaultStoreCode = Bootstrap::getObjectManager() + ->get('Magento\Store\Model\StoreManagerInterface') + ->getStore() + ->getCode(); + } + + /** + * {@inheritdoc} + * @throws \Exception + */ + public function call($serviceInfo, $arguments = []) + { + $resourcePath = '/' . $this->defaultStoreCode . $this->_getRestResourcePath($serviceInfo); + $httpMethod = $this->_getRestHttpMethod($serviceInfo); + //Get a valid token + $accessCredentials = \Magento\TestFramework\Authentication\OauthHelper::getApiAccessCredentials(); + /** @var $oAuthClient \Magento\TestFramework\Authentication\Rest\OauthClient */ + $oAuthClient = $accessCredentials['oauth_client']; + $urlFormEncoded = false; + // we're always using JSON + $authHeader = []; + $restServiceInfo = $serviceInfo['rest']; + if (array_key_exists('token', $restServiceInfo)) { + $authHeader = $oAuthClient->buildBearerTokenAuthorizationHeader($restServiceInfo['token']); + } else { + $authHeader = $oAuthClient->buildOauthAuthorizationHeader( + $this->curlClient->constructResourceUrl($resourcePath), + $accessCredentials['key'], + $accessCredentials['secret'], + ($httpMethod == 'PUT' || $httpMethod == 'POST') && $urlFormEncoded ? $arguments : [], + $httpMethod + ); + } + $authHeader = array_merge($authHeader, ['Accept: application/json', 'Content-Type: application/json']); + switch ($httpMethod) { + case Config::HTTP_METHOD_GET: + $response = $this->curlClient->get($resourcePath, [], $authHeader); + break; + case Config::HTTP_METHOD_POST: + $response = $this->curlClient->post($resourcePath, $arguments, $authHeader); + break; + case Config::HTTP_METHOD_PUT: + $response = $this->curlClient->put($resourcePath, $arguments, $authHeader); + break; + case Config::HTTP_METHOD_DELETE: + $response = $this->curlClient->delete($resourcePath, $authHeader); + break; + default: + throw new \LogicException("HTTP method '{$httpMethod}' is not supported."); + } + if (defined('GENERATE_REST_DOCUMENTATION') && GENERATE_REST_DOCUMENTATION) { + $this->documentationGenerator->generateDocumentation($httpMethod, $resourcePath, $arguments, $response); + } + return $response; + } + + /** + * Retrieve REST endpoint from $serviceInfo array and return it to the caller. + * + * @param array $serviceInfo + * @return string + * @throws \Exception + */ + protected function _getRestResourcePath($serviceInfo) + { + if (isset($serviceInfo['rest']['resourcePath'])) { + $resourcePath = $serviceInfo['rest']['resourcePath']; + } + if (!isset($resourcePath)) { + throw new \Exception("REST endpoint cannot be identified."); + } + return $resourcePath; + } + + /** + * Retrieve HTTP method to be used in REST request. + * + * @param array $serviceInfo + * @return string + * @throws \Exception + */ + protected function _getRestHttpMethod($serviceInfo) + { + if (isset($serviceInfo['rest']['httpMethod'])) { + $httpMethod = $serviceInfo['rest']['httpMethod']; + } + if (!isset($httpMethod)) { + throw new \Exception("REST HTTP method cannot be identified."); + } + return $httpMethod; + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Rest/CurlClient.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Rest/CurlClient.php new file mode 100644 index 0000000000000000000000000000000000000000..a907a4ca8b55e8f788f7be7da3d61eb1e6bba71b --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Rest/CurlClient.php @@ -0,0 +1,308 @@ +<?php +/** + * Client for invoking REST API + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestFramework\TestCase\Webapi\Adapter\Rest; + +class CurlClient +{ + const EMPTY_REQUEST_BODY = 'Empty body'; + /** + * @var string REST URL base path + */ + protected $restBasePath = '/rest/'; + + /** + * @var array Response array + */ + protected $responseArray; + + /** + * @var array JSON Error code to error message mapping + */ + protected $_jsonErrorMessages = [ + JSON_ERROR_DEPTH => 'Maximum depth exceeded', + JSON_ERROR_STATE_MISMATCH => 'State mismatch', + JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', + JSON_ERROR_SYNTAX => 'Syntax error, invalid JSON', + ]; + + /** + * Perform HTTP GET request + * + * @param string $resourcePath Resource URL like /V1/Resource1/123 + * @param array $data + * @param array $headers + * @return mixed + */ + public function get($resourcePath, $data = [], $headers = []) + { + $url = $this->constructResourceUrl($resourcePath); + if (!empty($data)) { + $url .= '?' . http_build_query($data); + } + + $curlOpts = []; + $curlOpts[CURLOPT_CUSTOMREQUEST] = \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET; + $resp = $this->_invokeApi($url, $curlOpts, $headers); + $respArray = $this->_jsonDecode($resp["body"]); + return $respArray; + } + + /** + * Perform HTTP POST request + * + * @param string $resourcePath Resource URL like /V1/Resource1/123 + * @param array $data + * @param array $headers + * @return mixed + */ + public function post($resourcePath, $data, $headers = []) + { + return $this->_postOrPut($resourcePath, $data, false, $headers); + } + + /** + * Perform HTTP PUT request + * + * @param string $resourcePath Resource URL like /V1/Resource1/123 + * @param array $data + * @param array $headers + * @return mixed + */ + public function put($resourcePath, $data, $headers = []) + { + return $this->_postOrPut($resourcePath, $data, true, $headers); + } + + /** + * Perform HTTP DELETE request + * + * @param string $resourcePath Resource URL like /V1/Resource1/123 + * @param array $headers + * @return mixed + */ + public function delete($resourcePath, $headers = []) + { + $url = $this->constructResourceUrl($resourcePath); + + $curlOpts = []; + $curlOpts[CURLOPT_CUSTOMREQUEST] = \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE; + + $resp = $this->_invokeApi($url, $curlOpts, $headers); + $respArray = $this->_jsonDecode($resp["body"]); + + return $respArray; + } + + /** + * Perform HTTP POST or PUT request + * + * @param string $resourcePath Resource URL like /V1/Resource1/123 + * @param array $data + * @param boolean $put Set true to post data as HTTP PUT operation (update). If this value is set to false, + * HTTP POST (create) will be used + * @param array $headers + * @return mixed + */ + protected function _postOrPut($resourcePath, $data, $put = false, $headers = []) + { + $url = $this->constructResourceUrl($resourcePath); + + if (in_array("Content-Type: application/json", $headers)) { + // json encode data + if ($data != self::EMPTY_REQUEST_BODY) { + $data = $this->_jsonEncode($data); + } else { + $data = ''; + } + } + + $curlOpts = []; + if ($put) { + $curlOpts[CURLOPT_CUSTOMREQUEST] = \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT; + } else { + $curlOpts[CURLOPT_CUSTOMREQUEST] = \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST; + } + $headers[] = 'Content-Length: ' . strlen($data); + $curlOpts[CURLOPT_POSTFIELDS] = $data; + + $this->responseArray = $this->_invokeApi($url, $curlOpts, $headers); + $respBodyArray = $this->_jsonDecode($this->responseArray["body"]); + + return $respBodyArray; + } + + /** + * Set Rest base path if available + * + * @param string $restBasePath + * + * @return void + */ + public function setRestBasePath($restBasePath) + { + $this->restBasePath = $restBasePath; + } + + /** + * Get current response array + * + * @return array + */ + public function getCurrentResponseArray() + { + return $this->responseArray; + } + + /** + * @param string $resourcePath Resource URL like /V1/Resource1/123 + * @return string resource URL + * @throws \Exception + */ + public function constructResourceUrl($resourcePath) + { + return rtrim(TESTS_BASE_URL, '/') . $this->restBasePath . ltrim($resourcePath, '/'); + } + + /** + * Makes the REST api call using passed $curl object + * + * @param string $url + * @param array $additionalCurlOpts cURL Options + * @param array $headers + * @return array + * @throws \Exception + */ + protected function _invokeApi($url, $additionalCurlOpts, $headers = []) + { + // initialize cURL + $curl = curl_init($url); + if ($curl === false) { + throw new \Exception("Error Initializing cURL for baseUrl: " . $url); + } + + // get cURL options + $curlOpts = $this->_getCurlOptions($additionalCurlOpts, $headers); + + // add CURL opts + foreach ($curlOpts as $opt => $val) { + curl_setopt($curl, $opt, $val); + } + + $response = curl_exec($curl); + if ($response === false) { + throw new \Exception(curl_error($curl)); + } + + $resp = []; + $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE); + $resp["header"] = substr($response, 0, $headerSize); + $resp["body"] = substr($response, $headerSize); + + $resp["meta"] = curl_getinfo($curl); + if ($resp["meta"] === false) { + throw new \Exception(curl_error($curl)); + } + + curl_close($curl); + + $meta = $resp["meta"]; + if ($meta && $meta['http_code'] >= 400) { + throw new \Exception($resp["body"], $meta['http_code']); + } + + return $resp; + } + + /** + * Constructs and returns a curl options array + * + * @param array $customCurlOpts Additional / overridden cURL options + * @param array $headers + * @return array + */ + protected function _getCurlOptions($customCurlOpts = [], $headers = []) + { + // default curl options + $curlOpts = [ + CURLOPT_RETURNTRANSFER => true, // return result instead of echoing + CURLOPT_SSL_VERIFYPEER => false, // stop cURL from verifying the peer's certificate + CURLOPT_FOLLOWLOCATION => false, // follow redirects, Location: headers + CURLOPT_MAXREDIRS => 10, // but don't redirect more than 10 times + CURLOPT_HTTPHEADER => [], + CURLOPT_HEADER => 1, + ]; + + // merge headers + $headers = array_merge($curlOpts[CURLOPT_HTTPHEADER], $headers); + if (TESTS_XDEBUG_ENABLED) { + $headers[] = 'Cookie: XDEBUG_SESSION=' . TESTS_XDEBUG_SESSION; + } + $curlOpts[CURLOPT_HTTPHEADER] = $headers; + + // merge custom Curl Options & return + foreach ($customCurlOpts as $opt => $val) { + $curlOpts[$opt] = $val; + } + + return $curlOpts; + } + + /** + * JSON encode with error checking + * + * @param mixed $data + * @return string + * @throws \Exception + */ + protected function _jsonEncode($data) + { + $ret = json_encode($data); + $this->_checkJsonError($data); + + // return the json String + return $ret; + } + + /** + * Decode a JSON string with error checking + * + * @param string $data + * @param bool $asArray + * @throws \Exception + * @return mixed + */ + protected function _jsonDecode($data, $asArray = true) + { + $ret = json_decode($data, $asArray); + $this->_checkJsonError($data); + + // return the array + return $ret; + } + + /** + * Checks for JSON error in the latest encoding / decoding and throws an exception in case of error + * + * @throws \Exception + */ + protected function _checkJsonError() + { + $jsonError = json_last_error(); + if ($jsonError !== JSON_ERROR_NONE) { + // find appropriate error message + $message = 'Unknown JSON Error'; + if (isset($this->_jsonErrorMessages[$jsonError])) { + $message = $this->_jsonErrorMessages[$jsonError]; + } + + throw new \Exception( + 'JSON Encoding / Decoding error: ' . $message . var_export(func_get_arg(0), true), + $jsonError + ); + } + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Rest/DocumentationGenerator.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Rest/DocumentationGenerator.php new file mode 100644 index 0000000000000000000000000000000000000000..27cce9d7d6203ab6e45b1e4c7d19d1e49afaeeb5 --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Rest/DocumentationGenerator.php @@ -0,0 +1,238 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestFramework\TestCase\Webapi\Adapter\Rest; + +/** + * Generator for documentation + * + */ +class DocumentationGenerator +{ + /** + * Generate documentation based on request-response data during REST requests. + * + * @param string $httpMethod + * @param string $resourcePath + * @param array $arguments + * @param array $response + */ + public function generateDocumentation($httpMethod, $resourcePath, $arguments, $response) + { + $content = $this->generateHtmlContent($httpMethod, $resourcePath, $arguments, $response); + $filePath = $this->generateFileName($resourcePath); + if (is_null($filePath)) { + return; + } + if (!is_writable(dirname($filePath))) { + throw new \RuntimeException('Cannot write to documentation directory.'); + } elseif (file_exists($filePath)) { + $fileContent = file_get_contents($filePath); + $endHtml = $this->generateHtmlFooter(); + $fileContent = str_replace($endHtml, '', $fileContent); + $content = "{$fileContent}{$content}"; + unlink($filePath); + file_put_contents($filePath, $content, FILE_APPEND); + } else { + file_put_contents($filePath, $content, FILE_APPEND); + } + } + + /** + * Prepare HTML for the generated documentation. + * + * @param string $httpMethod + * @param string $resourcePath + * @param array $arguments + * @param array $response + * @return string + */ + protected function generateHtmlContent($httpMethod, $resourcePath, $arguments, $response) + { + if (empty($arguments)) { + $arguments = 'This call does not accept a request body.'; + $requestParametersHtml = ''; + } else { + $requestParameters = $this->retrieveParametersAsHtml($arguments); + $arguments = json_encode($arguments, JSON_PRETTY_PRINT); + $requestParametersHtml = <<<HTML + <table class="docutils field-list" frame="void" rules="none" width="400"> + <colgroup> + <col width="35%" class="field-name"> + <col width="65%" class="field-body"> + </colgroup> + <tbody valign="top"> + <tr class="field-odd field"> + <th class="field-name">Request parameters:</th> + <td class="field-body"> + <ul class="first last simple"> + {$requestParameters} + </ul> + </td> + </tr> + </tbody> + </table> +HTML; + } + if (is_array($response)) { + $responseArrayKeys = array_keys($response); + $responseParameters = "Parameters should be specified manually."; + foreach ($responseArrayKeys as $key) { + if (!is_int($key)) { + $responseParameters = ''; + break; + } + } + } + if (empty($responseParameters)) { + $responseParameters = $this->retrieveParametersAsHtml($response); + } + $response = json_encode($response, JSON_PRETTY_PRINT); + $responseParametersHtml = <<<HTML + <table class="docutils field-list" frame="void" rules="none" width="400"> + <colgroup> + <col width="35%" class="field-name"> + <col width="65%" class="field-body"> + </colgroup> + <tbody valign="top"> + <tr class="field-odd field"> + <th class="field-name">Response attributes:</th> + <td class="field-body"> + <ul class="first last simple"> + {$responseParameters} + </ul> + </td> + </tr> + </tbody> + </table> +HTML; + $resourcePath = urldecode($resourcePath); + $resource = str_replace('/', '-', preg_replace('#/\w*/V\d+/(.*)#', '${1}', $resourcePath)); + $lowerCaseResource = strtolower($resource); + $lowerCaseMethod = strtolower($httpMethod); + $beginningHtml = <<<HTML +<div class="col-xs-9" role="main"> + <div class="bs-docs-section"> +HTML; + $headingHtml = <<<HTML + <h2 class="api2" id="$lowerCaseResource">$resource</h2> + <h3 class="api3" id="$lowerCaseMethod-$lowerCaseResource">$httpMethod $resourcePath</h3> + <h4 class="api4">Request</h4> +HTML; + $responseHtml = <<<HTML + <h4 class="api4" id=â€$lowerCaseResource-response>Response</h4> +HTML; + $requestResponseParametersHtml = <<<HTML + <h3 class="api3" id="$lowerCaseResource-parameters">Request and response parameters</h3> +HTML; + $endHtml = $this->generateHtmlFooter(); + $content = "{$beginningHtml}{$headingHtml}<pre>{$arguments}</pre>{$responseHtml}<pre>{$response}" + . "</pre>{$requestResponseParametersHtml}{$requestParametersHtml}{$responseParametersHtml}{$endHtml}"; + return $content; + } + + /** + * Generate the end html text; + * + * @return string + */ + protected function generateHtmlFooter() + { + $endHtml = <<<HTML + <h3 class="api3" id="products-responses">Response codes</h3> + <table class="docutils field-list" frame="void" rules="none" width="400"> + <colgroup> + <col width="35%" class="field-name"> + <col width="65%" class="field-body"> + </colgroup> + <tbody valign="top"> + <tr class="field-odd field"> + <th class="field-name">Normal response codes:</th> + <td class="field-body"> + <ul class="first last simple"> + <li><strong>SUCCESS_CODE</strong> - SUCCESS_DESCRIPTION</li> + </ul> + </td> + </tr> + </tbody> + </table> + <table class="docutils field-list" frame="void" rules="none" width="400"> + <colgroup> + <col width="35%" class="field-name"> + <col width="65%" class="field-body"> + </colgroup> + <tbody valign="top"> + <tr class="field-odd field"> + <th class="field-name">Error response codes:</th> + <td class="field-body"> + <ul class="first last simple"> + <li><strong>ERROR_CODE</strong> - ERROR_DESCRIPTION</li> + </ul> + </td> + </tr> + </tbody> + </table> + </div> +</div> +HTML; + return $endHtml; + } + + /** + * Generate a name of file + * + * @return string|null + * @throws \RuntimeException + */ + protected function generateFileName() + { + $varDir = realpath(__DIR__ . '/../../../../../../..') . '/var'; + $documentationDir = $varDir . '/log/rest-documentation/'; + $debugBackTrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + $pathToFile = $documentationDir; + $fileName = null; + foreach ($debugBackTrace as $traceItem) { + /** Test invocation trace item is the only item which has 3 elements, other trace items have 5 elements */ + if (count($traceItem) == 3) { + /** Remove 'test' prefix from method name, e.g. testCreate => create */ + $fileName = lcfirst(substr($traceItem['function'], 4)); + /** Remove 'Test' suffix from test class name */ + $pathToFile .= str_replace('\\', '/', substr($traceItem['class'], 0, -4)) . '/'; + break; + } + } + if (!file_exists($pathToFile)) { + if (!mkdir($pathToFile, 0755, true)) { + throw new \RuntimeException('Unable to create missing directory for REST documentation generation'); + } + } + if (!is_null($fileName)) { + $filePath = $pathToFile . $fileName . '.html'; + return $filePath; + } + return null; + } + + /** + * Retrieve parameters of response/request + * + * @param array|string $parameters + * @return string + */ + protected function retrieveParametersAsHtml($parameters) + { + $parametersAsHtml = ''; + if (is_array($parameters)) { + foreach (array_keys($parameters) as $parameter) { + $parametersAsHtml = $parametersAsHtml . '<li><strong>' . $parameter . + '</strong> (<em>Change type manually!</em>) TBD.</li>'; + } + } else { + $parametersAsHtml = '<li><strong>' . 'scalar_value' . + '</strong> (<em>Change type manually!</em>) TBD.</li>'; + } + return $parametersAsHtml; + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Soap.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Soap.php new file mode 100644 index 0000000000000000000000000000000000000000..73f6d8a6582c314bf4e7447452e89e8f77d97be9 --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Soap.php @@ -0,0 +1,238 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestFramework\TestCase\Webapi\Adapter; + +use Magento\Framework\Api\SimpleDataObjectConverter; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Webapi\Controller\Soap\Request\Handler as SoapHandler; + +/** + * Test client for SOAP API testing. + */ +class Soap implements \Magento\TestFramework\TestCase\Webapi\AdapterInterface +{ + const WSDL_BASE_PATH = '/soap'; + + /** + * SOAP client initialized with different WSDLs. + * + * @var \Zend\Soap\Client[] + */ + protected $_soapClients = []; + + /** + * @var \Magento\Webapi\Model\Soap\Config + */ + protected $_soapConfig; + + /** + * @var \Magento\Webapi\Helper\Data + */ + protected $_helper; + + /** + * @var SimpleDataObjectConverter + */ + protected $_converter; + + /** + * Initialize dependencies. + */ + public function __construct() + { + /** @var $objectManager \Magento\TestFramework\ObjectManager */ + $objectManager = Bootstrap::getObjectManager(); + $this->_soapConfig = $objectManager->get('Magento\Webapi\Model\Soap\Config'); + $this->_helper = $objectManager->get('Magento\Webapi\Helper\Data'); + $this->_converter = $objectManager->get('Magento\Framework\Api\SimpleDataObjectConverter'); + } + + /** + * {@inheritdoc} + */ + public function call($serviceInfo, $arguments = []) + { + $soapOperation = $this->_getSoapOperation($serviceInfo); + $arguments = $this->_converter->convertKeysToCamelCase($arguments); + $soapResponse = $this->_getSoapClient($serviceInfo)->$soapOperation($arguments); + //Convert to snake case for tests to use same assertion data for both SOAP and REST tests + $result = (is_array($soapResponse) || is_object($soapResponse)) + ? $this->toSnakeCase($this->_converter->convertStdObjectToArray($soapResponse, true)) + : $soapResponse; + /** Remove result wrappers */ + $result = isset($result[SoapHandler::RESULT_NODE_NAME]) ? $result[SoapHandler::RESULT_NODE_NAME] : $result; + return $result; + } + + /** + * Get proper SOAP client instance that is initialized with with WSDL corresponding to requested service interface. + * + * @param string $serviceInfo PHP service interface name, should include version if present + * @return \Zend\Soap\Client + */ + protected function _getSoapClient($serviceInfo) + { + $wsdlUrl = $this->generateWsdlUrl( + [$this->_getSoapServiceName($serviceInfo) . $this->_getSoapServiceVersion($serviceInfo)] + ); + /** Check if there is SOAP client initialized with requested WSDL available */ + if (!isset($this->_soapClients[$wsdlUrl])) { + $token = isset($serviceInfo['soap']['token']) ? $serviceInfo['soap']['token'] : null; + $this->_soapClients[$wsdlUrl] = $this->instantiateSoapClient($wsdlUrl, $token); + } + return $this->_soapClients[$wsdlUrl]; + } + + /** + * Create SOAP client instance and initialize it with provided WSDL URL. + * + * @param string $wsdlUrl + * @param string $token Authentication token + * @return \Zend\Soap\Client + */ + public function instantiateSoapClient($wsdlUrl, $token = null) + { + $accessCredentials = $token + ? $token + : \Magento\TestFramework\Authentication\OauthHelper::getApiAccessCredentials()['key']; + $opts = ['http' => ['header' => "Authorization: Bearer " . $accessCredentials]]; + $context = stream_context_create($opts); + $soapClient = new \Zend\Soap\Client($wsdlUrl); + $soapClient->setSoapVersion(SOAP_1_2); + $soapClient->setStreamContext($context); + if (TESTS_XDEBUG_ENABLED) { + $soapClient->setCookie('XDEBUG_SESSION', 1); + } + return $soapClient; + } + + /** + * Generate WSDL URL. + * + * @param array $services e.g.<pre> + * array( + * 'catalogProductV1', + * 'customerV2' + * );</pre> + * @return string + */ + public function generateWsdlUrl($services) + { + /** Sort list of services to avoid having different WSDL URLs for the identical lists of services. */ + //TODO: This may change since same resource of multiple versions may be allowed after namespace changes + ksort($services); + /** @var \Magento\Store\Model\StoreManagerInterface $storeManager */ + $storeManager = Bootstrap::getObjectManager()->get('Magento\Store\Model\StoreManagerInterface'); + $storeCode = $storeManager->getStore()->getCode(); + /** TESTS_BASE_URL is initialized in PHPUnit configuration */ + $wsdlUrl = rtrim(TESTS_BASE_URL, '/') . self::WSDL_BASE_PATH . '/' . $storeCode . '?wsdl=1&services='; + $wsdlResourceArray = []; + foreach ($services as $serviceName) { + $wsdlResourceArray[] = $serviceName; + } + return $wsdlUrl . implode(",", $wsdlResourceArray); + } + + /** + * Retrieve SOAP operation name from available service info. + * + * @param array $serviceInfo + * @return string + * @throws \LogicException + */ + protected function _getSoapOperation($serviceInfo) + { + if (isset($serviceInfo['soap']['operation'])) { + $soapOperation = $serviceInfo['soap']['operation']; + } elseif (isset($serviceInfo['serviceInterface']) && isset($serviceInfo['method'])) { + $soapOperation = $this->_soapConfig->getSoapOperation( + $serviceInfo['serviceInterface'], + $serviceInfo['method'] + ); + } else { + throw new \LogicException("SOAP operation cannot be identified."); + } + return $soapOperation; + } + + /** + * Retrieve service version from available service info. + * + * @param array $serviceInfo + * @return string + * @throws \LogicException + */ + protected function _getSoapServiceVersion($serviceInfo) + { + if (isset($serviceInfo['soap']['operation'])) { + /* + TODO: Need to rework this to remove version call for serviceInfo array with 'operation' key + since version will be part of the service name + */ + return ''; + } elseif (isset($serviceInfo['serviceInterface'])) { + preg_match( + \Magento\Webapi\Model\Config::SERVICE_CLASS_PATTERN, + $serviceInfo['serviceInterface'], + $matches + ); + if (isset($matches[3])) { + $version = $matches[3]; + } else { + //TODO: Need to add this temporary version until version is added back for new MSC based services + $version = 1; + //throw new \LogicException("Service interface name is invalid."); + } + } else { + throw new \LogicException("Service version cannot be identified."); + } + /** Normalize version */ + $version = 'V' . ltrim($version, 'vV'); + return $version; + } + + /** + * Retrieve service name from available service info. + * + * @param array $serviceInfo + * @return string + * @throws \LogicException + */ + protected function _getSoapServiceName($serviceInfo) + { + if (isset($serviceInfo['soap']['service'])) { + $serviceName = $serviceInfo['soap']['service']; + } elseif (isset($serviceInfo['serviceInterface'])) { + $serviceName = $this->_helper->getServiceName($serviceInfo['serviceInterface'], false); + } else { + throw new \LogicException("Service name cannot be identified."); + } + return $serviceName; + } + + /** + * Recursively transform array keys from camelCase to snake_case. + * + * Utility method for converting SOAP responses. Webapi framework's SOAP processing outputs + * snake case Data Object properties(ex. item_id) as camel case(itemId) to adhere to the WSDL. + * This method allows tests to use the same data for asserting both SOAP and REST responses. + * + * @param array $objectData An array of data. + * @return array The array with all camelCase keys converted to snake_case. + */ + protected function toSnakeCase(array $objectData) + { + $data = []; + foreach ($objectData as $key => $value) { + $key = strtolower(preg_replace("/(?<=\\w)(?=[A-Z])/", "_$1", $key)); + if (is_array($value)) { + $data[$key] = $this->toSnakeCase($value); + } else { + $data[$key] = $value; + } + } + return $data; + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/AdapterInterface.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/AdapterInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..e34d3cb702d6ae71e46ac6778660ec42a3f75d8f --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/AdapterInterface.php @@ -0,0 +1,37 @@ +<?php +/** + * API tests adapter interface. + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestFramework\TestCase\Webapi; + +interface AdapterInterface +{ + /** + * Perform call to the specified service method. + * + * @param array $serviceInfo <pre> + * array( + * 'rest' => array( + * 'resourcePath' => $resourcePath, // e.g. /products/:id + * 'httpMethod' => $httpMethod, // e.g. GET + * 'token' => '21hasbtlaqy8t3mj73kjh71cxxkqj4aq' // optional : for token based Authentication. Will + * override default Oauth based authentication provided + * by test framework + * ), + * 'soap' => array( + * 'service' => $soapService, // soap service name with Version suffix e.g. catalogProductV1, customerV2 + * 'operation' => $operation // soap operation name e.g. catalogProductCreate + * ), + * OR + * 'serviceInterface' => $phpServiceInterfaceName, // e.g. \Magento\Catalog\Api\ProductInterface + * 'method' => $serviceMethodName // e.g. create + * 'entityId' => $entityId // is used in REST route placeholder (if applicable) + * ); + * </pre> + * @param array $arguments + * @return array|string|int|float|bool + */ + public function call($serviceInfo, $arguments = []); +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Curl.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Curl.php new file mode 100644 index 0000000000000000000000000000000000000000..655f31579c729e40b5922e5f39f87ae66c4beff7 --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Curl.php @@ -0,0 +1,93 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\TestFramework\TestCase\Webapi; + +/** + * A Curl client that can be called independently, outside of REST controller. + * + * Used by CookieManager tests. + */ +class Curl extends Adapter\Rest\CurlClient +{ + const COOKIE_HEADER = 'Set-Cookie: '; + + /** + * @param string $resourcePath Resource URL like /V1/Resource1/123 + * @return string resource URL + * @throws \Exception + */ + public function constructResourceUrl($resourcePath) + { + return rtrim(TESTS_BASE_URL, '/') . ltrim($resourcePath, '/'); + } + + /** + * Perform HTTP GET request + * + * @param string $resourcePath Resource URL like /V1/Resource1/123 + * @param array $data + * @param array $headers + * @return array + */ + public function get($resourcePath, $data = [], $headers = []) + { + $url = $this->constructResourceUrl($resourcePath); + if (!empty($data)) { + $url .= '?' . http_build_query($data); + } + + $curlOpts = []; + $curlOpts[CURLOPT_CUSTOMREQUEST] = \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET; + $curlOpts[CURLOPT_SSLVERSION] = 3; + $response = $this->_invokeApi($url, $curlOpts, $headers); + $response['cookies'] = $this->cookieParse($response['header']); + return $response; + } + + /** + * Takes a string in the form of an HTTP header block, returns cookie data. + * + * Return array is in the form of: + * [ + * [ + * 'name' = <cookie_name>, + * 'value' = <cookie_value>, + * <cookie_metadata_name> => <cookie_metadata_value> || 'true' + * ], + * ] + * + * @param $headerBlock + * @return array + */ + private function cookieParse($headerBlock) + { + $header = explode("\r\n", $headerBlock); + $cookies = []; + foreach ($header as $line) { + $line = trim($line); + if (substr($line, 0, strlen(self::COOKIE_HEADER)) == self::COOKIE_HEADER) { + $line = trim(substr($line, strlen(self::COOKIE_HEADER))); + $cookieData = []; + // Check if cookie contains attributes + if (strpos($line, ';') === false) { + // no attributes, just name and value + list($cookieData['name'], $cookieData['value']) = explode('=', $line); + } else { + // has attributes, must parse them out and loop through + list($nvPair, $cookieMetadata) = explode(';', $line, 2); + list($cookieData['name'], $cookieData['value']) = explode('=', $nvPair); + $rawCookieData = explode(';', $cookieMetadata); + foreach ($rawCookieData as $keyValuePairs) { + list($key, $value) = array_merge(explode('=', $keyValuePairs), ['true']); + $cookieData[strtolower(trim($key))] = trim($value); + } + } + $cookies[] = $cookieData; + } + } + return $cookies; + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/WebapiAbstract.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/WebapiAbstract.php new file mode 100644 index 0000000000000000000000000000000000000000..d02247b75a0838f352d1f3844dff87ab36cf475e --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/WebapiAbstract.php @@ -0,0 +1,665 @@ +<?php +/** + * Generic test case for Web API functional tests. + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestFramework\TestCase; + +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Filesystem; +use Magento\Webapi\Model\Soap\Fault; + +abstract class WebapiAbstract extends \PHPUnit_Framework_TestCase +{ + /** TODO: Reconsider implementation of fixture-management methods after implementing several tests */ + /**#@+ + * Auto tear down options in setFixture + */ + const AUTO_TEAR_DOWN_DISABLED = 0; + const AUTO_TEAR_DOWN_AFTER_METHOD = 1; + const AUTO_TEAR_DOWN_AFTER_CLASS = 2; + /**#@-*/ + + /**#@+ + * Web API adapters that are used to perform actual calls. + */ + const ADAPTER_SOAP = 'soap'; + const ADAPTER_REST = 'rest'; + /**#@-*/ + + /** + * Application cache model. + * + * @var \Magento\Framework\App\Cache + */ + protected $_appCache; + + /** + * The list of models to be deleted automatically in tearDown(). + * + * @var array + */ + protected $_modelsToDelete = []; + + /** + * Namespace for fixtures is different for each test case. + * + * @var string + */ + protected static $_fixturesNamespace; + + /** + * The list of registered fixtures. + * + * @var array + */ + protected static $_fixtures = []; + + /** + * Fixtures to be deleted in tearDown(). + * + * @var array + */ + protected static $_methodLevelFixtures = []; + + /** + * Fixtures to be deleted in tearDownAfterClass(). + * + * @var array + */ + protected static $_classLevelFixtures = []; + + /** + * Original Magento config values. + * + * @var array + */ + protected $_origConfigValues = []; + + /** + * The list of instantiated Web API adapters. + * + * @var \Magento\TestFramework\TestCase\Webapi\AdapterInterface[] + */ + protected $_webApiAdapters; + + /** + * The list of available Web API adapters. + * + * @var array + */ + protected $_webApiAdaptersMap = [ + self::ADAPTER_SOAP => 'Magento\TestFramework\TestCase\Webapi\Adapter\Soap', + self::ADAPTER_REST => 'Magento\TestFramework\TestCase\Webapi\Adapter\Rest', + ]; + + /** + * Initialize fixture namespaces. + */ + public static function setUpBeforeClass() + { + parent::setUpBeforeClass(); + self::_setFixtureNamespace(); + } + + /** + * Run garbage collector for cleaning memory + * + * @return void + */ + public static function tearDownAfterClass() + { + //clear garbage in memory + if (version_compare(PHP_VERSION, '5.3', '>=')) { + gc_collect_cycles(); + } + + $fixtureNamespace = self::_getFixtureNamespace(); + if (isset(self::$_classLevelFixtures[$fixtureNamespace]) + && count(self::$_classLevelFixtures[$fixtureNamespace]) + ) { + self::_deleteFixtures(self::$_classLevelFixtures[$fixtureNamespace]); + } + + //ever disable secure area on class down + self::_enableSecureArea(false); + self::_unsetFixtureNamespace(); + parent::tearDownAfterClass(); + } + + /** + * Call safe delete for models which added to delete list + * Restore config values changed during the test + * + * @return void + */ + protected function tearDown() + { + $fixtureNamespace = self::_getFixtureNamespace(); + if (isset(self::$_methodLevelFixtures[$fixtureNamespace]) + && count(self::$_methodLevelFixtures[$fixtureNamespace]) + ) { + self::_deleteFixtures(self::$_methodLevelFixtures[$fixtureNamespace]); + } + $this->_callModelsDelete(); + $this->_restoreAppConfig(); + parent::tearDown(); + } + + /** + * Perform Web API call to the system under test. + * + * @see \Magento\TestFramework\TestCase\Webapi\AdapterInterface::call() + * @param array $serviceInfo + * @param array $arguments + * @param string|null $webApiAdapterCode + * @return array|int|string|float|bool Web API call results + */ + protected function _webApiCall($serviceInfo, $arguments = [], $webApiAdapterCode = null) + { + if (is_null($webApiAdapterCode)) { + /** Default adapter code is defined in PHPUnit configuration */ + $webApiAdapterCode = strtolower(TESTS_WEB_API_ADAPTER); + } + return $this->_getWebApiAdapter($webApiAdapterCode)->call($serviceInfo, $arguments); + } + + /** + * Mark test to be executed for SOAP adapter only. + */ + protected function _markTestAsSoapOnly($message = null) + { + if (TESTS_WEB_API_ADAPTER != self::ADAPTER_SOAP) { + $this->markTestSkipped($message ? $message : "The test is intended to be executed for SOAP adapter only."); + } + } + + /** + * Mark test to be executed for REST adapter only. + */ + protected function _markTestAsRestOnly($message = null) + { + if (TESTS_WEB_API_ADAPTER != self::ADAPTER_REST) { + $this->markTestSkipped($message ? $message : "The test is intended to be executed for REST adapter only."); + } + } + + /** + * Set fixture to registry + * + * @param string $key + * @param mixed $fixture + * @param int $tearDown + * @return void + */ + public static function setFixture($key, $fixture, $tearDown = self::AUTO_TEAR_DOWN_AFTER_METHOD) + { + $fixturesNamespace = self::_getFixtureNamespace(); + if (!isset(self::$_fixtures[$fixturesNamespace])) { + self::$_fixtures[$fixturesNamespace] = []; + } + self::$_fixtures[$fixturesNamespace][$key] = $fixture; + if ($tearDown == self::AUTO_TEAR_DOWN_AFTER_METHOD) { + if (!isset(self::$_methodLevelFixtures[$fixturesNamespace])) { + self::$_methodLevelFixtures[$fixturesNamespace] = []; + } + self::$_methodLevelFixtures[$fixturesNamespace][] = $key; + } else { + if ($tearDown == self::AUTO_TEAR_DOWN_AFTER_CLASS) { + if (!isset(self::$_classLevelFixtures[$fixturesNamespace])) { + self::$_classLevelFixtures[$fixturesNamespace] = []; + } + self::$_classLevelFixtures[$fixturesNamespace][] = $key; + } + } + } + + /** + * Get fixture by key + * + * @param string $key + * @return mixed + */ + public static function getFixture($key) + { + $fixturesNamespace = self::_getFixtureNamespace(); + if (array_key_exists($key, self::$_fixtures[$fixturesNamespace])) { + return self::$_fixtures[$fixturesNamespace][$key]; + } + return null; + } + + /** + * Call safe delete for model + * + * @param \Magento\Framework\Model\AbstractModel $model + * @param bool $secure + * @return \Magento\TestFramework\TestCase\WebapiAbstract + */ + public static function callModelDelete($model, $secure = false) + { + if ($model instanceof \Magento\Framework\Model\AbstractModel && $model->getId()) { + if ($secure) { + self::_enableSecureArea(); + } + $model->delete(); + if ($secure) { + self::_enableSecureArea(false); + } + } + } + + /** + * Call safe delete for model + * + * @param \Magento\Framework\Model\AbstractModel $model + * @param bool $secure + * @return \Magento\TestFramework\TestCase\WebapiAbstract + */ + public function addModelToDelete($model, $secure = false) + { + $this->_modelsToDelete[] = ['model' => $model, 'secure' => $secure]; + return $this; + } + + /** + * Get Web API adapter (create if requested one does not exist). + * + * @param string $webApiAdapterCode + * @return \Magento\TestFramework\TestCase\Webapi\AdapterInterface + * @throws \LogicException When requested Web API adapter is not declared + */ + protected function _getWebApiAdapter($webApiAdapterCode) + { + if (!isset($this->_webApiAdapters[$webApiAdapterCode])) { + if (!isset($this->_webApiAdaptersMap[$webApiAdapterCode])) { + throw new \LogicException( + sprintf('Declaration of the requested Web API adapter "%s" was not found.', $webApiAdapterCode) + ); + } + $this->_webApiAdapters[$webApiAdapterCode] = new $this->_webApiAdaptersMap[$webApiAdapterCode](); + } + return $this->_webApiAdapters[$webApiAdapterCode]; + } + + /** + * Set fixtures namespace + * + * @throws \RuntimeException + */ + protected static function _setFixtureNamespace() + { + if (!is_null(self::$_fixturesNamespace)) { + throw new \RuntimeException('Fixture namespace is already set.'); + } + self::$_fixturesNamespace = uniqid(); + } + + /** + * Unset fixtures namespace + */ + protected static function _unsetFixtureNamespace() + { + $fixturesNamespace = self::_getFixtureNamespace(); + unset(self::$_fixtures[$fixturesNamespace]); + self::$_fixturesNamespace = null; + } + + /** + * Get fixtures namespace + * + * @throws \RuntimeException + * @return string + */ + protected static function _getFixtureNamespace() + { + $fixtureNamespace = self::$_fixturesNamespace; + if (is_null($fixtureNamespace)) { + throw new \RuntimeException('Fixture namespace must be set.'); + } + return $fixtureNamespace; + } + + /** + * Enable secure/admin area + * + * @param bool $flag + * @return void + */ + protected static function _enableSecureArea($flag = true) + { + /** @var $objectManager \Magento\TestFramework\ObjectManager */ + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $objectManager->get('Magento\Framework\Registry')->unregister('isSecureArea'); + if ($flag) { + $objectManager->get('Magento\Framework\Registry')->register('isSecureArea', $flag); + } + } + + /** + * Call delete models from list + * + * @return \Magento\TestFramework\TestCase\WebapiAbstract + */ + protected function _callModelsDelete() + { + if ($this->_modelsToDelete) { + foreach ($this->_modelsToDelete as $key => $modelData) { + /** @var $model \Magento\Framework\Model\AbstractModel */ + $model = $modelData['model']; + $this->callModelDelete($model, $modelData['secure']); + unset($this->_modelsToDelete[$key]); + } + } + return $this; + } + + /** + * Check if all error messages are expected ones + * + * @param array $expectedMessages + * @param array $receivedMessages + */ + protected function _assertMessagesEqual($expectedMessages, $receivedMessages) + { + foreach ($receivedMessages as $message) { + $this->assertContains($message, $expectedMessages, "Unexpected message: '{$message}'"); + } + $expectedErrorsCount = count($expectedMessages); + $this->assertCount($expectedErrorsCount, $receivedMessages, 'Invalid messages quantity received'); + } + + /** + * Delete array of fixtures + * + * @param array $fixtures + */ + protected static function _deleteFixtures($fixtures) + { + foreach ($fixtures as $fixture) { + self::deleteFixture($fixture, true); + } + } + + /** + * Delete fixture by key + * + * @param string $key + * @param bool $secure + * @return void + */ + public static function deleteFixture($key, $secure = false) + { + $fixturesNamespace = self::_getFixtureNamespace(); + if (array_key_exists($key, self::$_fixtures[$fixturesNamespace])) { + self::callModelDelete(self::$_fixtures[$fixturesNamespace][$key], $secure); + unset(self::$_fixtures[$fixturesNamespace][$key]); + } + } + + /** TODO: Remove methods below if not used, otherwise fix them (after having some tests implemented)*/ + + /** + * Get application cache model + * + * @return \Magento\Framework\App\Cache + */ + protected function _getAppCache() + { + if (null === $this->_appCache) { + //set application path + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Framework\App\Config\ScopeConfigInterface $config */ + $config = $objectManager->get('Magento\Framework\App\Config\ScopeConfigInterface'); + $options = $config->getOptions(); + $currentCacheDir = $options->getCacheDir(); + $currentEtcDir = $options->getEtcDir(); + /** @var Filesystem $filesystem */ + $filesystem = $objectManager->get('Magento\Framework\Filesystem'); + $options->setCacheDir($filesystem->getDirectoryRead(DirectoryList::CACHE)->getAbsolutePath()); + $options->setEtcDir($filesystem->getDirectoryRead(DirectoryList::CONFIG)->getAbsolutePath()); + + $this->_appCache = $objectManager->get('Magento\Framework\App\Cache'); + + //revert paths options + $options->setCacheDir($currentCacheDir); + $options->setEtcDir($currentEtcDir); + } + return $this->_appCache; + } + + /** + * Clean config cache of application + * + * @return bool + */ + protected function _cleanAppConfigCache() + { + return $this->_getAppCache()->clean(\Magento\Framework\App\Config::CACHE_TAG); + } + + /** + * Update application config data + * + * @param string $path Config path with the form "section/group/node" + * @param string|int|null $value Value of config item + * @param bool $cleanAppCache If TRUE application cache will be refreshed + * @param bool $updateLocalConfig If TRUE local config object will be updated too + * @param bool $restore If TRUE config value will be restored after test run + * @return \Magento\TestFramework\TestCase\WebapiAbstract + * @throws \RuntimeException + */ + protected function _updateAppConfig( + $path, + $value, + $cleanAppCache = true, + $updateLocalConfig = false, + $restore = false + ) { + list($section, $group, $node) = explode('/', $path); + + if (!$section || !$group || !$node) { + throw new \RuntimeException( + sprintf('Config path must have view as "section/group/node" but now it "%s"', $path) + ); + } + + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var $config \Magento\Backend\Model\Config */ + $config = $objectManager->create('Magento\Backend\Model\Config'); + $data[$group]['fields'][$node]['value'] = $value; + $config->setSection($section)->setGroups($data)->save(); + + if ($restore && !isset($this->_origConfigValues[$path])) { + $this->_origConfigValues[$path] = (string)$objectManager->get( + 'Magento\Framework\App\Config\ScopeConfigInterface' + )->getNode( + $path, + 'default' + ); + } + + //refresh local cache + if ($cleanAppCache) { + if ($updateLocalConfig) { + $objectManager->get('Magento\Framework\App\Config\ReinitableConfigInterface')->reinit(); + $objectManager->get('Magento\Store\Model\StoreManagerInterface')->reinitStores(); + } + + if (!$this->_cleanAppConfigCache()) { + throw new \RuntimeException('Application configuration cache cannot be cleaned.'); + } + } + + return $this; + } + + /** + * Restore config values changed during tests + */ + protected function _restoreAppConfig() + { + foreach ($this->_origConfigValues as $configPath => $origValue) { + $this->_updateAppConfig($configPath, $origValue, true, true); + } + } + + /** + * @param \Exception $e + * @return array + * <pre> ex. + * 'message' => "No such entity with %fieldName1 = %value1, %fieldName2 = %value2" + * 'parameters' => [ + * "fieldName1" => "email", + * "value1" => "dummy@example.com", + * "fieldName2" => "websiteId", + * "value2" => 0 + * ] + * + * </pre> + */ + public function processRestExceptionResult(\Exception $e) + { + $error = json_decode($e->getMessage(), true); + //Remove line breaks and replace with space + $error['message'] = trim(preg_replace('/\s+/', ' ', $error['message'])); + // remove trace and type, will only be present if server is in dev mode + unset($error['trace']); + unset($error['type']); + return $error; + } + + /** + * Verify that SOAP fault contains necessary information. + * + * @param \SoapFault $soapFault + * @param string $expectedMessage + * @param string $expectedFaultCode + * @param array $expectedErrorParams + * @param array $expectedWrappedErrors + * @param string $traceString + */ + protected function checkSoapFault( + $soapFault, + $expectedMessage, + $expectedFaultCode, + $expectedErrorParams = [], + $expectedWrappedErrors = [], + $traceString = null + ) { + $this->assertContains($expectedMessage, $soapFault->getMessage(), "Fault message is invalid."); + + $errorDetailsNode = 'GenericFault'; + $errorDetails = isset($soapFault->detail->$errorDetailsNode) ? $soapFault->detail->$errorDetailsNode : null; + if (!empty($expectedErrorParams) || !empty($expectedWrappedErrors)) { + /** Check SOAP fault details */ + $this->assertNotNull($errorDetails, "Details must be present."); + $this->_checkFaultParams($expectedErrorParams, $errorDetails); + $this->_checkWrappedErrors($expectedWrappedErrors, $errorDetails); + } + + if ($traceString) { + /** Check error trace */ + $traceNode = Fault::NODE_DETAIL_TRACE; + $mode = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\App\State') + ->getMode(); + if ($mode == \Magento\Framework\App\State::MODE_DEVELOPER) { + /** Developer mode changes tested behavior and it cannot properly be tested for now */ + $this->assertContains( + $traceString, + $errorDetails->$traceNode, + 'Trace Information is incorrect.' + ); + } else { + $this->assertNull($errorDetails, "Details are not expected."); + } + } + + /** Check SOAP fault code */ + $this->assertNotNull($soapFault->faultcode, "Fault code must not be empty."); + $this->assertEquals($expectedFaultCode, $soapFault->faultcode, "Fault code is invalid."); + } + + /** + * Check additional error parameters. + * + * @param array $expectedErrorParams + * @param \stdClass $errorDetails + */ + protected function _checkFaultParams($expectedErrorParams, $errorDetails) + { + $paramsNode = Fault::NODE_DETAIL_PARAMETERS; + if ($expectedErrorParams) { + $paramNode = Fault::NODE_DETAIL_PARAMETER; + $paramKey = Fault::NODE_DETAIL_PARAMETER_KEY; + $paramValue = Fault::NODE_DETAIL_PARAMETER_VALUE; + $actualParams = []; + if (isset($errorDetails->$paramsNode->$paramNode)) { + if (is_array($errorDetails->$paramsNode->$paramNode)) { + foreach ($errorDetails->$paramsNode->$paramNode as $param) { + $actualParams[$param->$paramKey] = $param->$paramValue; + } + } else { + $param = $errorDetails->$paramsNode->$paramNode; + $actualParams[$param->$paramKey] = $param->$paramValue; + } + } + $this->assertEquals( + $expectedErrorParams, + $actualParams, + "Parameters in fault details are invalid." + ); + } else { + $this->assertFalse(isset($errorDetails->$paramsNode), "Parameters are not expected in fault details."); + } + } + + /** + * Check additional wrapped errors. + * + * @param array $expectedWrappedErrors + * @param \stdClass $errorDetails + */ + protected function _checkWrappedErrors($expectedWrappedErrors, $errorDetails) + { + $wrappedErrorsNode = Fault::NODE_DETAIL_WRAPPED_ERRORS; + if ($expectedWrappedErrors) { + $wrappedErrorNode = Fault::NODE_DETAIL_WRAPPED_ERROR; + $wrappedErrorNodeFieldName = 'fieldName'; + $wrappedErrorNodeValue = Fault::NODE_DETAIL_WRAPPED_ERROR_VALUE; + $actualWrappedErrors = []; + if (isset($errorDetails->$wrappedErrorsNode->$wrappedErrorNode)) { + if (is_array($errorDetails->$wrappedErrorsNode->$wrappedErrorNode)) { + foreach ($errorDetails->$wrappedErrorsNode->$wrappedErrorNode as $error) { + $actualParameters = []; + foreach ($error->parameters->parameter as $parameter) { + $actualParameters[$parameter->key] = $parameter->value; + } + $actualWrappedErrors[] = [ + 'message' => $error->message, + 'params' => $actualParameters, + ]; + } + } else { + $error = $errorDetails->$wrappedErrorsNode->$wrappedErrorNode; + $actualWrappedErrors[] = [ + "fieldName" => $error->$wrappedErrorNodeFieldName, + "value" => $error->$wrappedErrorNodeValue, + ]; + } + } + $this->assertEquals( + $expectedWrappedErrors, + $actualWrappedErrors, + "Wrapped errors in fault details are invalid." + ); + } else { + $this->assertFalse( + isset($errorDetails->$wrappedErrorsNode), + "Wrapped errors are not expected in fault details." + ); + } + } +} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/WebApiApplication.php b/dev/tests/api-functional/framework/Magento/TestFramework/WebApiApplication.php new file mode 100644 index 0000000000000000000000000000000000000000..055fa381ae23bb427e1d4c9512158396ce874a32 --- /dev/null +++ b/dev/tests/api-functional/framework/Magento/TestFramework/WebApiApplication.php @@ -0,0 +1,62 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\TestFramework; + + +/** + * Provides access to the application for the tests + * + * Allows installation and uninstallation + */ +class WebApiApplication extends Application +{ + /** + * {@inheritdoc} + */ + public function run() + { + throw new \Exception( + "Can't start application: purpose of Web API Application is to use classes and models from the application" + . " and don't run it" + ); + } + + /** + * {@inheritdoc} + */ + public function install() + { + $installOptions = $this->getInstallConfig(); + + /* Install application */ + if ($installOptions) { + $installCmd = 'php -f ' . BP . '/setup/index.php install'; + $installArgs = []; + foreach ($installOptions as $optionName => $optionValue) { + if (is_bool($optionValue)) { + if (true === $optionValue) { + $installCmd .= " --$optionName"; + } + continue; + } + if (!empty($optionValue)) { + $installCmd .= " --$optionName=%s"; + $installArgs[] = $optionValue; + } + } + $this->_shell->execute($installCmd, $installArgs); + } + } + + /** + * Use the application as is + * + * {@inheritdoc} + */ + protected function getCustomDirs() + { + return []; + } +} diff --git a/dev/tests/api-functional/framework/autoload.php b/dev/tests/api-functional/framework/autoload.php new file mode 100644 index 0000000000000000000000000000000000000000..231e39080884504cd02a427a6333e875d0dae087 --- /dev/null +++ b/dev/tests/api-functional/framework/autoload.php @@ -0,0 +1,14 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +require_once __DIR__ . '/../../../../app/autoload.php'; + +$testsBaseDir = dirname(__DIR__); +$integrationTestsDir = realpath("{$testsBaseDir}/../integration/"); + +$autoloadWrapper = \Magento\Framework\Autoload\AutoloaderRegistry::getAutoloader(); +$autoloadWrapper->addPsr4('Magento\\TestFramework\\', "{$testsBaseDir}/framework/Magento/TestFramework/"); +$autoloadWrapper->addPsr4('Magento\\TestFramework\\', "{$integrationTestsDir}/framework/Magento/TestFramework/"); +$autoloadWrapper->addPsr4('Magento\\', "{$testsBaseDir}/testsuite/Magento/"); diff --git a/dev/tests/api-functional/framework/bootstrap.php b/dev/tests/api-functional/framework/bootstrap.php new file mode 100644 index 0000000000000000000000000000000000000000..ae037a554b21cd9e7529fd5bb320d5ea087b6580 --- /dev/null +++ b/dev/tests/api-functional/framework/bootstrap.php @@ -0,0 +1,77 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Autoload\AutoloaderRegistry; + +require_once __DIR__ . '/../../../../app/bootstrap.php'; +require_once __DIR__ . '/autoload.php'; + +$testsBaseDir = dirname(__DIR__); +$integrationTestsDir = realpath("{$testsBaseDir}/../integration"); + +$logWriter = new \Zend_Log_Writer_Stream('php://output'); +$logWriter->setFormatter(new \Zend_Log_Formatter_Simple('%message%' . PHP_EOL)); +$logger = new \Zend_Log($logWriter); + +/** Copy test modules to app/code/Magento to make them visible for Magento instance */ +$pathToCommittedTestModules = __DIR__ . '/../_files/Magento'; +$pathToInstalledMagentoInstanceModules = __DIR__ . '/../../../../app/code/Magento'; +$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pathToCommittedTestModules)); +/** @var SplFileInfo $file */ +foreach ($iterator as $file) { + if (!$file->isDir()) { + $source = $file->getPathname(); + $relativePath = substr($source, strlen($pathToCommittedTestModules)); + $destination = $pathToInstalledMagentoInstanceModules . $relativePath; + $targetDir = dirname($destination); + if (!is_dir($targetDir)) { + mkdir($targetDir, 0755, true); + } + copy($source, $destination); + } +} +unset($iterator, $file); + +/* Bootstrap the application */ +$settings = new \Magento\TestFramework\Bootstrap\Settings($testsBaseDir, get_defined_constants()); +$shell = new \Magento\Framework\Shell(new \Magento\Framework\Shell\CommandRenderer(), $logger); + +$installConfigFile = $settings->getAsConfigFile('TESTS_INSTALL_CONFIG_FILE'); +if (!file_exists($installConfigFile)) { + $installConfigFile = $installConfigFile . '.dist'; +} +$dirList = new \Magento\Framework\App\Filesystem\DirectoryList(BP); +$application = new \Magento\TestFramework\WebApiApplication( + $shell, + $dirList->getPath(DirectoryList::VAR_DIR), + $installConfigFile, + BP . '/app/etc/', + $settings->get('TESTS_MAGENTO_MODE'), + AutoloaderRegistry::getAutoloader() +); + +if (defined('TESTS_MAGENTO_INSTALLATION') && TESTS_MAGENTO_INSTALLATION === 'enabled') { + if (defined('TESTS_CLEANUP') && TESTS_CLEANUP === 'enabled') { + $application->cleanup(); + } + $application->install(); +} + +$bootstrap = new \Magento\TestFramework\Bootstrap( + $settings, + new \Magento\TestFramework\Bootstrap\Environment(), + new \Magento\TestFramework\Bootstrap\WebapiDocBlock("{$integrationTestsDir}/testsuite"), + new \Magento\TestFramework\Bootstrap\Profiler(new \Magento\Framework\Profiler\Driver\Standard()), + $shell, + $application, + new \Magento\TestFramework\Bootstrap\MemoryFactory($shell) +); +$bootstrap->runBootstrap(); +$application->initialize(); + +\Magento\TestFramework\Helper\Bootstrap::setInstance(new \Magento\TestFramework\Helper\Bootstrap($bootstrap)); +\Magento\Framework\Test\Utility\Files::setInstance(new \Magento\Framework\Test\Utility\Files(BP)); +unset($bootstrap, $application, $settings, $shell); diff --git a/dev/tests/api-functional/phpunit.xml.dist b/dev/tests/api-functional/phpunit.xml.dist new file mode 100644 index 0000000000000000000000000000000000000000..b885beab08ed0fbbbaf06705775f250543ef32d6 --- /dev/null +++ b/dev/tests/api-functional/phpunit.xml.dist @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * PHPUnit configuration for Web API functional tests. + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +--> +<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd" + colors="true" + bootstrap="./framework/bootstrap.php" +> + <!-- Test suites definition --> + <testsuites> + <testsuite name="Magento Web API Functional Tests"> + <directory suffix="Test.php">testsuite</directory> + </testsuite> + </testsuites> + + <!-- Code coverage filters --> + <filter> + <whitelist> + <!-- All CE modules --> + <directory suffix=".php">../../app/code/Magento</directory> + <exclude> + <!-- Excluding installation and upgrade scripts --> + <directory>../../app/code/Magento/*/sql</directory> + <!-- Excluding data installation and upgrade scripts --> + <directory>../../app/code/Magento/*/data</directory> + </exclude> + </whitelist> + </filter> + + <!-- PHP INI settings and constants definition --> + <php> + <includePath>./testsuite</includePath> + <const name="TESTS_INSTALL_CONFIG_FILE" value="config/install-config-mysql.php"/> + <!-- WebSerivice Type. Possible values: soap, rest --> + <const name="TESTS_WEB_API_ADAPTER" value="rest"/> + <!-- Webserver URL --> + <const name="TESTS_BASE_URL" value="http://magento.url"/> + <!-- Webserver API user --> + <const name="TESTS_WEBSERVICE_USER" value="admin"/> + <!-- Webserver API key --> + <const name="TESTS_WEBSERVICE_APIKEY" value="123123q"/> + <!-- Define if debugger should be started using XDEBUG_SESSION cookie --> + <const name="TESTS_XDEBUG_ENABLED" value="false"/> + <!-- Define XDEBUG_SESSION cookie value--> + <const name="TESTS_XDEBUG_SESSION" value="phpstorm" /> + <!--Generate documentation from REST tests and put it into var/log/rest-documentation directory--> + <const name="GENERATE_REST_DOCUMENTATION" value="false" /> + + <ini name="date.timezone" value="America/Los_Angeles"/> + <ini name="soap.wsdl_cache_enabled" value="0" /> + + <!-- Semicolon-separated 'glob' patterns, that match global XML configuration files --> + <const name="TESTS_GLOBAL_CONFIG_DIR" value="../../../app/etc"/> + <!-- Whether to cleanup the application before running tests or not --> + <const name="TESTS_CLEANUP" value="enabled"/> + <!--Defines if Magento should be installed before tests execution--> + <const name="TESTS_MAGENTO_INSTALLATION" value="disabled"/> + <!-- Magento mode for tests execution. Possible values are "default", "developer" and "production". --> + <const name="TESTS_MAGENTO_MODE" value="default"/> + </php> + + <!-- Test listeners --> + <listeners> + <listener class="Magento\TestFramework\Event\PhpUnit"/> + </listeners> +</phpunit> diff --git a/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductLinkManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductLinkManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..078d61a66d8e91ed7b55c2c8414e5942c4b26f03 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductLinkManagementTest.php @@ -0,0 +1,163 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Bundle\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Webapi\Model\Rest\Config; + +class ProductLinkManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'bundleProductLinkManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/bundle-products'; + + /** + * @magentoApiDataFixture Magento/Bundle/_files/product.php + */ + public function testGetChildren() + { + $productSku = 'bundle-product'; + $expected = [ + [ + 'sku' => 'simple', + 'position' => 0, + 'qty' => 1, + ], + ]; + + $result = $this->getChildren($productSku); + + $this->assertArrayHasKey(0, $result); + $this->assertArrayHasKey('option_id', $result[0]); + $this->assertArrayHasKey('is_default', $result[0]); + $this->assertArrayHasKey('is_defined', $result[0]); + $this->assertArrayHasKey('price', $result[0]); + $this->assertArrayHasKey('price_type', $result[0]); + + unset($result[0]['option_id'], $result[0]['is_default'], $result[0]['is_defined']); + unset($result[0]['price'], $result[0]['price_type']); + + ksort($result[0]); + ksort($expected[0]); + $this->assertEquals($expected, $result); + } + + /** + * @magentoApiDataFixture Magento/Bundle/_files/product.php + */ + public function testRemoveChild() + { + $productSku = 'bundle-product'; + $childSku = 'simple'; + $optionIds = $this->getProductOptions(3); + $optionId = array_shift($optionIds); + $this->assertTrue($this->removeChild($productSku, $optionId, $childSku)); + } + + /** + * @magentoApiDataFixture Magento/Bundle/_files/product.php + * @magentoApiDataFixture Magento/Catalog/_files/product_virtual.php + */ + public function testAddChild() + { + $productSku = 'bundle-product'; + $children = $this->getChildren($productSku); + + $optionId = $children[0]['option_id']; + + $linkedProduct = [ + 'sku' => 'virtual-product', + 'option_id' => $optionId, + 'position' => '1', + 'is_default' => 1, + 'priceType' => 2, + 'price' => 151.34, + 'qty' => 8, + 'can_change_quantity' => 1, + ]; + + $childId = $this->addChild($productSku, $optionId, $linkedProduct); + $this->assertGreaterThan(0, $childId); + } + + /** + * @param string $productSku + * @param int $optionId + * @param array $linkedProduct + * @return string + */ + private function addChild($productSku, $optionId, $linkedProduct) + { + $resourcePath = self::RESOURCE_PATH . '/:productSku/links/:optionId'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => str_replace( + [':productSku', ':optionId'], + [$productSku, $optionId], + $resourcePath + ), + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'AddChildByProductSku', + ], + ]; + return $this->_webApiCall( + $serviceInfo, + ['productSku' => $productSku, 'optionId' => $optionId, 'linkedProduct' => $linkedProduct] + ); + } + + protected function getProductOptions($productId) + { + /** @var \Magento\Catalog\Model\Product $product */ + $product = Bootstrap::getObjectManager()->get('Magento\Catalog\Model\Product'); + $product->load($productId); + /** @var \Magento\Bundle\Model\Product\Type $type */ + $type = Bootstrap::getObjectManager()->get('Magento\Bundle\Model\Product\Type'); + return $type->getOptionsIds($product); + } + + protected function removeChild($productSku, $optionId, $childSku) + { + $resourcePath = self::RESOURCE_PATH . '/%s/option/%s/child/%s'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => sprintf($resourcePath, $productSku, $optionId, $childSku), + 'httpMethod' => Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'removeChild', + ], + ]; + $requestData = ['productSku' => $productSku, 'optionId' => $optionId, 'childSku' => $childSku]; + return $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @param string $productSku + * @return string + */ + protected function getChildren($productSku) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/children', + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getChildren', + ], + ]; + return $this->_webApiCall($serviceInfo, ['productId' => $productSku]); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductOptionRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductOptionRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..2b35e1c4ff5be9dab24c6cc24b26eac6fad91cbd --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductOptionRepositoryTest.php @@ -0,0 +1,267 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Bundle\Api; + +use Magento\Webapi\Model\Rest\Config; + +class ProductOptionRepositoryTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'bundleProductOptionRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/bundle-products/:productSku/option'; + + /** + * @magentoApiDataFixture Magento/Bundle/_files/product.php + */ + public function testGet() + { + $productSku = 'bundle-product'; + $expected = [ + 'required' => true, + 'position' => 0, + 'type' => 'select', + 'title' => 'Bundle Product Items', + 'sku' => $productSku, + 'product_links' => [ + [ + 'sku' => 'simple', + 'qty' => 1, + 'position' => 0, + 'is_defined' => true, + 'is_default' => false, + 'price' => null, + 'price_type' => null, + ], + ], + ]; + $optionId = $this->getList($productSku)[0]['option_id']; + $result = $this->get($productSku, $optionId); + + $this->assertArrayHasKey('option_id', $result); + $expected['product_links'][0]['option_id'] = $result['option_id']; + unset($result['option_id']); + + ksort($expected); + ksort($result); + $this->assertEquals($expected, $result); + } + + /** + * @magentoApiDataFixture Magento/Bundle/_files/product.php + */ + public function testGetList() + { + $productSku = 'bundle-product'; + $expected = [ + [ + 'required' => true, + 'position' => 0, + 'type' => 'select', + 'title' => 'Bundle Product Items', + 'sku' => $productSku, + 'product_links' => [ + [ + 'sku' => 'simple', + 'qty' => 1, + 'position' => 0, + 'is_defined' => true, + 'is_default' => false, + 'price' => null, + 'price_type' => null, + ], + ], + ], + ]; + $result = $this->getList($productSku); + + $this->assertArrayHasKey(0, $result); + $this->assertArrayHasKey('option_id', $result[0]); + $expected[0]['product_links'][0]['option_id'] = $result[0]['option_id']; + unset($result[0]['option_id']); + + ksort($expected[0]); + ksort($result[0]); + $this->assertEquals($expected, $result); + } + + /** + * @magentoApiDataFixture Magento/Bundle/_files/product.php + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + */ + public function testRemove() + { + $productSku = 'bundle-product'; + + $optionId = $this->getList($productSku)[0]['option_id']; + $result = $this->remove($productSku, $optionId); + + $this->assertTrue($result); + + try { + $this->get($productSku, $optionId); + } catch (\Exception $e) { + throw new \Magento\Framework\Exception\NoSuchEntityException(); + } + } + + /** + * @magentoApiDataFixture Magento/Bundle/_files/product.php + */ + public function testAdd() + { + $productSku = 'bundle-product'; + $request = [ + 'required' => true, + 'position' => 0, + 'type' => 'select', + 'title' => 'test product', + 'product_links' => [], + 'sku' => $productSku, + ]; + + $optionId = $this->add($request); + $this->assertGreaterThan(0, $optionId); + $result = $this->get($productSku, $optionId); + + $this->assertArrayHasKey('option_id', $result); + $this->assertArrayHasKey('sku', $result); + unset($result['option_id']); + + ksort($result); + ksort($request); + $this->assertEquals($request, $result); + } + + /** + * @magentoApiDataFixture Magento/Bundle/_files/product.php + */ + public function testUpdate() + { + $productSku = 'bundle-product'; + $request = [ + 'title' => 'someTitle', + 'sku' => $productSku, + ]; + + $optionId = $this->getList($productSku)[0]['option_id']; + $result = $this->update($optionId, $request); + + $this->assertEquals($result, $optionId); + + $result = $this->get($productSku, $optionId); + + $this->assertCount(7, $result); + $this->assertArrayHasKey('title', $result); + $this->assertEquals($request['title'], $result['title']); + } + + /** + * @param int $optionId + * @param array $option + * @return string + */ + protected function update($optionId, $option) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/bundle-products/option/' . $optionId, + 'httpMethod' => Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'bundleProductOptionManagementV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'bundleProductOptionManagementV1Save', + ], + ]; + + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $option['optionId'] = $optionId; + } + return $this->_webApiCall($serviceInfo, ['option' => $option]); + } + + /** + * @param array $option + * @return string + */ + protected function add($option) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/bundle-products/option/add', + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => 'bundleProductOptionManagementV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'bundleProductOptionManagementV1Save', + ], + ]; + return $this->_webApiCall($serviceInfo, ['option' => $option]); + } + + /** + * @param string $productSku + * @param int $optionId + * @return string + */ + protected function remove($productSku, $optionId) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => str_replace(':productSku', $productSku, self::RESOURCE_PATH) . '/' . $optionId, + 'httpMethod' => Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ]; + return $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'optionId' => $optionId]); + } + + /** + * @param string $productSku + * @return string + */ + protected function getList($productSku) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => str_replace(':productSku', $productSku, self::RESOURCE_PATH) . '/all', + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + return $this->_webApiCall($serviceInfo, ['productSku' => $productSku]); + } + + /** + * @param string $productSku + * @param int $optionId + * @return string + */ + protected function get($productSku, $optionId) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => str_replace(':productSku', $productSku, self::RESOURCE_PATH) . '/' . $optionId, + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + return $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'optionId' => $optionId]); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductOptionTypeListTest.php b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductOptionTypeListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..4d4be9a704ce9e18608f3476b7cafb1b6f7afd80 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductOptionTypeListTest.php @@ -0,0 +1,47 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Bundle\Api; + +use Magento\Webapi\Model\Rest\Config; + +class ProductOptionTypeListTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_READ_NAME = 'bundleProductOptionTypeListV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/bundle-products/option/types'; + + public function testGetTypes() + { + $expected = [ + ['label' => 'Drop-down', 'code' => 'select'], + ['label' => 'Radio Buttons', 'code' => 'radio'], + ['label' => 'Checkbox', 'code' => 'checkbox'], + ['label' => 'Multiple Select', 'code' => 'multi'], + ]; + $result = $this->getTypes(); + + $this->assertEquals($expected, $result); + } + + /** + * @return string + */ + protected function getTypes() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'getItems', + ], + ]; + return $this->_webApiCall($serviceInfo); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..68db7d521095ae798280dfd5ede1e4dd5b095059 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductServiceTest.php @@ -0,0 +1,170 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Bundle\Api; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\Api\AbstractExtensibleObject; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class ProductServiceTest for testing Bundle Product API + */ +class ProductServiceTest extends WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products'; + + /** + * @var \Magento\Catalog\Model\Resource\Product\Collection + */ + protected $productCollection; + + /** + * Execute per test initialization + */ + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->productCollection = $objectManager->get('Magento\Catalog\Model\Resource\Product\Collection'); + } + + /** + * Execute per test cleanup + */ + public function tearDown() + { + /** @var \Magento\Framework\Registry $registry */ + $registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry'); + + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', true); + + $this->productCollection->addFieldToFilter( + 'sku', + ['in' => ['sku-test-product-bundle']] + )->delete(); + unset($this->productCollection); + + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', false); + parent::tearDown(); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/products_new.php + */ + public function testCreateBundle() + { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->markTestIncomplete('MAGETWO-31016: incompatible with ZF 1.12.9'); + } + $bundleProductOptions = [ + "attribute_code" => "bundle_product_options", + "value" => [ + [ + "title" => "test option", + "type" => "checkbox", + "required" => 1, + "product_links" => [ + [ + "sku" => 'simple', + "qty" => 1, + ], + ], + ], + ], + ]; + + $uniqueId = 'sku-test-product-bundle'; + $product = [ + "sku" => $uniqueId, + "name" => $uniqueId, + "type_id" => "bundle", + "price" => 50, + 'attribute_set_id' => 4, + "custom_attributes" => [ + "price_type" => [ + 'attribute_code' => 'price_type', + 'value' => \Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC + ], + "bundle_product_options" => $bundleProductOptions, + "price_view" => [ + "attribute_code" => "price_view", + "value" => "test", + ], + ], + ]; + + $response = $this->createProduct($product); + + $this->assertEquals($uniqueId, $response[ProductInterface::SKU]); + $this->assertEquals( + $bundleProductOptions, + $response[AbstractExtensibleObject::CUSTOM_ATTRIBUTES_KEY]["bundle_product_options"] + ); + + $response = $this->getProduct($uniqueId); + $foundBundleProductOptions = false; + foreach ($response[AbstractExtensibleObject::CUSTOM_ATTRIBUTES_KEY] as $customAttribute) { + if ($customAttribute["attribute_code"] === 'bundle_product_options') { + $this->assertEquals('simple', $customAttribute["value"][0]["product_links"][0]["sku"]); + $foundBundleProductOptions = true; + } + } + $this->assertTrue($foundBundleProductOptions); + } + + /** + * Get product + * + * @param string $productSku + * @return array the product data + */ + protected function getProduct($productSku) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + + $response = (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) ? + $this->_webApiCall($serviceInfo, ['productSku' => $productSku]) : $this->_webApiCall($serviceInfo); + + return $response; + } + + /** + * Create product + * + * @param array $product + * @return array the created product data + */ + protected function createProduct($product) + { + $serviceInfo = [ + 'rest' => ['resourcePath' => self::RESOURCE_PATH, 'httpMethod' => RestConfig::HTTP_METHOD_POST], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $requestData = ['product' => $product]; + $response = $this->_webApiCall($serviceInfo, $requestData); + $product[ProductInterface::SKU] = $response[ProductInterface::SKU]; + return $product; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..34dd1076b8843813b129b1e22f93027eec34b1f2 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetManagementTest.php @@ -0,0 +1,221 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Exception as HTTPExceptionCodes; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class AttributeSetManagementTest extends WebapiAbstract +{ + /** + * @var array + */ + private $createServiceInfo; + + protected function setUp() + { + $this->createServiceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/attribute-sets', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => 'catalogAttributeSetManagementV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogAttributeSetManagementV1Create', + ], + ]; + } + + public function testCreate() + { + $entityTypeCode = 'catalog_product'; + $entityType = $this->getEntityTypeByCode($entityTypeCode); + $attributeSetName = 'new_attribute_set'; + + $arguments = [ + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 500, + ], + 'skeletonId' => $entityType->getDefaultAttributeSetId(), + ]; + $result = $this->_webApiCall($this->createServiceInfo, $arguments); + $this->assertNotNull($result); + $attributeSet = $this->getAttributeSetByName($attributeSetName); + $this->assertNotNull($attributeSet); + $this->assertEquals($attributeSet->getId(), $result['attribute_set_id']); + $this->assertEquals($attributeSet->getAttributeSetName(), $result['attribute_set_name']); + $this->assertEquals($attributeSet->getEntityTypeId(), $result['entity_type_id']); + $this->assertEquals($attributeSet->getEntityTypeId(), $entityType->getId()); + $this->assertEquals($attributeSet->getSortOrder(), $result['sort_order']); + $this->assertEquals($attributeSet->getSortOrder(), 500); + + // Clean up database + $attributeSet->delete(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Invalid value + */ + public function testCreateThrowsExceptionIfGivenAttributeSetAlreadyHasId() + { + $entityTypeCode = 'catalog_product'; + $entityType = $this->getEntityTypeByCode($entityTypeCode); + $attributeSetName = 'new_attribute_set'; + + $arguments = [ + 'attributeSet' => [ + 'attribute_set_id' => 1, + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 100, + ], + 'skeletonId' => $entityType->getDefaultAttributeSetId(), + ]; + $this->_webApiCall($this->createServiceInfo, $arguments); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Can not create attribute set based on not existing attribute set + */ + public function testCreateThrowsExceptionIfGivenSkeletonIdIsInvalid() + { + $attributeSetName = 'new_attribute_set'; + $arguments = [ + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 200, + ], + 'skeletonId' => 0, + ]; + $this->_webApiCall($this->createServiceInfo, $arguments); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Can not create attribute set based on non product attribute set. + */ + public function testCreateThrowsExceptionIfGivenSkeletonIdHasWrongEntityType() + { + $attributeSetName = 'new_attribute_set'; + $arguments = [ + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 200, + ], + 'skeletonId' => 7, + ]; + $this->_webApiCall($this->createServiceInfo, $arguments); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Can not create attribute set based on not existing attribute set + */ + public function testCreateThrowsExceptionIfGivenSkeletonAttributeSetDoesNotExist() + { + $attributeSetName = 'new_attribute_set'; + $arguments = [ + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 300, + ], + 'skeletonId' => 9999, + ]; + $this->_webApiCall($this->createServiceInfo, $arguments); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Attribute set name is empty. + */ + public function testCreateThrowsExceptionIfAttributeSetNameIsEmpty() + { + $entityTypeCode = 'catalog_product'; + $entityType = $this->getEntityTypeByCode($entityTypeCode); + $attributeSetName = ''; + + $arguments = [ + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 500, + ], + 'skeletonId' => $entityType->getDefaultAttributeSetId(), + ]; + $this->_webApiCall($this->createServiceInfo, $arguments); + } + + public function testCreateThrowsExceptionIfAttributeSetWithGivenNameAlreadyExists() + { + $entityTypeCode = 'catalog_product'; + $entityType = $this->getEntityTypeByCode($entityTypeCode); + $attributeSetName = 'Default'; + $expectedMessage = 'An attribute set with the "Default" name already exists.'; + + $arguments = [ + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 550, + ], + 'skeletonId' => $entityType->getDefaultAttributeSetId(), + ]; + + try { + $this->_webApiCall($this->createServiceInfo, $arguments); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals( + $expectedMessage, + $errorObj['message'] + ); + $this->assertEquals(HTTPExceptionCodes::HTTP_BAD_REQUEST, $e->getCode()); + } + } + + /** + * Retrieve attribute set based on given name. + * This utility methods assumes that there is only one attribute set with given name, + * + * @param string $attributeSetName + * @return \Magento\Eav\Model\Entity\Attribute\Set|null + */ + protected function getAttributeSetByName($attributeSetName) + { + $objectManager = Bootstrap::getObjectManager(); + /** @var \Magento\Eav\Model\Entity\Attribute\Set $attributeSet */ + $attributeSet = $objectManager->create('Magento\Eav\Model\Entity\Attribute\Set') + ->load($attributeSetName, 'attribute_set_name'); + if ($attributeSet->getId() === null) { + return null; + } + return $attributeSet; + } + + /** + * Retrieve entity type based on given code. + * + * @param string $entityTypeCode + * @return \Magento\Eav\Model\Entity\Type|null + */ + protected function getEntityTypeByCode($entityTypeCode) + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Eav\Model\Entity\Type $entityType */ + $entityType = $objectManager->create('Magento\Eav\Model\Config') + ->getEntityType($entityTypeCode); + return $entityType; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7b2bb1d5b2e74b2b9f3bc0cb3efd387dc4731fdf --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php @@ -0,0 +1,228 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class AttributeSetRepositoryTest extends WebapiAbstract +{ + /** + * @magentoApiDataFixture Magento/Eav/_files/empty_attribute_set.php + */ + public function testGet() + { + $attributeSetName = 'empty_attribute_set'; + $attributeSet = $this->getAttributeSetByName($attributeSetName); + $attributeSetId = $attributeSet->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/attribute-sets/' . $attributeSetId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'catalogAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogAttributeSetRepositoryV1Get', + ], + ]; + $arguments = [ + 'attributeSetId' => $attributeSetId, + ]; + $result = $this->_webApiCall($serviceInfo, $arguments); + $this->assertNotNull($result); + $this->assertEquals($attributeSet->getId(), $result['attribute_set_id']); + $this->assertEquals($attributeSet->getAttributeSetName(), $result['attribute_set_name']); + $this->assertEquals($attributeSet->getEntityTypeId(), $result['entity_type_id']); + $this->assertEquals($attributeSet->getSortOrder(), $result['sort_order']); + } + + /** + * @expectedException \Exception + */ + public function testGetThrowsExceptionIfRequestedAttributeSetDoesNotExist() + { + $attributeSetId = 9999; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/attribute-sets/' . $attributeSetId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'catalogAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogAttributeSetRepositoryV1Get', + ], + ]; + $arguments = [ + 'attributeSetId' => $attributeSetId, + ]; + $this->_webApiCall($serviceInfo, $arguments); + } + + /** + * @magentoApiDataFixture Magento/Eav/_files/empty_attribute_set.php + */ + public function testSave() + { + $attributeSetName = 'empty_attribute_set'; + $attributeSet = $this->getAttributeSetByName($attributeSetName); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/attribute-sets/' . $attributeSet->getId(), + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'catalogAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogAttributeSetRepositoryV1Save', + ], + ]; + + $updatedSortOrder = $attributeSet->getSortOrder() + 200; + + $arguments = [ + 'attributeSet' => [ + 'attribute_set_id' => $attributeSet->getId(), + // name is the same, because it is used by fixture rollback script + 'attribute_set_name' => $attributeSet->getAttributeSetName(), + 'entity_type_id' => $attributeSet->getEntityTypeId(), + 'sort_order' => $updatedSortOrder, + ], + ]; + $result = $this->_webApiCall($serviceInfo, $arguments); + $this->assertNotNull($result); + // Reload attribute set data + $attributeSet = $this->getAttributeSetByName($attributeSetName); + $this->assertEquals($attributeSet->getAttributeSetId(), $result['attribute_set_id']); + $this->assertEquals($attributeSet->getAttributeSetName(), $result['attribute_set_name']); + $this->assertEquals($attributeSet->getEntityTypeId(), $result['entity_type_id']); + $this->assertEquals($updatedSortOrder, $result['sort_order']); + $this->assertEquals($attributeSet->getSortOrder(), $result['sort_order']); + } + + /** + * @magentoApiDataFixture Magento/Eav/_files/empty_attribute_set.php + */ + public function testDeleteById() + { + $attributeSetName = 'empty_attribute_set'; + $attributeSet = $this->getAttributeSetByName($attributeSetName); + $attributeSetId = $attributeSet->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/attribute-sets/' . $attributeSetId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => 'catalogAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogAttributeSetRepositoryV1DeleteById', + ], + ]; + + $arguments = [ + 'attributeSetId' => $attributeSetId, + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, $arguments)); + $this->assertNull($this->getAttributeSetByName($attributeSetName)); + } + + /** + * @expectedException \Exception + */ + public function testDeleteByIdThrowsExceptionIfRequestedAttributeSetDoesNotExist() + { + $attributeSetId = 9999; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/attribute-sets/' . $attributeSetId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => 'catalogAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogAttributeSetRepositoryV1DeleteById', + ], + ]; + + $arguments = [ + 'attributeSetId' => $attributeSetId, + ]; + $this->_webApiCall($serviceInfo, $arguments); + } + + /** + * @magentoApiDataFixture Magento/Eav/_files/empty_attribute_set.php + */ + public function testGetList() + { + $searchCriteria = [ + 'searchCriteria' => [ + 'filter_groups' => [ + [ + 'filters' => [ + [ + 'field' => 'entity_type_code', + 'value' => 'catalog_product', + 'condition_type' => 'eq', + ], + ], + ], + ], + 'current_page' => 1, + 'page_size' => 2, + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/attribute-sets/sets/list', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'catalogAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogAttributeSetRepositoryV1GetList', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, $searchCriteria); + + $this->assertArrayHasKey('search_criteria', $response); + $this->assertArrayHasKey('total_count', $response); + $this->assertArrayHasKey('items', $response); + + $this->assertEquals($searchCriteria['searchCriteria'], $response['search_criteria']); + $this->assertTrue($response['total_count'] > 0); + $this->assertTrue(count($response['items']) > 0); + + $this->assertNotNull($response['items'][0]['attribute_set_id']); + $this->assertNotNull($response['items'][0]['attribute_set_name']); + } + + /** + * Retrieve attribute set based on given name. + * This utility methods assumes that there is only one attribute set with given name, + * + * @param string $attributeSetName + * @return \Magento\Eav\Model\Entity\Attribute\Set|null + */ + protected function getAttributeSetByName($attributeSetName) + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Eav\Model\Entity\Attribute\Set $attributeSet */ + $attributeSet = $objectManager->create('Magento\Eav\Model\Entity\Attribute\Set') + ->load($attributeSetName, 'attribute_set_name'); + if ($attributeSet->getId() === null) { + return null; + } + return $attributeSet; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryAttributeOptionManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryAttributeOptionManagementInterfaceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d7540f1b3a348f62e6a78ffb45241aeedb536e3b --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryAttributeOptionManagementInterfaceTest.php @@ -0,0 +1,47 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class CategoryAttributeOptionManagementInterfaceTest extends WebapiAbstract +{ + const SERVICE_NAME = 'catalogCategoryAttributeOptionManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/categories/attributes'; + + public function testGetItems() + { + $testAttributeCode = 'include_in_menu'; + $expectedOptions = [ + [ + 'label' => 'Yes', + 'value' => '1', + ], + [ + 'label' => 'No', + 'value' => '0', + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $testAttributeCode . '/options', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getItems', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, ['attributeCode' => $testAttributeCode]); + + $this->assertTrue(is_array($response)); + $this->assertEquals($expectedOptions, $response); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryAttributeRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryAttributeRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a206507971116cb7118c717cd822923e29e2c058 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryAttributeRepositoryTest.php @@ -0,0 +1,96 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class CategoryAttributeRepositoryTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'catalogCategoryAttributeRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/categories/attributes'; + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category_attribute.php + */ + public function testGet() + { + $attributeCode = 'test_attribute_code_666'; + $attribute = $this->getAttribute($attributeCode); + + $this->assertTrue(is_array($attribute)); + $this->assertArrayHasKey('attribute_id', $attribute); + $this->assertArrayHasKey('attribute_code', $attribute); + $this->assertEquals($attributeCode, $attribute['attribute_code']); + } + + public function testGetList() + { + $searchCriteria = [ + 'searchCriteria' => [ + 'filter_groups' => [ + [ + 'filters' => [ + [ + 'field' => 'frontend_input', + 'value' => 'text', + 'condition_type' => 'eq', + ], + ], + ], + ], + 'current_page' => 1, + 'page_size' => 2, + ], + 'entityTypeCode' => \Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE, + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, $searchCriteria); + + $this->assertArrayHasKey('search_criteria', $response); + $this->assertArrayHasKey('total_count', $response); + $this->assertArrayHasKey('items', $response); + + $this->assertEquals($searchCriteria['searchCriteria'], $response['search_criteria']); + $this->assertTrue($response['total_count'] > 0); + $this->assertTrue(count($response['items']) > 0); + + $this->assertNotNull($response['items'][0]['default_frontend_label']); + $this->assertNotNull($response['items'][0]['attribute_id']); + } + + /** + * @param $attributeCode + * @return array|bool|float|int|string + */ + protected function getAttribute($attributeCode) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $attributeCode, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + return $this->_webApiCall($serviceInfo, ['attributeCode' => $attributeCode]); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryLinkManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryLinkManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..fc64e880b646e0110d17ff9a46808fe372206385 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryLinkManagementTest.php @@ -0,0 +1,65 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +class CategoryLinkManagementTest extends WebapiAbstract +{ + const SERVICE_WRITE_NAME = 'catalogCategoryLinkManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH_SUFFIX = '/V1/categories'; + const RESOURCE_PATH_PREFIX = 'products'; + + private $modelId = 333; + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category_product.php + */ + public function testAssignedProducts() + { + $expected = [ + [ + 'sku' => 'simple333', + 'position' => '1', + 'category_id' => '333', + ], + ]; + $result = $this->getAssignedProducts($this->modelId); + + $this->assertEquals($expected, $result); + } + + public function testInfoNoSuchEntityException() + { + try { + $this->getAssignedProducts(-1); + } catch (\Exception $e) { + $this->assertContains('No such entity with %fieldName = %fieldValue', $e->getMessage()); + } + } + + /** + * @param int $id category id + * @return string + */ + protected function getAssignedProducts($id) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_SUFFIX . '/' . $id . '/' . self::RESOURCE_PATH_PREFIX, + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_WRITE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_WRITE_NAME . 'GetAssignedProducts', + ], + ]; + return $this->_webApiCall($serviceInfo, ['categoryId' => $id]); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryLinkRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryLinkRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..99ecffa03a07c598cb5f94e11fcd00b0fafb5b9f --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryLinkRepositoryTest.php @@ -0,0 +1,149 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +class CategoryLinkRepositoryTest extends WebapiAbstract +{ + const SERVICE_WRITE_NAME = 'catalogCategoryLinkRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH_SUFFIX = '/V1/categories'; + const RESOURCE_PATH_PREFIX = 'products'; + + private $categoryId = 333; + + /** + * @dataProvider saveDataProvider + * @magentoApiDataFixture Magento/Catalog/_files/products_in_category.php + * @param int $productId + * @param string[] $productLink + * @param int $productPosition + */ + public function testSave($productLink, $productId, $productPosition = 0) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_SUFFIX + . '/' . $this->categoryId . '/' . self::RESOURCE_PATH_PREFIX, + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_WRITE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_WRITE_NAME . 'Save', + ], + ]; + $result = $this->_webApiCall($serviceInfo, ['productLink' => $productLink]); + $this->assertTrue($result); + $this->assertTrue($this->isProductInCategory($this->categoryId, $productId, $productPosition)); + } + + public function saveDataProvider() + { + return [ + [ + ['sku' => 'simple_with_cross', 'position' => 7, 'category_id' => $this->categoryId], + 334, + 7, + ], + [ + ['sku' => 'simple_with_cross', 'category_id' => $this->categoryId], + 334, + 0 + ], + ]; + } + + /** + * @dataProvider updateProductProvider + * @magentoApiDataFixture Magento/Catalog/_files/products_in_category.php + * @param int $productId + * @param string[] $productLink + * @param int $productPosition + */ + public function testUpdateProduct($productLink, $productId, $productPosition = 0) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_SUFFIX + . '/' . $this->categoryId . '/' . self::RESOURCE_PATH_PREFIX, + 'httpMethod' => Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_WRITE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_WRITE_NAME . 'Save', + ], + ]; + $result = $this->_webApiCall($serviceInfo, ['productLink' => $productLink]); + $this->assertTrue($result); + $this->assertFalse($this->isProductInCategory($this->categoryId, $productId, $productPosition)); + } + + public function updateProductProvider() + { + return [ + [ + ['sku' => 'simple_with_cross', 'position' => 7, 'categoryId' => $this->categoryId], + 333, + 4, + ], + [ + ['sku' => 'simple_with_cross', 'categoryId' => $this->categoryId], + 333, + 0 + ], + ]; + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/products_in_category.php + */ + public function testDelete() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_SUFFIX . '/' . $this->categoryId . + '/' . self::RESOURCE_PATH_PREFIX . '/simple', + 'httpMethod' => Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_WRITE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_WRITE_NAME . 'DeleteByIds', + ], + ]; + $result = $this->_webApiCall( + $serviceInfo, + ['productSku' => 'simple', 'categoryId' => $this->categoryId] + ); + $this->assertTrue($result); + $this->assertFalse($this->isProductInCategory($this->categoryId, 333, 10)); + } + + /** + * @param int $categoryId + * @param int $productId + * @param int $productPosition + * @return bool + */ + private function isProductInCategory($categoryId, $productId, $productPosition) + { + /** @var \Magento\Catalog\Api\CategoryRepositoryInterface $categoryLoader */ + $categoryLoader = Bootstrap::getObjectManager()->create('Magento\Catalog\Api\CategoryRepositoryInterface'); + $category = $categoryLoader->get($categoryId); + $productsPosition = $category->getProductsPosition(); + + if (isset($productsPosition[$productId]) && $productsPosition[$productId] == $productPosition) { + return true; + } else { + return false; + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..eaa58bae0e501b3fcaed3a062d3dbed85361c48b --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryManagementTest.php @@ -0,0 +1,94 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\ObjectManager; + +class CategoryManagementTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/categories'; + + const SERVICE_NAME = 'catalogCategoryManagementV1'; + + /** + * @dataProvider treeDataProvider + * @magentoApiDataFixture Magento/Catalog/_files/category_tree.php + */ + public function testTree($rootCategoryId, $depth, $expectedLevel, $expectedId) + { + $requestData = ['rootCategoryId' => $rootCategoryId, 'depth' => $depth]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '?' . http_build_query($requestData), + 'httpMethod' => Config::HTTP_METHOD_GET + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'GetTree' + ] + ]; + $result = $this->_webApiCall($serviceInfo, $requestData); + + for($i = 0; $i < $expectedLevel; $i++) { + $result = $result['children_data'][0]; + } + $this->assertEquals($expectedId, $result['id']); + $this->assertEmpty($result['children_data']); + } + + public function treeDataProvider() + { + return [ + [2, 100, 3, 402], + [2, null, 3, 402], + [400, 1, 1, 401], + [401, 0, 0, 401], + ]; + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category_tree.php + * @dataProvider updateMoveDataProvider + */ + public function testUpdateMove($categoryId, $parentId, $afterId, $expectedPosition) + { + $expectedPath = '1/2/400/' . $categoryId; + $categoryData = ['categoryId' => $categoryId, 'parentId' => $parentId, 'afterId' => $afterId]; + $serviceInfo = + [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $categoryId . '/move', + 'httpMethod' => Config::HTTP_METHOD_PUT + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'Move' + ] + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, $categoryData)); + /** @var \Magento\Catalog\Model\Category $model */ + $readService = Bootstrap::getObjectManager()->create('Magento\Catalog\Api\CategoryRepositoryInterface'); + $model = $readService->get($categoryId); + $this->assertEquals($expectedPath, $model->getPath()); + $this->assertEquals($expectedPosition, $model->getPosition()); + $this->assertEquals($parentId, $model->getParentId()); + } + + public function updateMoveDataProvider() + { + return [ + [402, 400, null, 2], + [402, 400, 401, 2], + [402, 400, 999, 2], + [402, 400, 0, 1] + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a6a2a5d9efe59c57b0ff284aea06e64b04dd07ce --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php @@ -0,0 +1,253 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +class CategoryRepositoryTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/categories'; + const SERVICE_NAME = 'catalogCategoryRepositoryV1'; + + private $modelId = 333; + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category_backend.php + */ + public function testGet() + { + $expected = [ + 'parent_id' => 2, + 'path' => '1/2/3', + 'position' => 1, + 'level' => 2, + 'available_sort_by' => ['position', 'name'], + 'include_in_menu' => true, + 'name' => 'Category 1', + 'id' => 333, + 'is_active' => true, + ]; + + $result = $this->getInfoCategory($this->modelId); + + $this->assertArrayHasKey('created_at', $result); + $this->assertArrayHasKey('updated_at', $result); + $this->assertArrayHasKey('children', $result); + unset($result['created_at'], $result['updated_at'], $result['children']); + ksort($expected); + ksort($result); + $this->assertEquals($expected, $result); + } + + public function testInfoNoSuchEntityException() + { + try { + $this->getInfoCategory(-1); + } catch (\Exception $e) { + $this->assertContains('No such entity with %fieldName = %fieldValue', $e->getMessage()); + } + } + + /** + * @param int $id + * @return string + */ + protected function getInfoCategory($id) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $id, + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + return $this->_webApiCall($serviceInfo, ['categoryId' => $id]); + } + /** + * @return array + */ + public function categoryCreationProvider() + { + return [ + [ + $this->getSimpleCategoryData( + [ + 'name' => 'Test Category Name', + ] + ), + ] + ]; + } + + /** + * Test for create category process + * + * @magentoApiDataFixture Magento/Catalog/Model/Category/_files/service_category_create.php + * @dataProvider categoryCreationProvider + */ + public function testCreate($category) + { + $category = $this->createCategory($category); + $this->assertGreaterThan(0, $category['id']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category.php + */ + public function testDelete() + { + $this->assertTrue($this->deleteCategory($this->modelId)); + } + + public function testDeleteNoSuchEntityException() + { + try { + $this->deleteCategory(-1); + } catch (\Exception $e) { + $this->assertContains('No such entity with %fieldName = %fieldValue', $e->getMessage()); + } + } + + /** + * @dataProvider deleteSystemOrRootDataProvider + * @expectedException \Exception + */ + public function testDeleteSystemOrRoot() + { + $this->deleteCategory($this->modelId); + } + + public function deleteSystemOrRootDataProvider() + { + return [ + [\Magento\Catalog\Model\Category::TREE_ROOT_ID], + [2] //Default root category + ]; + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category.php + */ + public function testUpdate() + { + $categoryId = 333; + $categoryData = [ + 'name' => "Update Category Test", + 'custom_attributes' => [ + [ + 'attribute_code' => 'description', + 'value' => "Update Category Description Test", + ], + ], + ]; + $result = $this->updateCategory($categoryId, $categoryData); + $this->assertEquals($categoryId, $result['id']); + /** @var \Magento\Catalog\Model\Category $model */ + $model = Bootstrap::getObjectManager()->get('Magento\Catalog\Model\Category'); + $category = $model->load($categoryId); + $this->assertEquals("Update Category Test", $category->getName()); + $this->assertEquals("Update Category Description Test", $category->getDescription()); + } + + protected function getSimpleCategoryData($categoryData = []) + { + return [ + 'path' => '2', + 'parent_id' => '2', + 'name' => isset($categoryData['name']) + ? $categoryData['name'] : uniqid('Category-', true), + 'is_active' => '1', + 'custom_attributes' => [ + ['attribute_code' => 'url_key', 'value' => ''], + ['attribute_code' => 'description', 'value' => 'Custom description'], + ['attribute_code' => 'meta_title', 'value' => ''], + ['attribute_code' => 'meta_keywords', 'value' => ''], + ['attribute_code' => 'meta_description', 'value' => ''], + ['attribute_code' => 'include_in_menu', 'value' => '1'], + ['attribute_code' => 'display_mode', 'value' => 'PRODUCTS'], + ['attribute_code' => 'landing_page', 'value' => ''], + ['attribute_code' => 'is_anchor', 'value' => '0'], + ['attribute_code' => 'custom_use_parent_settings', 'value' => '0'], + ['attribute_code' => 'custom_apply_to_products', 'value' => '0'], + ['attribute_code' => 'custom_design', 'value' => ''], + ['attribute_code' => 'custom_design_from', 'value' => ''], + ['attribute_code' => 'custom_design_to', 'value' => ''], + ['attribute_code' => 'page_layout', 'value' => ''], + ] + ]; + } + + /** + * Create category process + * + * @param $category + * @return int + */ + protected function createCategory($category) + { + $serviceInfo = [ + 'rest' => ['resourcePath' => self::RESOURCE_PATH, 'httpMethod' => Config::HTTP_METHOD_POST], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $requestData = ['category' => $category]; + return $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @param int $id + * @return bool + * @throws \Exception + */ + protected function deleteCategory($id) + { + $serviceInfo = + [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $id, + 'httpMethod' => Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'DeleteByIdentifier', + ], + ]; + return $this->_webApiCall($serviceInfo, ['categoryId' => $id]); + } + + protected function updateCategory($id, $data) + { + $serviceInfo = + [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $id, + 'httpMethod' => Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $data['id'] = $id; + return $this->_webApiCall($serviceInfo, ['id' => $id, 'category' => $data]); + } else { + return $this->_webApiCall($serviceInfo, ['category' => $data]); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeGroupRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeGroupRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..daf34f578a9bd3947ed0622d0790eb2a8e2023a0 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeGroupRepositoryTest.php @@ -0,0 +1,191 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductAttributeGroupRepositoryTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductAttributeGroupRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/attribute-sets'; + + /** + * @magentoApiDataFixture Magento/Catalog/_files/empty_attribute_group.php + */ + public function testCreateGroup() + { + $attributeSetId = 1; + $groupData = $this->createGroupData($attributeSetId); + $groupData['attribute_group_name'] = 'empty_attribute_group_updated'; + + $result = $this->createGroup($attributeSetId, $groupData); + $this->assertArrayHasKey('attribute_group_id', $result); + $this->assertNotNull($result['attribute_group_id']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/empty_attribute_group.php + */ + public function testDeleteGroup() + { + $group = $this->getGroupByName('empty_attribute_group'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/groups/" . $group->getId(), + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, ['groupId' => $group->getId()])); + } + + /** + * @expectedException \Exception + */ + public function testCreateGroupWithAttributeSetThatDoesNotExist() + { + $attributeSetId = -1; + $this->createGroup($attributeSetId); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/empty_attribute_group.php + */ + public function testUpdateGroup() + { + $attributeSetId = 1; + $group = $this->getGroupByName('empty_attribute_group'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $attributeSetId . '/groups', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $newGroupData = $this->createGroupData($attributeSetId); + $newGroupData['attribute_group_name'] = 'empty_attribute_group_updated'; + $newGroupData['attribute_group_id'] = $group->getId(); + + $result = $this->_webApiCall($serviceInfo, ['group' => $newGroupData]); + + $this->assertArrayHasKey('attribute_group_id', $result); + $this->assertEquals($group->getId(), $result['attribute_group_id']); + $this->assertArrayHasKey('attribute_group_name', $result); + $this->assertEquals($newGroupData['attribute_group_name'], $result['attribute_group_name']); + } + + public function testGetList() + { + $searchCriteria = [ + 'searchCriteria' => [ + 'filter_groups' => [ + [ + 'filters' => [ + [ + 'field' => 'attribute_set_id', + 'value' => 1, + 'condition_type' => 'eq', + ], + ], + ], + ], + 'current_page' => 1, + 'page_size' => 2, + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/groups/list", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, $searchCriteria); + + $this->assertArrayHasKey('search_criteria', $response); + $this->assertArrayHasKey('total_count', $response); + $this->assertArrayHasKey('items', $response); + + $this->assertEquals($searchCriteria['searchCriteria'], $response['search_criteria']); + $this->assertTrue($response['total_count'] > 0); + $this->assertTrue(count($response['items']) > 0); + + $this->assertNotNull($response['items'][0]['attribute_group_name']); + $this->assertNotNull($response['items'][0]['attribute_group_id']); + } + + /** + * @param $attributeSetId + * @return array|bool|float|int|string + */ + protected function createGroup($attributeSetId, $groupData = null) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/groups', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + return $this->_webApiCall( + $serviceInfo, + ['group' => $groupData ? $groupData : $this->createGroupData($attributeSetId)] + ); + } + + /** + * @param $attributeSetId + * @return array + */ + protected function createGroupData($attributeSetId) + { + return [ + 'attribute_group_name' => 'empty_attribute_group', + 'attribute_set_id' => $attributeSetId + ]; + } + + /** + * Retrieve attribute group based on given name. + * This utility methods assumes that there is only one attribute group with given name, + * + * @param string $groupName + * @return \Magento\Eav\Model\Entity\Attribute\Group|null + */ + protected function getGroupByName($groupName) + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Eav\Model\Entity\Attribute\Group */ + $attributeGroup = $objectManager->create('Magento\Eav\Model\Entity\Attribute\Group') + ->load($groupName, 'attribute_group_name'); + if ($attributeGroup->getId() === null) { + return null; + } + return $attributeGroup; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..14f8614829e033dfd41bd61ee6ba9cd815608979 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeManagementTest.php @@ -0,0 +1,184 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Webapi\Exception as HTTPExceptionCodes; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductAttributeManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductAttributeManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/attribute-sets'; + + public function testGetAttributes() + { + $attributeSetId = \Magento\Catalog\Api\Data\ProductAttributeInterface::DEFAULT_ATTRIBUTE_SET_ID; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $attributeSetId . '/attributes', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetAttributes', + ], + ]; + $attributes = $this->_webApiCall($serviceInfo, ['attributeSetId' => $attributeSetId]); + + $this->assertTrue(count($attributes) > 0); + $this->assertArrayHasKey('attribute_code', $attributes[0]); + $this->assertArrayHasKey('attribute_id', $attributes[0]); + $this->assertArrayHasKey('default_frontend_label', $attributes[0]); + $this->assertNotNull($attributes[0]['attribute_code']); + $this->assertNotNull($attributes[0]['attribute_id']); + $this->assertNotNull($attributes[0]['default_frontend_label']); + } + + public function testAssignAttribute() + { + $this->assertNotNull( + $this->_webApiCall( + $this->getAssignServiceInfo(), + $this->getAttributeData() + ) + ); + } + + public function testAssignAttributeWrongAttributeSet() + { + $payload = $this->getAttributeData(); + $payload['attributeSetId'] = -1; + + $expectedMessage = 'AttributeSet with id "' . $payload['attributeSetId'] . '" does not exist.'; + + try { + $this->_webApiCall($this->getAssignServiceInfo(), $payload); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals($expectedMessage, $errorObj['message']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } + + public function testAssignAttributeWrongAttributeGroup() + { + $payload = $this->getAttributeData(); + $payload['attributeGroupId'] = -1; + $expectedMessage = 'Group with id "' . $payload['attributeGroupId'] . '" does not exist.'; + + try { + $this->_webApiCall($this->getAssignServiceInfo(), $payload); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals($expectedMessage, $errorObj['message']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } + + public function testAssignAttributeWrongAttribute() + { + $payload = $this->getAttributeData(); + $payload['attributeCode'] = 'badCode'; + $expectedMessage = 'Attribute with attributeCode "' . $payload['attributeCode'] . '" does not exist.'; + + try { + $this->_webApiCall($this->getAssignServiceInfo(), $payload); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals($expectedMessage, $errorObj['message']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } + + public function testUnassignAttribute() + { + $payload = $this->getAttributeData(); + + //Assign attribute to attribute set + /** @var \Magento\Eav\Model\AttributeManagement $attributeManagement */ + $attributeManagement = Bootstrap::getObjectManager()->get('Magento\Eav\Model\AttributeManagement'); + $attributeManagement->assign( + \Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE, + $payload['attributeSetId'], + $payload['attributeGroupId'], + $payload['attributeCode'], + $payload['sortOrder'] + ); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . + '/' . $payload['attributeSetId'] . + '/attributes/' . + $payload['attributeCode'], + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Unassign', + ], + ]; + $this->assertTrue($this->_webApiCall( + $serviceInfo, + [ + 'attributeSetId' => $payload['attributeSetId'], + 'attributeCode' => $payload['attributeCode'] + ] + ) + ); + } + + protected function getAttributeData() + { + return [ + 'attributeSetId' => \Magento\Catalog\Api\Data\ProductAttributeInterface::DEFAULT_ATTRIBUTE_SET_ID, + 'attributeGroupId' => 8, + 'attributeCode' => 'cost', + 'sortOrder' => 3 + ]; + } + + protected function getAssignServiceInfo() + { + return [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/attributes', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Assign', + ], + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..cb480d3702a2130ac68a57566b7938f3fe0ba482 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php @@ -0,0 +1,647 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\Webapi\Model\Rest\Config as RestConfig; +use Magento\TestFramework\Helper\Bootstrap; + +class ProductAttributeMediaGalleryManagementInterfaceTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + /** + * Default create service request information (product with SKU 'simple' is used) + * + * @var array + */ + protected $createServiceInfo; + + /** + * Default update service request information (product with SKU 'simple' is used) + * + * @var array + */ + protected $updateServiceInfo; + + /** + * Default delete service request information (product with SKU 'simple' is used) + * + * @var array + */ + protected $deleteServiceInfo; + + /** + * @var string + */ + protected $testImagePath; + + protected function setUp() + { + $this->createServiceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/simple/media', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => 'catalogProductAttributeMediaGalleryManagementV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogProductAttributeMediaGalleryManagementV1Create', + ], + ]; + $this->updateServiceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/simple/media', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'catalogProductAttributeMediaGalleryManagementV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogProductAttributeMediaGalleryManagementV1Update', + ], + ]; + $this->deleteServiceInfo = [ + 'rest' => [ + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => 'catalogProductAttributeMediaGalleryManagementV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogProductAttributeMediaGalleryManagementV1Remove', + ], + ]; + $this->testImagePath = __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'test_image.jpg'; + } + + /** + * Retrieve product that was updated by test + * + * @return \Magento\Catalog\Model\Product + */ + protected function getTargetSimpleProduct() + { + $objectManager = Bootstrap::getObjectManager(); + return $objectManager->get('Magento\Catalog\Model\ProductFactory')->create()->load(1); + } + + /** + * Retrieve target product image ID + * + * Target product must have single image if this function is used + * + * @return int + */ + protected function getTargetGalleryEntryId() + { + $mediaGallery = $this->getTargetSimpleProduct()->getData('media_gallery'); + return (int)$mediaGallery['images'][0]['value_id']; + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testCreate() + { + $requestData = [ + 'productSku' => 'simple', + 'entry' => [ + 'id' => null, + 'label' => 'Image Text', + 'position' => 1, + 'types' => ['image'], + 'is_disabled' => false, + ], + 'entryContent' => [ + 'entry_data' => base64_encode(file_get_contents($this->testImagePath)), + 'mime_type' => 'image/jpeg', + 'name' => 'test_image', + ], + // Store ID is not provided so the default one must be used + ]; + + $actualResult = $this->_webApiCall($this->createServiceInfo, $requestData); + $targetProduct = $this->getTargetSimpleProduct(); + $mediaGallery = $targetProduct->getData('media_gallery'); + + $this->assertCount(1, $mediaGallery['images']); + $updatedImage = $mediaGallery['images'][0]; + $this->assertEquals($actualResult, $updatedImage['value_id']); + $this->assertEquals('Image Text', $updatedImage['label']); + $this->assertEquals(1, $updatedImage['position']); + $this->assertEquals(0, $updatedImage['disabled']); + $this->assertEquals('Image Text', $updatedImage['label_default']); + $this->assertEquals(1, $updatedImage['position_default']); + $this->assertEquals(0, $updatedImage['disabled_default']); + $this->assertStringStartsWith('/t/e/test_image', $updatedImage['file']); + $this->assertEquals($updatedImage['file'], $targetProduct->getData('image')); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testCreateWithNotDefaultStoreId() + { + $requestData = [ + 'productSku' => 'simple', + 'entry' => [ + 'id' => null, + 'label' => 'Image Text', + 'position' => 1, + 'types' => ['image'], + 'is_disabled' => false, + ], + 'entryContent' => [ + 'entry_data' => base64_encode(file_get_contents($this->testImagePath)), + 'mime_type' => 'image/jpeg', + 'name' => 'test_image', + ], + 'storeId' => 1, + ]; + + $actualResult = $this->_webApiCall($this->createServiceInfo, $requestData); + $targetProduct = $this->getTargetSimpleProduct(); + $mediaGallery = $targetProduct->getData('media_gallery'); + $this->assertCount(1, $mediaGallery['images']); + $updatedImage = $mediaGallery['images'][0]; + // Values for not default store view were provided + $this->assertEquals('Image Text', $updatedImage['label']); + $this->assertEquals($actualResult, $updatedImage['value_id']); + $this->assertEquals(1, $updatedImage['position']); + $this->assertEquals(0, $updatedImage['disabled']); + $this->assertStringStartsWith('/t/e/test_image', $updatedImage['file']); + $this->assertEquals($updatedImage['file'], $targetProduct->getData('image')); + // No values for default store view were provided + $this->assertNull($updatedImage['label_default']); + $this->assertNull($updatedImage['position_default']); + $this->assertNull($updatedImage['disabled_default']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_image.php + */ + public function testUpdate() + { + $requestData = [ + 'productSku' => 'simple', + 'entry' => [ + 'id' => $this->getTargetGalleryEntryId(), + 'label' => 'Updated Image Text', + 'position' => 10, + 'types' => ['thumbnail'], + 'is_disabled' => true, + ], + // Store ID is not provided so the default one must be used + ]; + + $this->updateServiceInfo['rest']['resourcePath'] = $this->updateServiceInfo['rest']['resourcePath'] + . '/' . $this->getTargetGalleryEntryId(); + + $this->assertTrue($this->_webApiCall($this->updateServiceInfo, $requestData)); + + $targetProduct = $this->getTargetSimpleProduct(); + $this->assertEquals('/m/a/magento_image.jpg', $targetProduct->getData('thumbnail')); + $this->assertNull($targetProduct->getData('image')); + $this->assertNull($targetProduct->getData('small_image')); + $mediaGallery = $targetProduct->getData('media_gallery'); + $this->assertCount(1, $mediaGallery['images']); + $updatedImage = $mediaGallery['images'][0]; + $this->assertEquals('Updated Image Text', $updatedImage['label']); + $this->assertEquals('/m/a/magento_image.jpg', $updatedImage['file']); + $this->assertEquals(10, $updatedImage['position']); + $this->assertEquals(1, $updatedImage['disabled']); + $this->assertEquals('Updated Image Text', $updatedImage['label_default']); + $this->assertEquals(10, $updatedImage['position_default']); + $this->assertEquals(1, $updatedImage['disabled_default']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_image.php + */ + public function testUpdateWithNotDefaultStoreId() + { + $requestData = [ + 'productSku' => 'simple', + 'entry' => [ + 'id' => $this->getTargetGalleryEntryId(), + 'label' => 'Updated Image Text', + 'position' => 10, + 'types' => ['thumbnail'], + 'is_disabled' => true, + ], + 'storeId' => 1, + ]; + + $this->updateServiceInfo['rest']['resourcePath'] = $this->updateServiceInfo['rest']['resourcePath'] + . '/' . $this->getTargetGalleryEntryId(); + + $this->assertTrue($this->_webApiCall($this->updateServiceInfo, $requestData)); + + $targetProduct = $this->getTargetSimpleProduct(); + $this->assertEquals('/m/a/magento_image.jpg', $targetProduct->getData('thumbnail')); + $this->assertNull($targetProduct->getData('image')); + $this->assertNull($targetProduct->getData('small_image')); + $mediaGallery = $targetProduct->getData('media_gallery'); + $this->assertCount(1, $mediaGallery['images']); + $updatedImage = $mediaGallery['images'][0]; + // Not default store view values were updated + $this->assertEquals('Updated Image Text', $updatedImage['label']); + $this->assertEquals('/m/a/magento_image.jpg', $updatedImage['file']); + $this->assertEquals(10, $updatedImage['position']); + $this->assertEquals(1, $updatedImage['disabled']); + // Default store view values were not updated + $this->assertEquals('Image Alt Text', $updatedImage['label_default']); + $this->assertEquals(1, $updatedImage['position_default']); + $this->assertEquals(0, $updatedImage['disabled_default']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_image.php + */ + public function testDelete() + { + $entryId = $this->getTargetGalleryEntryId(); + $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/simple/media/{$entryId}"; + $requestData = [ + 'productSku' => 'simple', + 'entryId' => $this->getTargetGalleryEntryId(), + ]; + + $this->assertTrue($this->_webApiCall($this->deleteServiceInfo, $requestData)); + $targetProduct = $this->getTargetSimpleProduct(); + $mediaGallery = $targetProduct->getData('media_gallery'); + $this->assertCount(0, $mediaGallery['images']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @expectedException \Exception + * @expectedExceptionMessage There is no store with provided ID. + */ + public function testCreateThrowsExceptionIfThereIsNoStoreWithProvidedStoreId() + { + $requestData = [ + 'productSku' => 'simple', + 'entry' => [ + 'id' => null, + 'label' => 'Image Text', + 'position' => 1, + 'types' => ['image'], + 'is_disabled' => false, + ], + 'storeId' => 9999, // target store view does not exist + 'entryContent' => [ + 'entry_data' => base64_encode(file_get_contents($this->testImagePath)), + 'mime_type' => 'image/jpeg', + 'name' => 'test_image', + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @expectedException \Exception + * @expectedExceptionMessage The image content must be valid base64 encoded data. + */ + public function testCreateThrowsExceptionIfProvidedContentIsNotBase64Encoded() + { + $encodedContent = 'not_a_base64_encoded_content'; + $requestData = [ + 'productSku' => 'simple', + 'entry' => [ + 'id' => null, + 'label' => 'Image Text', + 'position' => 1, + 'is_disabled' => false, + 'types' => ['image'], + ], + 'entryContent' => [ + 'entry_data' => $encodedContent, + 'mime_type' => 'image/jpeg', + 'name' => 'test_image', + ], + 'storeId' => 0, + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @expectedException \Exception + * @expectedExceptionMessage The image content must be valid base64 encoded data. + */ + public function testCreateThrowsExceptionIfProvidedContentIsNotAnImage() + { + $encodedContent = base64_encode('not_an_image'); + $requestData = [ + 'productSku' => 'simple', + 'entry' => [ + 'id' => null, + 'is_disabled' => false, + 'label' => 'Image Text', + 'position' => 1, + 'types' => ['image'], + ], + 'entryContent' => [ + 'entry_data' => $encodedContent, + 'mime_type' => 'image/jpeg', + 'name' => 'test_image', + ], + 'storeId' => 0, + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @expectedException \Exception + * @expectedExceptionMessage The image MIME type is not valid or not supported. + */ + public function testCreateThrowsExceptionIfProvidedImageHasWrongMimeType() + { + $encodedContent = base64_encode(file_get_contents($this->testImagePath)); + $requestData = [ + 'entry' => [ + 'id' => null, + 'label' => 'Image Text', + 'position' => 1, + 'types' => ['image'], + 'is_disabled' => false, + ], + 'productSku' => 'simple', + 'entryContent' => [ + 'entry_data' => $encodedContent, + 'mime_type' => 'wrong_mime_type', + 'name' => 'test_image', + ], + 'storeId' => 0, + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Requested product doesn't exist + */ + public function testCreateThrowsExceptionIfTargetProductDoesNotExist() + { + $this->createServiceInfo['rest']['resourcePath'] = '/V1/products/wrong_product_sku/media'; + $requestData = [ + 'productSku' => 'wrong_product_sku', + 'entry' => [ + 'id' => null, + 'position' => 1, + 'label' => 'Image Text', + 'types' => ['image'], + 'is_disabled' => false, + ], + 'entryContent' => [ + 'entry_data' => base64_encode(file_get_contents($this->testImagePath)), + 'mime_type' => 'image/jpeg', + 'name' => 'test_image', + ], + 'storeId' => 0, + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @expectedException \Exception + * @expectedExceptionMessage Provided image name contains forbidden characters. + */ + public function testCreateThrowsExceptionIfProvidedImageNameContainsForbiddenCharacters() + { + $requestData = [ + 'productSku' => 'simple', + 'entry' => [ + 'id' => null, + 'label' => 'Image Text', + 'position' => 1, + 'types' => ['image'], + 'is_disabled' => false, + ], + 'entryContent' => [ + 'entry_data' => base64_encode(file_get_contents($this->testImagePath)), + 'mime_type' => 'image/jpeg', + 'name' => 'test/\\{}|:"<>', // Cannot contain \ / : * ? " < > | + ], + 'storeId' => 0, + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_image.php + * @expectedException \Exception + * @expectedExceptionMessage There is no store with provided ID. + */ + public function testUpdateIfThereIsNoStoreWithProvidedStoreId() + { + $requestData = [ + 'productSku' => 'simple', + 'entry' => [ + 'id' => $this->getTargetGalleryEntryId(), + 'label' => 'Updated Image Text', + 'position' => 10, + 'types' => ['thumbnail'], + 'is_disabled' => true, + ], + 'storeId' => 9999, // target store view does not exist + ]; + + $this->updateServiceInfo['rest']['resourcePath'] = $this->updateServiceInfo['rest']['resourcePath'] + . '/' . $this->getTargetGalleryEntryId(); + + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Requested product doesn't exist + */ + public function testUpdateThrowsExceptionIfTargetProductDoesNotExist() + { + $this->updateServiceInfo['rest']['resourcePath'] = '/V1/products/wrong_product_sku/media' + . '/' . $this->getTargetGalleryEntryId(); + $requestData = [ + 'productSku' => 'wrong_product_sku', + 'entry' => [ + 'id' => 9999, + 'label' => 'Updated Image Text', + 'position' => 1, + 'types' => ['thumbnail'], + 'is_disabled' => true, + ], + 'storeId' => 0, + ]; + + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_image.php + * @expectedException \Exception + * @expectedExceptionMessage There is no image with provided ID. + */ + public function testUpdateThrowsExceptionIfThereIsNoImageWithGivenId() + { + $requestData = [ + 'productSku' => 'simple', + 'entry' => [ + 'id' => 9999, + 'label' => 'Updated Image Text', + 'position' => 1, + 'types' => ['thumbnail'], + 'is_disabled' => true, + ], + 'storeId' => 0, + ]; + + $this->updateServiceInfo['rest']['resourcePath'] = $this->updateServiceInfo['rest']['resourcePath'] + . '/' . $this->getTargetGalleryEntryId(); + + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Requested product doesn't exist + */ + public function testDeleteThrowsExceptionIfTargetProductDoesNotExist() + { + $this->deleteServiceInfo['rest']['resourcePath'] = '/V1/products/wrong_product_sku/media/9999'; + $requestData = [ + 'productSku' => 'wrong_product_sku', + 'entryId' => 9999, + ]; + + $this->_webApiCall($this->deleteServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_image.php + * @expectedException \Exception + * @expectedExceptionMessage There is no image with provided ID. + */ + public function testDeleteThrowsExceptionIfThereIsNoImageWithGivenId() + { + $this->deleteServiceInfo['rest']['resourcePath'] = '/V1/products/simple/media/9999'; + $requestData = [ + 'productSku' => 'simple', + 'entryId' => 9999, + ]; + + $this->_webApiCall($this->deleteServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_image.php + */ + public function testGet() + { + $productSku = 'simple'; + + $objectManager = \Magento\TestFramework\ObjectManager::getInstance(); + /** @var \Magento\Catalog\Model\ProductRepository $repository */ + $repository = $objectManager->create('Magento\Catalog\Model\ProductRepository'); + $product = $repository->get($productSku); + $image = current($product->getMediaGallery('images')); + $imageId = $image['value_id']; + + $expected = [ + 'label' => $image['label'], + 'position' => $image['position'], + 'is_disabled' => (bool)$image['disabled'], + 'file' => $image['file'], + 'types' => ['image', 'small_image', 'thumbnail'], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $productSku . '/media/' . $imageId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'catalogProductAttributeMediaGalleryManagementV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogProductAttributeMediaGalleryManagementV1Get', + ], + ]; + $requestData = [ + 'productSku' => $productSku, + 'imageId' => $imageId, + ]; + $data = $this->_webApiCall($serviceInfo, $requestData); + $actual = (array) $data; + $this->assertEquals($expected['label'], $actual['label']); + $this->assertEquals($expected['position'], $actual['position']); + $this->assertEquals($expected['file'], $actual['file']); + $this->assertEquals($expected['types'], $actual['types']); + $this->assertEquals($expected['is_disabled'], (bool)$actual['is_disabled']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_image.php + */ + public function testGetList() + { + $productSku = 'simple'; //from fixture + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . urlencode($productSku) . '/media', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'catalogProductAttributeMediaGalleryManagementV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogProductAttributeMediaGalleryManagementV1GetList', + ], + ]; + + $requestData = [ + 'productSku' => $productSku, + ]; + $imageList = $this->_webApiCall($serviceInfo, $requestData); + + $image = reset($imageList); + $this->assertEquals('/m/a/magento_image.jpg', $image['file']); + $this->assertNotEmpty($image['types']); + $imageTypes = $image['types']; + $this->assertContains('image', $imageTypes); + $this->assertContains('small_image', $imageTypes); + $this->assertContains('thumbnail', $imageTypes); + } + + public function testGetListForAbsentSku() + { + $productSku = 'absent_sku_' . time(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . urlencode($productSku) . '/media', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'catalogProductAttributeMediaGalleryManagementV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogProductAttributeMediaGalleryManagementV1GetList', + ], + ]; + + $requestData = [ + 'productSku' => $productSku, + ]; + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->setExpectedException('SoapFault', 'Requested product doesn\'t exist'); + } else { + $this->setExpectedException('Exception', '', 404); + } + $this->_webApiCall($serviceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1b687f2a6f4fe15216c03ebd355a75feb756243f --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php @@ -0,0 +1,152 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\Eav\Api\Data\AttributeOptionInterface; +use Magento\Eav\Api\Data\AttributeOptionLabelInterface; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductAttributeOptionManagementInterfaceTest extends WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductAttributeOptionManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/attributes'; + + public function testGetItems() + { + $testAttributeCode = 'quantity_and_stock_status'; + $expectedOptions = [ + [ + AttributeOptionInterface::VALUE => '1', + AttributeOptionInterface::LABEL => 'In Stock', + ], + [ + AttributeOptionInterface::VALUE => '0', + AttributeOptionInterface::LABEL => 'Out of Stock', + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $testAttributeCode . '/options', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getItems', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, ['attributeCode' => $testAttributeCode]); + + $this->assertTrue(is_array($response)); + $this->assertEquals($expectedOptions, $response); + } + + /** + * @magentoApiDataFixture Magento/Catalog/Model/Product/Attribute/_files/select_attribute.php + */ + public function testAdd() + { + $testAttributeCode = 'select_attribute'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $testAttributeCode . '/options', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'add', + ], + ]; + + $optionData = [ + AttributeOptionInterface::LABEL => 'new color', + AttributeOptionInterface::VALUE => 'grey', + AttributeOptionInterface::SORT_ORDER => 100, + AttributeOptionInterface::IS_DEFAULT => true, + AttributeOptionInterface::STORE_LABELS => [ + [ + AttributeOptionLabelInterface::LABEL => 'DE label', + AttributeOptionLabelInterface::STORE_ID => 1, + ], + ], + ]; + + $response = $this->_webApiCall( + $serviceInfo, + [ + 'attributeCode' => $testAttributeCode, + 'option' => $optionData, + ] + ); + + $this->assertTrue($response); + $updatedData = $this->getAttributeOptions($testAttributeCode); + $lastOption = array_pop($updatedData); + $this->assertEquals( + $optionData[AttributeOptionInterface::STORE_LABELS][0][AttributeOptionLabelInterface::LABEL], + $lastOption['label'] + ); + } + + /** + * @magentoApiDataFixture Magento/Catalog/Model/Product/Attribute/_files/select_attribute.php + */ + public function testDelete() + { + $attributeCode = 'select_attribute'; + //get option Id + $optionList = $this->getAttributeOptions($attributeCode); + $this->assertGreaterThan(0, count($optionList)); + $lastOption = array_pop($optionList); + $this->assertNotEmpty($lastOption['value']); + $optionId = $lastOption['value']; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $attributeCode . '/options/' . $optionId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'delete', + ], + ]; + $this->assertTrue($this->_webApiCall( + $serviceInfo, + [ + 'attributeCode' => $attributeCode, + 'optionId' => $optionId, + ] + )); + $updatedOptions = $this->getAttributeOptions($attributeCode); + $this->assertEquals($optionList, $updatedOptions); + } + + /** + * @param $testAttributeCode + * @return array|bool|float|int|string + */ + private function getAttributeOptions($testAttributeCode) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $testAttributeCode . '/options', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getItems', + ], + ]; + return $this->_webApiCall($serviceInfo, ['attributeCode' => $testAttributeCode]); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..20742ba9ee0e64cc8972160e1c4fb4c109355f0a --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php @@ -0,0 +1,266 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\Webapi\Exception as HTTPExceptionCodes; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductAttributeRepositoryTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductAttributeRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/attributes'; + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_attribute.php + */ + public function testGet() + { + $attributeCode = 'test_attribute_code_333'; + $attribute = $this->getAttribute($attributeCode); + + $this->assertTrue(is_array($attribute)); + $this->assertArrayHasKey('attribute_id', $attribute); + $this->assertArrayHasKey('attribute_code', $attribute); + $this->assertEquals($attributeCode, $attribute['attribute_code']); + } + + public function testGetList() + { + $searchCriteria = [ + 'searchCriteria' => [ + 'filter_groups' => [ + [ + 'filters' => [ + [ + 'field' => 'frontend_input', + 'value' => 'textarea', + 'condition_type' => 'eq', + ], + ], + ], + ], + 'current_page' => 1, + 'page_size' => 2, + ], + 'entityTypeCode' => \Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE, + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + $response = $this->_webApiCall($serviceInfo, $searchCriteria); + + $this->assertArrayHasKey('search_criteria', $response); + $this->assertArrayHasKey('total_count', $response); + $this->assertArrayHasKey('items', $response); + + $this->assertEquals($searchCriteria['searchCriteria'], $response['search_criteria']); + $this->assertTrue($response['total_count'] > 0); + $this->assertTrue(count($response['items']) > 0); + + $this->assertNotNull($response['items'][0]['default_frontend_label']); + $this->assertNotNull($response['items'][0]['attribute_id']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/Model/Product/Attribute/_files/create_attribute_service.php + */ + public function testCreate() + { + $attributeCode = 'label_attr_code3df4tr3'; + $attribute = $this->createAttribute($attributeCode); + $this->assertArrayHasKey('attribute_id', $attribute); + $this->assertEquals($attributeCode, $attribute['attribute_code']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_attribute.php + */ + public function testCreateWithExceptionIfAttributeAlreadyExists() + { + $attributeCode = 'test_attribute_code_333'; + try { + $this->createAttribute($attributeCode); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + //Expects soap exception + } catch (\Exception $e) { + $this->assertEquals(HTTPExceptionCodes::HTTP_INTERNAL_ERROR, $e->getCode()); + } + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_attribute.php + */ + public function testUpdate() + { + $attributeCode = 'test_attribute_code_333'; + $attribute = $this->getAttribute($attributeCode); + + $attributeData = [ + 'attribute' => [ + 'attribute_code' => $attributeCode, + 'frontend_labels' => [ + ['store_id' => 0, 'label' => 'front_lbl_new'], + ], + 'default_value' => 'default value new', + 'is_required' => false, + 'frontend_input' => 'text', + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $attribute['attribute_id'], + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $attributeData['attribute']['attributeId'] = $attribute['attribute_id']; + } + $result = $this->_webApiCall($serviceInfo, $attributeData); + + $this->assertEquals($attribute['attribute_id'], $result['attribute_id']); + $this->assertEquals($attributeCode, $result['attribute_code']); + $this->assertEquals('default value new', $result['default_value']); + $this->assertEquals('front_lbl_new', $result['default_frontend_label']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_attribute.php + */ + public function testDeleteById() + { + $attributeCode = 'test_attribute_code_333'; + $this->assertTrue($this->deleteAttribute($attributeCode)); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_attribute.php + */ + public function testDeleteNoSuchEntityException() + { + $attributeCode = 'some_test_code'; + $expectedMessage = 'Attribute with attributeCode "' . $attributeCode . '" does not exist.'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $attributeCode, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'deleteById', + ], + ]; + + try { + $this->_webApiCall($serviceInfo, ['attributeCode' => $attributeCode]); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals($expectedMessage, $errorObj['message']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } + + /** + * @param $attributeCode + * @return array|bool|float|int|string + */ + protected function createAttribute($attributeCode) + { + $attributeData = [ + 'attribute' => [ + 'attribute_code' => $attributeCode, + 'frontend_labels' => [ + ['store_id' => 0, 'label' => 'front_lbl'], + ], + 'default_value' => 'default value', + 'frontend_input' => 'textarea', + 'is_required' => true, + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + return $this->_webApiCall($serviceInfo, $attributeData); + } + + /** + * @param $attributeCode + * @return array|bool|float|int|string + */ + protected function getAttribute($attributeCode) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $attributeCode, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + + return $this->_webApiCall($serviceInfo, ['attributeCode' => $attributeCode]); + } + + /** + * Delete attribute by code + * + * @param $attributeCode + * @return array|bool|float|int|string + */ + protected function deleteAttribute($attributeCode) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $attributeCode, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'deleteById', + ], + ]; + return $this->_webApiCall($serviceInfo, ['attributeCode' => $attributeCode]); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeTypesListTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeTypesListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5967b8503bfcd635db17e0725b60dcef321e33f4 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeTypesListTest.php @@ -0,0 +1,37 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductAttributeTypesListTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductAttributeTypesListV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/attributes'; + + public function testGetItems() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/types', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetItems', + ], + ]; + $types = $this->_webApiCall($serviceInfo); + + $this->assertTrue(count($types) > 0); + $this->assertArrayHasKey('value', $types[0]); + $this->assertArrayHasKey('label', $types[0]); + $this->assertNotNull($types[0]['value']); + $this->assertNotNull($types[0]['label']); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1995c194bd5b81d0fa45d0c3027c04628e228854 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php @@ -0,0 +1,367 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Catalog\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; + +class ProductCustomOptionRepositoryTest extends WebapiAbstract +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + const SERVICE_NAME = 'catalogProductCustomOptionRepositoryV1'; + + /** + * @var \Magento\Catalog\Model\ProductFactory + */ + protected $productFactory; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->productFactory = $this->objectManager->get('Magento\Catalog\Model\ProductFactory'); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_options.php + * @magentoAppIsolation enabled + */ + public function testRemove() + { + $sku = 'simple'; + /** @var \Magento\Catalog\Model\Product $product */ + $product = $this->objectManager->create('Magento\Catalog\Model\Product'); + $product->load(1); + $customOptions = $product->getOptions(); + $optionId = array_pop($customOptions)->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => "/V1/products/$sku/options/$optionId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'DeleteByIdentifier', + ], + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, ['productSku' => $sku, 'optionId' => $optionId])); + /** @var \Magento\Catalog\Model\Product $product */ + $product = $this->objectManager->create('Magento\Catalog\Model\Product'); + $product->load(1); + $this->assertNull($product->getOptionById($optionId)); + $this->assertEquals(9, count($product->getOptions())); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_options.php + * @magentoAppIsolation enabled + */ + public function testGet() + { + $productSku = 'simple'; + /** @var \Magento\Catalog\Api\ProductCustomOptionRepositoryInterface $service */ + $service = Bootstrap::getObjectManager() + ->get('Magento\Catalog\Api\ProductCustomOptionRepositoryInterface'); + $options = $service->getList('simple'); + $option = current($options); + $optionId = $option->getOptionId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $productSku . "/options/" . $optionId, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + $option = $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'optionId' => $optionId]); + unset($option['product_sku']); + unset($option['option_id']); + $excepted = include '_files/product_options.php'; + $this->assertEquals($excepted[0], $option); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_options.php + * @magentoAppIsolation enabled + */ + public function testGetList() + { + $productSku = 'simple'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $productSku . "/options", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + $options = $this->_webApiCall($serviceInfo, ['productSku' => $productSku]); + + /** Unset dynamic data */ + foreach ($options as $key => $value) { + unset($options[$key]['product_sku']); + unset($options[$key]['option_id']); + if (!empty($options[$key]['values'])) { + foreach ($options[$key]['values'] as $newKey => $valueData) { + unset($options[$key]['values'][$newKey]['option_type_id']); + } + } + } + + $excepted = include '_files/product_options.php'; + $this->assertEquals(count($excepted), count($options)); + + //in order to make assertion result readable we need to check each element separately + foreach ($excepted as $index => $value) { + $this->assertEquals($value, $options[$index]); + } + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_without_options.php + * @magentoAppIsolation enabled + * @dataProvider optionDataProvider + */ + public function testSave($optionData) + { + $productSku = 'simple'; + + $optionDataPost = $optionData; + $optionDataPost['product_sku'] = $productSku; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/options', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, ['option' => $optionDataPost]); + unset($result['product_sku']); + unset($result['option_id']); + if (!empty($result['values'])) { + foreach ($result['values'] as $key => $value) { + unset($result['values'][$key]['option_type_id']); + } + } + $this->assertEquals($optionData, $result); + } + + public function optionDataProvider() + { + $fixtureOptions = []; + $fixture = include '_files/product_options.php'; + foreach ($fixture as $item) { + $fixtureOptions[$item['type']] = [ + 'optionData' => $item, + ]; + }; + + return $fixtureOptions; + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_without_options.php + * @magentoAppIsolation enabled + * @dataProvider optionNegativeDataProvider + */ + public function testAddNegative($optionData) + { + $productSku = 'simple'; + $optionDataPost = $optionData; + $optionDataPost['product_sku'] = $productSku; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => "/V1/products/options", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->setExpectedException('SoapFault', 'Could not save product option'); + } else { + $this->setExpectedException('Exception', '', 400); + } + $this->_webApiCall($serviceInfo, ['option' => $optionDataPost]); + } + + public function optionNegativeDataProvider() + { + $fixtureOptions = []; + $fixture = include '_files/product_options_negative.php'; + foreach ($fixture as $key => $item) { + $fixtureOptions[$key] = [ + 'optionData' => $item, + ]; + }; + + return $fixtureOptions; + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_options.php + * @magentoAppIsolation enabled + */ + public function testUpdate() + { + $productSku = 'simple'; + /** @var \Magento\Catalog\Model\ProductRepository $optionReadService */ + $productRepository = $this->objectManager->create( + 'Magento\Catalog\Model\ProductRepository' + ); + + $options = $productRepository->get($productSku, true)->getOptions(); + $option = array_shift($options); + $optionId = $option->getOptionId(); + $optionDataPost = [ + 'product_sku' => $productSku, + 'title' => $option->getTitle() . "_updated", + 'type' => $option->getType(), + 'sort_order' => $option->getSortOrder(), + 'is_require' => $option->getIsRequire(), + 'price' => $option->getPrice(), + 'price_type' => $option->getPriceType(), + 'sku' => $option->getSku(), + 'max_characters' => 500, + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/options/' . $optionId, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $optionDataPost['option_id'] = $optionId; + $updatedOption = $this->_webApiCall( + $serviceInfo, [ 'id' => $optionId, 'option' => $optionDataPost] + ); + } else { + $updatedOption = $this->_webApiCall( + $serviceInfo, ['option' => $optionDataPost] + ); + } + + unset($updatedOption['values']); + $optionDataPost['option_id'] = $option->getOptionId(); + $this->assertEquals($optionDataPost, $updatedOption); + } + + /** + * @param string $optionType + * + * @magentoApiDataFixture Magento/Catalog/_files/product_with_options.php + * @magentoAppIsolation enabled + * @dataProvider validOptionDataProvider + */ + public function testUpdateOptionAddingNewValue($optionType) + { + $productId = 1; + $fixtureOption = null; + $valueData = [ + 'price' => 100500, + 'price_type' => 'fixed', + 'sku' => 'new option sku ' . $optionType, + 'title' => 'New Option Title', + 'sort_order' => 100, + ]; + + $product = $this->productFactory->create(); + $product->load($productId); + + /**@var $option \Magento\Catalog\Model\Product\Option */ + foreach ($product->getOptions() as $option) { + if ($option->getType() == $optionType) { + $fixtureOption = $option; + break; + } + } + + $values = []; + foreach ($option->getValues() as $key => $value) { + $values[] = [ + 'price' => $value->getPrice(), + 'price_type' => $value->getPriceType(), + 'sku' => $value->getSku(), + 'title' => $value->getTitle(), + 'sort_order' => $value->getSortOrder(), + ]; + } + $values[] = $valueData; + $data = [ + 'product_sku' => $option->getProductSku(), + 'title' => $option->getTitle(), + 'type' => $option->getType(), + 'is_require' => $option->getIsRequire(), + 'sort_order' => $option->getSortOrder(), + 'values' => $values, + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/options/' . $fixtureOption->getId(), + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $data['option_id'] = $fixtureOption->getId(); + $valueObject = $this->_webApiCall( + $serviceInfo, [ 'option_id' => $fixtureOption->getId(), 'option' => $data] + ); + } else { + $valueObject = $this->_webApiCall( + $serviceInfo, ['option' => $data] + ); + } + + $values = end($valueObject['values']); + $this->assertEquals($valueData['price'], $values['price']); + $this->assertEquals($valueData['price_type'], $values['price_type']); + $this->assertEquals($valueData['sku'], $values['sku']); + $this->assertEquals('New Option Title', $values['title']); + $this->assertEquals(100, $values['sort_order']); + } + + public function validOptionDataProvider() + { + return [ + 'drop_down' => ['drop_down'], + 'checkbox' => ['checkbox'], + 'radio' => ['radio'], + 'multiple' => ['multiple'] + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionTypeListTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionTypeListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..eb0f890231e58871102aa684a33ccb699d8902b1 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionTypeListTest.php @@ -0,0 +1,42 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Catalog\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; + +class ProductCustomOptionTypeListTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/products/options/'; + + const SERVICE_NAME = 'catalogProductCustomOptionTypeListV1'; + + /** + * @magentoAppIsolation enabled + */ + public function testGetTypes() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "types", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'GetItems', + ], + ]; + $types = $this->_webApiCall($serviceInfo); + $excepted = [ + 'label' => __('Drop-down'), + 'code' => 'drop_down', + 'group' => __('Select'), + ]; + $this->assertGreaterThanOrEqual(10, count($types)); + $this->assertContains($excepted, $types); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductGroupPriceManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductGroupPriceManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..035931302519d5baa2b598bb2865008828b1e045 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductGroupPriceManagementTest.php @@ -0,0 +1,118 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Catalog\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductGroupPriceManagementTest extends WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductGroupPriceManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/'; + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_group_prices.php + */ + public function testGetList() + { + $productSku = 'simple_with_group_price'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $productSku . '/group-prices', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + $groupPriceList = $this->_webApiCall($serviceInfo, ['productSku' => $productSku]); + $this->assertCount(2, $groupPriceList); + $this->assertEquals(9, $groupPriceList[0]['value']); + $this->assertEquals(7, $groupPriceList[1]['value']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_group_prices.php + */ + public function testDelete() + { + $productSku = 'simple_with_group_price'; + $customerGroupId = \Magento\Customer\Model\GroupManagement::NOT_LOGGED_IN_ID; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $productSku . "/group-prices/" . $customerGroupId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Remove', + ], + ]; + $requestData = ['productSku' => $productSku, 'customerGroupId' => $customerGroupId]; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testAdd() + { + $productSku = 'simple'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $productSku . '/group-prices/1/price/10', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Add', + ], + ]; + $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'customerGroupId' => 1, 'price' => 10]); + $objectManager = \Magento\TestFramework\ObjectManager::getInstance(); + /** @var \Magento\Catalog\Api\ProductGroupPriceManagementInterface $service */ + $service = $objectManager->get('Magento\Catalog\Api\ProductGroupPriceManagementInterface'); + $prices = $service->getList($productSku); + $this->assertCount(1, $prices); + $this->assertEquals(10, $prices[0]->getValue()); + $this->assertEquals(1, $prices[0]->getCustomerGroupId()); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @magentoApiDataFixture Magento/Store/_files/website.php + */ + public function testAddForDifferentWebsite() + { + $productSku = 'simple'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $productSku . '/group-prices/1/price/10', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Add', + ], + + ]; + $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'customerGroupId' => 1, 'price' => 10]); + $objectManager = \Magento\TestFramework\ObjectManager::getInstance(); + /** @var \Magento\Catalog\Api\ProductGroupPriceManagementInterface $service */ + $service = $objectManager->get('Magento\Catalog\Api\ProductGroupPriceManagementInterface'); + $prices = $service->getList($productSku); + $this->assertCount(1, $prices); + $this->assertEquals(10, $prices[0]->getValue()); + $this->assertEquals(1, $prices[0]->getCustomerGroupId()); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkManagementInterfaceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..67df2361c2c7ae928c9ba2f80e83f2d17abec267 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkManagementInterfaceTest.php @@ -0,0 +1,143 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductLinkManagementInterfaceTest extends WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductLinkManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/'; + + /** + * @var \Magento\Framework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/products_crosssell.php + */ + public function testGetLinkedProductsCrossSell() + { + $productSku = 'simple_with_cross'; + $linkType = 'crosssell'; + + $this->assertLinkedProducts($productSku, $linkType); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/products_related.php + */ + public function testGetLinkedProductsRelated() + { + $productSku = 'simple_with_cross'; + $linkType = 'related'; + + $this->assertLinkedProducts($productSku, $linkType); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/products_upsell.php + */ + public function testGetLinkedProductsUpSell() + { + $productSku = 'simple_with_upsell'; + $linkType = 'upsell'; + + $this->assertLinkedProducts($productSku, $linkType); + } + + /** + * @param string $productSku + * @param int $linkType + */ + protected function assertLinkedProducts($productSku, $linkType) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $productSku . '/links/' . $linkType, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetLinkedItemsByType', + ], + ]; + + $actual = $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'type' => $linkType]); + + $this->assertEquals('simple', $actual[0]['linked_product_type']); + $this->assertEquals('simple', $actual[0]['linked_product_sku']); + $this->assertEquals(1, $actual[0]['position']); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @magentoApiDataFixture Magento/Catalog/_files/product_virtual.php + */ + public function testAssign() + { + $linkType = 'related'; + $productSku = 'simple'; + $linkData = [ + 'linked_product_type' => 'virtual', + 'linked_product_sku' => 'virtual-product', + 'position' => 100, + 'product_sku' => 'simple', + 'link_type' => 'related', + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $productSku . '/links/' . $linkType, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'SetProductLinks', + ], + ]; + + $arguments = [ + 'productSku' => $productSku, + 'items' => [$linkData], + 'type' => $linkType, + ]; + + $this->_webApiCall($serviceInfo, $arguments); + $actual = $this->getLinkedProducts($productSku, 'related'); + array_walk($actual, function (&$item) { + $item = $item->__toArray(); + }); + $this->assertEquals([$linkData], $actual); + } + + /** + * Get list of linked products + * + * @param string $sku + * @param string $linkType + * @return \Magento\Catalog\Api\Data\ProductLinkInterface[] + */ + protected function getLinkedProducts($sku, $linkType) + { + /** @var \Magento\Catalog\Model\ProductLink\Management $linkManagement */ + $linkManagement = $this->objectManager->get('Magento\Catalog\Api\ProductLinkManagementInterface'); + $linkedProducts = $linkManagement->getLinkedItemsByType($sku, $linkType); + + return $linkedProducts; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkRepositoryInterfaceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ff04d9044a11382fb656ef82e2d8f3a476f147ff --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkRepositoryInterfaceTest.php @@ -0,0 +1,103 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductLinkRepositoryInterfaceTest extends WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductLinkRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/'; + + /** + * @var \Magento\Framework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/products_related_multiple.php + * @magentoAppIsolation enabled + */ + public function testDelete() + { + $productSku = 'simple_with_cross'; + $linkedSku = 'simple'; + $linkType = 'related'; + $this->_webApiCall( + [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $productSku . '/links/' . $linkType . '/' . $linkedSku, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ], + [ + 'productSku' => $productSku, + 'type' => $linkType, + 'linkedProductSku' => $linkedSku + ] + ); + /** @var \Magento\Catalog\Model\ProductLink\Management $linkManagement */ + $linkManagement = $this->objectManager->create('Magento\Catalog\Api\ProductLinkManagementInterface'); + $linkedProducts = $linkManagement->getLinkedItemsByType($productSku, $linkType); + $this->assertCount(1, $linkedProducts); + /** @var \Magento\Catalog\Api\Data\ProductLinkInterface $product */ + $product = current($linkedProducts); + $this->assertEquals($product->getLinkedProductSku(), 'simple_with_cross_two'); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/products_related.php + */ + public function testSave() + { + $productSku = 'simple_with_cross'; + $linkType = 'related'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $productSku . '/links/' . $linkType, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $this->_webApiCall( + $serviceInfo, + [ + 'entity' => [ + 'product_sku' => 'simple_with_cross', + 'link_type' => 'related', + 'linked_product_sku' => 'simple', + 'linked_product_type' => 'simple', + 'position' => 1000, + ] + ] + ); + + /** @var \Magento\Catalog\Model\ProductLink\Management $linkManagement */ + $linkManagement = $this->objectManager->get('Magento\Catalog\Api\ProductLinkManagementInterface'); + $actual = $linkManagement->getLinkedItemsByType($productSku, $linkType); + $this->assertCount(1, $actual, 'Invalid actual linked products count'); + $this->assertEquals(1000, $actual[0]->getPosition(), 'Product position is not updated'); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkTypeListTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkTypeListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3fb46da2b49e8c635499136c87d24a159b4557f0 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductLinkTypeListTest.php @@ -0,0 +1,53 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\Catalog\Model\Product\Link; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductLinkTypeListTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductLinkTypeListV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/'; + + public function testGetItems() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . 'links/types', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetItems', + ], + ]; + $actual = $this->_webApiCall($serviceInfo); + $expectedItems = ['name' => 'related', 'code' => Link::LINK_TYPE_RELATED]; + $this->assertContains($expectedItems, $actual); + } + + public function testGetItemAttributes() + { + $linkType = 'related'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . 'links/' . $linkType . '/attributes', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetItemAttributes', + ], + ]; + $actual = $this->_webApiCall($serviceInfo, ['type' => $linkType]); + $expected = [['code' => 'position', 'type' => 'int']]; + $this->assertEquals($expected, $actual); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductMediaAttributeManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductMediaAttributeManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..8939bf5c362a322708c760a29f64d055e686c8f0 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductMediaAttributeManagementTest.php @@ -0,0 +1,60 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductMediaAttributeManagementTest extends WebapiAbstract +{ + /** + * @magentoApiDataFixture Magento/Catalog/_files/attribute_set_with_image_attribute.php + */ + public function testGetList() + { + $attributeSetName = 'attribute_set_with_media_attribute'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/media/types/' . $attributeSetName, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'catalogProductMediaAttributeManagementV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogProductMediaAttributeManagementV1GetList', + ], + ]; + + $requestData = [ + 'attributeSetName' => $attributeSetName, + ]; + + $mediaAttributes = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertNotEmpty($mediaAttributes); + $attribute = $this->getAttributeByCode($mediaAttributes, 'funny_image'); + $this->assertNotNull($attribute); + $this->assertEquals('Funny image', $attribute['default_frontend_label']); + $this->assertEquals(1, $attribute['is_user_defined']); + } + + /** + * Retrieve attribute based on given attribute code + * + * @param array $attributeList + * @param string $attributeCode + * @return array|null + */ + protected function getAttributeByCode($attributeList, $attributeCode) + { + foreach ($attributeList as $attribute) { + if ($attributeCode == $attribute['attribute_code']) { + return $attribute; + } + } + + return null; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7b9e84a65f4d1adc2bf76578c9dad4d3e77d70b4 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php @@ -0,0 +1,279 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Exception as HTTPExceptionCodes; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductRepositoryInterfaceTest extends WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products'; + + private $productData = [ + [ + ProductInterface::SKU => 'simple', + ProductInterface::NAME => 'Simple Related Product', + ProductInterface::TYPE_ID => 'simple', + ProductInterface::PRICE => 10, + ], + [ + ProductInterface::SKU => 'simple_with_cross', + ProductInterface::NAME => 'Simple Product With Related Product', + ProductInterface::TYPE_ID => 'simple', + ProductInterface::PRICE => 10 + ], + ]; + + /** + * @magentoApiDataFixture Magento/Catalog/_files/products_related.php + */ + public function testGet() + { + $productData = $this->productData[0]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productData[ProductInterface::SKU], + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, ['productSku' => $productData[ProductInterface::SKU]]); + foreach ([ProductInterface::SKU, ProductInterface::NAME, ProductInterface::PRICE] as $key) { + $this->assertEquals($productData[$key], $response[$key]); + } + } + + public function testGetNoSuchEntityException() + { + $invalidSku = '(nonExistingSku)'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $invalidSku, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + + $expectedMessage = 'Requested product doesn\'t exist'; + + try { + $this->_webApiCall($serviceInfo, ['productSku' => $invalidSku]); + $this->fail("Expected throwing exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals($expectedMessage, $errorObj['message']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } + + /** + * @return array + */ + public function productCreationProvider() + { + $productBuilder = function ($data) { + return array_replace_recursive( + $this->getSimpleProductData(), + $data + ); + }; + return [ + [$productBuilder([ProductInterface::TYPE_ID => 'simple', ProductInterface::SKU => 'psku-test-1'])], + [$productBuilder([ProductInterface::TYPE_ID => 'virtual', ProductInterface::SKU => 'psku-test-2'])], + ]; + } + + /** + * @dataProvider productCreationProvider + */ + public function testCreate($product) + { + $response = $this->saveProduct($product); + $this->assertArrayHasKey(ProductInterface::SKU, $response); + $this->deleteProduct($product[ProductInterface::SKU]); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testUpdate() + { + $productData = [ + ProductInterface::NAME => 'Very Simple Product', //new name + ProductInterface::SKU => 'simple', //sku from fixture + ]; + $product = $this->getSimpleProductData($productData); + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_REST) { + $product[ProductInterface::SKU] = null; + } + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productData[ProductInterface::SKU], + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $requestData = ['product' => $product]; + $response = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertArrayHasKey(ProductInterface::SKU, $response); + $this->assertArrayHasKey(ProductInterface::NAME, $response); + $this->assertEquals($productData[ProductInterface::NAME], $response[ProductInterface::NAME]); + $this->assertEquals($productData[ProductInterface::SKU], $response[ProductInterface::SKU]); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testDelete() + { + $response = $this->deleteProduct('simple'); + $this->assertTrue($response); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testGetList() + { + $searchCriteria = [ + 'searchCriteria' => [ + 'filter_groups' => [ + [ + 'filters' => [ + [ + 'field' => 'sku', + 'value' => 'simple', + 'condition_type' => 'eq', + ], + ], + ], + ], + 'current_page' => 1, + 'page_size' => 2, + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, $searchCriteria); + + $this->assertArrayHasKey('search_criteria', $response); + $this->assertArrayHasKey('total_count', $response); + $this->assertArrayHasKey('items', $response); + + $this->assertEquals($searchCriteria['searchCriteria'], $response['search_criteria']); + $this->assertTrue($response['total_count'] > 0); + $this->assertTrue(count($response['items']) > 0); + + $this->assertNotNull($response['items'][0]['sku']); + $this->assertEquals('simple', $response['items'][0]['sku']); + } + + /** + * Get Simple Product Data + * + * @param array $productData + * @return array + */ + protected function getSimpleProductData($productData = []) + { + return [ + ProductInterface::SKU => isset($productData[ProductInterface::SKU]) + ? $productData[ProductInterface::SKU] : uniqid('sku-', true), + ProductInterface::NAME => isset($productData[ProductInterface::NAME]) + ? $productData[ProductInterface::NAME] : uniqid('sku-', true), + ProductInterface::VISIBILITY => 4, + ProductInterface::TYPE_ID => 'simple', + ProductInterface::PRICE => 3.62, + ProductInterface::STATUS => 1, + ProductInterface::TYPE_ID => 'simple', + ProductInterface::ATTRIBUTE_SET_ID => 4, + 'custom_attributes' => [ + ['attribute_code' => 'cost', 'value' => ''], + ['attribute_code' => 'description', 'value' => 'Description'], + ] + ]; + } + + /** + * @param $product + * @return mixed + */ + protected function saveProduct($product) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $requestData = ['product' => $product]; + return $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * Delete Product + * + * @param string $sku + * @return boolean + */ + protected function deleteProduct($sku) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $sku, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ]; + + return (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) ? + $this->_webApiCall($serviceInfo, ['productSku' => $sku]) : $this->_webApiCall($serviceInfo); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..04f3d9c3d447f46be7318e207586eedf1134edef --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php @@ -0,0 +1,205 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Catalog\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductTierPriceManagementTest extends WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductTierPriceManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/'; + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @dataProvider getListDataProvider + */ + public function testGetList($customerGroupId, $count, $value, $qty) + { + $productSku = 'simple'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $productSku . '/group-prices/' . $customerGroupId . '/tiers', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + + $groupPriceList = $this->_webApiCall( + $serviceInfo, + ['productSku' => $productSku, 'customerGroupId' => $customerGroupId] + ); + + $this->assertCount($count, $groupPriceList); + if ($count) { + $this->assertEquals($value, $groupPriceList[0]['value']); + $this->assertEquals($qty, $groupPriceList[0]['qty']); + } + } + + public function getListDataProvider() + { + return [ + [0, 1, 5, 3], + [1, 0, null, null], + ['all', 2, 8, 2], + ]; + } + + /** + * @param string|int $customerGroupId + * @param int $qty + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @dataProvider deleteDataProvider + */ + public function testDelete($customerGroupId, $qty) + { + $productSku = 'simple'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH + . $productSku . "/group-prices/" . $customerGroupId . "/tiers/" . $qty, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Remove', + ], + ]; + $requestData = ['productSku' => $productSku, 'customerGroupId' => $customerGroupId, 'qty' => $qty]; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + } + + public function deleteDataProvider() + { + return [ + 'delete_tier_price_for_specific_customer_group' => [0, 3], + 'delete_tier_price_for_all_customer_group' => ['all', 5] + ]; + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @magentoAppIsolation enabled + */ + public function testAdd() + { + $productSku = 'simple'; + $customerGroupId = 1; + $qty = 50; + $price = 10; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $productSku + . '/group-prices/' . $customerGroupId . '/tiers/' . $qty . '/price/' . $price, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Add', + ], + ]; + + $requestData = [ + 'productSku' => $productSku, + 'customerGroupId' => $customerGroupId, + 'qty' => $qty, + 'price' => $price, + ]; + $this->_webApiCall($serviceInfo, $requestData); + $objectManager = \Magento\TestFramework\ObjectManager::getInstance(); + /** @var \Magento\Catalog\Api\ProductTierPriceManagementInterface $service */ + $service = $objectManager->get('Magento\Catalog\Api\ProductTierPriceManagementInterface'); + $prices = $service->getList($productSku, 1); + $this->assertCount(1, $prices); + $this->assertEquals(10, $prices[0]->getValue()); + $this->assertEquals(50, $prices[0]->getQty()); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @magentoAppIsolation enabled + */ + public function testAddWithAllCustomerGrouped() + { + $productSku = 'simple'; + $customerGroupId = 'all'; + $qty = 50; + $price = 20; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $productSku + . '/group-prices/' . $customerGroupId . '/tiers/' . $qty . '/price/' . $price, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Add', + ], + ]; + $requestData = [ + 'productSku' => $productSku, + 'customerGroupId' => $customerGroupId, + 'qty' => $qty, + 'price' => $price, + ]; + $this->_webApiCall($serviceInfo, $requestData); + $objectManager = \Magento\TestFramework\ObjectManager::getInstance(); + /** @var \Magento\Catalog\Api\ProductTierPriceManagementInterface $service */ + $service = $objectManager->get('Magento\Catalog\Api\ProductTierPriceManagementInterface'); + $prices = $service->getList($productSku, 'all'); + $this->assertCount(3, $prices); + $this->assertEquals(20, (int)$prices[2]->getValue()); + $this->assertEquals(50, (int)$prices[2]->getQty()); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @magentoAppIsolation enabled + */ + public function testUpdateWithAllGroups() + { + $productSku = 'simple'; + $customerGroupId = 'all'; + $qty = 2; + $price = 20; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $productSku + . '/group-prices/' . $customerGroupId . '/tiers/' . $qty . '/price/' . $price, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Add', + ], + ]; + $requestData = [ + 'productSku' => $productSku, + 'customerGroupId' => $customerGroupId, + 'qty' => $qty, + 'price' => $price, + ]; + $this->_webApiCall($serviceInfo, $requestData); + $objectManager = \Magento\TestFramework\ObjectManager::getInstance(); + /** @var \Magento\Catalog\Api\ProductTierPriceManagementInterface $service */ + $service = $objectManager->get('Magento\Catalog\Api\ProductTierPriceManagementInterface'); + $prices = $service->getList($productSku, 'all'); + $this->assertCount(2, $prices); + $this->assertEquals(20, (int)$prices[0]->getValue()); + $this->assertEquals(2, (int)$prices[0]->getQty()); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTypeListTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTypeListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..da15ba53f9221093f39b9154879fe9f8bddc1f9c --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTypeListTest.php @@ -0,0 +1,59 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Catalog\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductTypeListTest extends WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductTypeListV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/'; + + public function testGetProductTypes() + { + $expectedProductTypes = [ + [ + 'name' => 'simple', + 'label' => 'Simple Product', + ], + [ + 'name' => 'virtual', + 'label' => 'Virtual Product', + ], + [ + 'name' => 'downloadable', + 'label' => 'Downloadable Product', + ], + [ + 'name' => 'bundle', + 'label' => 'Bundle Product', + ], + [ + 'name' => 'configurable', + 'label' => 'Configurable Product', + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/types', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetProductTypes', + ], + ]; + + $productTypes = $this->_webApiCall($serviceInfo); + + foreach ($expectedProductTypes as $expectedProductType) { + $this->assertContains($expectedProductType, $productTypes); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php new file mode 100644 index 0000000000000000000000000000000000000000..a302a11ae9388df415cb27d9f667edc997149ab0 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php @@ -0,0 +1,162 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +return [ + [ + 'title' => 'test_option_code_1', + 'type' => 'field', + 'sort_order' => 1, + 'is_require' => 1, + 'price' => 10, + 'price_type' => 'fixed', + 'sku' => 'sku1', + 'max_characters' => 10, + 'values' => [], + ], + [ + 'title' => 'area option', + 'type' => 'area', + 'sort_order' => 2, + 'is_require' => 0, + 'price' => 20, + 'price_type' => 'percent', + 'sku' => 'sku2', + 'max_characters' => 20, + 'values' => [] + ], + [ + 'title' => 'file option', + 'type' => 'file', + 'sort_order' => 3, + 'is_require' => 1, + 'price' => 30, + 'price_type' => 'percent', + 'sku' => 'sku3', + 'file_extension' => 'jpg, png, gif', + 'image_size_x' => 10, + 'image_size_y' => 20, + 'values' => [] + ], + [ + 'title' => 'drop_down option', + 'type' => 'drop_down', + 'sort_order' => 4, + 'is_require' => 1, + 'values' => [ + [ + 'title' => 'drop_down option 1', + 'sort_order' => 1, + 'price' => 10, + 'price_type' => 'fixed', + 'sku' => 'drop_down option 1 sku', + + ], + [ + 'title' => 'drop_down option 2', + 'sort_order' => 2, + 'price' => 20, + 'price_type' => 'fixed', + 'sku' => 'drop_down option 2 sku' + ], + ], + ], + [ + 'title' => 'radio option', + 'type' => 'radio', + 'sort_order' => 5, + 'is_require' => 1, + 'values' => [ + [ + 'title' => 'radio option 1', + 'sort_order' => 1, + 'price' => 10, + 'price_type' => 'fixed', + 'sku' => 'radio option 1 sku', + ], + [ + 'title' => 'radio option 2', + 'sort_order' => 2, + 'price' => 20, + 'price_type' => 'fixed', + 'sku' => 'radio option 2 sku', + ], + ], + ], + [ + 'title' => 'checkbox option', + 'type' => 'checkbox', + 'sort_order' => 6, + 'is_require' => 1, + 'values' => [ + [ + 'title' => 'checkbox option 1', + 'sort_order' => 1, + 'price' => 10, + 'price_type' => 'fixed', + 'sku' => 'checkbox option 1 sku', + ], + [ + 'title' => 'checkbox option 2', + 'sort_order' => 2, + 'price' => 20, + 'price_type' => 'fixed', + 'sku' => 'checkbox option 2 sku' + ], + ], + ], + [ + 'title' => 'multiple option', + 'type' => 'multiple', + 'sort_order' => 7, + 'is_require' => 1, + 'values' => [ + [ + 'title' => 'multiple option 1', + 'sort_order' => 1, + 'price' => 10, + 'price_type' => 'fixed', + 'sku' => 'multiple option 1 sku', + ], + [ + 'title' => 'multiple option 2', + 'sort_order' => 2, + 'price' => 20, + 'price_type' => 'fixed', + 'sku' => 'multiple option 2 sku' + ], + ], + ], + [ + 'title' => 'date option', + 'type' => 'date', + 'is_require' => 1, + 'sort_order' => 8, + 'price' => 80.0, + 'price_type' => 'fixed', + 'sku' => 'date option sku', + 'values' => [] + + ], + [ + 'title' => 'date_time option', + 'type' => 'date_time', + 'is_require' => 1, + 'sort_order' => 9, + 'price' => 90.0, + 'price_type' => 'fixed', + 'sku' => 'date_time option sku', + 'values' => [] + ], + [ + 'title' => 'time option', + 'type' => 'time', + 'is_require' => 1, + 'sort_order' => 10, + 'price' => 100.0, + 'price_type' => 'fixed', + 'sku' => 'time option sku', + 'values' => [] + ], +]; diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options_negative.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options_negative.php new file mode 100644 index 0000000000000000000000000000000000000000..24fb82474ec0acce36ff5e886f657bb29730a276 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options_negative.php @@ -0,0 +1,91 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +return [ + 'empty_required_field' => [ + 'title' => '', + 'type' => 'field', + 'sort_order' => 1, + 'is_require' => 1, + 'price' => 10, + 'price_type' => 'fixed', + 'sku' => 'sku1', + 'max_characters' => 10, + ], + 'negative_price' => [ + 'title' => 'area option', + 'type' => 'area', + 'sort_order' => 2, + 'is_require' => 0, + 'price' => -20, + 'price_type' => 'percent', + 'sku' => 'sku2', + 'max_characters' => 20, + + ], + 'negative_value_of_image_size' => [ + 'title' => 'file option', + 'type' => 'file', + 'sort_order' => 3, + 'is_require' => 1, + 'price' => 30, + 'price_type' => 'percent', + 'sku' => 'sku3', + 'file_extension' => 'jpg', + 'image_size_x' => -10, + 'image_size_y' => -20, + ], + 'option_with_type_select_without_options' => [ + 'title' => 'drop_down option', + 'type' => 'drop_down', + 'sort_order' => 4, + 'is_require' => 1, + ], + 'title_is_empty' => [ + 'title' => 'radio option', + 'type' => 'radio', + 'sort_order' => 5, + 'is_require' => 1, + 'values' => [ + [ + 'price' => 10, + 'price_type' => 'fixed', + 'sku' => 'radio option 1 sku', + 'title' => '', + 'sort_order' => 1, + ], + ], + ], + 'option_with_non_existing_price_type' => [ + 'title' => 'checkbox option', + 'type' => 'checkbox', + 'sort_order' => 6, + 'is_require' => 1, + 'values' => [ + [ + 'price' => 10, + 'price_type' => 'fixed_one', + 'sku' => 'checkbox option 1 sku', + 'title' => 'checkbox option 1', + 'sort_order' => 1, + ], + ], + ], + 'option_with_non_existing_option_type' => [ + 'title' => 'multiple option', + 'type' => 'multiple_some_value', + 'sort_order' => 7, + 'is_require' => 1, + 'values' => [ + [ + 'price' => 10, + 'price_type' => 'fixed', + 'sku' => 'multiple option 1 sku', + 'title' => 'multiple option 1', + 'sort_order' => 1, + ], + ], + ], +]; diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/test_image.jpg b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/test_image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad6b747f73dd9d20f73b8fc780e74d1ff7952762 Binary files /dev/null and b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/test_image.jpg differ diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/LowStockItemsTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/LowStockItemsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..67c42fe79b822a94d69b605b2a3bb5496bd9a0a4 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/LowStockItemsTest.php @@ -0,0 +1,79 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\CatalogInventory\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class LowStockItemsTest + */ +class LowStockItemsTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/stockItem/lowStock/'; + + /** + * @param float $qty + * @param int $currentPage + * @param int $pageSize + * @param array $result + * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php + * @dataProvider getLowStockItemsDataProvider + */ + public function testGetLowStockItems($qty, $currentPage, $pageSize, $result) + { + $requestData = ['websiteId' => 1, 'qty' => $qty, 'pageSize' => $pageSize, 'currentPage' => $currentPage]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '?' . http_build_query($requestData), + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'catalogInventoryStockRegistryV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'catalogInventoryStockRegistryV1GetLowStockItems', + ], + ]; + $output = $this->_webApiCall($serviceInfo, $requestData); + $this->assertArrayHasKey('items', $output); + } + + /** + * @return array + */ + public function getLowStockItemsDataProvider() + { + return [ + [ + 100, + 1, + 10, + [ + 'search_criteria' => ['current_page' => 1, 'page_size' => 10, 'qty' => 100], + 'total_count' => 2, + 'items' => [ + [ + 'product_id' => 10, + 'website_id' => 1, + 'stock_id' => 1, + 'qty' => 100, + 'stock_status' => null, + 'stock_item' => null, + ], + [ + 'product_id' => 12, + 'website_id' => 1, + 'stock_id' => 1, + 'qty' => 140, + 'stock_status' => null, + 'stock_item' => null + ], + ] + ], + ], + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bab5b01aa08d8c107023d11b69fe9d6a89037d42 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php @@ -0,0 +1,222 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\CatalogInventory\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; + +/** + * Class StockItemTest + */ +class StockItemTest extends WebapiAbstract +{ + /** + * Service name + */ + const SERVICE_NAME = 'catalogInventoryStockItemApi'; + + /** + * Service version + */ + const SERVICE_VERSION = 'V1'; + + /** + * Resource path + */ + const RESOURCE_PATH = '/V1/stockItem'; + + /** @var \Magento\Catalog\Model\Resource\Product\Collection */ + protected $productCollection; + + /** @var \Magento\Framework\ObjectManagerInterface */ + protected $objectManager; + + /** + * Execute per test initialization + */ + public function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->productCollection = $this->objectManager->get('Magento\Catalog\Model\Resource\Product\Collection'); + } + + /** + * Execute per test cleanup + */ + public function tearDown() + { + /** @var \Magento\Framework\Registry $registry */ + $registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry'); + + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', true); + + $this->productCollection->addFieldToFilter('entity_id', ['in' => [10, 11, 12]])->delete(); + unset($this->productCollection); + + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', false); + } + + /** + * @param array $result + * @return array + */ + protected function getStockItemBySku($result) + { + $productSku = 'simple1'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$productSku", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'catalogInventoryStockRegistryV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'catalogInventoryStockRegistryV1GetStockItemBySku', + ], + ]; + $arguments = ['productSku' => $productSku]; + $apiResult = $this->_webApiCall($serviceInfo, $arguments); + $result['item_id'] = $apiResult['item_id']; + $this->assertEquals($result, $apiResult, 'The stock data does not match.'); + return $apiResult; + } + + /** + * @param array $newData + * @param array $expectedResult + * @param array $fixtureData + * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php + * @dataProvider saveStockItemBySkuWithWrongInputDataProvider + */ + public function testStockItemPUTWithWrongInput($newData, $expectedResult, $fixtureData) + { + $stockItemOld = $this->getStockItemBySku($fixtureData); + $productSku = 'simple1'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$productSku", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'catalogInventoryStockRegistryV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'catalogInventoryStockRegistryV1UpdateStockItemBySku', + ], + ]; + + $stockItemDetailsDo = $this->objectManager->get( + 'Magento\CatalogInventory\Api\Data\StockItemInterfaceBuilder' + )->populateWithArray($newData)->create(); + $arguments = ['productSku' => $productSku, 'stockItem' => $stockItemDetailsDo->getData()]; + $this->assertEquals($stockItemOld['item_id'], $this->_webApiCall($serviceInfo, $arguments)); + + $stockItemFactory = $this->objectManager->get('Magento\CatalogInventory\Api\Data\StockItemInterfaceFactory'); + $stockItem = $stockItemFactory->create(); + $stockItemResource = $this->objectManager->get('Magento\CatalogInventory\Model\Resource\Stock\Item'); + $stockItemResource->loadByProductId($stockItem, $stockItemOld['product_id'], $stockItemOld['website_id']); + $expectedResult['item_id'] = $stockItem->getItemId(); + $this->assertEquals($expectedResult, $stockItem->getData()); + } + + /** + * @return array + */ + public function saveStockItemBySkuWithWrongInputDataProvider() + { + return [ + [ + [ + 'item_id' => 222, + 'product_id' => 222, + 'stock_id' => 1, + 'website_id' => 1, + 'qty' => '111.0000', + 'min_qty' => '0.0000', + 'use_config_min_qty' => 1, + 'is_qty_decimal' => 0, + 'backorders' => 0, + 'use_config_backorders' => 1, + 'min_sale_qty' => '1.0000', + 'use_config_min_sale_qty' => 1, + 'max_sale_qty' => '0.0000', + 'use_config_max_sale_qty' => 1, + 'is_in_stock' => 1, + 'low_stock_date' => '', + 'notify_stock_qty' => NULL, + 'use_config_notify_stock_qty' => 1, + 'manage_stock' => 0, + 'use_config_manage_stock' => 1, + 'stock_status_changed_auto' => 0, + 'use_config_qty_increments' => 1, + 'qty_increments' => '0.0000', + 'use_config_enable_qty_inc' => 1, + 'enable_qty_increments' => 0, + 'is_decimal_divided' => 0, + 'show_default_notification_message' => false, + ], + [ + 'item_id' => '1', + 'product_id' => '10', + 'stock_id' => '1', + 'qty' => '111.0000', + 'min_qty' => '0.0000', + 'use_config_min_qty' => '1', + 'is_qty_decimal' => '0', + 'backorders' => '0', + 'use_config_backorders' => '1', + 'min_sale_qty' => '1.0000', + 'use_config_min_sale_qty' => '1', + 'max_sale_qty' => '0.0000', + 'use_config_max_sale_qty' => '1', + 'is_in_stock' => '1', + 'low_stock_date' => NULL, + 'notify_stock_qty' => NULL, + 'use_config_notify_stock_qty' => '1', + 'manage_stock' => '0', + 'use_config_manage_stock' => '1', + 'stock_status_changed_auto' => '0', + 'use_config_qty_increments' => '1', + 'qty_increments' => '0.0000', + 'use_config_enable_qty_inc' => '1', + 'enable_qty_increments' => '0', + 'is_decimal_divided' => '0', + 'website_id' => '1', + 'type_id' => 'simple', + ], + [ + 'item_id' => 1, + 'product_id' => 10, + 'website_id' => 1, + 'stock_id' => 1, + 'qty' => 100, + 'is_in_stock' => 1, + 'is_qty_decimal' => '', + 'show_default_notification_message' => '', + 'use_config_min_qty' => 1, + 'min_qty' => 0, + 'use_config_min_sale_qty' => 1, + 'min_sale_qty' => 1, + 'use_config_max_sale_qty' => 1, + 'max_sale_qty' => 10000, + 'use_config_backorders' => 1, + 'backorders' => 0, + 'use_config_notify_stock_qty' => 1, + 'notify_stock_qty' => 1, + 'use_config_qty_increments' => 1, + 'qty_increments' => 0, + 'use_config_enable_qty_inc' => 1, + 'enable_qty_increments' => '', + 'use_config_manage_stock' => 1, + 'manage_stock' => 1, + 'low_stock_date' => 0, + 'is_decimal_divided' => '', + 'stock_status_changed_auto' => 0 + ], + ], + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockStatusTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockStatusTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1ab00d4b085b5313427d6828afdbc5863317d092 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockStatusTest.php @@ -0,0 +1,48 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\CatalogInventory\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class StockStatusTest + */ +class StockStatusTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/stockStatus'; + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testGetProductStockStatus() + { + $productSku = 'simple'; + $objectManager = Bootstrap::getObjectManager(); + + /** @var \Magento\Catalog\Model\Product $product */ + $product = $objectManager->get('Magento\Catalog\Model\Product')->load(1); + $expectedData = $product->getQuantityAndStockStatus(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$productSku", + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'catalogInventoryStockRegistryV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'catalogInventoryStockRegistryV1GetStockStatusBySku', + ], + ]; + + $requestData = ['productSku' => $productSku]; + $actualData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertArrayHasKey('stock_item', $actualData); + $this->assertEquals($expectedData['is_in_stock'], $actualData['stock_item']['is_in_stock']); + $this->assertEquals($expectedData['qty'], $actualData['stock_item']['qty']); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Billing/ReadServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Billing/ReadServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..961d7caf314fc7b61cd83da7cc945bbbe7dc006f --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Billing/ReadServiceTest.php @@ -0,0 +1,85 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Checkout\Service\V1\Address\Billing; + +use Magento\Checkout\Service\V1\Data\Cart\Address; +use Magento\Checkout\Service\V1\Data\Cart\Address\Region; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ReadServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutAddressBillingReadServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testGetAddress() + { + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + + /** @var \Magento\Sales\Model\Quote\Address $address */ + $address = $quote->getBillingAddress(); + + $data = [ + Address::KEY_COUNTRY_ID => $address->getCountryId(), + Address::KEY_ID => (int)$address->getId(), + Address::KEY_CUSTOMER_ID => $address->getCustomerId(), + Address::KEY_REGION => [ + Region::REGION => $address->getRegion(), + Region::REGION_ID => $address->getRegionId(), + Region::REGION_CODE => $address->getRegionCode(), + ], + Address::KEY_STREET => $address->getStreet(), + Address::KEY_COMPANY => $address->getCompany(), + Address::KEY_TELEPHONE => $address->getTelephone(), + Address::KEY_POSTCODE => $address->getPostcode(), + Address::KEY_CITY => $address->getCity(), + Address::KEY_FIRSTNAME => $address->getFirstname(), + Address::KEY_LASTNAME => $address->getLastname(), + Address::KEY_EMAIL => $address->getEmail(), + Address::CUSTOM_ATTRIBUTES_KEY => [['attribute_code' => 'disable_auto_group_change', 'value' => null]], + ]; + + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/billing-address', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetAddress', + ], + ]; + + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + unset($data[Address::KEY_PREFIX]); + unset($data[Address::KEY_SUFFIX]); + unset($data[Address::KEY_MIDDLENAME]); + unset($data[Address::KEY_FAX]); + unset($data[Address::KEY_VAT_ID]); + } + + $requestData = ["cartId" => $cartId]; + $this->assertEquals($data, $this->_webApiCall($serviceInfo, $requestData)); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Billing/WriteServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Billing/WriteServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d69ab59b5d99cb1dee9fee7af0b62886a67d741b --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Billing/WriteServiceTest.php @@ -0,0 +1,97 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Checkout\Service\V1\Address\Billing; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class WriteServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutAddressBillingWriteServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + /** + * @var \Magento\Checkout\Service\V1\Data\Cart\AddressBuilder + */ + protected $builder; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->builder = $this->objectManager->create('Magento\Checkout\Service\V1\Data\Cart\AddressBuilder'); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testSetAddress() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $quote->getId() . '/billing-address', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'SetAddress', + ], + ]; + + $addressData = [ + 'firstname' => 'John', + 'lastname' => 'Smith', + 'email' => 'cat@dog.com', + 'company' => 'eBay Inc', + 'street' => ['Typical Street', 'Tiny House 18'], + 'city' => 'Big City', + 'region' => [ + 'region_id' => 12, + 'region' => 'California', + 'region_code' => 'CA', + ], + 'postcode' => '0985432', + 'country_id' => 'US', + 'telephone' => '88776655', + 'fax' => '44332255', + ]; + $requestData = [ + "cartId" => $quote->getId(), + 'addressData' => $addressData, + ]; + + $addressId = $this->_webApiCall($serviceInfo, $requestData); + + //reset $quote to reload data + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + $savedData = $quote->getBillingAddress()->getData(); + $this->assertEquals($addressId, $savedData['address_id']); + //custom checks for street, region and address_type + foreach ($addressData['street'] as $streetLine) { + $this->assertContains($streetLine, $quote->getBillingAddress()->getStreet()); + } + unset($addressData['street']); + $this->assertEquals($addressData['region']['region_id'], $savedData['region_id']); + $this->assertEquals($addressData['region']['region'], $savedData['region']); + unset($addressData['region']); + $this->assertEquals('billing', $savedData['address_type']); + //check the rest of fields + foreach ($addressData as $key => $value) { + $this->assertEquals($value, $savedData[$key]); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Shipping/ReadServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Shipping/ReadServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..da2908227abafe78327683472aa43680bfb6e955 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Shipping/ReadServiceTest.php @@ -0,0 +1,111 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Checkout\Service\V1\Address\Shipping; + +use Magento\Checkout\Service\V1\Data\Cart\Address; +use Magento\Checkout\Service\V1\Data\Cart\Address\Region; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ReadServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutAddressShippingReadServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testGetAddress() + { + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + + /** @var \Magento\Sales\Model\Quote\Address $address */ + $address = $quote->getShippingAddress(); + + $data = [ + Address::KEY_COUNTRY_ID => $address->getCountryId(), + Address::KEY_ID => (int)$address->getId(), + Address::KEY_CUSTOMER_ID => $address->getCustomerId(), + Address::KEY_REGION => [ + Region::REGION => $address->getRegion(), + Region::REGION_ID => $address->getRegionId(), + Region::REGION_CODE => $address->getRegionCode(), + ], + Address::KEY_STREET => $address->getStreet(), + Address::KEY_COMPANY => $address->getCompany(), + Address::KEY_TELEPHONE => $address->getTelephone(), + Address::KEY_POSTCODE => $address->getPostcode(), + Address::KEY_CITY => $address->getCity(), + Address::KEY_FIRSTNAME => $address->getFirstname(), + Address::KEY_LASTNAME => $address->getLastname(), + Address::KEY_EMAIL => $address->getEmail(), + Address::CUSTOM_ATTRIBUTES_KEY => [['attribute_code' => 'disable_auto_group_change', 'value' => null]], + ]; + + $cartId = $quote->getId(); + + $serviceInfo = $this->getServiceInfo(); + $serviceInfo['rest']['resourcePath'] = str_replace('{cart_id}', $cartId, $serviceInfo['rest']['resourcePath']); + + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + unset($data[Address::KEY_PREFIX]); + unset($data[Address::KEY_SUFFIX]); + unset($data[Address::KEY_MIDDLENAME]); + unset($data[Address::KEY_FAX]); + unset($data[Address::KEY_VAT_ID]); + } + + $requestData = ["cartId" => $cartId]; + $this->assertEquals($data, $this->_webApiCall($serviceInfo, $requestData)); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_and_address.php + * + * @expectedException \Exception + * @expectedExceptionMessage Cart contains virtual product(s) only. Shipping address is not applicable + */ + public function testGetAddressOfQuoteWithVirtualProduct() + { + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $cartId = $quote->load('test_order_with_virtual_product', 'reserved_order_id')->getId(); + + $serviceInfo = $this->getServiceInfo(); + $serviceInfo['rest']['resourcePath'] = str_replace('{cart_id}', $cartId, $serviceInfo['rest']['resourcePath']); + + $this->_webApiCall($serviceInfo, ["cartId" => $cartId]); + } + + /** + * @return array + */ + protected function getServiceInfo() + { + return $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '{cart_id}/shipping-address', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetAddress', + ], + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Shipping/WriteServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Shipping/WriteServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1a8e322508d99d34ad92bdf17d759094fe96af86 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Address/Shipping/WriteServiceTest.php @@ -0,0 +1,147 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Checkout\Service\V1\Address\Shipping; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class WriteServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutAddressShippingWriteServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + /** + * @var \Magento\Checkout\Service\V1\Data\Cart\AddressBuilder + */ + protected $builder; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->builder = $this->objectManager->create('Magento\Checkout\Service\V1\Data\Cart\AddressBuilder'); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testSetAddress() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $quote->getId() . '/shipping-address', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'SetAddress', + ], + ]; + + $addressData = [ + 'firstname' => 'John', + 'lastname' => 'Smith', + 'email' => 'cat@dog.com', + 'company' => 'eBay Inc', + 'street' => ['Typical Street', 'Tiny House 18'], + 'city' => 'Big City', + 'region' => [ + 'region_id' => 12, + 'region' => 'California', + 'region_code' => 'CA', + ], + 'postcode' => '0985432', + 'country_id' => 'US', + 'telephone' => '88776655', + 'fax' => '44332255', + ]; + $requestData = [ + "cartId" => $quote->getId(), + 'addressData' => $addressData, + ]; + + $addressId = $this->_webApiCall($serviceInfo, $requestData); + + //reset $quote to reload data + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + $savedData = $quote->getShippingAddress()->getData(); + $this->assertEquals($addressId, $savedData['address_id']); + $this->assertEquals(0, $savedData['same_as_billing']); + //custom checks for street, region and address_type + $this->assertEquals($addressData['street'], $quote->getShippingAddress()->getStreet()); + unset($addressData['street']); + $this->assertEquals($addressData['region']['region_id'], $savedData['region_id']); + $this->assertEquals($addressData['region']['region'], $savedData['region']); + unset($addressData['region']); + $this->assertEquals('shipping', $savedData['address_type']); + //check the rest of fields + foreach ($addressData as $key => $value) { + $this->assertEquals($value, $savedData[$key]); + } + } + + /** + * Set address to quote with virtual products only + * + * @expectedException \Exception + * @expectedExceptionMessage Cart contains virtual product(s) only. Shipping address is not applicable + * + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_and_address.php + */ + public function testSetAddressForVirtualQuote() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_with_virtual_product', 'reserved_order_id'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $quote->getId() . '/shipping-address', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'SetAddress', + ], + ]; + + $addressData = [ + 'firstname' => 'John', + 'lastname' => 'Smith', + 'email' => 'cat@dog.com', + 'company' => 'eBay Inc', + 'street' => ['Typical Street', 'Tiny House 18'], + 'city' => 'Big City', + 'region' => [ + 'region_id' => 12, + 'region' => 'California', + 'region_code' => 'CA', + ], + 'postcode' => '0985432', + 'country_id' => 'US', + 'telephone' => '88776655', + 'fax' => '44332255', + ]; + $requestData = [ + "cartId" => $quote->getId(), + 'addressData' => $addressData, + ]; + + $this->_webApiCall($serviceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Cart/ReadServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Cart/ReadServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..2d2f8063b359c9c231a6ebdff9149f469ce46183 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Cart/ReadServiceTest.php @@ -0,0 +1,297 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Checkout\Service\V1\Cart; + +use Magento\Checkout\Service\V1\Data\Cart; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SearchCriteria; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\TestFramework\ObjectManager; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ReadServiceTest extends WebapiAbstract +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var SearchCriteriaBuilder + */ + private $searchBuilder; + + /** + * @var SortOrderBuilder + */ + private $sortOrderBuilder; + + /** + * @var FilterBuilder + */ + private $filterBuilder; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->filterBuilder = $this->objectManager->create( + 'Magento\Framework\Api\FilterBuilder' + ); + $this->sortOrderBuilder = $this->objectManager->create( + 'Magento\Framework\Api\SortOrderBuilder' + ); + $this->searchBuilder = $this->objectManager->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + } + + protected function tearDown() + { + try { + $cart = $this->getCart('test01'); + $cart->delete(); + } catch (\InvalidArgumentException $e) { + // Do nothing if cart fixture was not used + } + parent::tearDown(); + } + + /** + * Retrieve quote by given reserved order ID + * + * @param string $reservedOrderId + * @return \Magento\Sales\Model\Quote + * @throws \InvalidArgumentException + */ + protected function getCart($reservedOrderId) + { + /** @var $cart \Magento\Sales\Model\Quote */ + $cart = $this->objectManager->get('Magento\Sales\Model\Quote'); + $cart->load($reservedOrderId, 'reserved_order_id'); + if (!$cart->getId()) { + throw new \InvalidArgumentException('There is no quote with provided reserved order ID.'); + } + return $cart; + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/quote.php + */ + public function testGetCart() + { + $cart = $this->getCart('test01'); + $cartId = $cart->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $cartId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'checkoutCartReadServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutCartReadServiceV1GetCart', + ], + ]; + + $requestData = ['cartId' => $cartId]; + $cartData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($cart->getId(), $cartData['id']); + $this->assertEquals($cart->getCreatedAt(), $cartData['created_at']); + $this->assertEquals($cart->getUpdatedAt(), $cartData['updated_at']); + $this->assertEquals($cart->getStoreId(), $cartData['store_id']); + $this->assertEquals($cart->getIsActive(), $cartData['is_active']); + $this->assertEquals($cart->getIsVirtual(), $cartData['is_virtual']); + $this->assertEquals($cart->getOrigOrderId(), $cartData['orig_order_id']); + $this->assertEquals($cart->getItemsCount(), $cartData['items_count']); + $this->assertEquals($cart->getItemsQty(), $cartData['items_qty']); + + $this->assertContains('customer', $cartData); + $this->assertEquals(1, $cartData['customer']['is_guest']); + $this->assertContains('totals', $cartData); + $this->assertEquals($cart->getSubtotal(), $cartData['totals']['subtotal']); + $this->assertEquals($cart->getGrandTotal(), $cartData['totals']['grand_total']); + $this->assertContains('currency', $cartData); + $this->assertEquals($cart->getGlobalCurrencyCode(), $cartData['currency']['global_currency_code']); + $this->assertEquals($cart->getBaseCurrencyCode(), $cartData['currency']['base_currency_code']); + $this->assertEquals($cart->getQuoteCurrencyCode(), $cartData['currency']['quote_currency_code']); + $this->assertEquals($cart->getStoreCurrencyCode(), $cartData['currency']['store_currency_code']); + $this->assertEquals($cart->getBaseToGlobalRate(), $cartData['currency']['base_to_global_rate']); + $this->assertEquals($cart->getBaseToQuoteRate(), $cartData['currency']['base_to_quote_rate']); + $this->assertEquals($cart->getStoreToBaseRate(), $cartData['currency']['store_to_base_rate']); + $this->assertEquals($cart->getStoreToQuoteRate(), $cartData['currency']['store_to_quote_rate']); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage No such entity with + */ + public function testGetCartThrowsExceptionIfThereIsNoCartWithProvidedId() + { + $cartId = 9999; + + $serviceInfo = [ + 'soap' => [ + 'service' => 'checkoutCartReadServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutCartReadServiceV1GetCart', + ], + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $cartId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + ]; + + $requestData = ['cartId' => $cartId]; + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/quote_with_customer.php + */ + public function testGetCartForCustomer() + { + $cart = $this->getCart('test01'); + $customerId = $cart->getCustomer()->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/customer/' . $customerId . '/cart', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'checkoutCartReadServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutCartReadServiceV1GetCartForCustomer', + ], + ]; + + $requestData = ['customerId' => $customerId]; + $cartData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($cart->getId(), $cartData['id']); + $this->assertEquals($cart->getCreatedAt(), $cartData['created_at']); + $this->assertEquals($cart->getUpdatedAt(), $cartData['updated_at']); + $this->assertEquals($cart->getStoreId(), $cartData['store_id']); + $this->assertEquals($cart->getIsActive(), $cartData['is_active']); + $this->assertEquals($cart->getIsVirtual(), $cartData['is_virtual']); + $this->assertEquals($cart->getOrigOrderId(), $cartData['orig_order_id']); + $this->assertEquals($cart->getItemsCount(), $cartData['items_count']); + $this->assertEquals($cart->getItemsQty(), $cartData['items_qty']); + + $this->assertContains('customer', $cartData); + $this->assertEquals(0, $cartData['customer']['is_guest']); + $this->assertContains('totals', $cartData); + $this->assertEquals($cart->getSubtotal(), $cartData['totals']['subtotal']); + $this->assertEquals($cart->getGrandTotal(), $cartData['totals']['grand_total']); + $this->assertContains('currency', $cartData); + $this->assertEquals($cart->getGlobalCurrencyCode(), $cartData['currency']['global_currency_code']); + $this->assertEquals($cart->getBaseCurrencyCode(), $cartData['currency']['base_currency_code']); + $this->assertEquals($cart->getQuoteCurrencyCode(), $cartData['currency']['quote_currency_code']); + $this->assertEquals($cart->getStoreCurrencyCode(), $cartData['currency']['store_currency_code']); + $this->assertEquals($cart->getBaseToGlobalRate(), $cartData['currency']['base_to_global_rate']); + $this->assertEquals($cart->getBaseToQuoteRate(), $cartData['currency']['base_to_quote_rate']); + $this->assertEquals($cart->getStoreToBaseRate(), $cartData['currency']['store_to_base_rate']); + $this->assertEquals($cart->getStoreToQuoteRate(), $cartData['currency']['store_to_quote_rate']); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/quote.php + */ + public function testGetCartList() + { + $cart = $this->getCart('test01'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/carts', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'checkoutCartReadServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutCartReadServiceV1GetCartList', + ], + ]; + + // The following two filters are used as alternatives. The target cart does not match the first one. + $grandTotalFilter = $this->filterBuilder->setField('grand_total') + ->setConditionType('gteq') + ->setValue(15) + ->create(); + $subtotalFilter = $this->filterBuilder->setField('subtotal') + ->setConditionType('eq') + ->setValue($cart->getSubtotal()) + ->create(); + + $yesterdayDate = (new \DateTime())->sub(new \DateInterval('P1D'))->format('Y-m-d'); + $tomorrowDate = (new \DateTime())->add(new \DateInterval('P1D'))->format('Y-m-d'); + $minCreatedAtFilter = $this->filterBuilder->setField(Cart::CREATED_AT) + ->setConditionType('gteq') + ->setValue($yesterdayDate) + ->create(); + $maxCreatedAtFilter = $this->filterBuilder->setField(Cart::CREATED_AT) + ->setConditionType('lteq') + ->setValue($tomorrowDate) + ->create(); + + $this->searchBuilder->addFilter([$grandTotalFilter, $subtotalFilter]); + $this->searchBuilder->addFilter([$minCreatedAtFilter]); + $this->searchBuilder->addFilter([$maxCreatedAtFilter]); + /** @var SortOrder $sortOrder */ + $sortOrder = $this->sortOrderBuilder->setField('subtotal')->setDirection(SearchCriteria::SORT_ASC)->create(); + $this->searchBuilder->setSortOrders([$sortOrder]); + $searchCriteria = $this->searchBuilder->create()->__toArray(); + + $requestData = ['searchCriteria' => $searchCriteria]; + $searchResult = $this->_webApiCall($serviceInfo, $requestData); + $this->assertArrayHasKey('total_count', $searchResult); + $this->assertEquals(1, $searchResult['total_count']); + $this->assertArrayHasKey('items', $searchResult); + $this->assertCount(1, $searchResult['items']); + + $cartData = $searchResult['items'][0]; + $this->assertEquals($cart->getId(), $cartData['id']); + $this->assertEquals($cart->getCreatedAt(), $cartData['created_at']); + $this->assertEquals($cart->getUpdatedAt(), $cartData['updated_at']); + $this->assertEquals($cart->getIsActive(), $cartData['is_active']); + $this->assertEquals($cart->getStoreId(), $cartData['store_id']); + + $this->assertContains('totals', $cartData); + $this->assertEquals($cart->getBaseSubtotal(), $cartData['totals']['base_subtotal']); + $this->assertEquals($cart->getBaseGrandTotal(), $cartData['totals']['base_grand_total']); + $this->assertContains('customer', $cartData); + $this->assertEquals(1, $cartData['customer']['is_guest']); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Field 'invalid_field' cannot be used for search. + */ + public function testGetCartListThrowsExceptionIfProvidedSearchFieldIsInvalid() + { + $serviceInfo = [ + 'soap' => [ + 'service' => 'checkoutCartReadServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutCartReadServiceV1GetCartList', + ], + 'rest' => [ + 'resourcePath' => '/V1/carts', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + + $invalidFilter = $this->filterBuilder->setField('invalid_field') + ->setConditionType('eq') + ->setValue(0) + ->create(); + + $this->searchBuilder->addFilter([$invalidFilter]); + $searchCriteria = $this->searchBuilder->create()->__toArray(); + $requestData = ['searchCriteria' => $searchCriteria]; + $this->_webApiCall($serviceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Cart/TotalsServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Cart/TotalsServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9c6a50f2d7e7249d1843797faede152509b29224 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Cart/TotalsServiceTest.php @@ -0,0 +1,174 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Checkout\Service\V1\Cart; + +use Magento\Checkout\Service\V1\Data\Cart\Totals; +use Magento\Checkout\Service\V1\Data\Cart\Totals\Item as ItemTotals; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\TestFramework\ObjectManager; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class TotalsServiceTest extends WebapiAbstract +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var SearchCriteriaBuilder + */ + private $searchBuilder; + + /** + * @var FilterBuilder + */ + private $filterBuilder; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->searchBuilder = $this->objectManager->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + $this->filterBuilder = $this->objectManager->create( + 'Magento\Framework\Api\FilterBuilder' + ); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_shipping_method.php + */ + public function testGetTotals() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + $cartId = $quote->getId(); + + /** @var \Magento\Sales\Model\Quote\Address $shippingAddress */ + $shippingAddress = $quote->getShippingAddress(); + + $data = [ + Totals::BASE_GRAND_TOTAL => $quote->getBaseGrandTotal(), + Totals::GRAND_TOTAL => $quote->getGrandTotal(), + Totals::BASE_SUBTOTAL => $quote->getBaseSubtotal(), + Totals::SUBTOTAL => $quote->getSubtotal(), + Totals::BASE_SUBTOTAL_WITH_DISCOUNT => $quote->getBaseSubtotalWithDiscount(), + Totals::SUBTOTAL_WITH_DISCOUNT => $quote->getSubtotalWithDiscount(), + Totals::DISCOUNT_AMOUNT => $shippingAddress->getDiscountAmount(), + Totals::BASE_DISCOUNT_AMOUNT => $shippingAddress->getBaseDiscountAmount(), + Totals::SHIPPING_AMOUNT => $shippingAddress->getShippingAmount(), + Totals::BASE_SHIPPING_AMOUNT => $shippingAddress->getBaseShippingAmount(), + Totals::SHIPPING_DISCOUNT_AMOUNT => $shippingAddress->getShippingDiscountAmount(), + Totals::BASE_SHIPPING_DISCOUNT_AMOUNT => $shippingAddress->getBaseShippingDiscountAmount(), + Totals::TAX_AMOUNT => $shippingAddress->getTaxAmount(), + Totals::BASE_TAX_AMOUNT => $shippingAddress->getBaseTaxAmount(), + Totals::SHIPPING_TAX_AMOUNT => $shippingAddress->getShippingTaxAmount(), + Totals::BASE_SHIPPING_TAX_AMOUNT => $shippingAddress->getBaseShippingTaxAmount(), + Totals::SUBTOTAL_INCL_TAX => $shippingAddress->getSubtotalInclTax(), + Totals::BASE_SUBTOTAL_INCL_TAX => $shippingAddress->getBaseSubtotalTotalInclTax(), + Totals::SHIPPING_INCL_TAX => $shippingAddress->getShippingInclTax(), + Totals::BASE_SHIPPING_INCL_TAX => $shippingAddress->getBaseShippingInclTax(), + Totals::BASE_CURRENCY_CODE => $quote->getBaseCurrencyCode(), + Totals::QUOTE_CURRENCY_CODE => $quote->getQuoteCurrencyCode(), + Totals::ITEMS => [$this->getQuoteItemTotalsData($quote)], + ]; + + $requestData = ['cartId' => $cartId]; + + $data = $this->formatTotalsData($data); + + $this->assertEquals($data, $this->_webApiCall($this->getServiceInfoForTotalsService($cartId), $requestData)); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage No such entity + */ + public function testGetTotalsWithAbsentQuote() + { + $cartId = 'unknownCart'; + $requestData = ['cartId' => $cartId]; + $this->_webApiCall($this->getServiceInfoForTotalsService($cartId), $requestData); + } + + /** + * Get service info for totals service + * + * @param string $cartId + * @return array + */ + protected function getServiceInfoForTotalsService($cartId) + { + return [ + 'soap' => [ + 'service' => 'checkoutCartTotalsServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutCartTotalsServiceV1GetTotals', + ], + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $cartId . '/totals', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + ]; + } + + /** + * Adjust response details for SOAP protocol + * + * @param array $data + * @return array + */ + protected function formatTotalsData($data) + { + foreach ($data as $key => $field) { + if (is_numeric($field)) { + $data[$key] = round($field, 1); + if ($data[$key] === null) { + $data[$key] = 0.0; + } + } + } + + unset($data[Totals::BASE_SUBTOTAL_INCL_TAX]); + + return $data; + } + + /** + * Fetch quote item totals data from quote + * + * @param \Magento\Sales\Model\Quote $quote + * @return array + */ + protected function getQuoteItemTotalsData(\Magento\Sales\Model\Quote $quote) + { + $items = $quote->getAllItems(); + $item = array_shift($items); + + return [ + ItemTotals::PRICE => $item->getPrice(), + ItemTotals::BASE_PRICE => $item->getBasePrice(), + ItemTotals::QTY => $item->getQty(), + ItemTotals::ROW_TOTAL => $item->getRowTotal(), + ItemTotals::BASE_ROW_TOTAL => $item->getBaseRowTotal(), + ItemTotals::ROW_TOTAL_WITH_DISCOUNT => $item->getRowTotalWithDiscount(), + ItemTotals::TAX_AMOUNT => $item->getTaxAmount(), + ItemTotals::BASE_TAX_AMOUNT => $item->getBaseTaxAmount(), + ItemTotals::TAX_PERCENT => $item->getTaxPercent(), + ItemTotals::DISCOUNT_AMOUNT => $item->getDiscountAmount(), + ItemTotals::BASE_DISCOUNT_AMOUNT => $item->getBaseDiscountAmount(), + ItemTotals::DISCOUNT_PERCENT => $item->getDiscountPercent(), + ItemTotals::PRICE_INCL_TAX => $item->getPriceInclTax(), + ItemTotals::BASE_PRICE_INCL_TAX => $item->getBasePriceInclTax(), + ItemTotals::ROW_TOTAL_INCL_TAX => $item->getRowTotalInclTax(), + ItemTotals::BASE_ROW_TOTAL_INCL_TAX => $item->getBaseRowTotalInclTax(), + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Cart/WriteServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Cart/WriteServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..781ce89f50be79a94b2cf8d44595ef5f7db2b797 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Cart/WriteServiceTest.php @@ -0,0 +1,299 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Checkout\Service\V1\Cart; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class WriteServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutCartWriteServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + protected $createdQuotes = []; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + public function testCreate() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Create', + ], + ]; + + $quoteId = $this->_webApiCall($serviceInfo); + $this->assertGreaterThan(0, $quoteId); + $this->createdQuotes[] = $quoteId; + } + + public function tearDown() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + foreach ($this->createdQuotes as $quoteId) { + $quote->load($quoteId); + $quote->delete(); + } + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/quote.php + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testAssignCustomer() + { + /** @var $quote \Magento\Sales\Model\Quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote')->load('test01', 'reserved_order_id'); + $cartId = $quote->getId(); + /** @var $repository \Magento\Customer\Api\CustomerRepositoryInterface */ + $repository = $this->objectManager->create('Magento\Customer\Api\CustomerRepositoryInterface'); + /** @var $customer \Magento\Customer\Api\Data\CustomerInterface */ + $customer = $repository->getById(1); + $customerId = $customer->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $cartId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'checkoutCartWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutCartWriteServiceV1AssignCustomer', + ], + ]; + + $requestData = [ + 'cartId' => $cartId, + 'customerId' => $customerId, + ]; + // Cart must be anonymous (see fixture) + $this->assertEmpty($quote->getCustomerId()); + + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + // Reload target quote + $quote = $this->objectManager->create('Magento\Sales\Model\Quote')->load('test01', 'reserved_order_id'); + $this->assertEquals(0, $quote->getCustomerIsGuest()); + $this->assertEquals($customer->getId(), $quote->getCustomerId()); + $this->assertEquals($customer->getFirstname(), $quote->getCustomerFirstname()); + $this->assertEquals($customer->getLastname(), $quote->getCustomerLastname()); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/quote.php + * @expectedException \Exception + */ + public function testAssignCustomerThrowsExceptionIfThereIsNoCustomerWithGivenId() + { + /** @var $quote \Magento\Sales\Model\Quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote')->load('test01', 'reserved_order_id'); + $cartId = $quote->getId(); + $customerId = 9999; + $serviceInfo = [ + 'soap' => [ + 'serviceVersion' => 'V1', + 'service' => 'checkoutCartWriteServiceV1', + 'operation' => 'checkoutCartWriteServiceV1AssignCustomer', + ], + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $cartId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + $requestData = [ + 'cartId' => $cartId, + 'customerId' => $customerId, + ]; + + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @expectedException \Exception + */ + public function testAssignCustomerThrowsExceptionIfThereIsNoCartWithGivenId() + { + $cartId = 9999; + $customerId = 1; + $serviceInfo = [ + 'soap' => [ + 'service' => 'checkoutCartWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutCartWriteServiceV1AssignCustomer', + ], + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $cartId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + $requestData = [ + 'cartId' => $cartId, + 'customerId' => $customerId, + ]; + + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/quote_with_customer.php + * @expectedException \Exception + * @expectedExceptionMessage Cannot assign customer to the given cart. The cart is not anonymous. + */ + public function testAssignCustomerThrowsExceptionIfTargetCartIsNotAnonymous() + { + /** @var $customer \Magento\Customer\Model\Customer */ + $customer = $this->objectManager->create('Magento\Customer\Model\Customer')->load(1); + $customerId = $customer->getId(); + /** @var $quote \Magento\Sales\Model\Quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote')->load('test01', 'reserved_order_id'); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + 'resourcePath' => '/V1/carts/' . $cartId, + ], + 'soap' => [ + 'service' => 'checkoutCartWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutCartWriteServiceV1AssignCustomer', + ], + ]; + + $requestData = [ + 'cartId' => $cartId, + 'customerId' => $customerId, + ]; + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/quote.php + * @magentoApiDataFixture Magento/Customer/_files/customer_non_default_website_id.php + * @expectedException \Exception + * @expectedExceptionMessage Cannot assign customer to the given cart. The cart belongs to different store. + */ + public function testAssignCustomerThrowsExceptionIfCartIsAssignedToDifferentStore() + { + $repository = $this->objectManager->create('Magento\Customer\Api\CustomerRepositoryInterface'); + /** @var $customer \Magento\Customer\Api\Data\CustomerInterface */ + $customer = $repository->getById(1); + /** @var $quote \Magento\Sales\Model\Quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote')->load('test01', 'reserved_order_id'); + + $customerId = $customer->getId(); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'soap' => [ + 'service' => 'checkoutCartWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutCartWriteServiceV1AssignCustomer', + ], + 'rest' => [ + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + 'resourcePath' => '/V1/carts/' . $cartId, + ], + ]; + + $requestData = [ + 'cartId' => $cartId, + 'customerId' => $customerId, + ]; + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + * @magentoApiDataFixture Magento/Sales/_files/quote.php + * @expectedException \Exception + * @expectedExceptionMessage Cannot assign customer to the given cart. Customer already has active cart. + */ + public function testAssignCustomerThrowsExceptionIfCustomerAlreadyHasActiveCart() + { + /** @var $customer \Magento\Customer\Model\Customer */ + $customer = $this->objectManager->create('Magento\Customer\Model\Customer')->load(1); + // Customer has a quote with reserved order ID test_order_1 (see fixture) + /** @var $customerQuote \Magento\Sales\Model\Quote */ + $customerQuote = $this->objectManager->create('Magento\Sales\Model\Quote') + ->load('test_order_1', 'reserved_order_id'); + $customerQuote->setIsActive(1)->save(); + /** @var $quote \Magento\Sales\Model\Quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote')->load('test01', 'reserved_order_id'); + + $cartId = $quote->getId(); + $customerId = $customer->getId(); + + $serviceInfo = [ + 'soap' => [ + 'service' => 'checkoutCartWriteServiceV1', + 'operation' => 'checkoutCartWriteServiceV1AssignCustomer', + 'serviceVersion' => 'V1', + ], + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $cartId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + + $requestData = [ + 'cartId' => $cartId, + 'customerId' => $customerId, + ]; + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_check_payment.php + */ + public function testOrderPlacesOrder() + { + /** @var $quote \Magento\Sales\Model\Quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote')->load('test_order_1', 'reserved_order_id'); + + $cartId = $quote->getId(); + + $serviceInfo = [ + 'soap' => [ + 'service' => 'checkoutCartWriteServiceV1', + 'operation' => 'checkoutCartWriteServiceV1Order', + 'serviceVersion' => 'V1', + ], + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $cartId . '/order', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + + $requestData = [ + 'cartId' => $cartId, + ]; + $this->_webApiCall($serviceInfo, $requestData); + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->objectManager->create('Magento\Sales\Model\Order')->load(1); + $items = $order->getAllItems(); + $this->assertCount(1, $items); + $this->assertEquals('Simple Product', $items[0]->getName()); + $quote->delete(); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Coupon/ReadServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Coupon/ReadServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d36d4289fec3b938c49d92c19287d14b87dbb672 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Coupon/ReadServiceTest.php @@ -0,0 +1,55 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Checkout\Service\V1\Coupon; + +use Magento\Checkout\Service\V1\Data\Cart\Coupon as Coupon; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ReadServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutCouponReadServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_coupon_saved.php + */ + public function testGet() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + $cartId = $quote->getId(); + $data = [ + Coupon::COUPON_CODE => $quote->getCouponCode(), + ]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/coupons', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + + $requestData = ["cartId" => $cartId]; + $this->assertEquals($data, $this->_webApiCall($serviceInfo, $requestData)); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Coupon/WriteServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Coupon/WriteServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f6dfbf57eb0e4b5928db2d5e9b8b1e6cf9699270 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Coupon/WriteServiceTest.php @@ -0,0 +1,129 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Checkout\Service\V1\Coupon; + +use Magento\Checkout\Service\V1\Data\Cart\Coupon; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class WriteServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutCouponWriteServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_coupon_saved.php + */ + public function testDelete() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + $cartId = $quote->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/coupons', + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Delete', + ], + ]; + $requestData = ["cartId" => $cartId]; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + $quote->load('test_order_1', 'reserved_order_id'); + $this->assertEquals('', $quote->getCouponCode()); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + * @expectedException \Exception + * @expectedExceptionMessage Coupon code is not valid + */ + public function testSetCouponThrowsExceptionIfCouponDoesNotExist() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/coupons', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Set', + ], + ]; + + $data = [Coupon::COUPON_CODE => 'invalid_coupon_code']; + + $requestData = [ + "cartId" => $cartId, + "couponCodeData" => $data, + ]; + + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/quote.php + * @magentoApiDataFixture Magento/Checkout/_files/discount_10percent.php + */ + public function testSetCouponSuccess() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test01', 'reserved_order_id'); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/coupons', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Set', + ], + ]; + + $salesRule = $this->objectManager->create('Magento\SalesRule\Model\Rule'); + $salesRule->load('Test Coupon', 'name'); + + $couponCode = $salesRule->getCouponCode(); + $data = [Coupon::COUPON_CODE => $couponCode]; + + $requestData = [ + "cartId" => $cartId, + "couponCodeData" => $data, + ]; + + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + + $quoteWithCoupon = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quoteWithCoupon->load('test01', 'reserved_order_id'); + + $this->assertEquals($quoteWithCoupon->getCouponCode(), $couponCode); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Item/ReadServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Item/ReadServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6f099951a762b2a8c7cf9468749002192b3909c4 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Item/ReadServiceTest.php @@ -0,0 +1,65 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Checkout\Service\V1\Item; + +use Magento\Checkout\Service\V1\Data\Cart\Item as Item; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ReadServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutItemReadServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_items_saved.php + */ + public function testGetList() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_item_with_items', 'reserved_order_id'); + $cartId = $quote->getId(); + $output = []; + foreach ($quote->getAllItems() as $item) { + $data = [ + Item::ITEM_ID => $item->getId(), + Item::SKU => $item->getSku(), + Item::NAME => $item->getName(), + Item::PRICE => $item->getPrice(), + Item::QTY => $item->getQty(), + Item::PRODUCT_TYPE => $item->getProductType(), + ]; + + $output[] = $data; + } + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/items', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + + $requestData = ["cartId" => $cartId]; + $this->assertEquals($output, $this->_webApiCall($serviceInfo, $requestData)); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Item/WriteServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Item/WriteServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..857475f87e8af2ca2d17960b31b7453dd9090c97 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/Item/WriteServiceTest.php @@ -0,0 +1,136 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Checkout\Service\V1\Item; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class WriteServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutItemWriteServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testAddItem() + { + $product = $this->objectManager->create('Magento\Catalog\Model\Product')->load(2); + $productSku = $product->getSku(); + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + $cartId = $quote->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/items', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'AddItem', + ], + ]; + + $requestData = [ + "cartId" => $cartId, + "data" => [ + "sku" => $productSku, + "qty" => 7, + ], + ]; + $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($quote->hasProductId(2)); + $this->assertEquals(7, $quote->getItemByProduct($product)->getQty()); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_items_saved.php + */ + public function testRemoveItem() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_item_with_items', 'reserved_order_id'); + $cartId = $quote->getId(); + $product = $this->objectManager->create('Magento\Catalog\Model\Product'); + $productId = $product->getIdBySku('simple_one'); + $product->load($productId); + $itemId = $quote->getItemByProduct($product)->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/items/' . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'RemoveItem', + ], + ]; + + $requestData = [ + "cartId" => $cartId, + "itemId" => $itemId, + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_item_with_items', 'reserved_order_id'); + $this->assertFalse($quote->hasProductId($productId)); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_items_saved.php + */ + public function testUpdateItem() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_item_with_items', 'reserved_order_id'); + $cartId = $quote->getId(); + $product = $this->objectManager->create('Magento\Catalog\Model\Product'); + $productId = $product->getIdBySku('simple_one'); + $product->load($productId); + $itemId = $quote->getItemByProduct($product)->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/items/' . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'UpdateItem', + ], + ]; + + $requestData = [ + "cartId" => $cartId, + "itemId" => $itemId, + "data" => [ + "qty" => 5, + ], + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_item_with_items', 'reserved_order_id'); + $this->assertTrue($quote->hasProductId(1)); + $this->assertEquals(5, $quote->getItemByProduct($product)->getQty()); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/PaymentMethod/ReadServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/PaymentMethod/ReadServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..befd81cb2cdbeaac0196e06f594b559d051ef89b --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/PaymentMethod/ReadServiceTest.php @@ -0,0 +1,89 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Checkout\Service\V1\PaymentMethod; + +use Magento\Checkout\Service\V1\Data\PaymentMethod; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ReadServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutPaymentMethodReadServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testGetList() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/payment-methods', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getList', + ], + ]; + + $requestData = ["cartId" => $cartId]; + $requestResponse = $this->_webApiCall($serviceInfo, $requestData); + + $expectedResponse = [ + PaymentMethod::CODE => 'checkmo', + PaymentMethod::TITLE => 'Check / Money order', + ]; + + $this->assertGreaterThan(0, count($requestResponse)); + $this->assertContains($expectedResponse, $requestResponse); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_payment_saved.php + */ + public function testGetPayment() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1_with_payment', 'reserved_order_id'); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/selected-payment-methods', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getPayment', + ], + ]; + + $requestData = ["cartId" => $cartId]; + $requestResponse = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertArrayHasKey('method', $requestResponse); + $this->assertEquals('checkmo', $requestResponse['method']); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/PaymentMethod/WriteServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/PaymentMethod/WriteServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..fd796eeb90da93200ee9638c21ff1c3d66445a09 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/PaymentMethod/WriteServiceTest.php @@ -0,0 +1,211 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Checkout\Service\V1\PaymentMethod; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class WriteServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutPaymentMethodWriteServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_payment_saved.php + */ + public function testReSetPayment() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1_with_payment', 'reserved_order_id'); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/selected-payment-methods', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'set', + ], + ]; + + $requestData = [ + "cartId" => $cartId, + "method" => [ + 'method' => 'checkmo', + 'po_number' => null, + 'cc_owner' => 'John', + 'cc_type' => null, + 'cc_exp_year' => null, + 'cc_exp_month' => null, + ], + ]; + + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_and_address.php + */ + public function testSetPaymentWithVirtualProduct() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_with_virtual_product', 'reserved_order_id'); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/selected-payment-methods', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'set', + ], + ]; + + $requestData = [ + "cartId" => $cartId, + "method" => [ + 'method' => 'checkmo', + 'po_number' => '200', + 'cc_owner' => 'tester', + 'cc_type' => 'test', + 'cc_exp_year' => '2014', + 'cc_exp_month' => '1', + ], + ]; + $this->assertNotNull($this->_webApiCall($serviceInfo, $requestData)); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testSetPaymentWithSimpleProduct() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/selected-payment-methods', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'set', + ], + ]; + + $requestData = [ + "cartId" => $cartId, + "method" => [ + 'method' => 'checkmo', + 'po_number' => '200', + 'cc_owner' => 'tester', + 'cc_type' => 'test', + 'cc_exp_year' => '2014', + 'cc_exp_month' => '1', + ], + ]; + + $this->assertNotNull($this->_webApiCall($serviceInfo, $requestData)); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php + * @expectedException \Exception + * @expectedExceptionMessage Billing address is not set + */ + public function testSetPaymentWithVirtualProductWithoutAddress() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_with_virtual_product_without_address', 'reserved_order_id'); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/selected-payment-methods', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'set', + ], + ]; + + $requestData = [ + "cartId" => $cartId, + "method" => [ + 'method' => 'checkmo', + 'po_number' => '200', + 'cc_owner' => 'tester', + 'cc_type' => 'test', + 'cc_exp_year' => '2014', + 'cc_exp_month' => '1', + ], + ]; + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + * @expectedException \Exception + * @expectedExceptionMessage Shipping address is not set + */ + public function testSetPaymentWithSimpleProductWithoutAddress() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_with_simple_product_without_address', 'reserved_order_id'); + $cartId = $quote->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/selected-payment-methods', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'set', + ], + ]; + + $requestData = [ + "cartId" => $cartId, + "method" => [ + 'method' => 'checkmo', + 'po_number' => '200', + 'cc_owner' => 'tester', + 'cc_type' => 'test', + 'cc_exp_year' => '2014', + 'cc_exp_month' => '1', + ], + ]; + $this->_webApiCall($serviceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/ShippingMethod/ReadServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/ShippingMethod/ReadServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a1d95dea7a13d6036da233cdddff674a33360b57 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/ShippingMethod/ReadServiceTest.php @@ -0,0 +1,174 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Checkout\Service\V1\ShippingMethod; + +use Magento\Checkout\Service\V1\Data\Cart\ShippingMethod; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ReadServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'checkoutShippingMethodReadServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_shipping_method.php + */ + public function testGetMethod() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + + $cartId = $quote->getId(); + + $shippingAddress = $quote->getShippingAddress(); + list($carrierCode, $methodCode) = explode('_', $shippingAddress->getShippingMethod()); + list($carrierTitle, $methodTitle) = explode(' - ', $shippingAddress->getShippingDescription()); + $data = [ + ShippingMethod::CARRIER_CODE => $carrierCode, + ShippingMethod::METHOD_CODE => $methodCode, + ShippingMethod::CARRIER_TITLE => $carrierTitle, + ShippingMethod::METHOD_TITLE => $methodTitle, + ShippingMethod::SHIPPING_AMOUNT => $shippingAddress->getShippingAmount(), + ShippingMethod::BASE_SHIPPING_AMOUNT => $shippingAddress->getBaseShippingAmount(), + ShippingMethod::AVAILABLE => true, + ]; + + $requestData = ["cartId" => $cartId]; + $this->assertEquals($data, $this->_webApiCall($this->getSelectedMethodServiceInfo($cartId), $requestData)); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_and_address.php + */ + public function testGetMethodOfVirtualCart() + { + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $cartId = $quote->load('test_order_with_virtual_product', 'reserved_order_id')->getId(); + + $result = $this->_webApiCall($this->getSelectedMethodServiceInfo($cartId), ["cartId" => $cartId]); + $this->assertEquals([], $result); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testGetMethodOfCartWithNoShippingMethod() + { + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $cartId = $quote->load('test_order_1', 'reserved_order_id')->getId(); + + $result = $this->_webApiCall($this->getSelectedMethodServiceInfo($cartId), ["cartId" => $cartId]); + $this->assertEquals([], $result); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_and_address.php + * + */ + public function testGetListForVirtualCart() + { + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $cartId = $quote->load('test_order_with_virtual_product', 'reserved_order_id')->getId(); + + $this->assertEquals([], $this->_webApiCall($this->getListServiceInfo($cartId), ["cartId" => $cartId])); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testGetList() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_1', 'reserved_order_id'); + $cartId = $quote->getId(); + if (!$cartId) { + $this->fail('quote fixture failed'); + } + $quote->getShippingAddress()->collectShippingRates(); + $expectedRates = $quote->getShippingAddress()->getGroupedAllShippingRates(); + + $expectedData = $this->convertRates($expectedRates, $quote->getQuoteCurrencyCode()); + + $requestData = ["cartId" => $cartId]; + + $returnedRates = $this->_webApiCall($this->getListServiceInfo($cartId), $requestData); + $this->assertEquals($expectedData, $returnedRates); + } + + /** + * @param string $cartId + * @return array + */ + protected function getSelectedMethodServiceInfo($cartId) + { + return $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/selected-shipping-method', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetMethod', + ], + ]; + } + + /** + * Service info + * + * @param int $cartId + * @return array + */ + protected function getListServiceInfo($cartId) + { + return [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/shipping-methods', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + } + + /** + * Convert rate models array to data array + * + * @param string $currencyCode + * @param \Magento\Sales\Model\Quote\Address\Rate[] $groupedRates + * @return array + */ + protected function convertRates($groupedRates, $currencyCode) + { + $result = []; + /** @var \Magento\Checkout\Service\V1\Data\Cart\ShippingMethodConverter $converter */ + $converter = $this->objectManager->create('Magento\Checkout\Service\V1\Data\Cart\ShippingMethodConverter'); + foreach ($groupedRates as $carrierRates) { + foreach ($carrierRates as $rate) { + $result[] = $converter->modelToDataObject($rate, $currencyCode)->__toArray(); + } + } + return $result; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/ShippingMethod/WriteServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/ShippingMethod/WriteServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..95539b9aa22a6f6cfc348f1172822cff73c704f6 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Checkout/Service/V1/ShippingMethod/WriteServiceTest.php @@ -0,0 +1,106 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Checkout\Service\V1\ShippingMethod; + +use Magento\TestFramework\ObjectManager; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class WriteServiceTest extends WebapiAbstract +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var \Magento\Sales\Model\Quote + */ + protected $quote; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + } + + protected function getServiceInfo() + { + return [ + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $this->quote->getId() . '/selected-shipping-method', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'checkoutShippingMethodWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutShippingMethodWriteServiceV1SetMethod', + ], + ]; + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testSetMethod() + { + $this->quote->load('test_order_1', 'reserved_order_id'); + $serviceInfo = $this->getServiceInfo(); + + $requestData = [ + 'cartId' => $this->quote->getId(), + 'carrierCode' => 'flatrate', + 'methodCode' => 'flatrate', + ]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(true, $result); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testSetMethodWrongMethod() + { + $this->quote->load('test_order_1', 'reserved_order_id'); + $serviceInfo = $this->getServiceInfo(); + + $requestData = [ + 'cartId' => $this->quote->getId(), + 'carrierCode' => 'flatrate', + 'methodCode' => 'wrongMethod', + ]; + try { + $this->_webApiCall($serviceInfo, $requestData); + } catch (\SoapFault $e) { + $message = $e->getMessage(); + } catch (\Exception $e) { + $message = json_decode($e->getMessage())->message; + } + $this->assertEquals('Carrier with such method not found: flatrate, wrongMethod', $message); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php + */ + public function testSetMethodWithoutShippingAddress() + { + $this->quote->load('test_order_with_simple_product_without_address', 'reserved_order_id'); + $serviceInfo = $this->getServiceInfo(); + + $requestData = [ + 'cartId' => $this->quote->getId(), + 'carrierCode' => 'flatrate', + 'methodCode' => 'flatrate', + ]; + try { + $this->_webApiCall($serviceInfo, $requestData); + } catch (\SoapFault $e) { + $message = $e->getMessage(); + } catch (\Exception $e) { + $message = json_decode($e->getMessage())->message; + } + $this->assertEquals('Shipping address is not set', $message); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/CheckoutAgreements/Service/V1/Agreement/ReadServiceTest.php b/dev/tests/api-functional/testsuite/Magento/CheckoutAgreements/Service/V1/Agreement/ReadServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..db6133696df0e1c5b26ffee84bba70c1a9f53504 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/CheckoutAgreements/Service/V1/Agreement/ReadServiceTest.php @@ -0,0 +1,84 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\CheckoutAgreements\Service\V1\Agreement; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ReadServiceTest extends WebapiAbstract +{ + /** + * @var array + */ + private $listServiceInfo; + + protected function setUp() + { + $this->listServiceInfo = [ + 'soap' => [ + 'service' => 'checkoutAgreementsAgreementReadServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'checkoutAgreementsAgreementReadServiceV1GetList', + ], + 'rest' => [ + 'resourcePath' => '/V1/carts/licence/', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + ]; + } + + /** + * Retrieve agreement by given name + * + * @param string $name + * @return \Magento\CheckoutAgreements\Model\Agreement + * @throws \InvalidArgumentException + */ + protected function getAgreementByName($name) + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var $agreement \Magento\CheckoutAgreements\Model\Agreement */ + $agreement = $objectManager->create('Magento\CheckoutAgreements\Model\Agreement'); + $agreement->load($name, 'name'); + if (!$agreement->getId()) { + throw new \InvalidArgumentException('There is no checkout agreement with provided ID.'); + } + return $agreement; + } + + /** + * @magentoApiDataFixture Magento/CheckoutAgreements/_files/agreement_active_with_html_content.php + * @magentoApiDataFixture Magento/CheckoutAgreements/_files/agreement_inactive_with_text_content.php + */ + public function testGetListReturnsEmptyListIfCheckoutAgreementsAreDisabledOnFrontend() + { + // Checkout agreements are disabled by default + $agreements = $this->_webApiCall($this->listServiceInfo, []); + $this->assertEmpty($agreements); + } + + /** + * @magentoApiDataFixture Magento/CheckoutAgreements/_files/agreement_active_with_html_content.php + * @magentoApiDataFixture Magento/CheckoutAgreements/_files/agreement_inactive_with_text_content.php + */ + public function testGetListReturnsTheListOfActiveCheckoutAgreements() + { + // checkout/options/enable_agreements must be set to 1 in system configuration + // @todo remove next statement when \Magento\TestFramework\TestCase\WebapiAbstract::_updateAppConfig is fixed + $this->markTestIncomplete('This test relies on system configuration state.'); + $agreementModel = $this->getAgreementByName('Checkout Agreement (active)'); + + $agreements = $this->_webApiCall($this->listServiceInfo, []); + $this->assertCount(1, $agreements); + $agreementData = $agreements[0]; + $this->assertEquals($agreementModel->getId(), $agreementData['id']); + $this->assertEquals($agreementModel->getName(), $agreementData['name']); + $this->assertEquals($agreementModel->getContent(), $agreementData['content']); + $this->assertEquals($agreementModel->getContentHeight(), $agreementData['content_height']); + $this->assertEquals($agreementModel->getCheckboxText(), $agreementData['checkbox_text']); + $this->assertEquals($agreementModel->getIsActive(), $agreementData['active']); + $this->assertEquals($agreementModel->getIsHtml(), $agreementData['html']); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/ConfigurableProductManagementTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/ConfigurableProductManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..487580b00352b660e8be5962a2fbddfe552203b4 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/ConfigurableProductManagementTest.php @@ -0,0 +1,79 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\ConfigurableProduct\Api; + +use Magento\Webapi\Model\Rest\Config as RestConfig; +use Magento\TestFramework\Helper\Bootstrap; + +class ConfigurableProductManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'configurableProductConfigurableProductManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/configurable-products/variation'; + + /** + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/configurable_attribute.php + */ + public function testGetVariation() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GenerateVariation' + ] + ]; + /** @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository */ + $attributeRepository = Bootstrap::getObjectManager()->get( + 'Magento\Catalog\Api\ProductAttributeRepositoryInterface' + ); + $attribute = $attributeRepository->get('test_configurable'); + $attributeOptionValue = $attribute->getOptions()[0]->getValue(); + $data = [ + 'product' => [ + 'sku' => 'test', + 'price' => 10.0 + ], + 'options' => [ + [ + 'attribute_id' => 'test_configurable', + 'values' => [ + [ + 'value_index' => $attributeOptionValue, + 'pricing_value' => 100.0 + ] + ] + ] + ] + + ]; + $actual = $this->_webApiCall($serviceInfo, $data); + + $expectedItems = [ + [ + 'sku' => 'test-', + 'price' => 110.0, + 'name' => '-', + 'store_id' => 1, + 'status' => 1, + 'visibility' => \Magento\Catalog\Model\Product\Visibility::VISIBILITY_NOT_VISIBLE, + 'custom_attributes' => [ + [ + 'attribute_code' => 'test_configurable', + 'value' => $attributeOptionValue + ] + ] + ] + ]; + ksort($expectedItems); + ksort($actual); + $this->assertEquals($expectedItems, $actual); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/LinkManagementTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/LinkManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e6c37af767e59e3017e0056be72fd05afebe7eda --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/LinkManagementTest.php @@ -0,0 +1,116 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\ConfigurableProduct\Api; + +use Magento\Webapi\Model\Rest\Config; + +class LinkManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'configurableProductLinkManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/configurable-products'; + + /** + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testGetChildren() + { + $productSku = 'configurable'; + + /** @var array $result */ + $result = $this->getChildren($productSku); + $this->assertCount(2, $result); + + foreach ($result as $product) { + $this->assertArrayHasKey('custom_attributes', $product); + $this->assertArrayHasKey('price', $product); + $this->assertArrayHasKey('updated_at', $product); + + $this->assertArrayHasKey('name', $product); + $this->assertContains('Configurable Option', $product['name']); + + $this->assertArrayHasKey('sku', $product); + $this->assertContains('simple_', $product['sku']); + + $this->assertArrayHasKey('status', $product); + $this->assertEquals('1', $product['status']); + + $this->assertArrayHasKey('visibility', $product); + $this->assertEquals('1', $product['visibility']); + } + } + + /** + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/delete_association.php + */ + public function testAddChild() + { + $productSku = 'configurable'; + $childSku = 'simple_10'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/child', + 'httpMethod' => Config::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'AddChild' + ] + ]; + $res = $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'childSku' => $childSku]); + $this->assertTrue($res); + } + + /** + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testRemoveChild() + { + $productSku = 'configurable'; + $childSku = 'simple_10'; + $this->assertTrue($this->removeChild($productSku, $childSku)); + } + + protected function removeChild($productSku, $childSku) + { + $resourcePath = self::RESOURCE_PATH . '/%s/child/%s'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => sprintf($resourcePath, $productSku, $childSku), + 'httpMethod' => Config::HTTP_METHOD_DELETE + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'RemoveChild' + ] + ]; + $requestData = ['productSku' => $productSku, 'childSku' => $childSku]; + return $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @param string $productSku + * @return string + */ + protected function getChildren($productSku) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/children', + 'httpMethod' => Config::HTTP_METHOD_GET + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetChildren' + ] + ]; + return $this->_webApiCall($serviceInfo, ['productSku' => $productSku]); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..01f3bd7a1bddec8b358529b3ea79d86fa5134ee9 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php @@ -0,0 +1,289 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\ConfigurableProduct\Api; + +use Magento\Webapi\Model\Rest\Config; + +class OptionRepositoryTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'configurableProductOptionRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/configurable-products'; + + /** + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testGet() + { + $productSku = 'configurable'; + + $options = $this->getList($productSku); + $this->assertTrue(is_array($options)); + $this->assertNotEmpty($options); + + foreach ($options as $option) { + /** @var array $result */ + $result = $this->get($productSku, $option['id']); + + $this->assertTrue(is_array($result)); + $this->assertNotEmpty($result); + + $this->assertArrayHasKey('id', $result); + $this->assertEquals($option['id'], $result['id']); + + $this->assertArrayHasKey('attribute_id', $result); + $this->assertEquals($option['attribute_id'], $result['attribute_id']); + + $this->assertArrayHasKey('label', $result); + $this->assertEquals($option['label'], $result['label']); + + $this->assertArrayHasKey('values', $result); + $this->assertTrue(is_array($result['values'])); + $this->assertEquals($option['values'], $result['values']); + } + } + + /** + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testGetList() + { + $productSku = 'configurable'; + + /** @var array $result */ + $result = $this->getList($productSku); + + $this->assertNotEmpty($result); + $this->assertTrue(is_array($result)); + $this->assertArrayHasKey(0, $result); + + $option = $result[0]; + + $this->assertNotEmpty($option); + $this->assertTrue(is_array($option)); + + $this->assertArrayHasKey('id', $option); + $this->assertArrayHasKey('label', $option); + $this->assertEquals($option['label'], 'Test Configurable'); + + $this->assertArrayHasKey('values', $option); + $this->assertTrue(is_array($option)); + $this->assertNotEmpty($option); + + $expectedValues = [ + ['pricing_value' => 5, 'is_percent' => 0], + ['pricing_value' => 5, 'is_percent' => 0] + ]; + + $this->assertCount(count($expectedValues), $option['values']); + + foreach ($option['values'] as $key => $value) { + $this->assertTrue(is_array($value)); + $this->assertNotEmpty($value); + + $this->assertArrayHasKey($key, $expectedValues); + $expectedValue = $expectedValues[$key]; + + $this->assertArrayHasKey('pricing_value', $value); + $this->assertEquals($expectedValue['pricing_value'], $value['pricing_value']); + + $this->assertArrayHasKey('is_percent', $value); + $this->assertEquals($expectedValue['is_percent'], $value['is_percent']); + } + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Requested product doesn't exist + */ + public function testGetUndefinedProduct() + { + $productSku = 'product_not_exist'; + $this->getList($productSku); + } + + /** + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @expectedException \Exception + * @expectedExceptionMessage Requested option doesn't exist: -42 + */ + public function testGetUndefinedOption() + { + $productSku = 'configurable'; + $attributeId = -42; + $this->get($productSku, $attributeId); + } + + /** + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testDelete() + { + $productSku = 'configurable'; + + $optionList = $this->getList($productSku); + $optionId = $optionList[0]['id']; + $resultRemove = $this->delete($productSku, $optionId); + $optionListRemoved = $this->getList($productSku); + + $this->assertTrue($resultRemove); + $this->assertEquals(count($optionList) - 1, count($optionListRemoved)); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/configurable_attribute.php + */ + public function testAdd() + { + $productSku = 'simple'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/options', + 'httpMethod' => Config::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save' + ] + ]; + $option = [ + 'attribute_id' => 'test_configurable', + 'type' => 'select', + 'label' => 'Test', + 'values' => [ + [ + 'value_index' => 1, + 'pricing_value' => '3', + 'is_percent' => 0 + ] + ], + ]; + /** @var int $result */ + $result = $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'option' => $option]); + $this->assertGreaterThan(0, $result); + } + + /** + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testUpdate() + { + $productSku = 'configurable'; + $configurableAttribute = $this->getConfigurableAttribute($productSku); + $optionId = $configurableAttribute[0]['id']; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/options' . '/' . $optionId, + 'httpMethod' => Config::HTTP_METHOD_PUT + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save' + ] + ]; + + $option = [ + 'label' => 'Update Test Configurable' + ]; + + $requestBody = ['option' => $option]; + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $requestBody['productSku'] = $productSku; + $requestBody['option']['id'] = $optionId; + } + + $result = $this->_webApiCall($serviceInfo, $requestBody); + $this->assertGreaterThan(0, $result); + $configurableAttribute = $this->getConfigurableAttribute($productSku); + $this->assertEquals($option['label'], $configurableAttribute[0]['label']); + } + + /** + * @param string $productSku + * @return array + */ + protected function getConfigurableAttribute($productSku) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/options/all', + 'httpMethod' => Config::HTTP_METHOD_GET + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList' + ] + ]; + return $this->_webApiCall($serviceInfo, ['productSku' => $productSku]); + } + + /** + * @param string $productSku + * @param int $optionId + * @return bool + */ + private function delete($productSku, $optionId) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/options/' . $optionId, + 'httpMethod' => Config::HTTP_METHOD_DELETE + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById' + ] + ]; + return $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'optionId' => $optionId]); + } + + /** + * @param $productSku + * @param $optionId + * @return array + */ + protected function get($productSku, $optionId) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/options/' . $optionId, + 'httpMethod' => Config::HTTP_METHOD_GET + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get' + ] + ]; + return $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'optionId' => $optionId]); + } + + /** + * @param $productSku + * @return array + */ + protected function getList($productSku) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/options/all', + 'httpMethod' => Config::HTTP_METHOD_GET + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList' + ] + ]; + return $this->_webApiCall($serviceInfo, ['productSku' => $productSku]); + } + +} diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionTypesListTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionTypesListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1a99fd960dba16752a08df70f60cf05ca7d041e6 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionTypesListTest.php @@ -0,0 +1,41 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\ConfigurableProduct\Api; + +use Magento\Webapi\Model\Rest\Config; + +class OptionTypesListTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_READ_NAME = 'configurableProductOptionTypesListV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/configurable-products/:productSku/options/'; + + public function testGetTypes() + { + $expectedTypes = ['multiselect', 'select']; + $result = $this->getTypes(); + $this->assertEquals($expectedTypes, $result); + } + + /** + * @return array + */ + protected function getTypes() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => str_replace(':productSku/', '', self::RESOURCE_PATH) . 'types', + 'httpMethod' => Config::HTTP_METHOD_GET + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'GetItems' + ] + ]; + return $this->_webApiCall($serviceInfo); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementMeTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementMeTest.php new file mode 100644 index 0000000000000000000000000000000000000000..32eca4e2256338056e569e6523e1f83c4dd3e31c --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementMeTest.php @@ -0,0 +1,335 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Customer\Api; + +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Model\CustomerRegistry; +use Magento\Integration\Model\Oauth\Token as TokenModel; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Customer as CustomerHelper; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class AccountManagementMeTest + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php + */ +class AccountManagementMeTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const RESOURCE_PATH = '/V1/customers/me'; + const RESOURCE_PATH_CUSTOMER_TOKEN = "/V1/integration/customer/token"; + + /** + * @var CustomerRepositoryInterface + */ + private $customerRepository; + + /** + * @var AccountManagementInterface + */ + private $customerAccountManagement; + + /** + * @var CustomerRegistry + */ + private $customerRegistry; + + /** + * @var CustomerHelper + */ + private $customerHelper; + + /** + * @var TokenModel + */ + private $token; + + /** + * @var CustomerInterface + */ + private $customerData; + + /** + * @var \Magento\Framework\Reflection\DataObjectProcessor + */ + private $dataObjectProcessor; + + /** + * Execute per test initialization. + */ + public function setUp() + { + $this->_markTestAsRestOnly(); + + $this->customerRegistry = Bootstrap::getObjectManager()->get( + 'Magento\Customer\Model\CustomerRegistry' + ); + + $this->customerRepository = Bootstrap::getObjectManager()->get( + 'Magento\Customer\Api\CustomerRepositoryInterface', + ['customerRegistry' => $this->customerRegistry] + ); + + $this->customerAccountManagement = Bootstrap::getObjectManager() + ->get('Magento\Customer\Api\AccountManagementInterface'); + + $this->customerHelper = new CustomerHelper(); + $this->customerData = $this->customerHelper->createSampleCustomer(); + + // get token + $this->resetTokenForCustomerSampleData(); + + $this->dataObjectProcessor = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Reflection\DataObjectProcessor' + ); + } + + /** + * Ensure that fixture customer and his addresses are deleted. + */ + public function tearDown() + { + unset($this->customerRepository); + + /** @var \Magento\Framework\Registry $registry */ + $registry = Bootstrap::getObjectManager()->get('Magento\Framework\Registry'); + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', true); + + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', false); + parent::tearDown(); + } + + public function testChangePassword() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/password', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + 'token' => $this->token, + ], + ]; + $requestData = ['currentPassword' => 'test@123', 'newPassword' => '123@test']; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + + $customerResponseData = $this->customerAccountManagement + ->authenticate($this->customerData[CustomerInterface::EMAIL], '123@test'); + $this->assertEquals($this->customerData[CustomerInterface::ID], $customerResponseData->getId()); + } + + public function testUpdateCustomer() + { + $customerData = $this->_getCustomerData($this->customerData[CustomerInterface::ID]); + $lastName = $customerData->getLastname(); + + $updatedCustomerData = $this->dataObjectProcessor->buildOutputDataArray( + $customerData, + 'Magento\Customer\Api\Data\CustomerInterface' + ); + $updatedCustomerData[CustomerInterface::LASTNAME] = $lastName . 'Updated'; + $updatedCustomerData[CustomerInterface::ID] = 25; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + 'token' => $this->token, + ], + ]; + $requestData = ['customer' => $updatedCustomerData]; + + $response = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($lastName . "Updated", $response[CustomerInterface::LASTNAME]); + + $customerData = $this->_getCustomerData($this->customerData[CustomerInterface::ID]); + $this->assertEquals($lastName . "Updated", $customerData->getLastname()); + } + + public function testGetCustomerData() + { + //Get expected details from the Service directly + $customerData = $this->_getCustomerData($this->customerData[CustomerInterface::ID]); + $expectedCustomerDetails = $this->dataObjectProcessor->buildOutputDataArray( + $customerData, + 'Magento\Customer\Api\Data\CustomerInterface' + ); + $expectedCustomerDetails['addresses'][0]['id'] = + (int)$expectedCustomerDetails['addresses'][0]['id']; + + $expectedCustomerDetails['addresses'][1]['id'] = + (int)$expectedCustomerDetails['addresses'][1]['id']; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + 'token' => $this->token, + ], + ]; + $customerDetailsResponse = $this->_webApiCall($serviceInfo); + + unset($expectedCustomerDetails['custom_attributes']); + unset($customerDetailsResponse['custom_attributes']); //for REST + + $this->assertEquals($expectedCustomerDetails, $customerDetailsResponse); + } + + public function testGetCustomerActivateCustomer() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/activate', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + 'token' => $this->token, + ], + ]; + $requestData = ['confirmationKey' => $this->customerData[CustomerInterface::CONFIRMATION]]; + $customerResponseData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($this->customerData[CustomerInterface::ID], $customerResponseData[CustomerInterface::ID]); + // Confirmation key is removed after confirmation + $this->assertFalse(isset($customerResponseData[CustomerInterface::CONFIRMATION])); + } + + /** + * Return the customer details. + * + * @param int $customerId + * @return \Magento\Customer\Api\Data\CustomerInterface + */ + protected function _getCustomerData($customerId) + { + $data = $this->customerRepository->getById($customerId); + $this->customerRegistry->remove($customerId); + return $data; + } + + public function testGetDefaultBillingAddress() + { + $this->resetTokenForCustomerFixture(); + + $fixtureCustomerId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => "/V1/customers/me/billingAddress", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + 'token' => $this->token, + ], + ]; + $requestData = ['customerId' => $fixtureCustomerId]; + $addressData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals( + $this->getFirstFixtureAddressData(), + $addressData, + "Default billing address data is invalid." + ); + } + + public function testGetDefaultShippingAddress() + { + $this->resetTokenForCustomerFixture(); + + $fixtureCustomerId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => "/V1/customers/me/shippingAddress", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + 'token' => $this->token, + ], + ]; + $requestData = ['customerId' => $fixtureCustomerId]; + $addressData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals( + $this->getFirstFixtureAddressData(), + $addressData, + "Default shipping address data is invalid." + ); + } + + /** + * Retrieve data of the first fixture address. + * + * @return array + */ + protected function getFirstFixtureAddressData() + { + return [ + 'firstname' => 'John', + 'lastname' => 'Smith', + 'city' => 'CityM', + 'country_id' => 'US', + 'company' => 'CompanyName', + 'postcode' => '75477', + 'telephone' => '3468676', + 'street' => ['Green str, 67'], + 'id' => 1, + 'default_billing' => true, + 'default_shipping' => true, + 'customer_id' => '1', + 'region' => ['region' => 'Alabama', 'region_id' => 1, 'region_code' => 'AL'], + ]; + } + + /** + * Retrieve data of the second fixture address. + * + * @return array + */ + protected function getSecondFixtureAddressData() + { + return [ + 'firstname' => 'John', + 'lastname' => 'Smith', + 'city' => 'CityX', + 'country_id' => 'US', + 'postcode' => '47676', + 'telephone' => '3234676', + 'street' => ['Black str, 48'], + 'id' => 2, + 'default_billing' => false, + 'default_shipping' => false, + 'customer_id' => '1', + 'region' => ['region' => 'Alabama', 'region_id' => 1, 'region_code' => 'AL'], + ]; + } + + /** + * Sets the test's access token for the customer fixture + */ + protected function resetTokenForCustomerFixture() + { + $this->resetTokenForCustomer('customer@example.com', 'password'); + } + + /** + * Sets the test's access token for the created customer sample data + */ + protected function resetTokenForCustomerSampleData() + { + $this->resetTokenForCustomer($this->customerData[CustomerInterface::EMAIL], 'test@123'); + } + + /** + * Sets the test's access token for a particular username and password. + * + * @param string $username + * @param string $password + */ + protected function resetTokenForCustomer($username, $password) + { + // get customer ID token + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_CUSTOMER_TOKEN, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + $requestData = ['username' => $username, 'password' => $password]; + $this->token = $this->_webApiCall($serviceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..50a2790634cf7a5ec4d45a3b6d885f7fb8d35fcd --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementTest.php @@ -0,0 +1,778 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Customer\Api; + +use Magento\Customer\Api\Data\CustomerInterface as Customer; +use Magento\Customer\Model\AccountManagement; +use Magento\Framework\Exception\InputException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Customer as CustomerHelper; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Exception as HTTPExceptionCodes; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Test class for Magento\Customer\Api\AccountManagementInterface + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class AccountManagementTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'customerAccountManagementV1'; + const RESOURCE_PATH = '/V1/customers'; + + /** + * Sample values for testing + */ + const ATTRIBUTE_CODE = 'attribute_code'; + const ATTRIBUTE_VALUE = 'attribute_value'; + + /** + * @var AccountManagementInterface + */ + private $accountManagement; + + /** + * @var \Magento\Customer\Api\Data\AddressDataBuilder + */ + private $addressBuilder; + + /** + * @var \Magento\Customer\Api\Data\CustomerDataBuilder + */ + private $customerBuilder; + + /** + * @var \Magento\Framework\Api\SearchCriteriaBuilder + */ + private $searchCriteriaBuilder; + + /** + * @var \Magento\Framework\Api\SortOrderBuilder + */ + private $sortOrderBuilder; + + /** + * @var \Magento\Framework\Api\Search\FilterGroupBuilder + */ + private $filterGroupBuilder; + + /** + * @var CustomerHelper + */ + private $customerHelper; + + /** + * @var array + */ + private $currentCustomerId; + + /** + * @var \Magento\Framework\Reflection\DataObjectProcessor + */ + private $dataObjectProcessor; + + /** + * Execute per test initialization. + */ + public function setUp() + { + $this->accountManagement = Bootstrap::getObjectManager()->get( + 'Magento\Customer\Api\AccountManagementInterface' + ); + $this->addressBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Customer\Api\Data\AddressDataBuilder' + ); + $this->customerBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Customer\Api\Data\CustomerDataBuilder' + ); + $this->searchCriteriaBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + $this->sortOrderBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\SortOrderBuilder' + ); + $this->filterGroupBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\Search\FilterGroupBuilder' + ); + $this->customerHelper = new CustomerHelper(); + + $this->dataObjectProcessor = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Reflection\DataObjectProcessor' + ); + } + + public function tearDown() + { + if (!empty($this->currentCustomerId)) { + foreach ($this->currentCustomerId as $customerId) { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $customerId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => CustomerRepositoryTest::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => CustomerRepositoryTest::SERVICE_NAME . 'DeleteById', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, ['customerId' => $customerId]); + + $this->assertTrue($response); + } + } + unset($this->accountManagement); + } + + public function testCreateCustomer() + { + $customerData = $this->_createCustomer(); + $this->assertNotNull($customerData['id']); + } + + public function testCreateCustomerWithErrors() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'CreateAccount', + ], + ]; + + $customerDataArray = $this->dataObjectProcessor->buildOutputDataArray( + $this->customerHelper->createSampleCustomerDataObject(), + '\Magento\Customer\Api\Data\CustomerInterface' + ); + $invalidEmail = 'invalid'; + $customerDataArray['email'] = $invalidEmail; + $requestData = ['customer' => $customerDataArray, 'password' => CustomerHelper::PASSWORD]; + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail('Expected exception did not occur.'); + } catch (\Exception $e) { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $expectedException = new InputException(); + $expectedException->addError( + InputException::INVALID_FIELD_VALUE, + ['fieldName' => 'email', 'value' => $invalidEmail] + ); + $this->assertInstanceOf('SoapFault', $e); + $this->checkSoapFault( + $e, + $expectedException->getRawMessage(), + 'env:Sender', + $expectedException->getParameters() // expected error parameters + ); + } else { + $this->assertEquals(HTTPExceptionCodes::HTTP_BAD_REQUEST, $e->getCode()); + $exceptionData = $this->processRestExceptionResult($e); + $expectedExceptionData = [ + 'message' => InputException::INVALID_FIELD_VALUE, + 'parameters' => [ + 'fieldName' => 'email', + 'value' => $invalidEmail, + ], + ]; + $this->assertEquals($expectedExceptionData, $exceptionData); + } + } + } + + /** + * Test customer activation when it is required + * + * @magentoConfigFixture default_store customer/create_account/confirm 0 + */ + public function testActivateCustomer() + { + $customerData = $this->_createCustomer(); + $this->assertNotNull($customerData[Customer::CONFIRMATION], 'Customer activation is not required'); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $customerData[Customer::EMAIL] . '/activate', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Activate', + ], + ]; + + $requestData = [ + 'email' => $customerData[Customer::EMAIL], + 'confirmationKey' => $customerData[Customer::CONFIRMATION], + ]; + + $result = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertEquals($customerData[Customer::ID], $result[Customer::ID], 'Wrong customer!'); + $this->assertTrue( + !isset($result[Customer::CONFIRMATION]) || $result[Customer::CONFIRMATION] === null, + 'Customer is not activated!' + ); + } + + public function testGetCustomerActivateCustomer() + { + $customerData = $this->_createCustomer(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $customerData[Customer::EMAIL] . '/activate', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Activate', + ], + ]; + $requestData = [ + 'email' => $customerData[Customer::EMAIL], + 'confirmationKey' => $customerData[Customer::CONFIRMATION], + ]; + + $customerResponseData = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertEquals($customerData[Customer::ID], $customerResponseData[Customer::ID]); + // Confirmation key is removed after confirmation + $this->assertFalse(isset($customerResponseData[Customer::CONFIRMATION])); + } + + public function testValidateResetPasswordLinkToken() + { + $customerData = $this->_createCustomer(); + /** @var \Magento\Customer\Model\Customer $customerModel */ + $customerModel = Bootstrap::getObjectManager()->create('Magento\Customer\Model\CustomerFactory') + ->create(); + $customerModel->load($customerData[Customer::ID]); + $rpToken = 'lsdj579slkj5987slkj595lkj'; + $customerModel->setRpToken('lsdj579slkj5987slkj595lkj'); + $customerModel->setRpTokenCreatedAt(date('Y-m-d')); + $customerModel->save(); + $path = self::RESOURCE_PATH . '/' . $customerData[Customer::ID] . '/password/resetLinkToken/' . $rpToken; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $path, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'ValidateResetPasswordLinkToken', + ], + ]; + + $this->_webApiCall( + $serviceInfo, + ['customerId' => $customerData['id'], 'resetPasswordLinkToken' => $rpToken] + ); + } + + public function testValidateResetPasswordLinkTokenInvalidToken() + { + $customerData = $this->_createCustomer(); + $invalidToken = 'fjjkafjie'; + $path = self::RESOURCE_PATH . '/' . $customerData[Customer::ID] . '/password/resetLinkToken/' . $invalidToken; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $path, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'ValidateResetPasswordLinkToken', + ], + ]; + + $expectedMessage = 'Reset password token mismatch.'; + + try { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->_webApiCall( + $serviceInfo, + ['customerId' => $customerData['id'], 'resetPasswordLinkToken' => 'invalid'] + ); + } else { + $this->_webApiCall($serviceInfo); + } + $this->fail("Expected exception to be thrown."); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception message does not match" + ); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals($expectedMessage, $errorObj['message']); + $this->assertEquals(HTTPExceptionCodes::HTTP_BAD_REQUEST, $e->getCode()); + } + } + + public function testInitiatePasswordMissingRequiredFields() + { + $this->_markTestAsRestOnly('Soap clients explicitly check for required fields based on WSDL.'); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/password', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ] + ]; + + try { + $this->_webApiCall($serviceInfo); + } catch (\Exception $e) { + $this->assertEquals(\Magento\Webapi\Exception::HTTP_BAD_REQUEST, $e->getCode()); + $exceptionData = $this->processRestExceptionResult($e); + $expectedExceptionData = [ + 'message' => InputException::DEFAULT_MESSAGE, + 'errors' => [ + [ + 'message' => InputException::REQUIRED_FIELD, + 'parameters' => [ + 'fieldName' => 'email', + ], + ], + [ + 'message' => InputException::REQUIRED_FIELD, + 'parameters' => [ + 'fieldName' => 'template', + ] + ], + ], + ]; + $this->assertEquals($expectedExceptionData, $exceptionData); + } + } + + public function testInitiatePasswordReset() + { + $customerData = $this->_createCustomer(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/password', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'InitiatePasswordReset', + ], + ]; + $requestData = [ + 'email' => $customerData[Customer::EMAIL], + 'template' => AccountManagement::EMAIL_RESET, + 'websiteId' => $customerData[Customer::WEBSITE_ID], + ]; + // This api doesn't return any response. + // No exception or response means the request was processed successfully. + // The webapi framework does not return the header information as yet. A check for HTTP 200 would be ideal here + $this->_webApiCall($serviceInfo, $requestData); + } + + public function testSendPasswordResetLinkBadEmailOrWebsite() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/password', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'InitiatePasswordReset', + ], + ]; + $requestData = [ + 'email' => 'dummy@example.com', + 'template' => AccountManagement::EMAIL_RESET, + 'websiteId' => 0, + ]; + try { + $this->_webApiCall($serviceInfo, $requestData); + } catch (\Exception $e) { + $expectedErrorParameters = + [ + 'fieldName' => 'email', + 'fieldValue' => 'dummy@example.com', + 'field2Name' => 'websiteId', + 'field2Value' => 0, + ]; + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_REST) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals( + NoSuchEntityException::MESSAGE_DOUBLE_FIELDS, + $errorObj['message'] + ); + $this->assertEquals($expectedErrorParameters, $errorObj['parameters']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } else { + $this->assertInstanceOf('SoapFault', $e); + $this->checkSoapFault( + $e, + NoSuchEntityException::MESSAGE_DOUBLE_FIELDS, + 'env:Sender', + $expectedErrorParameters + ); + } + } + } + + public function testGetConfirmationStatus() + { + $customerData = $this->_createCustomer(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $customerData[Customer::ID] . '/confirm', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetConfirmationStatus', + ], + ]; + + $confirmationResponse = $this->_webApiCall($serviceInfo, ['customerId' => $customerData['id']]); + + $this->assertEquals(AccountManagement::ACCOUNT_CONFIRMATION_NOT_REQUIRED, $confirmationResponse); + } + + public function testResendConfirmation() + { + $customerData = $this->_createCustomer(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/confirm', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'ResendConfirmation', + ], + ]; + $requestData = [ + 'email' => $customerData[Customer::EMAIL], + 'websiteId' => $customerData[Customer::WEBSITE_ID], + ]; + // This api doesn't return any response. + // No exception or response means the request was processed successfully. + // The webapi framework does not return the header information as yet. A check for HTTP 200 would be ideal here + $this->_webApiCall($serviceInfo, $requestData); + } + + public function testResendConfirmationBadEmailOrWebsite() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/confirm', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'ResendConfirmation', + ], + ]; + $requestData = [ + 'email' => 'dummy@example.com', + 'websiteId' => 0, + ]; + try { + $this->_webApiCall($serviceInfo, $requestData); + } catch (\Exception $e) { + $expectedErrorParameters = + [ + 'fieldName' => 'email', + 'fieldValue' => 'dummy@example.com', + 'field2Name' => 'websiteId', + 'field2Value' => 0, + ]; + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_REST) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals( + NoSuchEntityException::MESSAGE_DOUBLE_FIELDS, + $errorObj['message'] + ); + $this->assertEquals($expectedErrorParameters, $errorObj['parameters']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } else { + $this->assertInstanceOf('SoapFault', $e); + $this->checkSoapFault( + $e, + NoSuchEntityException::MESSAGE_DOUBLE_FIELDS, + 'env:Sender', + $expectedErrorParameters + ); + } + } + } + + public function testValidateCustomerData() + { + $customerData = $this->customerHelper->createSampleCustomerDataObject(); + $customerData = $this->customerBuilder->populate($customerData) + ->setFirstname(null)->setLastname(null)->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/validate', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Validate', + ], + ]; + $customerData = $this->dataObjectProcessor->buildOutputDataArray( + $customerData, + '\Magento\Customer\Api\Data\CustomerInterface' + ); + $requestData = ['customer' => $customerData]; + $validationResponse = $this->_webApiCall($serviceInfo, $requestData); + $this->assertFalse($validationResponse['valid']); + $this->assertEquals('The first name cannot be empty.', $validationResponse['messages'][0]); + $this->assertEquals('The last name cannot be empty.', $validationResponse['messages'][1]); + } + + public function testIsReadonly() + { + $customerData = $this->_createCustomer(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $customerData[Customer::ID] . '/permissions/readonly', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'IsReadonly', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, ['customerId' => $customerData['id']]); + + $this->assertFalse($response); + } + + public function testEmailAvailable() + { + $customerData = $this->_createCustomer(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/isEmailAvailable', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'IsEmailAvailable', + ], + ]; + $requestData = [ + 'customerEmail' => $customerData[Customer::EMAIL], + 'websiteId' => $customerData[Customer::WEBSITE_ID], + ]; + $this->assertFalse($this->_webApiCall($serviceInfo, $requestData)); + } + + public function testEmailAvailableInvalidEmail() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/isEmailAvailable', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'IsEmailAvailable', + ], + ]; + $requestData = [ + 'customerEmail' => 'invalid', + 'websiteId' => 0, + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/attribute_user_defined_address.php + * @magentoApiDataFixture Magento/Customer/_files/attribute_user_defined_customer.php + */ + public function testCustomAttributes() + { + //Sample customer data comes with the disable_auto_group_change custom attribute + $customerData = $this->customerHelper->createSampleCustomerDataObject(); + //address attribute code from fixture + $fixtureAddressAttributeCode = 'address_user_attribute'; + //customer attribute code from fixture + $fixtureCustomerAttributeCode = 'user_attribute'; + //Custom Attribute Values + $address1CustomAttributeValue = 'value1'; + $address2CustomAttributeValue = 'value2'; + $customerCustomAttributeValue = 'value3'; + + $addresses = $customerData->getAddresses(); + $address1 = $this->addressBuilder + ->populate($addresses[0]) + ->setCustomAttribute($fixtureAddressAttributeCode, $address1CustomAttributeValue) + ->create(); + $address2 = $this->addressBuilder + ->populate($addresses[1]) + ->setCustomAttribute($fixtureAddressAttributeCode, $address2CustomAttributeValue) + ->create(); + + $customer = $this->customerBuilder + ->populate($customerData) + ->setAddresses([$address1, $address2]) + ->setCustomAttribute($fixtureCustomerAttributeCode, $customerCustomAttributeValue) + ->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'CreateAccount', + ], + ]; + + $customerDataArray = $this->dataObjectProcessor->buildOutputDataArray( + $customer, + '\Magento\Customer\Api\Data\CustomerInterface' + ); + $requestData = ['customer' => $customerDataArray, 'password' => CustomerHelper::PASSWORD]; + $customerData = $this->_webApiCall($serviceInfo, $requestData); + $customerId = $customerData['id']; + //TODO: Fix assertions to verify custom attributes + $this->assertNotNull($customerData); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $customerId , + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => CustomerRepositoryTest::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => CustomerRepositoryTest::SERVICE_NAME . 'DeleteById', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, ['customerId' => $customerId]); + $this->assertTrue($response); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php + */ + public function testGetDefaultBillingAddress() + { + $fixtureCustomerId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$fixtureCustomerId/billingAddress", + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetDefaultBillingAddress', + ], + ]; + $requestData = ['customerId' => $fixtureCustomerId]; + $addressData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals( + $this->getFirstFixtureAddressData(), + $addressData, + "Default billing address data is invalid." + ); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php + */ + public function testGetDefaultShippingAddress() + { + $fixtureCustomerId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$fixtureCustomerId/shippingAddress", + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetDefaultShippingAddress', + ], + ]; + $requestData = ['customerId' => $fixtureCustomerId]; + $addressData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals( + $this->getFirstFixtureAddressData(), + $addressData, + "Default shipping address data is invalid." + ); + } + + /** + * @return array|bool|float|int|string + */ + protected function _createCustomer() + { + $customerData = $this->customerHelper->createSampleCustomer(); + $this->currentCustomerId[] = $customerData['id']; + return $customerData; + } + + /** + * Retrieve data of the first fixture address. + * + * @return array + */ + protected function getFirstFixtureAddressData() + { + return [ + 'firstname' => 'John', + 'lastname' => 'Smith', + 'city' => 'CityM', + 'country_id' => 'US', + 'company' => 'CompanyName', + 'postcode' => '75477', + 'telephone' => '3468676', + 'street' => ['Green str, 67'], + 'id' => 1, + 'default_billing' => true, + 'default_shipping' => true, + 'customer_id' => '1', + 'region' => ['region' => 'Alabama', 'region_id' => 1, 'region_code' => 'AL'], + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/AddressMetadataTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AddressMetadataTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f3acea94fc9bff6081ddd8f0647fc6e3f17020a7 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AddressMetadataTest.php @@ -0,0 +1,274 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Customer\Api; + +use Magento\Customer\Api\Data\AddressInterface as Address; +use Magento\Customer\Model\Data\AttributeMetadata; +use Magento\TestFramework\TestCase\WebapiAbstract; + +/** + * Class AddressMetadataTest + */ +class AddressMetadataTest extends WebapiAbstract +{ + const SERVICE_NAME = "customerAddressMetadataV1"; + const SERVICE_VERSION = "V1"; + const RESOURCE_PATH = "/V1/attributeMetadata/customerAddress"; + + /** + * Test retrieval of attribute metadata for the address entity type. + * + * @param string $attributeCode The attribute code of the requested metadata. + * @param array $expectedMetadata Expected entity metadata for the attribute code. + * @dataProvider getAttributeMetadataDataProvider + */ + public function testGetAttributeMetadata($attributeCode, $expectedMetadata) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/attribute/$attributeCode", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetAttributeMetadata', + ], + ]; + + $requestData = [ + 'attributeCode' => $attributeCode, + ]; + + $attributeMetadata = $this->_webapiCall($serviceInfo, $requestData); + $validationResult = $this->checkValidationRules($expectedMetadata, $attributeMetadata); + list($expectedMetadata, $attributeMetadata) = $validationResult; + $this->assertEquals($expectedMetadata, $attributeMetadata); + } + + /** + * Data provider for testGetAttributeMetadata. + * + * @return array + */ + public function getAttributeMetadataDataProvider() + { + return [ + Address::POSTCODE => [ + Address::POSTCODE, + [ + AttributeMetadata::ATTRIBUTE_CODE => 'postcode', + AttributeMetadata::FRONTEND_INPUT => 'text', + AttributeMetadata::INPUT_FILTER => '', + AttributeMetadata::STORE_LABEL => 'Zip/Postal Code', + AttributeMetadata::VALIDATION_RULES => [], + AttributeMetadata::VISIBLE => true, + AttributeMetadata::REQUIRED => false, + AttributeMetadata::MULTILINE_COUNT => 0, + AttributeMetadata::DATA_MODEL => 'Magento\Customer\Model\Attribute\Data\Postcode', + AttributeMetadata::OPTIONS => [], + AttributeMetadata::FRONTEND_CLASS => '', + AttributeMetadata::FRONTEND_LABEL => 'Zip/Postal Code', + AttributeMetadata::NOTE => '', + AttributeMetadata::SYSTEM => true, + AttributeMetadata::USER_DEFINED => false, + AttributeMetadata::BACKEND_TYPE => 'varchar', + AttributeMetadata::SORT_ORDER => 110 + ], + ] + ]; + } + + /** + * Test retrieval of all address attribute metadata. + */ + public function testGetAllAttributesMetadata() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetAllAttributesMetadata', + ], + ]; + + $attributeMetadata = $this->_webApiCall($serviceInfo); + $this->assertCount(19, $attributeMetadata); + $postcode = $this->getAttributeMetadataDataProvider()[Address::POSTCODE][1]; + $validationResult = $this->checkMultipleAttributesValidationRules($postcode, $attributeMetadata); + list($postcode, $attributeMetadata) = $validationResult; + $this->assertContains($postcode, $attributeMetadata); + } + + /** + * Test retrieval of custom address attribute metadata. + * + * @magentoApiDataFixture Magento/Customer/_files/attribute_user_defined_address_custom_attribute.php + */ + public function testGetCustomAttributesMetadata() + { + $customAttributeCode = 'custom_attribute1'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/custom', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetCustomAttributesMetadata', + ], + ]; + + $requestData = ['attribute_code' => $customAttributeCode]; + $attributeMetadata = $this->_webApiCall($serviceInfo, $requestData); + $this->assertCount(2, $attributeMetadata); + $this->assertEquals($customAttributeCode, $attributeMetadata[0]['attribute_code']); + } + + /** + * Test retrieval of attributes + * + * @param string $formCode Form code + * @param array $expectedMetadata The expected attribute metadata + * @dataProvider getAttributesDataProvider + */ + public function testGetAttributes($formCode, $expectedMetadata) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/form/$formCode", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetAttributes', + ], + ]; + + $requestData = [ + 'formCode' => $formCode, + ]; + + $attributeMetadataList = $this->_webApiCall($serviceInfo, $requestData); + foreach ($attributeMetadataList as $attributeMetadata) { + if (isset($attributeMetadata['attribute_code']) + && $attributeMetadata['attribute_code'] == $expectedMetadata['attribute_code'] + ) { + $validationResult = $this->checkValidationRules($expectedMetadata, $attributeMetadata); + list($expectedMetadata, $attributeMetadata) = $validationResult; + $this->assertEquals($expectedMetadata, $attributeMetadata); + break; + } + } + } + + /** + * Data provider for testGetAttributes. + * + * @return array + */ + public function getAttributesDataProvider() + { + $attributeMetadata = $this->getAttributeMetadataDataProvider(); + return [ + [ + 'customer_address_edit', + $attributeMetadata[Address::POSTCODE][1], + ] + ]; + } + + /** + * Checks that expected and actual attribute metadata validation rules are equal + * and removes the validation rules entry from expected and actual attribute metadata + * + * @param array $expectedResult + * @param array $actualResult + * @return array + */ + public function checkValidationRules($expectedResult, $actualResult) + { + $expectedRules = []; + $actualRules = []; + + if (isset($expectedResult[AttributeMetadata::VALIDATION_RULES])) { + $expectedRules = $expectedResult[AttributeMetadata::VALIDATION_RULES]; + unset($expectedResult[AttributeMetadata::VALIDATION_RULES]); + } + if (isset($actualResult[AttributeMetadata::VALIDATION_RULES])) { + $actualRules = $actualResult[AttributeMetadata::VALIDATION_RULES]; + unset($actualResult[AttributeMetadata::VALIDATION_RULES]); + } + + if (is_array($expectedRules) && is_array($actualRules)) { + foreach ($expectedRules as $expectedRule) { + if (isset($expectedRule['name']) && isset($expectedRule['value'])) { + $found = false; + foreach ($actualRules as $actualRule) { + if (isset($actualRule['name']) && isset($actualRule['value'])) { + if ($expectedRule['name'] == $actualRule['name'] + && $expectedRule['value'] == $actualRule['value'] + ) { + $found = true; + break; + } + } + } + $this->assertTrue($found); + } + } + } + return [$expectedResult, $actualResult]; + } + + /** + * Check specific attribute validation rules in set of multiple attributes + * + * @param array $expectedResult Set of expected attribute metadata + * @param array $actualResultSet Set of actual attribute metadata + * @return array + */ + public function checkMultipleAttributesValidationRules($expectedResult, $actualResultSet) + { + if (is_array($expectedResult) && is_array($actualResultSet)) { + if (isset($expectedResult[AttributeMetadata::ATTRIBUTE_CODE])) { + foreach ($actualResultSet as $actualAttributeKey => $actualAttribute) { + if (isset($actualAttribute[AttributeMetadata::ATTRIBUTE_CODE]) + && $expectedResult[AttributeMetadata::ATTRIBUTE_CODE] + == $actualAttribute[AttributeMetadata::ATTRIBUTE_CODE] + ) { + $this->checkValidationRules($expectedResult, $actualAttribute); + unset($actualResultSet[$actualAttributeKey][AttributeMetadata::VALIDATION_RULES]); + } + } + unset($expectedResult[AttributeMetadata::VALIDATION_RULES]); + } + } + return [$expectedResult, $actualResultSet]; + } + + /** + * Remove test attribute + */ + public static function tearDownAfterClass() + { + parent::tearDownAfterClass(); + /** @var \Magento\Customer\Model\Attribute $attribute */ + $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Customer\Model\Attribute' + ); + foreach (['custom_attribute1', 'custom_attribute2'] as $attributeCode) { + $attribute->loadByCode('customer_address', $attributeCode); + $attribute->delete(); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/AddressRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AddressRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5bc344be7173a39a1ddc571cdc56189029e56a6e --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AddressRepositoryTest.php @@ -0,0 +1,166 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Customer\Api; + +use Magento\TestFramework\Helper\Bootstrap; + +class AddressRepositoryTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SOAP_SERVICE_NAME = 'customerAddressRepositoryV1'; + const SOAP_SERVICE_VERSION = 'V1'; + + /** @var \Magento\Customer\Api\AddressRepositoryInterface */ + protected $addressRepository; + + /** @var \Magento\Customer\Api\CustomerRepositoryInterface */ + protected $customerRepository; + + protected function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->customerRepository = $objectManager->get( + 'Magento\Customer\Api\CustomerRepositoryInterface' + ); + $this->addressRepository = $objectManager->get( + 'Magento\Customer\Api\AddressRepositoryInterface' + ); + parent::setUp(); + } + + /** + * Ensure that fixture customer and his addresses are deleted. + */ + protected function tearDown() + { + /** @var \Magento\Framework\Registry $registry */ + $registry = Bootstrap::getObjectManager()->get('Magento\Framework\Registry'); + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', true); + + try { + $fixtureFirstAddressId = 1; + $this->addressRepository->deleteById($fixtureFirstAddressId); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + /** First address fixture was not used */ + } + try { + $fixtureSecondAddressId = 2; + $this->addressRepository->deleteById($fixtureSecondAddressId); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + /** Second address fixture was not used */ + } + try { + $fixtureCustomerId = 1; + $this->customerRepository->deleteById($fixtureCustomerId); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + /** Customer fixture was not used */ + } + + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', false); + parent::tearDown(); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/Customer/_files/customer_address.php + */ + public function testGetAddress() + { + $fixtureAddressId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => "/V1/customers/addresses/{$fixtureAddressId}", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SOAP_SERVICE_NAME, + 'serviceVersion' => self::SOAP_SERVICE_VERSION, + 'operation' => self::SOAP_SERVICE_NAME . 'GetById', + ], + ]; + $requestData = ['addressId' => $fixtureAddressId]; + $addressData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals( + $this->getFirstFixtureAddressData(), + $addressData, + "Address data is invalid." + ); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/Customer/_files/customer_address.php + */ + public function testDeleteAddress() + { + $fixtureAddressId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => "/V1/addresses/{$fixtureAddressId}", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SOAP_SERVICE_NAME, + 'serviceVersion' => self::SOAP_SERVICE_VERSION, + 'operation' => self::SOAP_SERVICE_NAME . 'DeleteById', + ], + ]; + $requestData = ['addressId' => $fixtureAddressId]; + $response = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($response, 'Expected response should be true.'); + + $this->setExpectedException('Magento\Framework\Exception\NoSuchEntityException', 'No such entity with addressId = 1'); + $this->addressRepository->getById($fixtureAddressId); + } + + /** + * Retrieve data of the first fixture address. + * + * @return array + */ + protected function getFirstFixtureAddressData() + { + return [ + 'firstname' => 'John', + 'lastname' => 'Smith', + 'city' => 'CityM', + 'country_id' => 'US', + 'company' => 'CompanyName', + 'postcode' => '75477', + 'telephone' => '3468676', + 'street' => ['Green str, 67'], + 'id' => 1, + 'default_billing' => true, + 'default_shipping' => true, + 'customer_id' => '1', + 'region' => ['region' => 'Alabama', 'region_id' => 1, 'region_code' => 'AL'], + ]; + } + + /** + * Retrieve data of the second fixture address. + * + * @return array + */ + protected function getSecondFixtureAddressData() + { + return [ + 'firstname' => 'John', + 'lastname' => 'Smith', + 'city' => 'CityX', + 'country_id' => 'US', + 'postcode' => '47676', + 'telephone' => '3234676', + 'street' => ['Black str, 48'], + 'id' => 2, + 'default_billing' => false, + 'default_shipping' => false, + 'customer_id' => '1', + 'region' => ['region' => 'Alabama', 'region_id' => 1, 'region_code' => 'AL'], + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bba031a61ccd5a60271279e14809de94ab72d468 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php @@ -0,0 +1,321 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Customer\Api; + +use Magento\Customer\Api\Data\CustomerInterface as Customer; +use Magento\Customer\Model\Data\AttributeMetadata; +use Magento\TestFramework\TestCase\WebapiAbstract; + +/** + * Class CustomerMetadataTest + */ +class CustomerMetadataTest extends WebapiAbstract +{ + const SERVICE_NAME = "customerCustomerMetadataV1"; + const SERVICE_VERSION = "V1"; + const RESOURCE_PATH = "/V1/attributeMetadata/customer"; + + /** + * Test retrieval of attribute metadata for the customer entity type. + * + * @param string $attributeCode The attribute code of the requested metadata. + * @param array $expectedMetadata Expected entity metadata for the attribute code. + * @dataProvider getAttributeMetadataDataProvider + */ + public function testGetAttributeMetadata($attributeCode, $expectedMetadata) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/attribute/$attributeCode", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetAttributeMetadata', + ], + ]; + + $requestData = [ + 'attributeCode' => $attributeCode, + ]; + + $attributeMetadata = $this->_webapiCall($serviceInfo, $requestData); + + $validationResult = $this->checkValidationRules($expectedMetadata, $attributeMetadata); + list($expectedMetadata, $attributeMetadata) = $validationResult; + $this->assertEquals($expectedMetadata, $attributeMetadata); + } + + /** + * Data provider for testGetAttributeMetadata. + * + * @return array + */ + public function getAttributeMetadataDataProvider() + { + return [ + Customer::FIRSTNAME => [ + Customer::FIRSTNAME, + [ + AttributeMetadata::ATTRIBUTE_CODE => 'firstname', + AttributeMetadata::FRONTEND_INPUT => 'text', + AttributeMetadata::INPUT_FILTER => '', + AttributeMetadata::STORE_LABEL => 'First Name', + AttributeMetadata::VALIDATION_RULES => [ + ['name' => 'min_text_length', 'value' => 1], + ['name' => 'max_text_length', 'value' => 255], + ], + AttributeMetadata::VISIBLE => true, + AttributeMetadata::REQUIRED => true, + AttributeMetadata::MULTILINE_COUNT => 0, + AttributeMetadata::DATA_MODEL => '', + AttributeMetadata::OPTIONS => [], + AttributeMetadata::FRONTEND_CLASS => ' required-entry', + AttributeMetadata::FRONTEND_LABEL => 'First Name', + AttributeMetadata::NOTE => '', + AttributeMetadata::SYSTEM => true, + AttributeMetadata::USER_DEFINED => false, + AttributeMetadata::BACKEND_TYPE => 'varchar', + AttributeMetadata::SORT_ORDER => 40 + ], + ], + Customer::GENDER => [ + Customer::GENDER, + [ + AttributeMetadata::ATTRIBUTE_CODE => 'gender', + AttributeMetadata::FRONTEND_INPUT => 'select', + AttributeMetadata::INPUT_FILTER => '', + AttributeMetadata::STORE_LABEL => 'Gender', + AttributeMetadata::VALIDATION_RULES => [], + AttributeMetadata::VISIBLE => false, + AttributeMetadata::REQUIRED => false, + AttributeMetadata::MULTILINE_COUNT => 0, + AttributeMetadata::DATA_MODEL => '', + AttributeMetadata::OPTIONS => [ + ['label' => '', 'value' => ''], + ['label' => 'Male', 'value' => '1'], + ['label' => 'Female', 'value' => '2'], + ], + AttributeMetadata::FRONTEND_CLASS => '', + AttributeMetadata::FRONTEND_LABEL => 'Gender', + AttributeMetadata::NOTE => '', + AttributeMetadata::SYSTEM => false, + AttributeMetadata::USER_DEFINED => false, + AttributeMetadata::BACKEND_TYPE => 'int', + AttributeMetadata::SORT_ORDER => 110 + ], + ], + Customer::WEBSITE_ID => [ + Customer::WEBSITE_ID, + [ + AttributeMetadata::ATTRIBUTE_CODE => 'website_id', + AttributeMetadata::FRONTEND_INPUT => 'select', + AttributeMetadata::INPUT_FILTER => '', + AttributeMetadata::STORE_LABEL => 'Associate to Website', + AttributeMetadata::VALIDATION_RULES => [], + AttributeMetadata::VISIBLE => true, + AttributeMetadata::REQUIRED => true, + AttributeMetadata::MULTILINE_COUNT => 0, + AttributeMetadata::DATA_MODEL => '', + AttributeMetadata::OPTIONS => [ + ['label' => 'Admin', 'value' => '0'], + ['label' => 'Main Website', 'value' => '1'], + ], + AttributeMetadata::FRONTEND_CLASS => ' required-entry', + AttributeMetadata::FRONTEND_LABEL => 'Associate to Website', + AttributeMetadata::NOTE => '', + AttributeMetadata::SYSTEM => true, + AttributeMetadata::USER_DEFINED => false, + AttributeMetadata::BACKEND_TYPE => 'static', + AttributeMetadata::SORT_ORDER => 10 + ], + ] + ]; + } + + /** + * Test retrieval of all customer attribute metadata. + */ + public function testGetAllAttributesMetadata() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetAllAttributesMetadata', + ], + ]; + + $attributeMetadata = $this->_webApiCall($serviceInfo); + + $this->assertCount(23, $attributeMetadata); + + $firstName = $this->getAttributeMetadataDataProvider()[Customer::FIRSTNAME][1]; + $validationResult = $this->checkMultipleAttributesValidationRules($firstName, $attributeMetadata); + list($firstName, $attributeMetadata) = $validationResult; + $this->assertContains($firstName, $attributeMetadata); + + $websiteId = $this->getAttributeMetadataDataProvider()[Customer::WEBSITE_ID][1]; + $validationResult = $this->checkMultipleAttributesValidationRules($websiteId, $attributeMetadata); + list($websiteId, $attributeMetadata) = $validationResult; + $this->assertContains($websiteId, $attributeMetadata); + } + + /** + * Test retrieval of custom customer attribute metadata. + */ + public function testGetCustomAttributesMetadata() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/custom', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetCustomAttributesMetadata', + ], + ]; + + $attributeMetadata = $this->_webApiCall($serviceInfo); + + //Default custom attribute code 'disable_auto_group_change' + $this->assertCount(1, $attributeMetadata); + $this->assertEquals('disable_auto_group_change', $attributeMetadata[0]['attribute_code']); + } + + /** + * Test retrieval of attributes + * + * @param string $formCode Form code + * @param array $expectedMetadata The expected attribute metadata + * @dataProvider getAttributesDataProvider + */ + public function testGetAttributes($formCode, $expectedMetadata) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/form/$formCode", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetAttributes', + ], + ]; + + $requestData = [ + 'formCode' => $formCode, + ]; + + $attributeMetadataList = $this->_webApiCall($serviceInfo, $requestData); + foreach ($attributeMetadataList as $attributeMetadata) { + if (isset($attributeMetadata['attribute_code']) + && $attributeMetadata['attribute_code'] == $expectedMetadata['attribute_code']) { + $validationResult = $this->checkValidationRules($expectedMetadata, $attributeMetadata); + list($expectedMetadata, $attributeMetadata) = $validationResult; + $this->assertEquals($expectedMetadata, $attributeMetadata); + break; + } + } + } + + /** + * Data provider for testGetAttributes. + * + * @return array + */ + public function getAttributesDataProvider() + { + $attributeMetadata = $this->getAttributeMetadataDataProvider(); + return [ + [ + 'adminhtml_customer', + $attributeMetadata[Customer::FIRSTNAME][1], + ], + [ + 'adminhtml_customer', + $attributeMetadata[Customer::GENDER][1] + ] + ]; + } + + /** + * Checks that expected and actual attribute metadata validation rules are equal + * and removes the validation rules entry from expected and actual attribute metadata + * + * @param array $expectedResult + * @param array $actualResult + * @return array + */ + public function checkValidationRules($expectedResult, $actualResult) + { + $expectedRules = []; + $actualRules = []; + + if (isset($expectedResult[AttributeMetadata::VALIDATION_RULES])) { + $expectedRules = $expectedResult[AttributeMetadata::VALIDATION_RULES]; + unset($expectedResult[AttributeMetadata::VALIDATION_RULES]); + } + if (isset($actualResult[AttributeMetadata::VALIDATION_RULES])) { + $actualRules = $actualResult[AttributeMetadata::VALIDATION_RULES]; + unset($actualResult[AttributeMetadata::VALIDATION_RULES]); + } + + if (is_array($expectedRules) && is_array($actualRules)) { + foreach ($expectedRules as $expectedRule) { + if (isset($expectedRule['name']) && isset($expectedRule['value'])) { + $found = false; + foreach ($actualRules as $actualRule) { + if (isset($actualRule['name']) && isset($actualRule['value'])) { + if ($expectedRule['name'] == $actualRule['name'] + && $expectedRule['value'] == $actualRule['value'] + ) { + $found = true; + break; + } + } + } + $this->assertTrue($found); + } + } + } + return [$expectedResult, $actualResult]; + } + + /** + * Check specific attribute validation rules in set of multiple attributes + * + * @param array $expectedResult Set of expected attribute metadata + * @param array $actualResultSet Set of actual attribute metadata + * @return array + */ + public function checkMultipleAttributesValidationRules($expectedResult, $actualResultSet) + { + if (is_array($expectedResult) && is_array($actualResultSet)) { + if (isset($expectedResult[AttributeMetadata::ATTRIBUTE_CODE])) { + foreach ($actualResultSet as $actualAttributeKey => $actualAttribute) { + if (isset($actualAttribute[AttributeMetadata::ATTRIBUTE_CODE]) + && $expectedResult[AttributeMetadata::ATTRIBUTE_CODE] + == $actualAttribute[AttributeMetadata::ATTRIBUTE_CODE] + ) { + $this->checkValidationRules($expectedResult, $actualAttribute); + unset($actualResultSet[$actualAttributeKey][AttributeMetadata::VALIDATION_RULES]); + } + } + unset($expectedResult[AttributeMetadata::VALIDATION_RULES]); + } + } + return [$expectedResult, $actualResultSet]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..db1b03f1f4772c921d98cb043c5d2d63dc6fd41a --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerRepositoryTest.php @@ -0,0 +1,659 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Customer\Api; + +use Magento\Customer\Api\Data\CustomerInterface as Customer; +use Magento\Framework\Api\SearchCriteria; +use Magento\Framework\Exception\InputException; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Customer as CustomerHelper; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Exception as HTTPExceptionCodes; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Test class for Magento\Customer\Api\CustomerRepositoryInterface + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class CustomerRepositoryTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'customerCustomerRepositoryV1'; + const RESOURCE_PATH = '/V1/customers'; + + /** + * Sample values for testing + */ + const ATTRIBUTE_CODE = 'attribute_code'; + const ATTRIBUTE_VALUE = 'attribute_value'; + + /** + * @var CustomerRepositoryInterface + */ + private $customerRepository; + + /** + * @var \Magento\Customer\Api\Data\AddressDataBuilder + */ + private $addressBuilder; + + /** + * @var \Magento\Customer\Api\Data\CustomerDataBuilder + */ + private $customerBuilder; + + /** + * @var \Magento\Framework\Api\SearchCriteriaBuilder + */ + private $searchCriteriaBuilder; + + /** + * @var \Magento\Framework\Api\SortOrderBuilder + */ + private $sortOrderBuilder; + + /** + * @var \Magento\Framework\Api\Search\FilterGroupBuilder + */ + private $filterGroupBuilder; + + /** + * @var \Magento\Customer\Model\CustomerRegistry + */ + private $customerRegistry; + + /** + * @var CustomerHelper + */ + private $customerHelper; + + /** + * @var array + */ + private $currentCustomerId; + + /** + * @var \Magento\Framework\Reflection\DataObjectProcessor + */ + private $dataObjectProcessor; + + /** + * Execute per test initialization. + */ + public function setUp() + { + $this->customerRegistry = Bootstrap::getObjectManager()->get( + 'Magento\Customer\Model\CustomerRegistry' + ); + + $this->customerRepository = Bootstrap::getObjectManager()->get( + 'Magento\Customer\Api\CustomerRepositoryInterface', + ['customerRegistry' => $this->customerRegistry] + ); + $this->addressBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Customer\Api\Data\AddressDataBuilder' + ); + $this->customerBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Customer\Api\Data\CustomerDataBuilder' + ); + $this->searchCriteriaBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + $this->sortOrderBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\SortOrderBuilder' + ); + $this->filterGroupBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\Search\FilterGroupBuilder' + ); + $this->customerHelper = new CustomerHelper(); + + $this->dataObjectProcessor = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Reflection\DataObjectProcessor' + ); + } + + public function tearDown() + { + if (!empty($this->currentCustomerId)) { + foreach ($this->currentCustomerId as $customerId) { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $customerId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, ['customerId' => $customerId]); + + $this->assertTrue($response); + } + } + unset($this->customerRepository); + } + + public function testDeleteCustomer() + { + $customerData = $this->_createCustomer(); + $this->currentCustomerId = []; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $customerData[Customer::ID], + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ]; + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $response = $this->_webApiCall($serviceInfo, ['customerId' => $customerData['id']]); + } else { + $response = $this->_webApiCall($serviceInfo); + } + + $this->assertTrue($response); + + //Verify if the customer is deleted + $this->setExpectedException( + 'Magento\Framework\Exception\NoSuchEntityException', + sprintf("No such entity with customerId = %s", $customerData[Customer::ID]) + ); + $this->_getCustomerData($customerData[Customer::ID]); + } + + public function testDeleteCustomerInvalidCustomerId() + { + $invalidId = -1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $invalidId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ]; + + $expectedMessage = 'No such entity with %fieldName = %fieldValue'; + + try { + $this->_webApiCall($serviceInfo, ['customerId' => $invalidId]); + + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals($expectedMessage, $errorObj['message']); + $this->assertEquals(['fieldName' => 'customerId', 'fieldValue' => $invalidId], $errorObj['parameters']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } + + public function testUpdateCustomer() + { + $customerData = $this->_createCustomer(); + $existingCustomerDataObject = $this->_getCustomerData($customerData[Customer::ID]); + $lastName = $existingCustomerDataObject->getLastname(); + $customerData[Customer::LASTNAME] = $lastName . 'Updated'; + $newCustomerDataObject = $this->customerBuilder->populateWithArray($customerData)->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/{$customerData[Customer::ID]}", + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $newCustomerDataObject = $this->dataObjectProcessor->buildOutputDataArray( + $newCustomerDataObject, + 'Magento\Customer\Api\Data\CustomerInterface' + ); + $requestData = ['customer' => $newCustomerDataObject]; + $response = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue(!is_null($response)); + + //Verify if the customer is updated + $existingCustomerDataObject = $this->_getCustomerData($customerData[Customer::ID]); + $this->assertEquals($lastName . "Updated", $existingCustomerDataObject->getLastname()); + } + + /** + * Verify expected behavior when the website id is not set + */ + public function testUpdateCustomerNoWebsiteId() + { + $customerData = $this->customerHelper->createSampleCustomer(); + $existingCustomerDataObject = $this->_getCustomerData($customerData[Customer::ID]); + $lastName = $existingCustomerDataObject->getLastname(); + $customerData[Customer::LASTNAME] = $lastName . 'Updated'; + $newCustomerDataObject = $this->customerBuilder->populateWithArray($customerData)->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/{$customerData[Customer::ID]}", + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $newCustomerDataObject = $this->dataObjectProcessor->buildOutputDataArray( + $newCustomerDataObject, + 'Magento\Customer\Api\Data\CustomerInterface' + ); + unset($newCustomerDataObject['website_id']); + $requestData = ['customer' => $newCustomerDataObject]; + + $expectedMessage = '"Associate to Website" is a required value.'; + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception."); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $errorObj = $this->customerHelper->processRestExceptionResult($e); + $this->assertEquals($expectedMessage, $errorObj['message'], 'Invalid message: "' . $e->getMessage() . '"'); + $this->assertEquals(HTTPExceptionCodes::HTTP_BAD_REQUEST, $e->getCode()); + } + } + + public function testUpdateCustomerException() + { + $customerData = $this->_createCustomer(); + $existingCustomerDataObject = $this->_getCustomerData($customerData[Customer::ID]); + $lastName = $existingCustomerDataObject->getLastname(); + + //Set non-existent id = -1 + $customerData[Customer::LASTNAME] = $lastName . 'Updated'; + $customerData[Customer::ID] = -1; + + $newCustomerDataObject = $this->customerBuilder->populateWithArray($customerData)->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/-1", + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $newCustomerDataObject = $this->dataObjectProcessor->buildOutputDataArray( + $newCustomerDataObject, + 'Magento\Customer\Api\Data\CustomerInterface' + ); + $requestData = ['customer' => $newCustomerDataObject]; + + $expectedMessage = 'No such entity with %fieldName = %fieldValue'; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception."); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals($expectedMessage, $errorObj['message']); + $this->assertEquals(['fieldName' => 'customerId', 'fieldValue' => -1], $errorObj['parameters']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } + + /** + * Test with a single filter + */ + public function testSearchCustomers() + { + $builder = Bootstrap::getObjectManager()->create('Magento\Framework\Api\FilterBuilder'); + $customerData = $this->_createCustomer(); + $filter = $builder + ->setField(Customer::EMAIL) + ->setValue($customerData[Customer::EMAIL]) + ->create(); + $this->searchCriteriaBuilder->addFilter([$filter]); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getList', + ], + ]; + $searchData = $this->dataObjectProcessor->buildOutputDataArray( + $this->searchCriteriaBuilder->create(), + 'Magento\Framework\Api\SearchCriteriaInterface' + ); + $requestData = ['searchCriteria' => $searchData]; + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(1, $searchResults['total_count']); + $this->assertEquals($customerData[Customer::ID], $searchResults['items'][0][Customer::ID]); + } + + /** + * Test with a single filter using GET + */ + public function testSearchCustomersUsingGET() + { + $this->_markTestAsRestOnly('SOAP test is covered in testSearchCustomers'); + $builder = Bootstrap::getObjectManager()->create('Magento\Framework\Api\FilterBuilder'); + $customerData = $this->_createCustomer(); + $filter = $builder + ->setField(Customer::EMAIL) + ->setValue($customerData[Customer::EMAIL]) + ->create(); + $this->searchCriteriaBuilder->addFilter([$filter]); + + $searchData = $this->searchCriteriaBuilder->create()->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchQueryString = http_build_query($requestData); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search?' . $searchQueryString, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + ]; + $searchResults = $this->_webApiCall($serviceInfo); + $this->assertEquals(1, $searchResults['total_count']); + $this->assertEquals($customerData[Customer::ID], $searchResults['items'][0][Customer::ID]); + } + + /** + * Test with empty GET based filter + */ + public function testSearchCustomersUsingGETEmptyFilter() + { + $this->_markTestAsRestOnly('Soap clients explicitly check for required fields based on WSDL.'); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + ]; + try { + $this->_webApiCall($serviceInfo); + } catch (\Exception $e) { + $this->assertEquals(HTTPExceptionCodes::HTTP_BAD_REQUEST, $e->getCode()); + $exceptionData = $this->processRestExceptionResult($e); + $expectedExceptionData = [ + 'message' => InputException::REQUIRED_FIELD, + 'parameters' => [ + 'fieldName' => 'searchCriteria' + ], + ]; + $this->assertEquals($expectedExceptionData, $exceptionData); + } + } + + /** + * Test using multiple filters + */ + public function testSearchCustomersMultipleFiltersWithSort() + { + $builder = Bootstrap::getObjectManager()->create('Magento\Framework\Api\FilterBuilder'); + $customerData1 = $this->_createCustomer(); + $customerData2 = $this->_createCustomer(); + $filter1 = $builder->setField(Customer::EMAIL) + ->setValue($customerData1[Customer::EMAIL]) + ->create(); + $filter2 = $builder->setField(Customer::EMAIL) + ->setValue($customerData2[Customer::EMAIL]) + ->create(); + $filter3 = $builder->setField(Customer::LASTNAME) + ->setValue($customerData1[Customer::LASTNAME]) + ->create(); + $this->searchCriteriaBuilder->addFilter([$filter1, $filter2]); + $this->searchCriteriaBuilder->addFilter([$filter3]); + + /**@var \Magento\Framework\Api\SortOrderBuilder $sortOrderBuilder */ + $sortOrderBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\SortOrderBuilder' + ); + /** @var \Magento\Framework\Api\SortOrder $sortOrder */ + $sortOrder = $sortOrderBuilder->setField(Customer::EMAIL)->setDirection(SearchCriteria::SORT_ASC)->create(); + $this->searchCriteriaBuilder->setSortOrders([$sortOrder]); + + $searchCriteria = $this->searchCriteriaBuilder->create(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getList', + ], + ]; + $searchData = $searchCriteria->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(2, $searchResults['total_count']); + $this->assertEquals($customerData1[Customer::ID], $searchResults['items'][0][Customer::ID]); + $this->assertEquals($customerData2[Customer::ID], $searchResults['items'][1][Customer::ID]); + } + + /** + * Test using multiple filters using GET + */ + public function testSearchCustomersMultipleFiltersWithSortUsingGET() + { + $this->_markTestAsRestOnly('SOAP test is covered in testSearchCustomers'); + $builder = Bootstrap::getObjectManager()->create('Magento\Framework\Api\FilterBuilder'); + $customerData1 = $this->_createCustomer(); + $customerData2 = $this->_createCustomer(); + $filter1 = $builder->setField(Customer::EMAIL) + ->setValue($customerData1[Customer::EMAIL]) + ->create(); + $filter2 = $builder->setField(Customer::EMAIL) + ->setValue($customerData2[Customer::EMAIL]) + ->create(); + $filter3 = $builder->setField(Customer::LASTNAME) + ->setValue($customerData1[Customer::LASTNAME]) + ->create(); + $this->searchCriteriaBuilder->addFilter([$filter1, $filter2]); + $this->searchCriteriaBuilder->addFilter([$filter3]); + $this->searchCriteriaBuilder->setSortOrders([Customer::EMAIL => SearchCriteria::SORT_ASC]); + $searchCriteria = $this->searchCriteriaBuilder->create(); + $searchData = $searchCriteria->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchQueryString = http_build_query($requestData); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search?' . $searchQueryString, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + ]; + $searchResults = $this->_webApiCall($serviceInfo); + $this->assertEquals(2, $searchResults['total_count']); + $this->assertEquals($customerData1[Customer::ID], $searchResults['items'][0][Customer::ID]); + $this->assertEquals($customerData2[Customer::ID], $searchResults['items'][1][Customer::ID]); + } + + /** + * Test and verify multiple filters using And-ed non-existent filter value + */ + public function testSearchCustomersNonExistentMultipleFilters() + { + $builder = Bootstrap::getObjectManager()->create('Magento\Framework\Api\FilterBuilder'); + $customerData1 = $this->_createCustomer(); + $customerData2 = $this->_createCustomer(); + $filter1 = $filter1 = $builder->setField(Customer::EMAIL) + ->setValue($customerData1[Customer::EMAIL]) + ->create(); + $filter2 = $builder->setField(Customer::EMAIL) + ->setValue($customerData2[Customer::EMAIL]) + ->create(); + $filter3 = $builder->setField(Customer::LASTNAME) + ->setValue('INVALID') + ->create(); + $this->searchCriteriaBuilder->addFilter([$filter1, $filter2]); + $this->searchCriteriaBuilder->addFilter([$filter3]); + $searchCriteria = $this->searchCriteriaBuilder->create(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getList', + ], + ]; + $searchData = $searchCriteria->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(0, $searchResults['total_count'], 'No results expected for non-existent email.'); + } + + /** + * Test and verify multiple filters using And-ed non-existent filter value using GET + */ + public function testSearchCustomersNonExistentMultipleFiltersGET() + { + $this->_markTestAsRestOnly('SOAP test is covered in testSearchCustomers'); + $builder = Bootstrap::getObjectManager()->create('Magento\Framework\Api\FilterBuilder'); + $customerData1 = $this->_createCustomer(); + $customerData2 = $this->_createCustomer(); + $filter1 = $filter1 = $builder->setField(Customer::EMAIL) + ->setValue($customerData1[Customer::EMAIL]) + ->create(); + $filter2 = $builder->setField(Customer::EMAIL) + ->setValue($customerData2[Customer::EMAIL]) + ->create(); + $filter3 = $builder->setField(Customer::LASTNAME) + ->setValue('INVALID') + ->create(); + $this->searchCriteriaBuilder->addFilter([$filter1, $filter2]); + $this->searchCriteriaBuilder->addFilter([$filter3]); + $searchCriteria = $this->searchCriteriaBuilder->create(); + $searchData = $searchCriteria->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchQueryString = http_build_query($requestData); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search?' . $searchQueryString, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + ]; + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(0, $searchResults['total_count'], 'No results expected for non-existent email.'); + } + + /** + * Test using multiple filters + */ + public function testSearchCustomersMultipleFilterGroups() + { + $customerData1 = $this->_createCustomer(); + + /** @var \Magento\Framework\Api\FilterBuilder $builder */ + $builder = Bootstrap::getObjectManager()->create('Magento\Framework\Api\FilterBuilder'); + $filter1 = $builder->setField(Customer::EMAIL) + ->setValue($customerData1[Customer::EMAIL]) + ->create(); + $filter2 = $builder->setField(Customer::MIDDLENAME) + ->setValue($customerData1[Customer::MIDDLENAME]) + ->create(); + $filter3 = $builder->setField(Customer::MIDDLENAME) + ->setValue('invalid') + ->create(); + $filter4 = $builder->setField(Customer::LASTNAME) + ->setValue($customerData1[Customer::LASTNAME]) + ->create(); + + $this->searchCriteriaBuilder->addFilter([$filter1]); + $this->searchCriteriaBuilder->addFilter([$filter2, $filter3]); + $this->searchCriteriaBuilder->addFilter([$filter4]); + $searchCriteria = $this->searchCriteriaBuilder->setCurrentPage(1)->setPageSize(10)->create(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getList', + ], + ]; + $searchData = $searchCriteria->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(1, $searchResults['total_count']); + $this->assertEquals($customerData1[Customer::ID], $searchResults['items'][0][Customer::ID]); + + // Add an invalid And-ed data with multiple groups to yield no result + $filter4 = $builder->setField(Customer::LASTNAME) + ->setValue('invalid') + ->create(); + + $this->searchCriteriaBuilder->addFilter([$filter1]); + $this->searchCriteriaBuilder->addFilter([$filter2, $filter3]); + $this->searchCriteriaBuilder->addFilter([$filter4]); + $searchCriteria = $this->searchCriteriaBuilder->create(); + $searchData = $searchCriteria->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(0, $searchResults['total_count']); + } + + /** + * Retrieve customer data by Id + * + * @param int $customerId + * @return \Magento\Customer\Api\Data\CustomerInterface + */ + protected function _getCustomerData($customerId) + { + $customerData = $this->customerRepository->getById($customerId); + $this->customerRegistry->remove($customerId); + return $customerData; + } + + /** + * @return array|bool|float|int|string + */ + protected function _createCustomer() + { + $customerData = $this->customerHelper->createSampleCustomer(); + $this->currentCustomerId[] = $customerData['id']; + return $customerData; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/GroupManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/GroupManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..70c6294ebb972258359846a461128d8e34822830 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/GroupManagementTest.php @@ -0,0 +1,228 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Customer\Api; + +use Magento\Customer\Model\Data\Group as CustomerGroup; +use Magento\Customer\Model\GroupRegistry; +use Magento\Customer\Model\Resource\GroupRepository; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; + +/** + * Class GroupManagementTest + */ +class GroupManagementTest extends WebapiAbstract +{ + const SERVICE_NAME = "customerGroupManagementV1"; + const SERVICE_VERSION = "V1"; + const RESOURCE_PATH = "/V1/customerGroups"; + + /** + * @var GroupRegistry + */ + private $groupRegistry; + + /** + * @var GroupRepository + */ + private $groupRepository; + + /** + * Execute per test initialization. + */ + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->groupRegistry = $objectManager->get('Magento\Customer\Model\GroupRegistry'); + $this->groupRepository = $objectManager->get('Magento\Customer\Model\Resource\GroupRepository'); + } + + /** + * Verify the retrieval of the default group for storeId equal to 1. + * + * @param int $storeId The store Id + * @param array $defaultGroupData The default group data for the store with the specified Id. + * + * @dataProvider getDefaultGroupDataProvider + */ + public function testGetDefaultGroup($storeId, $defaultGroupData) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/default/$storeId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupManagementV1GetDefaultGroup', + ], + ]; + $requestData = ['storeId' => $storeId]; + $groupData = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertEquals($defaultGroupData, $groupData, "The default group does not match."); + } + + /** + * The testGetDefaultGroup data provider. + * + * @return array + */ + public function getDefaultGroupDataProvider() + { + return [ + 'admin' => [ + 0, + [ + CustomerGroup::ID => 1, + CustomerGroup::CODE => 'General', + CustomerGroup::TAX_CLASS_ID => 3, + CustomerGroup::TAX_CLASS_NAME => 'Retail Customer' + ], + ], + 'base' => [ + 1, + [ + CustomerGroup::ID => 1, + CustomerGroup::CODE => 'General', + CustomerGroup::TAX_CLASS_ID => 3, + CustomerGroup::TAX_CLASS_NAME => 'Retail Customer' + ], + ] + ]; + } + + /** + * Verify the retrieval of a non-existent storeId will return an expected fault. + */ + public function testGetDefaultGroupNonExistentStore() + { + /* Store id should not exist */ + $nonExistentStoreId = 9876; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/default/$nonExistentStoreId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupManagementV1GetDefaultGroup', + ], + ]; + $requestData = ['storeId' => $nonExistentStoreId]; + $expectedMessage = 'No such entity with %fieldName = %fieldValue'; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + $this->assertContains((string)$nonExistentStoreId, $e->getMessage()); + } + } + + /** + * Verify that the group with the specified Id can or cannot be deleted. + * + * @param int $groupId The group Id + * @param bool $isDeleteable Whether the group can or cannot be deleted. + * + * @dataProvider isReadonlyDataProvider + */ + public function testIsReadonly($groupId, $isDeleteable) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$groupId/permissions", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupManagementV1IsReadonly', + ], + ]; + + $requestData = [CustomerGroup::ID => $groupId]; + + $isReadonly = $this->_webApiCall($serviceInfo, $requestData); + + $failureMessage = $isDeleteable + ? 'The group should be deleteable.' : 'The group should not be deleteable.'; + $this->assertEquals($isDeleteable, !$isReadonly, $failureMessage); + } + + /** + * The testIsReadonly data provider. + * + * @return array + */ + public function isReadonlyDataProvider() + { + return [ + 'NOT LOGGED IN' => [0, false], + 'General' => [1, false], + 'Wholesale' => [2, true], + 'Retailer' => [3, true] + ]; + } + + /** + * Verify that the group with the specified Id can or cannot be deleted. + */ + public function testIsReadonlyNoSuchGroup() + { + /* This group ID should not exist in the store. */ + $groupId = 9999; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$groupId/permissions", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupManagementV1IsReadonly', + ], + ]; + + $requestData = [CustomerGroup::ID => $groupId]; + + $expectedMessage = 'No such entity with %fieldName = %fieldValue'; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception."); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + $this->assertContains((string)$groupId, $e->getMessage()); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/GroupRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/GroupRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..862349c1cbe539b7bee28b8a844457e4c6e153c2 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/GroupRepositoryTest.php @@ -0,0 +1,1007 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Customer\Api; + +use Magento\Customer\Model\Data\Group as CustomerGroup; +use Magento\Customer\Model\GroupRegistry; +use Magento\Customer\Model\Resource\GroupRepository; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; + +/** + * Class GroupRepositoryTest + */ +class GroupRepositoryTest extends WebapiAbstract +{ + const SERVICE_NAME = "customerGroupRepositoryV1"; + const SERVICE_VERSION = "V1"; + const RESOURCE_PATH = "/V1/customerGroups"; + + /** + * @var GroupRegistry + */ + private $groupRegistry; + + /** + * @var GroupRepository + */ + private $groupRepository; + + /** + * Execute per test initialization. + */ + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->groupRegistry = $objectManager->get('Magento\Customer\Model\GroupRegistry'); + $this->groupRepository = $objectManager->get('Magento\Customer\Model\Resource\GroupRepository'); + } + + /** + * Execute per test cleanup. + */ + public function tearDown() + { + } + + /** + * Cleaning up the extra groups that might have been created as part of the testing. + */ + public static function tearDownAfterClass() + { + } + + /** + * Verify the retrieval of a customer group by Id. + * + * @param array $testGroup The group data for the group being retrieved. + * + * @dataProvider getGroupDataProvider + */ + public function testGetGroupById($testGroup) + { + $groupId = $testGroup[CustomerGroup::ID]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$groupId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1GetById', + ], + ]; + $requestData = [CustomerGroup::ID => $groupId]; + $groupData = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertEquals($testGroup, $groupData, "The group data does not match."); + } + + /** + * The testGetGroup data provider. + * + * @return array + */ + public function getGroupDataProvider() + { + return [ + 'NOT LOGGED IN' => [ + [ + CustomerGroup::ID => 0, + CustomerGroup::CODE => 'NOT LOGGED IN', + CustomerGroup::TAX_CLASS_ID => 3, + CustomerGroup::TAX_CLASS_NAME => 'Retail Customer', + ], + ], + 'General' => [ + [ + CustomerGroup::ID => 1, + CustomerGroup::CODE => 'General', + CustomerGroup::TAX_CLASS_ID => 3, + CustomerGroup::TAX_CLASS_NAME => 'Retail Customer', + ], + ], + 'Wholesale' => [ + [ + CustomerGroup::ID => 2, + CustomerGroup::CODE => 'Wholesale', + CustomerGroup::TAX_CLASS_ID => 3, + CustomerGroup::TAX_CLASS_NAME => 'Retail Customer', + ], + ], + 'Retailer' => [ + [ + CustomerGroup::ID => 3, + CustomerGroup::CODE => 'Retailer', + CustomerGroup::TAX_CLASS_ID => 3, + CustomerGroup::TAX_CLASS_NAME => 'Retail Customer', + ], + ], + ]; + } + + /** + * Verify that creating a new group works via REST. + */ + public function testCreateGroupRest() + { + $this->_markTestAsRestOnly(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + + $groupData = [ + CustomerGroup::ID => null, + CustomerGroup::CODE => 'Create Group REST', + CustomerGroup::TAX_CLASS_ID => 3, + ]; + $requestData = ['group' => $groupData]; + + $groupId = $this->_webApiCall($serviceInfo, $requestData)[CustomerGroup::ID]; + $this->assertNotNull($groupId); + + $newGroup = $this->groupRepository->getById($groupId); + $this->assertEquals($groupId, $newGroup->getId(), 'The group id does not match.'); + $this->assertEquals($groupData[CustomerGroup::CODE], $newGroup->getCode(), 'The group code does not match.'); + $this->assertEquals( + $groupData[CustomerGroup::TAX_CLASS_ID], + $newGroup->getTaxClassId(), + 'The group tax class id does not match.' + ); + } + + /** + * Verify that creating a new group with a duplicate group name fails with an error via REST. + */ + public function testCreateGroupDuplicateGroupRest() + { + $builder = Bootstrap::getObjectManager()->create('Magento\Customer\Api\Data\GroupDataBuilder'); + $this->_markTestAsRestOnly(); + + $duplicateGroupCode = 'Duplicate Group Code REST'; + + $this->createGroup( + $builder->populateWithArray([ + CustomerGroup::ID => null, + CustomerGroup::CODE => $duplicateGroupCode, + CustomerGroup::TAX_CLASS_ID => 3, + ])->create() + ); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + + $groupData = [ + CustomerGroup::ID => null, + CustomerGroup::CODE => $duplicateGroupCode, + CustomerGroup::TAX_CLASS_ID => 3, + ]; + $requestData = ['group' => $groupData]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception"); + } catch (\Exception $e) { + $errorData = json_decode($e->getMessage(), true); + + $this->assertEquals( + 'Customer Group already exists.', + $errorData['message'] + ); + $this->assertEquals(400, $e->getCode(), 'Invalid HTTP code'); + } + } + + /** + * Verify that creating a new group works via REST if tax class id is empty, defaults 3. + */ + public function testCreateGroupDefaultTaxClassIdRest() + { + $this->_markTestAsRestOnly(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + + $groupData = [ + CustomerGroup::ID => null, + CustomerGroup::CODE => 'Default Class Tax ID REST', + CustomerGroup::TAX_CLASS_ID => null, + ]; + $requestData = ['group' => $groupData]; + + $groupId = $this->_webApiCall($serviceInfo, $requestData)[CustomerGroup::ID]; + $this->assertNotNull($groupId); + + $newGroup = $this->groupRepository->getById($groupId); + $this->assertEquals($groupId, $newGroup->getId(), 'The group id does not match.'); + $this->assertEquals($groupData[CustomerGroup::CODE], $newGroup->getCode(), 'The group code does not match.'); + $this->assertEquals( + GroupRepository::DEFAULT_TAX_CLASS_ID, + $newGroup->getTaxClassId(), + 'The group tax class id does not match.' + ); + } + + /** + * Verify that creating a new group without a code fails with an error. + */ + public function testCreateGroupNoCodeExpectExceptionRest() + { + $this->_markTestAsRestOnly(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + + $groupData = [ + CustomerGroup::ID => null, + CustomerGroup::CODE => null, + CustomerGroup::TAX_CLASS_ID => null, + ]; + $requestData = ['group' => $groupData]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception"); + } catch (\Exception $e) { + // @codingStandardsIgnoreStart + $this->assertContains( + '{"message":"%fieldName is a required field.","parameters":{"fieldName":"code"}', + $e->getMessage(), + "Exception does not contain expected message." + ); + // @codingStandardsIgnoreEnd + } + } + + /** + * Verify that creating a new group with an invalid tax class id fails with an error. + */ + public function testCreateGroupInvalidTaxClassIdRest() + { + $this->_markTestAsRestOnly(); + + $invalidTaxClassId = 9999; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + + $groupData = [ + CustomerGroup::ID => null, + CustomerGroup::CODE => 'Invalid Tax Class Id Code', + CustomerGroup::TAX_CLASS_ID => $invalidTaxClassId, + ]; + $requestData = ['group' => $groupData]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception"); + } catch (\Exception $e) { + // @codingStandardsIgnoreStart + $this->assertContains( + '{"message":"Invalid value of \"%value\" provided for the %fieldName field.","parameters":{"fieldName":"taxClassId","value":9999}', + $e->getMessage(), + "Exception does not contain expected message." + ); + // codingStandardsIgnoreEnd + } + } + + /** + * Verify that an attempt to update via POST is not allowed. + */ + public function testCreateGroupWithIdRest() + { + $this->_markTestAsRestOnly(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + + $groupData = [ + CustomerGroup::ID => 88, + CustomerGroup::CODE => 'Create Group With Id REST', + CustomerGroup::TAX_CLASS_ID => 3, + ]; + $requestData = ['group' => $groupData]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail('Expected exception'); + } catch (\Exception $e) { + $this->assertContains( + '{"message":"No such entity with %fieldName = %fieldValue","parameters":{"fieldName":"id","fieldValue":88}', + $e->getMessage(), + "Exception does not contain expected message." + ); + } + } + + /** + * Verify that creating a new group fails via SOAP if there is an Id specified. + */ + public function testCreateGroupWithIdSoap() + { + $this->_markTestAsSoapOnly(); + + $serviceInfo = [ + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1Save', + ], + ]; + + $groupData = [ + CustomerGroup::ID => 88, + CustomerGroup::CODE => 'Create Group with Id SOAP', + CustomerGroup::TAX_CLASS_ID => 3, + ]; + $requestData = ['group' => $groupData]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + 'No such entity with %fieldName = %fieldValue', + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } + } + + /** + * Verify that updating an existing group works via REST. + */ + public function testUpdateGroupRest() + { + $this->_markTestAsRestOnly(); + $builder = Bootstrap::getObjectManager()->create('Magento\Customer\Api\Data\GroupDataBuilder'); + $groupId = $this->createGroup( + $builder->populateWithArray([ + CustomerGroup::ID => null, + CustomerGroup::CODE => 'New Group REST', + CustomerGroup::TAX_CLASS_ID => 3, + ])->create() + ); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$groupId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + ]; + + $groupData = [ + CustomerGroup::ID => $groupId, + CustomerGroup::CODE => 'Updated Group REST', + CustomerGroup::TAX_CLASS_ID => 3, + ]; + $requestData = ['group' => $groupData]; + + $this->assertEquals($groupId, $this->_webApiCall($serviceInfo, $requestData)[CustomerGroup::ID]); + + $group = $this->groupRepository->getById($groupId); + $this->assertEquals($groupData[CustomerGroup::CODE], $group->getCode(), 'The group code did not change.'); + $this->assertEquals( + $groupData[CustomerGroup::TAX_CLASS_ID], + $group->getTaxClassId(), + 'The group tax class id did not change' + ); + } + + /** + * Verify that updating a non-existing group throws an exception. + */ + public function testUpdateGroupNotExistingGroupRest() + { + $this->_markTestAsRestOnly(); + + $nonExistentGroupId = '9999'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$nonExistentGroupId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + ]; + + $groupData = [ + CustomerGroup::ID => $nonExistentGroupId, + CustomerGroup::CODE => 'Updated Group REST Does Not Exist', + CustomerGroup::TAX_CLASS_ID => 3, + ]; + $requestData = ['group' => $groupData]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail('Expected exception'); + } catch (\Exception $e) { + $expectedMessage = '{"message":"No such entity with %fieldName = %fieldValue",' + . '"parameters":{"fieldName":"id","fieldValue":9999}'; + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + } + + /** + * Verify that creating a new group works via SOAP. + */ + public function testCreateGroupSoap() + { + $this->_markTestAsSoapOnly(); + + $serviceInfo = [ + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1Save', + ], + ]; + + $groupData = [ + CustomerGroup::ID => null, + CustomerGroup::CODE => 'Create Group SOAP', + 'taxClassId' => 3, + ]; + $requestData = ['group' => $groupData]; + + $groupId = $this->_webApiCall($serviceInfo, $requestData)[CustomerGroup::ID]; + $this->assertNotNull($groupId); + + $newGroup = $this->groupRepository->getById($groupId); + $this->assertEquals($groupId, $newGroup->getId(), "The group id does not match."); + $this->assertEquals($groupData[CustomerGroup::CODE], $newGroup->getCode(), "The group code does not match."); + $this->assertEquals( + $groupData['taxClassId'], + $newGroup->getTaxClassId(), + "The group tax class id does not match." + ); + } + + /** + * Verify that creating a new group with a duplicate code fails with an error via SOAP. + */ + public function testCreateGroupDuplicateGroupSoap() + { + $this->_markTestAsSoapOnly(); + $builder = Bootstrap::getObjectManager()->create('Magento\Customer\Api\Data\GroupDataBuilder'); + $duplicateGroupCode = 'Duplicate Group Code SOAP'; + + $this->createGroup( + $builder->populateWithArray([ + CustomerGroup::ID => null, + CustomerGroup::CODE => $duplicateGroupCode, + CustomerGroup::TAX_CLASS_ID => 3, + ])->create() + ); + + $serviceInfo = [ + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1Save', + ], + ]; + + $groupData = [ + CustomerGroup::ID => null, + CustomerGroup::CODE => $duplicateGroupCode, + 'taxClassId' => 3, + ]; + $requestData = ['group' => $groupData]; + + $expectedMessage = 'Customer Group already exists.'; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + } + + /** + * Verify that creating a new group works via SOAP if tax class id is empty, defaults 3. + */ + public function testCreateGroupDefaultTaxClassIdSoap() + { + $this->_markTestAsSoapOnly(); + + $serviceInfo = [ + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1Save', + ], + ]; + + $groupData = [ + CustomerGroup::ID => null, + CustomerGroup::CODE => 'Default Class Tax ID SOAP', + 'taxClassId' => null, + 'taxClassName' => null, + ]; + $requestData = ['group' => $groupData]; + + $groupResponseData = $this->_webApiCall($serviceInfo, $requestData); + $groupId = $groupResponseData[CustomerGroup::ID]; + $this->assertNotNull($groupId); + + $newGroup = $this->groupRepository->getById($groupId); + $this->assertEquals($groupId, $newGroup->getId(), "The group id does not match."); + $this->assertEquals($groupData[CustomerGroup::CODE], $newGroup->getCode(), "The group code does not match."); + $this->assertEquals( + GroupRepository::DEFAULT_TAX_CLASS_ID, + $newGroup->getTaxClassId(), + "The group tax class id does not match." + ); + } + + /** + * Verify that creating a new group without a code fails with an error. + */ + public function testCreateGroupNoCodeExpectExceptionSoap() + { + $this->_markTestAsSoapOnly(); + + $serviceInfo = [ + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1Save', + ], + ]; + + $groupData = [ + CustomerGroup::ID => null, + CustomerGroup::CODE => null, + 'taxClassId' => null, + ]; + $requestData = ['group' => $groupData]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + '%fieldName is a required field.', + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } + } + + /** + * Verify that creating a new group fails via SOAP if tax class id is invalid. + */ + public function testCreateGroupInvalidTaxClassIdSoap() + { + $this->_markTestAsSoapOnly(); + + $invalidTaxClassId = 9999; + + $serviceInfo = [ + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1Save', + ], + ]; + + $groupData = [ + CustomerGroup::ID => null, + CustomerGroup::CODE => 'Invalid Class Tax ID SOAP', + 'taxClassId' => $invalidTaxClassId, + ]; + $requestData = ['group' => $groupData]; + + $expectedMessage = 'Invalid value of "%value" provided for the %fieldName field.'; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } + } + + /** + * Verify that updating an existing group works via SOAP. + */ + public function testUpdateGroupSoap() + { + $this->_markTestAsSoapOnly(); + $builder = Bootstrap::getObjectManager()->create('Magento\Customer\Api\Data\GroupDataBuilder'); + $groupId = $this->createGroup( + $builder->populateWithArray([ + CustomerGroup::ID => null, + CustomerGroup::CODE => 'New Group SOAP', + CustomerGroup::TAX_CLASS_ID => 3, + ])->create() + ); + + $serviceInfo = [ + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1Save', + ], + ]; + + $groupData = [ + CustomerGroup::ID => $groupId, + CustomerGroup::CODE => 'Updated Group SOAP', + 'taxClassId' => 3, + ]; + $this->_webApiCall($serviceInfo, ['group' => $groupData]); + + $group = $this->groupRepository->getById($groupId); + $this->assertEquals($groupData[CustomerGroup::CODE], $group->getCode(), 'The group code did not change.'); + $this->assertEquals( + $groupData['taxClassId'], + $group->getTaxClassId(), + 'The group tax class id did not change' + ); + } + + /** + * Verify that updating a non-existing group throws an exception via SOAP. + */ + public function testUpdateGroupNotExistingGroupSoap() + { + $this->_markTestAsSoapOnly(); + + $nonExistentGroupId = '9999'; + + $serviceInfo = [ + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1Save', + ], + ]; + + $groupData = [ + CustomerGroup::ID => $nonExistentGroupId, + CustomerGroup::CODE => 'Updated Non-Existent Group SOAP', + 'taxClassId' => 3, + ]; + $requestData = ['group' => $groupData]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + } catch (\Exception $e) { + $expectedMessage = 'No such entity with %fieldName = %fieldValue'; + + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + } + + /** + * Verify that deleting an existing group works. + */ + public function testDeleteGroupExists() + { + $builder = Bootstrap::getObjectManager()->create('Magento\Customer\Api\Data\GroupDataBuilder'); + $groupId = $this->createGroup( + $builder->populateWithArray([ + CustomerGroup::ID => null, + CustomerGroup::CODE => 'Delete Group', + CustomerGroup::TAX_CLASS_ID => 3, + ])->create() + ); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$groupId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1DeleteById', + ], + ]; + + $requestData = [CustomerGroup::ID => $groupId]; + $response = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($response, 'Expected response should be true.'); + + try { + $this->groupRepository->getById($groupId); + $this->fail('An expected NoSuchEntityException was not thrown.'); + } catch (NoSuchEntityException $e) { + $exception = NoSuchEntityException::singleField(CustomerGroup::ID, $groupId); + $this->assertEquals( + $exception->getMessage(), + $e->getMessage(), + 'Exception message does not match expected message.' + ); + } + } + + /** + * Verify that deleting an non-existing group works. + */ + public function testDeleteGroupNotExists() + { + $groupId = 4200; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$groupId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1DeleteById', + ], + ]; + + $requestData = [CustomerGroup::ID => $groupId]; + $expectedMessage = NoSuchEntityException::MESSAGE_SINGLE_FIELD; + $expectedParameters = ['fieldName' => CustomerGroup::ID, 'fieldValue' => $groupId]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + } catch (\SoapFault $e) { + $this->assertContains($expectedMessage, $e->getMessage(), "SoapFault does not contain expected message."); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals($expectedMessage, $errorObj['message']); + $this->assertEquals($expectedParameters, $errorObj['parameters']); + } + } + + /** + * Verify that the group with the specified Id cannot be deleted because it is the default group and a proper + * fault is returned. + */ + public function testDeleteGroupCannotDelete() + { + $groupIdAssignedDefault = 1; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$groupIdAssignedDefault", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1DeleteById', + ], + ]; + + $requestData = [CustomerGroup::ID => $groupIdAssignedDefault]; + $expectedMessage = "Cannot delete group."; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + + $this->assertNotNull($this->groupRepository->getById($groupIdAssignedDefault)); + } + + /** + * Create a test group. + * + * @param CustomerGroup $group The group to create and save. + * @return int The group Id of the group that was created. + */ + private function createGroup($group) + { + $groupId = $this->groupRepository->save($group)->getId(); + $this->assertNotNull($groupId); + + $newGroup = $this->groupRepository->getById($groupId); + $this->assertEquals($groupId, $newGroup->getId(), 'The group id does not match.'); + $this->assertEquals($group->getCode(), $newGroup->getCode(), 'The group code does not match.'); + $this->assertEquals( + $group->getTaxClassId(), + $newGroup->getTaxClassId(), + 'The group tax class id does not match.' + ); + + $this->groupRegistry->remove($groupId); + + return $groupId; + } + + /** + * Data provider for testSearchGroups + */ + public function testSearchGroupsDataProvider() + { + return [ + ['tax_class_id', '3', []], + ['tax_class_id', '0', null], + ['code', md5(mt_rand(0, 10000000000) . time()), null], + [ + 'id', + '0', + [ + 'id' => '0', + 'code' => 'NOT LOGGED IN', + 'tax_class_id' => '3', + 'tax_class_name' => 'Retail Customer' + ] + ], + [ + 'code', + 'General', + [ + 'id' => '1', + 'code' => 'General', + 'tax_class_id' => '3', + 'tax_class_name' => 'Retail Customer' + ] + ], + [ + 'id', + '2', + [ + 'id' => '2', + 'code' => 'Wholesale', + 'tax_class_id' => '3', + 'tax_class_name' => 'Retail Customer' + ] + ], + [ + 'code', + 'Retailer', + [ + 'id' => '3', + 'code' => 'Retailer', + 'tax_class_id' => '3', + 'tax_class_name' => 'Retail Customer' + ] + ] + ]; + } + + /** + * Test search customer group + * + * @param string $filterField Customer Group field to filter by + * @param string $filterValue Value of the field to be filtered by + * @param array $expectedResult Expected search result + * + * @dataProvider testSearchGroupsDataProvider + */ + public function testSearchGroups($filterField, $filterValue, $expectedResult) + { + $filterBuilder = Bootstrap::getObjectManager()->create('Magento\Framework\Api\FilterBuilder'); + $searchCriteriaBuilder = Bootstrap::getObjectManager() + ->create('Magento\Framework\Api\SearchCriteriaBuilder'); + $filter = $filterBuilder + ->setField($filterField) + ->setValue($filterValue) + ->create(); + $searchCriteriaBuilder->addFilter([$filter]); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/search", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'customerGroupRepositoryV1GetList', + ], + ]; + + $searchData = $searchCriteriaBuilder->create()->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + + $searchResult = $this->_webApiCall($serviceInfo, $requestData); + + if (is_null($expectedResult)) { + $this->assertEquals(0, $searchResult['total_count']); + } elseif (is_array($expectedResult)) { + $this->assertGreaterThan(0, $searchResult['total_count']); + if (!empty($expectedResult)) { + $this->assertEquals($expectedResult, $searchResult['items'][0]); + } + } + } + + /** + * Test search customer group using GET + * + * @param string $filterField Customer Group field to filter by + * @param string $filterValue Value of the field to be filtered by + * @param array $expectedResult Expected search result + * + * @dataProvider testSearchGroupsDataProvider + */ + public function testSearchGroupsWithGET($filterField, $filterValue, $expectedResult) + { + $this->_markTestAsRestOnly('SOAP is covered in '); + $filterBuilder = Bootstrap::getObjectManager()->create('Magento\Framework\Api\FilterBuilder'); + $searchCriteriaBuilder = Bootstrap::getObjectManager() + ->create('Magento\Framework\Api\SearchCriteriaBuilder'); + $filter = $filterBuilder + ->setField($filterField) + ->setValue($filterValue) + ->create(); + $searchCriteriaBuilder->addFilter([$filter]); + $searchData = $searchCriteriaBuilder->create()->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchQueryString = http_build_query($requestData); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search?' . $searchQueryString, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + ]; + $searchResult = $this->_webApiCall($serviceInfo); + + if (is_null($expectedResult)) { + $this->assertEquals(0, $searchResult['total_count']); + } elseif (is_array($expectedResult)) { + $this->assertGreaterThan(0, $searchResult['total_count']); + if (!empty($expectedResult)) { + $this->assertEquals($expectedResult, $searchResult['items'][0]); + } + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..4bade51570029bb3a5755c18db7e84ca553961d7 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/ReadServiceTest.php @@ -0,0 +1,155 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Downloadable\Service\V1\DownloadableLink; + +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ReadServiceTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + /** + * @dataProvider getListForAbsentProductProvider() + */ + public function testGetListForAbsentProduct($urlTail, $method) + { + $sku = 'absent-product' . time(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $sku . $urlTail, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'downloadableDownloadableLinkReadServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'downloadableDownloadableLinkReadServiceV1' . $method, + ], + ]; + + $requestData = ['productSku' => $sku]; + + $expectedMessage = 'Requested product doesn\'t exist'; + try { + $this->_webApiCall($serviceInfo, $requestData); + } catch (\SoapFault $e) { + $this->assertEquals($expectedMessage, $e->getMessage()); + } catch (\Exception $e) { + $this->assertContains($expectedMessage, $e->getMessage()); + } + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @dataProvider getListForAbsentProductProvider + */ + public function testGetListForSimpleProduct($urlTail, $method) + { + $sku = 'simple'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $sku . $urlTail, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'downloadableDownloadableLinkReadServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'downloadableDownloadableLinkReadServiceV1' . $method, + ], + ]; + + $requestData = ['productSku' => $sku]; + + $list = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEmpty($list); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php + * @dataProvider getListForAbsentProductProvider + */ + public function testGetList($urlTail, $method, $expectations) + { + $sku = 'downloadable-product'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $sku . $urlTail, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'downloadableDownloadableLinkReadServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'downloadableDownloadableLinkReadServiceV1' . $method, + ], + ]; + + $requestData = ['productSku' => $sku]; + + $list = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertEquals(1, count($list)); + + $link = reset($list); + foreach ($expectations['fields'] as $index => $value) { + $this->assertEquals($value, $link[$index]); + } + + foreach ($expectations['resources'] as $name => $fields) { + $this->assertNotEmpty($link[$name]); + $this->assertEquals($fields['file'], $link[$name]['file']); + $this->assertEquals($fields['type'], $link[$name]['type']); + } + } + + public function getListForAbsentProductProvider() + { + $sampleIndex = 'sample_resource'; + $linkIndex = 'link_resource'; + + $linkExpectation = [ + 'fields' => [ + 'shareable' => 2, + 'price' => 15, + 'number_of_downloads' => 15, + ], + 'resources' => [ + $sampleIndex => [ + 'file' => '/n/d/jellyfish_1_3.jpg', + 'type' => 'file', + ], + $linkIndex => [ + 'file' => '/j/e/jellyfish_2_4.jpg', + 'type' => 'file', + ], + ], + ]; + + $sampleExpectation = [ + 'fields' => [ + 'title' => 'Downloadable Product Sample Title', + 'sort_order' => 0, + ], + 'resources' => [ + $sampleIndex => [ + 'file' => '/f/u/jellyfish_1_4.jpg', + 'type' => 'file', + ], + ], + ]; + + return [ + 'links' => [ + '/downloadable-links', + 'GetLinks', + $linkExpectation, + ], + 'samples' => [ + '/downloadable-links/samples', + 'GetSamples', + $sampleExpectation, + ], + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6f96f1951755853aa409493058a9164cc0b68601 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/WriteServiceTest.php @@ -0,0 +1,796 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Downloadable\Service\V1\DownloadableLink; + +use Magento\Catalog\Model\Product; +use Magento\Downloadable\Model\Link; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class WriteServiceTest extends WebapiAbstract +{ + /** + + * @var array + */ + protected $createServiceInfo; + + /** + * @var array + */ + protected $updateServiceInfo; + + /** + * @var array + */ + protected $deleteServiceInfo; + + /** + * @var string + */ + protected $testImagePath; + + protected function setUp() + { + $this->createServiceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/downloadable-product/downloadable-links', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => 'downloadableDownloadableLinkWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'downloadableDownloadableLinkWriteServiceV1Create', + ], + ]; + + $this->updateServiceInfo = [ + 'rest' => [ + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'downloadableDownloadableLinkWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'downloadableDownloadableLinkWriteServiceV1Update', + ], + ]; + + $this->deleteServiceInfo = [ + 'rest' => [ + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => 'downloadableDownloadableLinkWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'downloadableDownloadableLinkWriteServiceV1Delete', + ], + ]; + + $this->testImagePath = __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'test_image.jpg'; + } + + /** + * Retrieve product that was updated by test + * + * @param bool $isScopeGlobal if true product store ID will be set to 0 + * @return Product + */ + protected function getTargetProduct($isScopeGlobal = false) + { + $objectManager = Bootstrap::getObjectManager(); + $product = $objectManager->get('Magento\Catalog\Model\ProductFactory')->create()->load(1); + if ($isScopeGlobal) { + $product->setStoreId(0); + } + return $product; + } + + /** + * Retrieve product link by its ID (or first link if ID is not specified) + * + * @param Product $product + * @param int|null $linkId + * @return Link|null + */ + protected function getTargetLink(Product $product, $linkId = null) + { + $links = $product->getTypeInstance()->getLinks($product); + if (!is_null($linkId)) { + return isset($links[$linkId]) ? $links[$linkId] : null; + } + // return first link + return reset($links); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + */ + public function testCreateUploadsProvidedFileContent() + { + $requestData = [ + 'isGlobalScopeContent' => true, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Title', + 'sort_order' => 1, + 'price' => 10.1, + 'shareable' => true, + 'number_of_downloads' => 100, + 'link_type' => 'file', + 'link_file' => [ + 'data' => base64_encode(file_get_contents($this->testImagePath)), + 'name' => 'image.jpg', + ], + 'sample_file' => [ + 'data' => base64_encode(file_get_contents($this->testImagePath)), + 'name' => 'image.jpg', + ], + 'sample_type' => 'file', + ], + ]; + + $newLinkId = $this->_webApiCall($this->createServiceInfo, $requestData); + $globalScopeLink = $this->getTargetLink($this->getTargetProduct(true), $newLinkId); + $link = $this->getTargetLink($this->getTargetProduct(), $newLinkId); + $this->assertNotNull($link); + $this->assertEquals($requestData['linkContent']['title'], $link->getTitle()); + $this->assertEquals($requestData['linkContent']['title'], $globalScopeLink->getTitle()); + $this->assertEquals($requestData['linkContent']['sort_order'], $link->getSortOrder()); + $this->assertEquals($requestData['linkContent']['price'], $link->getPrice()); + $this->assertEquals($requestData['linkContent']['price'], $globalScopeLink->getPrice()); + $this->assertEquals($requestData['linkContent']['shareable'], $link->getIsShareable()); + $this->assertEquals($requestData['linkContent']['number_of_downloads'], $link->getNumberOfDownloads()); + $this->assertEquals($requestData['linkContent']['link_type'], $link->getLinkType()); + $this->assertEquals($requestData['linkContent']['sample_type'], $link->getSampleType()); + $this->assertStringEndsWith('.jpg', $link->getSampleFile()); + $this->assertStringEndsWith('.jpg', $link->getLinkFile()); + $this->assertNull($link->getLinkUrl()); + $this->assertNull($link->getSampleUrl()); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + */ + public function testCreateSavesPriceAndTitleInStoreViewScope() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Store View Title', + 'sort_order' => 1, + 'price' => 150, + 'shareable' => true, + 'number_of_downloads' => 100, + 'link_url' => 'http://www.example.com/', + 'link_type' => 'url', + 'sample_url' => 'http://www.sample.example.com/', + 'sample_type' => 'url', + ], + ]; + + $newLinkId = $this->_webApiCall($this->createServiceInfo, $requestData); + $link = $this->getTargetLink($this->getTargetProduct(), $newLinkId); + $globalScopeLink = $this->getTargetLink($this->getTargetProduct(true), $newLinkId); + $this->assertNotNull($link); + $this->assertEquals($requestData['linkContent']['title'], $link->getTitle()); + $this->assertEquals($requestData['linkContent']['sort_order'], $link->getSortOrder()); + $this->assertEquals($requestData['linkContent']['price'], $link->getPrice()); + $this->assertEquals($requestData['linkContent']['shareable'], $link->getIsShareable()); + $this->assertEquals($requestData['linkContent']['number_of_downloads'], $link->getNumberOfDownloads()); + $this->assertEquals($requestData['linkContent']['link_url'], $link->getLinkUrl()); + $this->assertEquals($requestData['linkContent']['link_type'], $link->getLinkType()); + $this->assertEquals($requestData['linkContent']['sample_url'], $link->getSampleUrl()); + $this->assertEquals($requestData['linkContent']['sample_type'], $link->getSampleType()); + $this->assertEmpty($globalScopeLink->getTitle()); + $this->assertEmpty($globalScopeLink->getPrice()); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + */ + public function testCreateSavesProvidedUrls() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Link with URL resources', + 'sort_order' => 1, + 'price' => 10.1, + 'shareable' => true, + 'number_of_downloads' => 100, + 'link_url' => 'http://www.example.com/', + 'link_type' => 'url', + 'sample_url' => 'http://www.sample.example.com/', + 'sample_type' => 'url', + ], + ]; + + $newLinkId = $this->_webApiCall($this->createServiceInfo, $requestData); + $link = $this->getTargetLink($this->getTargetProduct(), $newLinkId); + $this->assertNotNull($link); + $this->assertEquals($requestData['linkContent']['title'], $link->getTitle()); + $this->assertEquals($requestData['linkContent']['sort_order'], $link->getSortOrder()); + $this->assertEquals($requestData['linkContent']['price'], $link->getPrice()); + $this->assertEquals($requestData['linkContent']['shareable'], $link->getIsShareable()); + $this->assertEquals($requestData['linkContent']['number_of_downloads'], $link->getNumberOfDownloads()); + $this->assertEquals($requestData['linkContent']['link_url'], $link->getLinkUrl()); + $this->assertEquals($requestData['linkContent']['link_type'], $link->getLinkType()); + $this->assertEquals($requestData['linkContent']['sample_type'], $link->getSampleType()); + $this->assertEquals($requestData['linkContent']['sample_url'], $link->getSampleUrl()); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Invalid link type. + */ + public function testCreateThrowsExceptionIfLinkTypeIsNotSpecified() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Link with URL resources', + 'sort_order' => 1, + 'price' => 10.1, + 'shareable' => true, + 'number_of_downloads' => 100, + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Provided content must be valid base64 encoded data. + */ + public function testCreateThrowsExceptionIfLinkFileContentIsNotAValidBase64EncodedString() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Link Title', + 'sort_order' => 1, + 'price' => 10, + 'shareable' => true, + 'number_of_downloads' => 100, + 'link_type' => 'url', + 'link_url' => 'http://www.example.com/', + 'sample_type' => 'file', + 'sample_file' => [ + 'data' => 'not_a_base64_encoded_content', + 'name' => 'image.jpg', + ], + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Provided content must be valid base64 encoded data. + */ + public function testCreateThrowsExceptionIfSampleFileContentIsNotAValidBase64EncodedString() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Link Title', + 'sort_order' => 1, + 'price' => 10, + 'shareable' => true, + 'number_of_downloads' => 100, + 'link_type' => 'file', + 'link_file' => [ + 'data' => 'not_a_base64_encoded_content', + 'name' => 'image.jpg', + ], + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Provided file name contains forbidden characters. + */ + public function testCreateThrowsExceptionIfLinkFileNameContainsForbiddenCharacters() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Title', + 'sort_order' => 15, + 'price' => 10, + 'shareable' => true, + 'number_of_downloads' => 100, + 'link_type' => 'file', + 'link_file' => [ + 'data' => base64_encode(file_get_contents($this->testImagePath)), + 'name' => 'name/with|forbidden{characters', + ], + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Provided file name contains forbidden characters. + */ + public function testCreateThrowsExceptionIfSampleFileNameContainsForbiddenCharacters() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Link Title', + 'sort_order' => 1, + 'price' => 10, + 'shareable' => true, + 'number_of_downloads' => 100, + 'link_type' => 'url', + 'link_url' => 'http://www.example.com/', + 'sample_type' => 'file', + 'sample_file' => [ + 'data' => base64_encode(file_get_contents($this->testImagePath)), + 'name' => 'name/with|forbidden{characters', + ], + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Link URL must have valid format. + */ + public function testCreateThrowsExceptionIfLinkUrlHasWrongFormat() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Link Title', + 'sort_order' => 1, + 'price' => 10, + 'shareable' => true, + 'number_of_downloads' => 100, + 'link_type' => 'url', + 'link_url' => 'http://example<.>com/', + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Sample URL must have valid format. + */ + public function testCreateThrowsExceptionIfSampleUrlHasWrongFormat() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Link Title', + 'sort_order' => 1, + 'price' => 150, + 'shareable' => true, + 'number_of_downloads' => 0, + 'sample_type' => 'url', + 'sample_url' => 'http://example<.>com/', + 'link_type' => 'url', + 'link_url' => 'http://example.com/', + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Link price must have numeric positive value. + * @dataProvider getInvalidLinkPrice + */ + public function testCreateThrowsExceptionIfLinkPriceIsInvalid($linkPrice) + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Link Title', + 'sort_order' => 1, + 'price' => $linkPrice, + 'shareable' => true, + 'number_of_downloads' => 0, + 'sample_type' => 'url', + 'sample_url' => 'http://example.com/', + 'link_type' => 'url', + 'link_url' => 'http://example.com/', + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @return array + */ + public function getInvalidLinkPrice() + { + return [ + ['string_value'], + [-1.5], + ]; + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Sort order must be a positive integer. + * @dataProvider getInvalidSortOrder + */ + public function testCreateThrowsExceptionIfSortOrderIsInvalid($sortOrder) + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Link Title', + 'sort_order' => $sortOrder, + 'price' => 10, + 'shareable' => false, + 'number_of_downloads' => 0, + 'sample_type' => 'url', + 'sample_url' => 'http://example.com/', + 'link_type' => 'url', + 'link_url' => 'http://example.com/', + ], + ]; + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @return array + */ + public function getInvalidSortOrder() + { + return [ + [-1], + ]; + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Number of downloads must be a positive integer. + * @dataProvider getInvalidNumberOfDownloads + */ + public function testCreateThrowsExceptionIfNumberOfDownloadsIsInvalid($numberOfDownloads) + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Link Title', + 'sort_order' => 0, + 'price' => 10, + 'shareable' => false, + 'number_of_downloads' => $numberOfDownloads, + 'sample_type' => 'url', + 'sample_url' => 'http://example.com/', + 'link_type' => 'url', + 'link_url' => 'http://example.com/', + ], + ]; + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @return array + */ + public function getInvalidNumberOfDownloads() + { + return [ + [-1], + ]; + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @expectedException \Exception + * @expectedExceptionMessage Product type of the product must be 'downloadable'. + */ + public function testCreateThrowsExceptionIfTargetProductTypeIsNotDownloadable() + { + $this->createServiceInfo['rest']['resourcePath'] = '/V1/products/simple/downloadable-links'; + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'simple', + 'linkContent' => [ + 'title' => 'Link Title', + 'sort_order' => 50, + 'price' => 200, + 'shareable' => false, + 'number_of_downloads' => 10, + 'sample_type' => 'url', + 'sample_url' => 'http://example.com/', + 'link_type' => 'url', + 'link_url' => 'http://example.com/', + ], + ]; + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Requested product doesn't exist + */ + public function testCreateThrowsExceptionIfTargetProductDoesNotExist() + { + $this->createServiceInfo['rest']['resourcePath'] = '/V1/products/wrong-sku/downloadable-links'; + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'wrong-sku', + 'linkContent' => [ + 'title' => 'Link Title', + 'sort_order' => 15, + 'price' => 200, + 'shareable' => true, + 'number_of_downloads' => 100, + 'sample_type' => 'url', + 'sample_url' => 'http://example.com/', + 'link_type' => 'url', + 'link_url' => 'http://example.com/', + ], + ]; + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + */ + public function testUpdate() + { + $linkId = $this->getTargetLink($this->getTargetProduct())->getId(); + $this->updateServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-product/downloadable-links/{$linkId}"; + $requestData = [ + 'isGlobalScopeContent' => false, + 'linkId' => $linkId, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Updated Title', + 'sort_order' => 2, + 'price' => 100.10, + 'shareable' => false, + 'number_of_downloads' => 50, + ], + ]; + + $this->assertTrue($this->_webApiCall($this->updateServiceInfo, $requestData)); + $link = $this->getTargetLink($this->getTargetProduct(), $linkId); + $this->assertNotNull($link); + $this->assertEquals($requestData['linkContent']['title'], $link->getTitle()); + $this->assertEquals($requestData['linkContent']['sort_order'], $link->getSortOrder()); + $this->assertEquals($requestData['linkContent']['price'], $link->getPrice()); + $this->assertEquals($requestData['linkContent']['shareable'], (bool)$link->getIsShareable()); + $this->assertEquals($requestData['linkContent']['number_of_downloads'], $link->getNumberOfDownloads()); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + */ + public function testUpdateSavesDataInGlobalScopeAndDoesNotAffectValuesStoredInStoreViewScope() + { + $originalLink = $this->getTargetLink($this->getTargetProduct()); + $linkId = $originalLink->getId(); + $this->updateServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-product/downloadable-links/{$linkId}"; + $requestData = [ + 'isGlobalScopeContent' => true, + 'linkId' => $linkId, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Updated Title', + 'sort_order' => 2, + 'price' => 100.10, + 'shareable' => false, + 'number_of_downloads' => 50, + ], + ]; + + $this->assertTrue($this->_webApiCall($this->updateServiceInfo, $requestData)); + $link = $this->getTargetLink($this->getTargetProduct(), $linkId); + $globalScopeLink = $this->getTargetLink($this->getTargetProduct(true), $linkId); + $this->assertNotNull($link); + // Title and price were set on store view level in fixture so they must be the same + $this->assertEquals($originalLink->getTitle(), $link->getTitle()); + $this->assertEquals($originalLink->getPrice(), $link->getPrice()); + $this->assertEquals($requestData['linkContent']['title'], $globalScopeLink->getTitle()); + $this->assertEquals($requestData['linkContent']['price'], $globalScopeLink->getPrice()); + $this->assertEquals($requestData['linkContent']['sort_order'], $link->getSortOrder()); + $this->assertEquals($requestData['linkContent']['shareable'], (bool)$link->getIsShareable()); + $this->assertEquals($requestData['linkContent']['number_of_downloads'], $link->getNumberOfDownloads()); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Requested product doesn't exist + */ + public function testUpdateThrowsExceptionIfTargetProductDoesNotExist() + { + $this->updateServiceInfo['rest']['resourcePath'] = '/V1/products/wrong-sku/downloadable-links/1'; + $requestData = [ + 'isGlobalScopeContent' => true, + 'linkId' => 1, + 'productSku' => 'wrong-sku', + 'linkContent' => [ + 'title' => 'Updated Title', + 'sort_order' => 2, + 'price' => 100.10, + 'shareable' => false, + 'number_of_downloads' => 50, + ], + ]; + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage There is no downloadable link with provided ID. + */ + public function testUpdateThrowsExceptionIfThereIsNoDownloadableLinkWithGivenId() + { + $linkId = 9999; + $this->updateServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-product/downloadable-links/{$linkId}"; + $requestData = [ + 'isGlobalScopeContent' => true, + 'linkId' => 9999, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Title', + 'sort_order' => 2, + 'price' => 100.10, + 'shareable' => false, + 'number_of_downloads' => 50, + ], + ]; + + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Link price must have numeric positive value. + * @dataProvider getInvalidLinkPrice + */ + public function testUpdateThrowsExceptionIfLinkPriceIsInvalid($linkPrice) + { + $linkId = $this->getTargetLink($this->getTargetProduct())->getId(); + $this->updateServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-product/downloadable-links/{$linkId}"; + $requestData = [ + 'isGlobalScopeContent' => false, + 'linkId' => $linkId, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Updated Link Title', + 'sort_order' => 2, + 'price' => $linkPrice, + 'shareable' => false, + 'number_of_downloads' => 50, + ], + ]; + + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Sort order must be a positive integer. + * @dataProvider getInvalidSortOrder + */ + public function testUpdateThrowsExceptionIfSortOrderIsInvalid($sortOrder) + { + $linkId = $this->getTargetLink($this->getTargetProduct())->getId(); + $this->updateServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-product/downloadable-links/{$linkId}"; + $requestData = [ + 'isGlobalScopeContent' => false, + 'linkId' => $linkId, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Updated Link Title', + 'sort_order' => $sortOrder, + 'price' => 100.50, + 'shareable' => false, + 'number_of_downloads' => 50, + ], + ]; + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Number of downloads must be a positive integer. + * @dataProvider getInvalidNumberOfDownloads + */ + public function testUpdateThrowsExceptionIfNumberOfDownloadsIsInvalid($numberOfDownloads) + { + $linkId = $this->getTargetLink($this->getTargetProduct())->getId(); + $this->updateServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-product/downloadable-links/{$linkId}"; + $requestData = [ + 'isGlobalScopeContent' => false, + 'linkId' => $linkId, + 'productSku' => 'downloadable-product', + 'linkContent' => [ + 'title' => 'Updated Link Title', + 'sort_order' => 200, + 'price' => 100.50, + 'shareable' => false, + 'number_of_downloads' => $numberOfDownloads, + ], + ]; + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + */ + public function testDelete() + { + $linkId = $this->getTargetLink($this->getTargetProduct())->getId(); + $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/{$linkId}"; + $requestData = [ + 'linkId' => $linkId, + ]; + + $this->assertTrue($this->_webApiCall($this->deleteServiceInfo, $requestData)); + $link = $this->getTargetLink($this->getTargetProduct(), $linkId); + $this->assertNull($link); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage There is no downloadable link with provided ID. + */ + public function testDeleteThrowsExceptionIfThereIsNoDownloadableLinkWithGivenId() + { + $linkId = 9999; + $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/{$linkId}"; + $requestData = [ + 'linkId' => $linkId, + ]; + + $this->_webApiCall($this->deleteServiceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/_files/test_image.jpg b/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/_files/test_image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad6b747f73dd9d20f73b8fc780e74d1ff7952762 Binary files /dev/null and b/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableLink/_files/test_image.jpg differ diff --git a/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..542e1527f8eb58111d8768c4d16708827a6374f1 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Downloadable/Service/V1/DownloadableSample/WriteServiceTest.php @@ -0,0 +1,509 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Downloadable\Service\V1\DownloadableSample; + +use Magento\Catalog\Model\Product; +use Magento\Downloadable\Model\Sample; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class WriteServiceTest extends WebapiAbstract +{ + /** + * @var array + */ + protected $createServiceInfo; + + /** + * @var string + */ + protected $testImagePath; + + /** + * @var array + */ + protected $updateServiceInfo; + + /** + * @var array + */ + protected $deleteServiceInfo; + + protected function setUp() + { + $this->createServiceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/downloadable-product/downloadable-links/samples', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => 'downloadableDownloadableSampleWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'downloadableDownloadableSampleWriteServiceV1Create', + ], + ]; + + $this->updateServiceInfo = [ + 'rest' => [ + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'downloadableDownloadableSampleWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'downloadableDownloadableSampleWriteServiceV1Update', + ], + ]; + + $this->deleteServiceInfo = [ + 'rest' => [ + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => 'downloadableDownloadableSampleWriteServiceV1', + 'serviceVersion' => 'V1', + 'operation' => 'downloadableDownloadableSampleWriteServiceV1Delete', + ], + ]; + + $this->testImagePath = __DIR__ + . str_replace('/', DIRECTORY_SEPARATOR, '/../DownloadableLink/_files/test_image.jpg'); + } + + /** + * Retrieve product that was updated by test + * + * @param bool $isScopeGlobal if true product store ID will be set to 0 + * @return Product + */ + protected function getTargetProduct($isScopeGlobal = false) + { + $product = Bootstrap::getObjectManager()->get('Magento\Catalog\Model\ProductFactory')->create()->load(1); + if ($isScopeGlobal) { + $product->setStoreId(0); + } + return $product; + } + + /** + * Retrieve product sample by its ID (or first sample if ID is not specified) + * + * @param Product $product + * @param int|null $sampleId + * @return Sample|null + */ + protected function getTargetSample(Product $product, $sampleId = null) + { + /** @var $samples \Magento\Downloadable\Model\Resource\Sample\Collection */ + $samples = $product->getTypeInstance()->getSamples($product); + if (!is_null($sampleId)) { + /* @var $sample \Magento\Downloadable\Model\Sample */ + foreach ($samples as $sample) { + if ($sample->getId() == $sampleId) { + return $sample; + } + } + return null; + } + // return first sample + return $samples->getFirstItem(); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + */ + public function testCreateUploadsProvidedFileContent() + { + $requestData = [ + 'isGlobalScopeContent' => true, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Title', + 'sort_order' => 1, + 'sample_file' => [ + 'data' => base64_encode(file_get_contents($this->testImagePath)), + 'name' => 'image.jpg', + ], + 'sample_type' => 'file', + ], + ]; + + $newSampleId = $this->_webApiCall($this->createServiceInfo, $requestData); + $globalScopeSample = $this->getTargetSample($this->getTargetProduct(true), $newSampleId); + $sample = $this->getTargetSample($this->getTargetProduct(), $newSampleId); + $this->assertNotNull($sample); + $this->assertEquals($requestData['sampleContent']['title'], $sample->getTitle()); + $this->assertEquals($requestData['sampleContent']['title'], $globalScopeSample->getTitle()); + $this->assertEquals($requestData['sampleContent']['sort_order'], $sample->getSortOrder()); + $this->assertEquals($requestData['sampleContent']['sample_type'], $sample->getSampleType()); + $this->assertStringEndsWith('.jpg', $sample->getSampleFile()); + $this->assertNull($sample->getSampleUrl()); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + */ + public function testCreateSavesTitleInStoreViewScope() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Store View Title', + 'sort_order' => 1, + 'sample_url' => 'http://www.sample.example.com/', + 'sample_type' => 'url', + ], + ]; + + $newSampleId = $this->_webApiCall($this->createServiceInfo, $requestData); + $sample = $this->getTargetSample($this->getTargetProduct(), $newSampleId); + $globalScopeSample = $this->getTargetSample($this->getTargetProduct(true), $newSampleId); + $this->assertNotNull($sample); + $this->assertEquals($requestData['sampleContent']['title'], $sample->getTitle()); + $this->assertEquals($requestData['sampleContent']['sort_order'], $sample->getSortOrder()); + $this->assertEquals($requestData['sampleContent']['sample_url'], $sample->getSampleUrl()); + $this->assertEquals($requestData['sampleContent']['sample_type'], $sample->getSampleType()); + $this->assertEmpty($globalScopeSample->getTitle()); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + */ + public function testCreateSavesProvidedUrls() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Sample with URL resource', + 'sort_order' => 1, + 'sample_url' => 'http://www.sample.example.com/', + 'sample_type' => 'url', + ], + ]; + + $newSampleId = $this->_webApiCall($this->createServiceInfo, $requestData); + $sample = $this->getTargetSample($this->getTargetProduct(), $newSampleId); + $this->assertNotNull($sample); + $this->assertEquals($requestData['sampleContent']['title'], $sample->getTitle()); + $this->assertEquals($requestData['sampleContent']['sort_order'], $sample->getSortOrder()); + $this->assertEquals($requestData['sampleContent']['sample_type'], $sample->getSampleType()); + $this->assertEquals($requestData['sampleContent']['sample_url'], $sample->getSampleUrl()); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Invalid sample type. + */ + public function testCreateThrowsExceptionIfSampleTypeIsNotSpecified() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Sample with URL resource', + 'sort_order' => 1, + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Provided content must be valid base64 encoded data. + */ + public function testCreateThrowsExceptionIfSampleFileContentIsNotAValidBase64EncodedString() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Sample Title', + 'sort_order' => 1, + 'sample_type' => 'file', + 'sample_file' => [ + 'data' => 'not_a_base64_encoded_content', + 'name' => 'image.jpg', + ], + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Provided file name contains forbidden characters. + */ + public function testCreateThrowsExceptionIfSampleFileNameContainsForbiddenCharacters() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Title', + 'sort_order' => 15, + 'sample_type' => 'file', + 'sample_file' => [ + 'data' => base64_encode(file_get_contents($this->testImagePath)), + 'name' => 'name/with|forbidden{characters', + ], + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Sample URL must have valid format. + */ + public function testCreateThrowsExceptionIfSampleUrlHasWrongFormat() + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Sample Title', + 'sort_order' => 1, + 'sample_type' => 'url', + 'sample_url' => 'http://example<.>com/', + ], + ]; + + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable.php + * @expectedException \Exception + * @expectedExceptionMessage Sort order must be a positive integer. + * @dataProvider getInvalidSortOrder + */ + public function testCreateThrowsExceptionIfSortOrderIsInvalid($sortOrder) + { + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Sample Title', + 'sort_order' => $sortOrder, + 'sample_type' => 'url', + 'sample_url' => 'http://example.com/', + ], + ]; + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @return array + */ + public function getInvalidSortOrder() + { + return [ + [-1], + ]; + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @expectedException \Exception + * @expectedExceptionMessage Product type of the product must be 'downloadable'. + */ + public function testCreateThrowsExceptionIfTargetProductTypeIsNotDownloadable() + { + $this->createServiceInfo['rest']['resourcePath'] + = '/V1/products/simple/downloadable-links/samples'; + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'simple', + 'sampleContent' => [ + 'title' => 'Sample Title', + 'sort_order' => 50, + 'sample_type' => 'url', + 'sample_url' => 'http://example.com/', + ], + ]; + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Requested product doesn't exist + */ + public function testCreateThrowsExceptionIfTargetProductDoesNotExist() + { + $this->createServiceInfo['rest']['resourcePath'] + = '/V1/products/wrong-sku/downloadable-links/samples'; + $requestData = [ + 'isGlobalScopeContent' => false, + 'productSku' => 'wrong-sku', + 'sampleContent' => [ + 'title' => 'Title', + 'sort_order' => 15, + 'sample_type' => 'url', + 'sample_url' => 'http://example.com/', + ], + ]; + $this->_webApiCall($this->createServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php + */ + public function testUpdate() + { + $sampleId = $this->getTargetSample($this->getTargetProduct())->getId(); + $this->updateServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}"; + $requestData = [ + 'isGlobalScopeContent' => false, + 'sampleId' => $sampleId, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Updated Title', + 'sort_order' => 2, + ], + ]; + + $this->assertTrue($this->_webApiCall($this->updateServiceInfo, $requestData)); + $sample = $this->getTargetSample($this->getTargetProduct(), $sampleId); + $this->assertNotNull($sample); + $this->assertEquals($requestData['sampleContent']['title'], $sample->getTitle()); + $this->assertEquals($requestData['sampleContent']['sort_order'], $sample->getSortOrder()); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php + */ + public function testUpdateSavesDataInGlobalScopeAndDoesNotAffectValuesStoredInStoreViewScope() + { + $originalSample = $this->getTargetSample($this->getTargetProduct()); + $sampleId = $originalSample->getId(); + $this->updateServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}"; + $requestData = [ + 'isGlobalScopeContent' => true, + 'sampleId' => $sampleId, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Updated Title', + 'sort_order' => 2, + ], + ]; + + $this->assertTrue($this->_webApiCall($this->updateServiceInfo, $requestData)); + $sample = $this->getTargetSample($this->getTargetProduct(), $sampleId); + $globalScopeSample = $this->getTargetSample($this->getTargetProduct(true), $sampleId); + $this->assertNotNull($sample); + // Title was set on store view level in fixture so it must be the same + $this->assertEquals($originalSample->getTitle(), $sample->getTitle()); + $this->assertEquals($requestData['sampleContent']['title'], $globalScopeSample->getTitle()); + $this->assertEquals($requestData['sampleContent']['sort_order'], $sample->getSortOrder()); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Requested product doesn't exist + */ + public function testUpdateThrowsExceptionIfTargetProductDoesNotExist() + { + $this->updateServiceInfo['rest']['resourcePath'] = '/V1/products/wrong-sku/downloadable-links/samples/1'; + $requestData = [ + 'isGlobalScopeContent' => true, + 'sampleId' => 1, + 'productSku' => 'wrong-sku', + 'sampleContent' => [ + 'title' => 'Updated Title', + 'sort_order' => 2, + ], + ]; + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php + * @expectedException \Exception + * @expectedExceptionMessage There is no downloadable sample with provided ID. + */ + public function testUpdateThrowsExceptionIfThereIsNoDownloadableSampleWithGivenId() + { + $sampleId = 9999; + $this->updateServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}"; + $requestData = [ + 'isGlobalScopeContent' => true, + 'sampleId' => 9999, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Title', + 'sort_order' => 2, + ], + ]; + + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php + * @expectedException \Exception + * @expectedExceptionMessage Sort order must be a positive integer. + * @dataProvider getInvalidSortOrder + */ + public function testUpdateThrowsExceptionIfSortOrderIsInvalid($sortOrder) + { + $sampleId = $this->getTargetSample($this->getTargetProduct())->getId(); + $this->updateServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}"; + $requestData = [ + 'isGlobalScopeContent' => false, + 'sampleId' => $sampleId, + 'productSku' => 'downloadable-product', + 'sampleContent' => [ + 'title' => 'Updated Sample Title', + 'sort_order' => $sortOrder, + ], + ]; + $this->_webApiCall($this->updateServiceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Downloadable/_files/product_downloadable_with_files.php + */ + public function testDelete() + { + $sampleId = $this->getTargetSample($this->getTargetProduct())->getId(); + $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/samples/{$sampleId}"; + $requestData = [ + 'sampleId' => $sampleId, + ]; + + $this->assertTrue($this->_webApiCall($this->deleteServiceInfo, $requestData)); + $sample = $this->getTargetSample($this->getTargetProduct(), $sampleId); + $this->assertNull($sample); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage There is no downloadable sample with provided ID. + */ + public function testDeleteThrowsExceptionIfThereIsNoDownloadableSampleWithGivenId() + { + $sampleId = 9999; + $this->deleteServiceInfo['rest']['resourcePath'] + = "/V1/products/downloadable-links/samples/{$sampleId}"; + $requestData = [ + 'sampleId' => $sampleId, + ]; + + $this->_webApiCall($this->deleteServiceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Eav/Api/AttributeSetManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Eav/Api/AttributeSetManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..83166269a7c332013e98eb9bbaf6f122fd3dd07d --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Eav/Api/AttributeSetManagementTest.php @@ -0,0 +1,235 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Eav\Api; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Exception as HTTPExceptionCodes; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class AttributeSetManagementTest extends WebapiAbstract +{ + /** + * @var array + */ + private $createServiceInfo; + + protected function setUp() + { + $this->createServiceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/eav/attribute-sets', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => 'eavAttributeSetManagementV1', + 'serviceVersion' => 'V1', + 'operation' => 'eavAttributeSetManagementV1Create', + ], + ]; + } + + public function testCreate() + { + $entityTypeCode = 'catalog_product'; + $entityType = $this->getEntityTypeByCode($entityTypeCode); + $attributeSetName = 'new_attribute_set'; + + $arguments = [ + 'entityTypeCode' => $entityTypeCode, + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 500, + ], + 'skeletonId' => $entityType->getDefaultAttributeSetId(), + ]; + $result = $this->_webApiCall($this->createServiceInfo, $arguments); + $this->assertNotNull($result); + $attributeSet = $this->getAttributeSetByName($attributeSetName); + $this->assertNotNull($attributeSet); + $this->assertEquals($attributeSet->getId(), $result['attribute_set_id']); + $this->assertEquals($attributeSet->getAttributeSetName(), $result['attribute_set_name']); + $this->assertEquals($attributeSet->getEntityTypeId(), $result['entity_type_id']); + $this->assertEquals($attributeSet->getEntityTypeId(), $entityType->getId()); + $this->assertEquals($attributeSet->getSortOrder(), $result['sort_order']); + $this->assertEquals($attributeSet->getSortOrder(), 500); + + // Clean up database + $attributeSet->delete(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Invalid value + */ + public function testCreateThrowsExceptionIfGivenAttributeSetAlreadyHasId() + { + $entityTypeCode = 'catalog_product'; + $entityType = $this->getEntityTypeByCode($entityTypeCode); + $attributeSetName = 'new_attribute_set'; + + $arguments = [ + 'entityTypeCode' => $entityTypeCode, + 'attributeSet' => [ + 'attribute_set_id' => 1, + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 100, + ], + 'skeletonId' => $entityType->getDefaultAttributeSetId(), + ]; + $this->_webApiCall($this->createServiceInfo, $arguments); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Invalid value + */ + public function testCreateThrowsExceptionIfGivenSkeletonIdIsInvalid() + { + $entityTypeCode = 'catalog_product'; + $attributeSetName = 'new_attribute_set'; + + $arguments = [ + 'entityTypeCode' => $entityTypeCode, + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 200, + ], + 'skeletonId' => 0, + ]; + $this->_webApiCall($this->createServiceInfo, $arguments); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage No such entity + */ + public function testCreateThrowsExceptionIfGivenSkeletonAttributeSetDoesNotExist() + { + $attributeSetName = 'new_attribute_set'; + $entityTypeCode = 'catalog_product'; + + $arguments = [ + 'entityTypeCode' => $entityTypeCode, + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 300, + ], + 'skeletonId' => 9999, + ]; + $this->_webApiCall($this->createServiceInfo, $arguments); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Invalid entity_type specified: invalid_entity_type + */ + public function testCreateThrowsExceptionIfGivenEntityTypeDoesNotExist() + { + $entityTypeCode = 'catalog_product'; + $entityType = $this->getEntityTypeByCode($entityTypeCode); + $attributeSetName = 'new_attribute_set'; + + $arguments = [ + 'entityTypeCode' => 'invalid_entity_type', + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 400, + ], + 'skeletonId' => $entityType->getDefaultAttributeSetId(), + ]; + $this->_webApiCall($this->createServiceInfo, $arguments); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Attribute set name is empty. + */ + public function testCreateThrowsExceptionIfAttributeSetNameIsEmpty() + { + $entityTypeCode = 'catalog_product'; + $entityType = $this->getEntityTypeByCode($entityTypeCode); + $attributeSetName = ''; + + $arguments = [ + 'entityTypeCode' => $entityTypeCode, + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 500, + ], + 'skeletonId' => $entityType->getDefaultAttributeSetId(), + ]; + $this->_webApiCall($this->createServiceInfo, $arguments); + } + + public function testCreateThrowsExceptionIfAttributeSetWithGivenNameAlreadyExists() + { + $entityTypeCode = 'catalog_product'; + $entityType = $this->getEntityTypeByCode($entityTypeCode); + $attributeSetName = 'Default'; + $expectedMessage = 'An attribute set with the "Default" name already exists.'; + + $arguments = [ + 'entityTypeCode' => $entityTypeCode, + 'attributeSet' => [ + 'attribute_set_name' => $attributeSetName, + 'sort_order' => 550, + ], + 'skeletonId' => $entityType->getDefaultAttributeSetId(), + ]; + + try { + $this->_webApiCall($this->createServiceInfo, $arguments); + $this->fail("Expected exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals( + $expectedMessage, + $errorObj['message'] + ); + $this->assertEquals(HTTPExceptionCodes::HTTP_BAD_REQUEST, $e->getCode()); + } + } + + /** + * Retrieve attribute set based on given name. + * This utility methods assumes that there is only one attribute set with given name, + * + * @param string $attributeSetName + * @return \Magento\Eav\Model\Entity\Attribute\Set|null + */ + protected function getAttributeSetByName($attributeSetName) + { + $objectManager = Bootstrap::getObjectManager(); + /** @var \Magento\Eav\Model\Entity\Attribute\Set $attributeSet */ + $attributeSet = $objectManager->create('Magento\Eav\Model\Entity\Attribute\Set') + ->load($attributeSetName, 'attribute_set_name'); + if ($attributeSet->getId() === null) { + return null; + } + return $attributeSet; + } + + /** + * Retrieve entity type based on given code. + * + * @param string $entityTypeCode + * @return \Magento\Eav\Model\Entity\Type|null + */ + protected function getEntityTypeByCode($entityTypeCode) + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Eav\Model\Entity\Type $entityType */ + $entityType = $objectManager->create('Magento\Eav\Model\Config') + ->getEntityType($entityTypeCode); + return $entityType; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Eav/Api/AttributeSetRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Eav/Api/AttributeSetRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..2a7024a290a2937bd165d246c01ff0d578027906 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Eav/Api/AttributeSetRepositoryTest.php @@ -0,0 +1,260 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Eav\Api; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class AttributeSetRepositoryTest extends WebapiAbstract +{ + /** + * @magentoApiDataFixture Magento/Eav/_files/empty_attribute_set.php + */ + public function testGet() + { + $attributeSetName = 'empty_attribute_set'; + $attributeSet = $this->getAttributeSetByName($attributeSetName); + $attributeSetId = $attributeSet->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/eav/attribute-sets/' . $attributeSetId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'eavAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'eavAttributeSetRepositoryV1Get', + ], + ]; + $arguments = [ + 'attributeSetId' => $attributeSetId, + ]; + $result = $this->_webApiCall($serviceInfo, $arguments); + $this->assertNotNull($result); + $this->assertEquals($attributeSet->getId(), $result['attribute_set_id']); + $this->assertEquals($attributeSet->getAttributeSetName(), $result['attribute_set_name']); + $this->assertEquals($attributeSet->getEntityTypeId(), $result['entity_type_id']); + $this->assertEquals($attributeSet->getSortOrder(), $result['sort_order']); + } + + /** + * @expectedException \Exception + */ + public function testGetThrowsExceptionIfRequestedAttributeSetDoesNotExist() + { + $attributeSetId = 9999; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/eav/attribute-sets/' . $attributeSetId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'eavAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'eavAttributeSetRepositoryV1Get', + ], + ]; + $arguments = [ + 'attributeSetId' => $attributeSetId, + ]; + $this->_webApiCall($serviceInfo, $arguments); + } + + /** + * @magentoApiDataFixture Magento/Eav/_files/empty_attribute_set.php + */ + public function testSave() + { + $attributeSetName = 'empty_attribute_set'; + $attributeSet = $this->getAttributeSetByName($attributeSetName); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/eav/attribute-sets', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'eavAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'eavAttributeSetRepositoryV1Save', + ], + ]; + + $updatedSortOrder = $attributeSet->getSortOrder() + 200; + + $arguments = [ + 'attributeSet' => [ + 'attribute_set_id' => $attributeSet->getId(), + // name is the same, because it is used by fixture rollback script + 'attribute_set_name' => $attributeSet->getAttributeSetName(), + 'entity_type_id' => $attributeSet->getEntityTypeId(), + 'sort_order' => $updatedSortOrder, + ], + ]; + $result = $this->_webApiCall($serviceInfo, $arguments); + $this->assertNotNull($result); + // Reload attribute set data + $attributeSet = $this->getAttributeSetByName($attributeSetName); + $this->assertEquals($attributeSet->getAttributeSetId(), $result['attribute_set_id']); + $this->assertEquals($attributeSet->getAttributeSetName(), $result['attribute_set_name']); + $this->assertEquals($attributeSet->getEntityTypeId(), $result['entity_type_id']); + $this->assertEquals($updatedSortOrder, $result['sort_order']); + $this->assertEquals($attributeSet->getSortOrder(), $result['sort_order']); + } + + /** + * @magentoApiDataFixture Magento/Eav/_files/empty_attribute_set.php + */ + public function testDeleteById() + { + $attributeSetName = 'empty_attribute_set'; + $attributeSet = $this->getAttributeSetByName($attributeSetName); + $attributeSetId = $attributeSet->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/eav/attribute-sets/' . $attributeSetId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => 'eavAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'eavAttributeSetRepositoryV1DeleteById', + ], + ]; + + $arguments = [ + 'attributeSetId' => $attributeSetId, + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, $arguments)); + $this->assertNull($this->getAttributeSetByName($attributeSetName)); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Default attribute set can not be deleted + */ + public function testDeleteByIdDefaultAttributeSet() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Eav\Model\Config */ + $eavConfig = $objectManager->create('Magento\Eav\Model\Config'); + + $defaultAttributeSetId = $eavConfig + ->getEntityType(\Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE) + ->getDefaultAttributeSetId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/eav/attribute-sets/' . $defaultAttributeSetId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => 'eavAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'eavAttributeSetRepositoryV1DeleteById', + ], + ]; + + $arguments = [ + 'attributeSetId' => $defaultAttributeSetId, + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, $arguments)); + } + + /** + * @expectedException \Exception + */ + public function testDeleteByIdThrowsExceptionIfRequestedAttributeSetDoesNotExist() + { + $attributeSetId = 9999; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/eav/attribute-sets/' . $attributeSetId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => 'eavAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'eavAttributeSetRepositoryV1DeleteById', + ], + ]; + + $arguments = [ + 'attributeSetId' => $attributeSetId, + ]; + $this->_webApiCall($serviceInfo, $arguments); + } + + /** + * @magentoApiDataFixture Magento/Eav/_files/empty_attribute_set.php + */ + public function testGetList() + { + $searchCriteria = [ + 'searchCriteria' => [ + 'filter_groups' => [ + [ + 'filters' => [ + [ + 'field' => 'entity_type_code', + 'value' => 'catalog_product', + 'condition_type' => 'eq', + ], + ], + ], + ], + 'current_page' => 1, + 'page_size' => 2, + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/eav/attribute-sets/list', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => 'eavAttributeSetRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'eavAttributeSetRepositoryV1GetList', + ], + ]; + + $response = $this->_webApiCall($serviceInfo, $searchCriteria); + + $this->assertArrayHasKey('search_criteria', $response); + $this->assertArrayHasKey('total_count', $response); + $this->assertArrayHasKey('items', $response); + + $this->assertEquals($searchCriteria['searchCriteria'], $response['search_criteria']); + $this->assertTrue($response['total_count'] > 0); + $this->assertTrue(count($response['items']) > 0); + + $this->assertNotNull($response['items'][0]['attribute_set_id']); + $this->assertNotNull($response['items'][0]['attribute_set_name']); + } + + /** + * Retrieve attribute set based on given name. + * This utility methods assumes that there is only one attribute set with given name, + * + * @param string $attributeSetName + * @return \Magento\Eav\Model\Entity\Attribute\Set|null + */ + protected function getAttributeSetByName($attributeSetName) + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Eav\Model\Entity\Attribute\Set $attributeSet */ + $attributeSet = $objectManager->create('Magento\Eav\Model\Entity\Attribute\Set') + ->load($attributeSetName, 'attribute_set_name'); + if ($attributeSet->getId() === null) { + return null; + } + return $attributeSet; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Framework/Stdlib/CookieManagerTest.php b/dev/tests/api-functional/testsuite/Magento/Framework/Stdlib/CookieManagerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1c90fcc223e698969319726ab87c9dec637e00d8 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Framework/Stdlib/CookieManagerTest.php @@ -0,0 +1,164 @@ +<?php +namespace Magento\Framework\Stdlib; + +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\Webapi\Curl; + +/** + * End to end test of the Cookie Manager, using curl. + * + * Uses controllers in TestModule1 to set and delete cookies and verify 'Set-Cookie' headers that come back. + */ +class CookieManagerTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + private $cookieTesterUrl = 'testmoduleone/CookieTester'; + + /** @var Curl */ + protected $curlClient; + + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->config = $objectManager->get('Magento\Webapi\Model\Config'); + $this->curlClient = $objectManager->get('Magento\TestFramework\TestCase\Webapi\Curl'); + } + + /** + * Set a sensitive Cookie and delete it. + * + */ + public function testSensitiveCookie() + { + $url = $this->cookieTesterUrl . '/SetSensitiveCookie'; + $cookieParams = + [ + 'cookie_name' => 'test-sensitive-cookie', + 'cookie_value' => 'test-sensitive-cookie-value', + ]; + $response = $this->curlClient->get($url, $cookieParams); + + $cookie = $this->findCookie($cookieParams['cookie_name'], $response['cookies']); + $this->assertNotNull($cookie); + $this->assertEquals($cookieParams['cookie_name'], $cookie['name']); + $this->assertEquals($cookieParams['cookie_value'], $cookie['value']); + $this->assertFalse(isset($cookie['domain'])); + $this->assertFalse(isset($cookie['path'])); + $this->assertEquals('true', $cookie['httponly']); + $this->assertFalse(isset($cookie['secure'])); + $this->assertFalse(isset($cookie['max-age'])); + } + + /** + * Set a public cookie + * + */ + public function testPublicCookieNameValue() + { + $url = $this->cookieTesterUrl . '/SetPublicCookie'; + $cookieParams = + [ + 'cookie_name' => 'test-cookie', + 'cookie_value' => 'test-cookie-value', + ]; + + $response = $this->curlClient->get($url, $cookieParams); + + $cookie = $this->findCookie($cookieParams['cookie_name'], $response['cookies']); + $this->assertNotNull($cookie); + $this->assertEquals($cookieParams['cookie_name'], $cookie['name']); + $this->assertEquals($cookieParams['cookie_value'], $cookie['value']); + $this->assertFalse(isset($cookie['domain'])); + $this->assertFalse(isset($cookie['path'])); + $this->assertFalse(isset($cookie['httponly'])); + $this->assertFalse(isset($cookie['secure'])); + $this->assertFalse(isset($cookie['max-age'])); + } + + /** + * Set a public cookie + * + */ + public function testPublicCookieAll() + { + $url = $this->cookieTesterUrl . '/SetPublicCookie'; + $cookieParams = + [ + 'cookie_name' => 'test-cookie', + 'cookie_value' => 'test-cookie-value', + 'cookie_domain' => 'www.example.com', + 'cookie_path' => '/test/path', + 'cookie_httponly' => 'true', + 'cookie_secure' => 'true', + 'cookie_duration' => '600', + ]; + + $response = $this->curlClient->get($url, $cookieParams); + + $cookie = $this->findCookie($cookieParams['cookie_name'], $response['cookies']); + $this->assertNotNull($cookie); + $this->assertEquals($cookieParams['cookie_name'], $cookie['name']); + $this->assertEquals($cookieParams['cookie_value'], $cookie['value']); + $this->assertEquals($cookieParams['cookie_domain'], $cookie['domain']); + $this->assertEquals($cookieParams['cookie_path'], $cookie['path']); + $this->assertEquals($cookieParams['cookie_httponly'], $cookie['httponly']); + $this->assertEquals($cookieParams['cookie_secure'], $cookie['secure']); + if (isset($cookie['max-age'])) { + $this->assertEquals($cookieParams['cookie_duration'], $cookie['max-age']); + } + $this->assertTrue(isset($cookie['expires'])); + } + + /** + * Delete a cookie + * + */ + public function testDeleteCookie() + { + $url = $this->cookieTesterUrl . '/DeleteCookie'; + $cookieParams = + [ + 'cookie_name' => 'test-cookie', + 'cookie_value' => 'test-cookie-value', + ]; + + $response = $this->curlClient->get( + $url, + $cookieParams, + ['Cookie: test-cookie=test-cookie-value; anothertestcookie=anothertestcookievalue'] + ); + + $cookie = $this->findCookie($cookieParams['cookie_name'], $response['cookies']); + $this->assertNotNull($cookie); + $this->assertEquals($cookieParams['cookie_name'], $cookie['name']); + $this->assertEquals('deleted', $cookie['value']); + $this->assertFalse(isset($cookie['domain'])); + $this->assertFalse(isset($cookie['path'])); + $this->assertFalse(isset($cookie['httponly'])); + $this->assertFalse(isset($cookie['secure'])); + if (isset($cookie['max-age'])) { + $this->assertEquals(0, $cookie['max-age']); + } + $this->assertEquals('Thu, 01-Jan-1970 00:00:01 GMT', $cookie['expires']); + } + + /** + * Find cookie with given name in the list of cookies + * + * @param string $cookieName + * @param array $cookies + * @return $cookie|null + */ + private function findCookie($cookieName, $cookies) + { + foreach ($cookies as $cookieIndex => $cookie) { + if ($cookie['name'] === $cookieName) { + return $cookie; + } + } + return null; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GiftMessage/Service/V1/ReadServiceTest.php b/dev/tests/api-functional/testsuite/Magento/GiftMessage/Service/V1/ReadServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a287d6c8e5106cac474a9a80492f1c02808f4aeb --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GiftMessage/Service/V1/ReadServiceTest.php @@ -0,0 +1,101 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\GiftMessage\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ReadServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'giftMessageReadServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/GiftMessage/_files/quote_with_message.php + */ + public function testGet() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('message_order_21', 'reserved_order_id'); + + $cartId = $quote->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/gift-message', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + + $expectedMessage = [ + 'recipient' => 'Mercutio', + 'sender' => 'Romeo', + 'message' => 'I thought all for the best.', + ]; + + $requestData = ["cartId" => $cartId]; + $resultMessage = $this->_webApiCall($serviceInfo, $requestData); + $this->assertCount(5, $resultMessage); + unset($resultMessage['gift_message_id']); + unset($resultMessage['customer_id']); + $this->assertEquals($expectedMessage, $resultMessage); + } + + /** + * @magentoApiDataFixture Magento/GiftMessage/_files/quote_with_item_message.php + */ + public function testGetItemMessage() + { + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_item_with_message', 'reserved_order_id'); + $product = $this->objectManager->create('Magento\Catalog\Model\Product'); + $product->load($product->getIdBySku('simple_with_message')); + $itemId = $quote->getItemByProduct($product)->getId(); + /** @var \Magento\Catalog\Model\Product $product */ + $cartId = $quote->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/gift-message/' . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getItemMessage', + ], + ]; + + $expectedMessage = [ + 'recipient' => 'Jane Roe', + 'sender' => 'John Doe', + 'message' => 'Gift Message Text', + ]; + + $requestData = ["cartId" => $cartId, "itemId" => $itemId]; + $resultMessage = $this->_webApiCall($serviceInfo, $requestData); + $this->assertCount(5, $resultMessage); + unset($resultMessage['gift_message_id']); + unset($resultMessage['customer_id']); + $this->assertEquals($expectedMessage, $resultMessage); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GiftMessage/Service/V1/WriteServiceTest.php b/dev/tests/api-functional/testsuite/Magento/GiftMessage/Service/V1/WriteServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..79185a68dca2b8618eaaa3e04e33ee82781f82e1 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GiftMessage/Service/V1/WriteServiceTest.php @@ -0,0 +1,115 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\GiftMessage\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class WriteServiceTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + const SERVICE_NAME = 'giftMessageWriteServiceV1'; + const RESOURCE_PATH = '/V1/carts/'; + + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/GiftMessage/_files/quote_with_item_message.php + */ + public function testSetForQuote() + { + // sales/gift_options/allow_order must be set to 1 in system configuration + // @todo remove next statement when \Magento\TestFramework\TestCase\WebapiAbstract::_updateAppConfig is fixed + $this->markTestIncomplete('This test relies on system configuration state.'); + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_item_with_message', 'reserved_order_id'); + + $cartId = $quote->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/gift-message', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'SetForQuote', + ], + ]; + + $requestData = [ + 'cartId' => $cartId, + 'giftMessage' => [ + 'recipient' => 'John Doe', + 'sender' => 'Jane Roe', + 'message' => 'Gift Message Text New', + ], + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + $quote->load('test_order_item_with_message', 'reserved_order_id'); + $quote->getGiftMessageId(); + /** @var \Magento\GiftMessage\Model\Message $message */ + $message = $this->objectManager->create('Magento\GiftMessage\Model\Message')->load($quote->getGiftMessageId()); + $this->assertEquals('John Doe', $message->getRecipient()); + $this->assertEquals('Jane Roe', $message->getSender()); + $this->assertEquals('Gift Message Text New', $message->getMessage()); + } + + /** + * @magentoApiDataFixture Magento/GiftMessage/_files/quote_with_item_message.php + */ + public function testSetForItem() + { + // sales/gift_options/allow_items must be set to 1 in system configuration + // @todo remove next statement when \Magento\TestFramework\TestCase\WebapiAbstract::_updateAppConfig is fixed + $this->markTestIncomplete('This test relies on system configuration state.'); + /** @var \Magento\Sales\Model\Quote $quote */ + $quote = $this->objectManager->create('Magento\Sales\Model\Quote'); + $quote->load('test_order_item_with_message', 'reserved_order_id'); + $cartId = $quote->getId(); + $product = $this->objectManager->create('Magento\Catalog\Model\Product'); + $product->load($product->getIdBySku('simple_with_message')); + $itemId = $quote->getItemByProduct($product)->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/gift-message/' . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'SetForItem', + ], + ]; + + $requestData = [ + 'cartId' => $cartId, + 'itemId' => $itemId, + 'giftMessage' => [ + 'recipient' => 'John Doe', + 'sender' => 'Jane Roe', + 'message' => 'Gift Message Text New', + ], + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); +// $quote->load('test_order_item_with_message', 'reserved_order_id'); + $messageId = $quote->getItemByProduct($product)->getGiftMessageId(); + /** @var \Magento\GiftMessage\Model\Message $message */ + $message = $this->objectManager->create('Magento\GiftMessage\Model\Message')->load($messageId); + $this->assertEquals('John Doe', $message->getRecipient()); + $this->assertEquals('Jane Roe', $message->getSender()); + $this->assertEquals('Gift Message Text New', $message->getMessage()); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkManagementTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..4a6ce3ac19f6f397cc24757950279022163d075e --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkManagementTest.php @@ -0,0 +1,72 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\GroupedProduct\Api; + +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductLinkManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductLinkManagementV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/'; + + /** + * @magentoApiDataFixture Magento/GroupedProduct/_files/product_grouped.php + */ + public function testGetLinkedItemsByType() + { + $productSku = 'grouped-product'; + $linkType = 'associated'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $productSku . '/links/' . $linkType, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetLinkedItemsByType', + ], + ]; + + $actual = $this->_webApiCall($serviceInfo, ['productSku' => $productSku, 'type' => $linkType]); + + $expected = [ + [ + 'product_sku' => 'grouped-product', + 'link_type' => 'associated', + 'linked_product_sku' => 'simple-1', + 'linked_product_type' => 'simple', + 'position' => 1, + ], + [ + 'product_sku' => 'grouped-product', + 'link_type' => 'associated', + 'linked_product_sku' => 'virtual-product', + 'linked_product_type' => 'virtual', + 'position' => 2, + ], + ]; + + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + array_walk( + $expected, + function (&$item) { + $item['custom_attributes'] = [['attribute_code' => 'qty', 'value' => 1.0000]]; + } + ); + } else { + array_walk( + $expected, + function (&$item) { + $item['custom_attributes'] = [['attribute_code' => 'qty', 'value' => 1.0000]]; + } + ); + } + $this->assertEquals($expected, $actual); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..80e1ca7370759d0df8adc3aaf2a5defd3b7cc6f6 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkRepositoryTest.php @@ -0,0 +1,66 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\GroupedProduct\Api; + +use Magento\Webapi\Model\Rest\Config as RestConfig; +use Magento\TestFramework\Helper\Bootstrap; + +class ProductLinkRepositoryTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductLinkRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/'; + + /** + * @var \Magento\Framework\ObjectManager + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + } + /** + * @magentoApiDataFixture Magento/Catalog/_files/products_new.php + * @magentoApiDataFixture Magento/GroupedProduct/_files/product_grouped.php + */ + public function testSave() + { + $productSku = 'grouped-product'; + $linkType = 'associated'; + $productData = [ + 'product_sku' => $productSku, + 'link_type' => $linkType, + 'linked_product_type' => 'simple', + 'linked_product_sku' => 'simple', + 'position' => 3, + 'custom_attributes' => [ + 'qty' => ['attribute_code' => 'qty', 'value' => (float) 300.0000], + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $productSku . '/links/' . $linkType, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $this->_webApiCall($serviceInfo, ['entity' => $productData]); + + /** @var \Magento\Catalog\Model\ProductLink\Management $linkManagement */ + $linkManagement = $this->objectManager->get('Magento\Catalog\Api\ProductLinkManagementInterface'); + $actual = $linkManagement->getLinkedItemsByType($productSku, $linkType); + array_walk($actual, function (&$item) { + $item = $item->__toArray(); + }); + $this->assertEquals($productData, $actual[2]); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkTypeListTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkTypeListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..cec4ba0b6777c74ba37ec0aade980d18bcae2933 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkTypeListTest.php @@ -0,0 +1,64 @@ +<?php +/** + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\GroupedProduct\Api; + +use Magento\GroupedProduct\Model\Resource\Product\Link; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ProductLinkTypeListTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductLinkTypeListV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/products/'; + + public function testGetItems() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . 'links/types', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetItems', + ], + ]; + + $actual = $this->_webApiCall($serviceInfo); + + /** + * Validate that product type links provided by Magento_GroupedProduct module are present + */ + $expectedItems = ['name' => 'associated', 'code' => Link::LINK_TYPE_GROUPED]; + $this->assertContains($expectedItems, $actual); + } + + public function testGetItemAttributes() + { + $linkType = 'associated'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . 'links/' . $linkType . '/attributes', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetItemAttributes', + ], + ]; + + $actual = $this->_webApiCall($serviceInfo, ['type' => $linkType]); + + $expected = [ + ['code' => 'position', 'type' => 'int'], + ['code' => 'qty', 'type' => 'decimal'], + ]; + $this->assertEquals($expected, $actual); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Integration/Service/V1/AdminTokenServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Integration/Service/V1/AdminTokenServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..91e6a4cad97841feb4c1d2d91c61a97bd7dfa2cd --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Integration/Service/V1/AdminTokenServiceTest.php @@ -0,0 +1,159 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Integration\Service\V1; + +use Magento\Framework\Exception\InputException; +use Magento\Integration\Model\Oauth\Token as TokenModel; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\User\Model\User as UserModel; +use Magento\Webapi\Exception as HTTPExceptionCodes; + +/** + * api-functional test for \Magento\Integration\Service\V1\AdminTokenService. + */ +class AdminTokenServiceTest extends WebapiAbstract +{ + const SERVICE_NAME = "integrationAdminTokenServiceV1"; + const SERVICE_VERSION = "V1"; + const RESOURCE_PATH_ADMIN_TOKEN = "/V1/integration/admin/token"; + const RESOURCE_PATH_CUSTOMER_TOKEN = "/V1/integration/customer/token"; + + /** + * @var AdminTokenServiceInterface + */ + private $tokenService; + + /** + * @var TokenModel + */ + private $tokenModel; + + /** + * @var UserModel + */ + private $userModel; + + /** + * Setup AdminTokenService + */ + public function setUp() + { + $this->_markTestAsRestOnly(); + $this->tokenService = Bootstrap::getObjectManager()->get('Magento\Integration\Service\V1\AdminTokenService'); + $this->tokenModel = Bootstrap::getObjectManager()->get('Magento\Integration\Model\Oauth\Token'); + $this->userModel = Bootstrap::getObjectManager()->get('Magento\User\Model\User'); + } + + /** + * @magentoApiDataFixture Magento/User/_files/user_with_role.php + */ + public function testCreateAdminAccessToken() + { + $adminUserNameFromFixture = 'adminUser'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_ADMIN_TOKEN, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + $requestData = [ + 'username' => $adminUserNameFromFixture, + 'password' => \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD, + ]; + $accessToken = $this->_webApiCall($serviceInfo, $requestData); + + $adminUserId = $this->userModel->loadByUsername($adminUserNameFromFixture)->getId(); + /** @var $token TokenModel */ + $token = $this->tokenModel + ->loadByAdminId($adminUserId) + ->getToken(); + $this->assertEquals($accessToken, $token); + } + + /** + * @dataProvider validationDataProvider + */ + public function testCreateAdminAccessTokenEmptyOrNullCredentials() + { + try { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_ADMIN_TOKEN, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + $requestData = ['username' => '', 'password' => '']; + $this->_webApiCall($serviceInfo, $requestData); + } catch (\Exception $e) { + $this->assertInputExceptionMessages($e); + } + } + + public function testCreateAdminAccessTokenInvalidCustomer() + { + $customerUserName = 'invalid'; + $password = 'invalid'; + try { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_CUSTOMER_TOKEN, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + $requestData = ['username' => $customerUserName, 'password' => $password]; + $this->_webApiCall($serviceInfo, $requestData); + } catch (\Exception $e) { + $this->assertEquals(HTTPExceptionCodes::HTTP_UNAUTHORIZED, $e->getCode()); + $exceptionData = $this->processRestExceptionResult($e); + $expectedExceptionData = ['message' => 'Invalid login or password.']; + } + $this->assertEquals($expectedExceptionData, $exceptionData); + } + + /** + * Provider to test input validation + * + * @return array + */ + public function validationDataProvider() + { + return [ + 'Check for empty credentials' => ['', ''], + 'Check for null credentials' => [null, null] + ]; + } + + /** + * Assert for presence of Input exception messages + * + * @param \Exception $e + */ + private function assertInputExceptionMessages($e) + { + $this->assertEquals(HTTPExceptionCodes::HTTP_BAD_REQUEST, $e->getCode()); + $exceptionData = $this->processRestExceptionResult($e); + $expectedExceptionData = [ + 'message' => InputException::DEFAULT_MESSAGE, + 'errors' => [ + [ + 'message' => InputException::REQUIRED_FIELD, + 'parameters' => [ + 'fieldName' => 'username', + ], + ], + [ + 'message' => InputException::REQUIRED_FIELD, + 'parameters' => [ + 'fieldName' => 'password', + ] + ], + ], + ]; + $this->assertEquals($expectedExceptionData, $exceptionData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Integration/Service/V1/CustomerTokenServiceTest.php b/dev/tests/api-functional/testsuite/Magento/Integration/Service/V1/CustomerTokenServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f6a4f4f2ce28bbcbf002beb7a2af25c70d51eb88 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Integration/Service/V1/CustomerTokenServiceTest.php @@ -0,0 +1,164 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Integration\Service\V1; + +use Magento\Customer\Api\AccountManagementInterface; +use Magento\Framework\Exception\InputException; +use Magento\Integration\Model\Oauth\Token as TokenModel; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\User\Model\User as UserModel; +use Magento\Webapi\Exception as HTTPExceptionCodes; + +/** + * api-functional test for \Magento\Integration\Service\V1\CustomerTokenService. + */ +class CustomerTokenServiceTest extends WebapiAbstract +{ + const SERVICE_NAME = "integrationCustomerTokenServiceV1"; + const SERVICE_VERSION = "V1"; + const RESOURCE_PATH_CUSTOMER_TOKEN = "/V1/integration/customer/token"; + const RESOURCE_PATH_ADMIN_TOKEN = "/V1/integration/admin/token"; + + /** + * @var CustomerTokenServiceInterface + */ + private $tokenService; + + /** + * @var AccountManagementInterface + */ + private $customerAccountManagement; + + /** + * @var TokenModel + */ + private $tokenModel; + + /** + * @var UserModel + */ + private $userModel; + + /** + * Setup CustomerTokenService + */ + public function setUp() + { + $this->_markTestAsRestOnly(); + $this->tokenService = Bootstrap::getObjectManager()->get('Magento\Integration\Service\V1\CustomerTokenService'); + $this->customerAccountManagement = Bootstrap::getObjectManager()->get( + 'Magento\Customer\Api\AccountManagementInterface' + ); + $this->tokenModel = Bootstrap::getObjectManager()->get('Magento\Integration\Model\Oauth\Token'); + $this->userModel = Bootstrap::getObjectManager()->get('Magento\User\Model\User'); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testCreateCustomerAccessToken() + { + $customerUserName = 'customer@example.com'; + $password = 'password'; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_CUSTOMER_TOKEN, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + $requestData = ['username' => $customerUserName, 'password' => $password]; + $accessToken = $this->_webApiCall($serviceInfo, $requestData); + + $customerData = $this->customerAccountManagement->authenticate($customerUserName, $password); + /** @var $token TokenModel */ + $token = $this->tokenModel->loadByCustomerId($customerData->getId())->getToken(); + $this->assertEquals($accessToken, $token); + } + + /** + * @dataProvider validationDataProvider + */ + public function testCreateCustomerAccessTokenEmptyOrNullCredentials($username, $password) + { + try { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_CUSTOMER_TOKEN, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + $requestData = ['username' => '', 'password' => '']; + $this->_webApiCall($serviceInfo, $requestData); + } catch (\Exception $e) { + $this->assertInputExceptionMessages($e); + } + } + + public function testCreateCustomerAccessTokenInvalidCustomer() + { + $customerUserName = 'invalid'; + $password = 'invalid'; + try { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_CUSTOMER_TOKEN, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + $requestData = ['username' => $customerUserName, 'password' => $password]; + $this->_webApiCall($serviceInfo, $requestData); + } catch (\Exception $e) { + $this->assertEquals(HTTPExceptionCodes::HTTP_UNAUTHORIZED, $e->getCode()); + $exceptionData = $this->processRestExceptionResult($e); + $expectedExceptionData = ['message' => 'Invalid login or password.']; + } + $this->assertEquals($expectedExceptionData, $exceptionData); + } + + /** + * Provider to test input validation + * + * @return array + */ + public function validationDataProvider() + { + return [ + 'Check for empty credentials' => ['', ''], + 'Check for null credentials' => [null, null] + ]; + } + + /** + * Assert for presence of Input exception messages + * + * @param \Exception $e + */ + private function assertInputExceptionMessages($e) + { + $this->assertEquals(HTTPExceptionCodes::HTTP_BAD_REQUEST, $e->getCode()); + $exceptionData = $this->processRestExceptionResult($e); + $expectedExceptionData = [ + 'message' => InputException::DEFAULT_MESSAGE, + 'errors' => [ + [ + 'message' => InputException::REQUIRED_FIELD, + 'parameters' => [ + 'fieldName' => 'username', + ], + ], + [ + 'message' => InputException::REQUIRED_FIELD, + 'parameters' => [ + 'fieldName' => 'password', + ] + ], + ], + ]; + $this->assertEquals($expectedExceptionData, $exceptionData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoAddCommentTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoAddCommentTest.php new file mode 100644 index 0000000000000000000000000000000000000000..885bcb8f8b717e5063748b2c2d4cbf229c6c56aa --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoAddCommentTest.php @@ -0,0 +1,82 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\Sales\Api\Data\CreditmemoCommentInterface as Comment; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class CreditmemoAddCommentTest + */ +class CreditmemoAddCommentTest extends WebapiAbstract +{ + /** + * Service read name + */ + const SERVICE_READ_NAME = 'salesCreditmemoCommentRepositoryV1'; + + /** + * Service version + */ + const SERVICE_VERSION = 'V1'; + + /** + * Creditmemo increment id + */ + const CREDITMEMO_INCREMENT_ID = '100000001'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Test creditmemo add comment service + * + * @magentoApiDataFixture Magento/Sales/_files/creditmemo_with_list.php + */ + public function testCreditmemoAddComment() + { + /** @var \Magento\Sales\Model\Resource\Order\Creditmemo\Collection $creditmemoCollection */ + $creditmemoCollection = $this->objectManager->get('Magento\Sales\Model\Resource\Order\Creditmemo\Collection'); + $creditmemo = $creditmemoCollection->getFirstItem(); + + $commentData = [ + Comment::COMMENT => 'Hello world!', + Comment::ENTITY_ID => null, + Comment::CREATED_AT => null, + Comment::PARENT_ID => $creditmemo->getId(), + Comment::IS_VISIBLE_ON_FRONT => true, + Comment::IS_CUSTOMER_NOTIFIED => true, + ]; + + $requestData = ['entity' => $commentData]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/creditmemo/comment', + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'save', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertNotEmpty($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCancelTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCancelTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e7ad70a57658f0c358b67f6d532b12e130e56d28 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCancelTest.php @@ -0,0 +1,47 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class CreditmemoCancelTest + */ +class CreditmemoCancelTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesCreditmemoManagementV1'; + + const CREDITMEMO_INCREMENT_ID = '100000001'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/creditmemo_with_list.php + */ + public function testCreditmemoCancel() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + /** @var \Magento\Sales\Model\Resource\Order\Creditmemo\Collection $creditmemoCollection */ + $creditmemoCollection = $objectManager->get('Magento\Sales\Model\Resource\Order\Creditmemo\Collection'); + $creditmemo = $creditmemoCollection->getFirstItem(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/creditmemo/' . $creditmemo->getId(), + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'cancel', + ], + ]; + $requestData = ['id' => $creditmemo->getId()]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCommentsListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCommentsListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..2566256747465ca80f3dcfa3f5f203675502e3d5 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCommentsListTest.php @@ -0,0 +1,62 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\Sales\Api\Data\CreditmemoCommentInterface; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class CreditmemoCommentsListTest + */ +class CreditmemoCommentsListTest extends WebapiAbstract +{ + const SERVICE_NAME = 'salesCreditmemoManagementV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/creditmemo_for_get.php + */ + public function testCreditmemoCommentsList() + { + $comment = 'Test comment'; + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Sales\Model\Resource\Order\Creditmemo\Collection $creditmemoCollection */ + $creditmemoCollection = $objectManager->get('Magento\Sales\Model\Resource\Order\Creditmemo\Collection'); + $creditmemo = $creditmemoCollection->getFirstItem(); + $creditmemoComment = $objectManager->get('Magento\Sales\Model\Order\Creditmemo\Comment'); + + $commentData = [ + CreditmemoCommentInterface::COMMENT => 'Hello world!', + CreditmemoCommentInterface::ENTITY_ID => null, + CreditmemoCommentInterface::CREATED_AT => null, + CreditmemoCommentInterface::PARENT_ID => $creditmemo->getId(), + CreditmemoCommentInterface::IS_VISIBLE_ON_FRONT => true, + CreditmemoCommentInterface::IS_CUSTOMER_NOTIFIED => true, + ]; + $creditmemoComment->setData($commentData)->save(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/creditmemo/' . $creditmemo->getId() . '/comments', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getCommentsList', + ], + ]; + $requestData = ['id' => $creditmemo->getId()]; + $result = $this->_webApiCall($serviceInfo, $requestData); + // TODO Test fails, due to the inability of the framework API to handle data collection + $this->assertNotEmpty($result); + foreach ($result['items'] as $item) { + $comment = $objectManager->get('Magento\Sales\Model\Order\Creditmemo\Comment')->load($item['entity_id']); + $this->assertEquals($comment->getComment(), $item['comment']); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCreateTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCreateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e7fb134e9d20243d6e04bdd75f7f47768336973f --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCreateTest.php @@ -0,0 +1,111 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class CreditmemoCreateTest + */ +class CreditmemoCreateTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/creditmemo'; + + const SERVICE_READ_NAME = 'salesCreditmemoRepositoryV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/invoice.php + */ + public function testInvoke() + { + /** @var \Magento\Sales\Model\Order $order */ + $orderCollection = $this->objectManager->get('Magento\Sales\Model\Resource\Order\Collection'); + $order = $orderCollection->getFirstItem(); + +// $order = $this->objectManager->create('Magento\Sales\Model\Order')->loadByIncrementId('100000001'); + /** @var \Magento\Sales\Model\Order\Item $orderItem */ + $orderItem = current($order->getAllItems()); + $items = [ + $orderItem->getId() => ['qty' => $orderItem->getQtyInvoiced(), 'order_item_id' => $orderItem->getId()], + ]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'save', + ], + ]; + $data = [ + 'adjustment' => null, + 'adjustment_negative' => null, + 'adjustment_positive' => null, + 'base_adjustment' => null, + 'base_adjustment_negative' => null, + 'base_adjustment_positive' => null, + 'base_currency_code' => null, + 'base_discount_amount' => null, + 'base_grand_total' => null, + 'base_hidden_tax_amount' => null, + 'base_shipping_amount' => null, + 'base_shipping_hidden_tax_amnt' => null, + 'base_shipping_incl_tax' => null, + 'base_shipping_tax_amount' => null, + 'base_subtotal' => null, + 'base_subtotal_incl_tax' => null, + 'base_tax_amount' => null, + 'base_to_global_rate' => null, + 'base_to_order_rate' => null, + 'billing_address_id' => null, + 'created_at' => null, + 'creditmemo_status' => null, + 'discount_amount' => null, + 'discount_description' => null, + 'email_sent' => null, + 'entity_id' => null, + 'global_currency_code' => null, + 'grand_total' => null, + 'hidden_tax_amount' => null, + 'increment_id' => null, + 'invoice_id' => null, + 'order_currency_code' => null, + 'order_id' => $order->getId(), + 'shipping_address_id' => null, + 'shipping_amount' => null, + 'shipping_hidden_tax_amount' => null, + 'shipping_incl_tax' => null, + 'shipping_tax_amount' => null, + 'state' => null, + 'store_currency_code' => null, + 'store_id' => null, + 'store_to_base_rate' => null, + 'store_to_order_rate' => null, + 'subtotal' => null, + 'subtotal_incl_tax' => null, + 'tax_amount' => null, + 'transaction_id' => null, + 'updated_at' => null, + 'items' => $items, + ]; + $result = $this->_webApiCall($serviceInfo, ['entity' => $data]); + $this->assertNotEmpty($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoEmailTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoEmailTest.php new file mode 100644 index 0000000000000000000000000000000000000000..828a0338c3669a7fab59d96d3dab1091f053fdc5 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoEmailTest.php @@ -0,0 +1,45 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class CreditmemoEmailTest + */ +class CreditmemoEmailTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesCreditmemoManagementV1'; + + const CREDITMEMO_INCREMENT_ID = '100000001'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/creditmemo_with_list.php + */ + public function testCreditmemoEmail() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + /** @var \Magento\Sales\Model\Resource\Order\Creditmemo\Collection $creditmemoCollection */ + $creditmemoCollection = $objectManager->get('Magento\Sales\Model\Resource\Order\Creditmemo\Collection'); + $creditmemo = $creditmemoCollection->getFirstItem(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/creditmemo/' . $creditmemo->getId(), + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'notify', + ], + ]; + $requestData = ['id' => $creditmemo->getId()]; + $this->_webApiCall($serviceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoGetTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoGetTest.php new file mode 100644 index 0000000000000000000000000000000000000000..2e11ef7791c2c70bf02800040c6c7012f6690b35 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoGetTest.php @@ -0,0 +1,108 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class CreditmemoGetTest + */ +class CreditmemoGetTest extends WebapiAbstract +{ + /** + * Resource path + */ + const RESOURCE_PATH = '/V1/creditmemo'; + + /** + * Service read name + */ + const SERVICE_READ_NAME = 'salesCreditmemoRepositoryV1'; + + /** + * Service version + */ + const SERVICE_VERSION = 'V1'; + + /** + * Creditmemo id + */ + const CREDITMEMO_INCREMENT_ID = '100000001'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + /** + * Required fields are in the answer + * + * @var array + */ + protected $requiredFields = [ + 'entity_id', + 'store_id', + 'base_shipping_tax_amount', + 'base_discount_amount', + 'grand_total', + 'base_subtotal_incl_tax', + 'shipping_amount', + 'subtotal_incl_tax', + 'base_shipping_amount', + 'base_adjustment', + 'base_subtotal', + 'discount_amount', + 'subtotal', + 'adjustment', + 'base_grand_total', + 'base_tax_amount', + 'shipping_tax_amount', + 'tax_amount', + 'order_id', + 'state', + 'increment_id', + ]; + + /** + * Set up + */ + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Test creditmemo get service + * + * @magentoApiDataFixture Magento/Sales/_files/creditmemo_for_get.php + */ + public function testCreditmemoGet() + { + /** @var \Magento\Sales\Model\Resource\Order\Creditmemo\Collection $creditmemoCollection */ + $creditmemoCollection = $this->objectManager->get('Magento\Sales\Model\Resource\Order\Creditmemo\Collection'); + $creditmemo = $creditmemoCollection->getFirstItem(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $creditmemo->getId(), + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'get', + ], + ]; + + $actual = $this->_webApiCall($serviceInfo, ['id' => $creditmemo->getId()]); + $expected = $creditmemo->getData(); + + foreach ($this->requiredFields as $field) { + $this->assertArrayHasKey($field, $actual); + $this->assertEquals($expected[$field], $actual[$field]); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a3b4dd59b1c3aa67bd9a95791454e1f679f0f091 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoListTest.php @@ -0,0 +1,89 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class CreditmemoListTest + */ +class CreditmemoListTest extends WebapiAbstract +{ + /** + * Resource path + */ + const RESOURCE_PATH = '/V1/creditmemos'; + + /** + * Service read name + */ + const SERVICE_READ_NAME = 'salesCreditmemoRepositoryV1'; + + /** + * Service version + */ + const SERVICE_VERSION = 'V1'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + /** + * Set up + */ + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + } + + /** + * Test creditmemo list service + * + * @magentoApiDataFixture Magento/Sales/_files/creditmemo_with_list.php + */ + public function testCreditmemoList() + { + /** @var $searchCriteriaBuilder \Magento\Framework\Api\SearchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + + /** @var $filterBuilder \Magento\Framework\Api\FilterBuilder */ + $filterBuilder = $this->objectManager->create( + 'Magento\Framework\Api\FilterBuilder' + ); + + $searchCriteriaBuilder->addFilter( + [ + $filterBuilder + ->setField('state') + ->setValue(\Magento\Sales\Model\Order\Creditmemo::STATE_OPEN) + ->create(), + ] + ); + $searchData = $searchCriteriaBuilder->create()->__toArray(); + + $requestData = ['criteria' => $searchData]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '?' . http_build_query($requestData), + 'httpMethod' => Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'getList', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, $requestData); + // TODO Test fails, due to the inability of the framework API to handle data collection + $this->assertArrayHasKey('items', $result); + $this->assertCount(1, $result['items']); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceAddCommentTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceAddCommentTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d76ae8a2778065ca05e41abfeb374751362bb1b1 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceAddCommentTest.php @@ -0,0 +1,63 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\Sales\Api\Data\InvoiceCommentInterface; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class InvoiceAddCommentTest + */ +class InvoiceAddCommentTest extends WebapiAbstract +{ + /** + * Service read name + */ + const SERVICE_READ_NAME = 'salesInvoiceCommentRepositoryV1'; + + /** + * Service version + */ + const SERVICE_VERSION = 'V1'; + + /** + * Test invoice add comment service + * + * @magentoApiDataFixture Magento/Sales/_files/invoice.php + */ + public function testInvoiceAddComment() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Sales\Model\Order\Invoice $invoice */ + $invoiceCollection = $objectManager->get('Magento\Sales\Model\Resource\Order\Invoice\Collection'); + $invoice = $invoiceCollection->getFirstItem(); + + $commentData = [ + InvoiceCommentInterface::COMMENT => 'Hello world!', + InvoiceCommentInterface::ENTITY_ID => null, + InvoiceCommentInterface::CREATED_AT => null, + InvoiceCommentInterface::PARENT_ID => $invoice->getId(), + InvoiceCommentInterface::IS_VISIBLE_ON_FRONT => true, + InvoiceCommentInterface::IS_CUSTOMER_NOTIFIED => true, + ]; + + $requestData = ['entity' => $commentData]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/invoice/comment', + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'save', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertNotEmpty($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCaptureTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCaptureTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ca013830487ef16025c181088bdb332deb2d341d --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCaptureTest.php @@ -0,0 +1,43 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class InvoiceCaptureTest + */ +class InvoiceCaptureTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesInvoiceManagementV1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/invoice.php + * @expectedException \Exception + */ + public function testInvoiceCapture() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Sales\Model\Order\Invoice $invoice */ + $invoice = $objectManager->get('Magento\Sales\Model\Order\Invoice')->loadByIncrementId('100000001'); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/invoices/' . $invoice->getId() . '/capture', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'setCapture', + ], + ]; + $requestData = ['id' => $invoice->getId()]; + $this->_webApiCall($serviceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCommentsListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCommentsListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1c5d7a5f343763f7b936202216113d6a4fffd523 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCommentsListTest.php @@ -0,0 +1,56 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class InvoiceCommentsListTest + */ +class InvoiceCommentsListTest extends WebapiAbstract +{ + const SERVICE_NAME = 'salesInvoiceManagementV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/invoice.php + */ + public function testInvoiceCommentsList() + { + $comment = 'Test comment'; + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + /** @var \Magento\Sales\Model\Resource\Order\Invoice\Collection $invoiceCollection */ + $invoiceCollection = $objectManager->get('Magento\Sales\Model\Resource\Order\Invoice\Collection'); + $invoice = $invoiceCollection->getFirstItem(); + $invoiceComment = $objectManager->get('Magento\Sales\Model\Order\Invoice\Comment'); + $invoiceComment->setComment($comment); + $invoiceComment->setParentId($invoice->getId()); + $invoiceComment->save(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/invoice/' . $invoice->getId() . '/comments', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getCommentsList', + ], + ]; + $requestData = ['id' => $invoice->getId()]; + // TODO Test fails, due to the inability of the framework API to handle data collection + $result = $this->_webApiCall($serviceInfo, $requestData); + foreach ($result['items'] as $item) { + /** @var \Magento\Sales\Model\Order\Invoice\Comment $invoiceHistoryStatus */ + $invoiceHistoryStatus = $objectManager->get('Magento\Sales\Model\Order\Invoice\Comment') + ->load($item['entity_id']); + $this->assertEquals($invoiceHistoryStatus->getComment(), $item['comment']); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCreateTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCreateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..fc5600ccfa72e13126eb8608c06bafdcfbbcaa9e --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCreateTest.php @@ -0,0 +1,127 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class InvoiceCreateTest + */ +class InvoiceCreateTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/invoice'; + + const SERVICE_READ_NAME = 'salesInvoiceRepositoryV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testInvoke() + { + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->objectManager->create('Magento\Sales\Model\Order')->loadByIncrementId('100000001'); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'save', + ], + ]; + $orderItems = $order->getAllItems(); + $data = [ + 'order_id' => $order->getId(), + 'base_currency_code' => null, + 'base_discount_amount' => null, + 'base_grand_total' => null, + 'base_hidden_tax_amount' => null, + 'base_shipping_amount' => null, + 'base_shipping_hidden_tax_amnt' => null, + 'base_shipping_incl_tax' => null, + 'base_shipping_tax_amount' => null, + 'base_subtotal' => null, + 'base_subtotal_incl_tax' => null, + 'base_tax_amount' => null, + 'base_total_refunded' => null, + 'base_to_global_rate' => null, + 'base_to_order_rate' => null, + 'billing_address_id' => null, + 'can_void_flag' => null, + 'created_at' => null, + 'discount_amount' => null, + 'discount_description' => null, + 'email_sent' => null, + 'entity_id' => null, + 'global_currency_code' => null, + 'grand_total' => null, + 'hidden_tax_amount' => null, + 'increment_id' => null, + 'is_used_for_refund' => null, + 'order_currency_code' => null, + 'shipping_address_id' => null, + 'shipping_amount' => null, + 'shipping_hidden_tax_amount' => null, + 'shipping_incl_tax' => null, + 'shipping_tax_amount' => null, + 'state' => null, + 'store_currency_code' => null, + 'store_id' => null, + 'store_to_base_rate' => null, + 'store_to_order_rate' => null, + 'subtotal' => null, + 'subtotal_incl_tax' => null, + 'tax_amount' => null, + 'total_qty' => '1', + 'transaction_id' => null, + 'updated_at' => null, + 'items' => [ + [ + 'orderItemId' => $orderItems[0]->getId(), + 'qty' => 2, + 'additionalData' => null, + 'baseCost' => null, + 'baseDiscountAmount' => null, + 'baseHiddenTaxAmount' => null, + 'basePrice' => null, + 'basePriceInclTax' => null, + 'baseRowTotal' => null, + 'baseRowTotalInclTax' => null, + 'baseTaxAmount' => null, + 'description' => null, + 'discountAmount' => null, + 'hiddenTaxAmount' => null, + 'name' => null, + 'entity_id' => null, + 'parentId' => null, + 'price' => null, + 'priceInclTax' => null, + 'productId' => null, + 'rowTotal' => null, + 'rowTotalInclTax' => null, + 'sku' => 'sku' . uniqid(), + 'taxAmount' => null, + ], + ], + ]; + $result = $this->_webApiCall($serviceInfo, ['entity' => $data]); + $this->assertNotEmpty($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceEmailTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceEmailTest.php new file mode 100644 index 0000000000000000000000000000000000000000..51ab88ff60a70ef4fe80ac2e044e0a31d62482c0 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceEmailTest.php @@ -0,0 +1,42 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class InvoiceEmailTest + */ +class InvoiceEmailTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesInvoiceManagementV1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/invoice.php + */ + public function testInvoiceEmail() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $invoiceCollection = $objectManager->get('Magento\Sales\Model\Resource\Order\Invoice\Collection'); + $invoice = $invoiceCollection->getFirstItem(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/invoice/' . $invoice->getId() . '/email', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'notify', + ], + ]; + $requestData = ['id' => $invoice->getId()]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceGetTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceGetTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5de3f1ff0a5613431f7f9a158b684d343e4269b0 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceGetTest.php @@ -0,0 +1,52 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class InvoiceGetTest + */ +class InvoiceGetTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/invoice'; + + const SERVICE_READ_NAME = 'salesInvoiceRepositoryV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/invoice.php + */ + public function testInvoiceGet() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Sales\Model\Order\Invoice $invoice */ + $invoiceCollection = $objectManager->get('Magento\Sales\Model\Resource\Order\Invoice\Collection'); + $invoice = $invoiceCollection->getFirstItem(); + $expectedInvoiceData = [ + 'grand_total' => '100.0000', + 'subtotal' => '100.0000', + 'increment_id' => $invoice->getIncrementId(), + ]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $invoice->getId(), + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'get', + ], + ]; + $result = $this->_webApiCall($serviceInfo, ['id' => $invoice->getId()]); + foreach ($expectedInvoiceData as $field => $value) { + $this->assertArrayHasKey($field, $result); + $this->assertEquals($value, $result[$field]); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ea0565c64bb8827ddb81a3205ad9403080039b2e --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceListTest.php @@ -0,0 +1,74 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class InvoiceListTest + */ +class InvoiceListTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/invoices'; + + const SERVICE_READ_NAME = 'salesInvoiceRepositoryV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/invoice.php + */ + public function testInvoiceList() + { + /** @var $searchCriteriaBuilder \Magento\Framework\Api\SearchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + + /** @var $filterBuilder \Magento\Framework\Api\FilterBuilder */ + $filterBuilder = $this->objectManager->create( + 'Magento\Framework\Api\FilterBuilder' + ); + + $searchCriteriaBuilder->addFilter( + [ + $filterBuilder + ->setField('state') + ->setValue(2) + ->create(), + ] + ); + $searchData = $searchCriteriaBuilder->create()->__toArray(); + + $requestData = ['criteria' => $searchData]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '?' . http_build_query($requestData), + 'httpMethod' => Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'getList', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, $requestData); + // TODO Test fails, due to the inability of the framework API to handle data collection + $this->assertArrayHasKey('items', $result); + $this->assertCount(1, $result['items']); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceVoidTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceVoidTest.php new file mode 100644 index 0000000000000000000000000000000000000000..58fe16154eb46c0ffe815c40d09cec9e04dd8daa --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceVoidTest.php @@ -0,0 +1,43 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class InvoiceVoidTest + */ +class InvoiceVoidTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesInvoiceManagementV1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/invoice.php + * @expectedException \Exception + */ + public function testInvoiceVoid() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Sales\Model\Order\Invoice $invoice */ + $invoice = $objectManager->get('Magento\Sales\Model\Order\Invoice')->loadByIncrementId('100000001'); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/invoices/' . $invoice->getId() . '/void', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'setVoid', + ], + ]; + $requestData = ['id' => $invoice->getId()]; + $this->_webApiCall($serviceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderAddressUpdateTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderAddressUpdateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5b99a39ca69e65eba98805151947b4518633ef3a --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderAddressUpdateTest.php @@ -0,0 +1,96 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\Sales\Api\Data\OrderAddressInterface as OrderAddress; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class OrderAddressUpdateTest + */ +class OrderAddressUpdateTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesOrderAddressRepositoryV1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testOrderAddressUpdate() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Sales\Model\Order $order */ + $order = $objectManager->get('Magento\Sales\Model\Order')->loadByIncrementId('100000001'); + + $address = [ + OrderAddress::REGION => 'CA', + OrderAddress::POSTCODE => '11111', + OrderAddress::LASTNAME => 'lastname', + OrderAddress::STREET => ['street'], + OrderAddress::CITY => 'city', + OrderAddress::EMAIL => 'email@email.com', + OrderAddress::COMPANY => 'company', + OrderAddress::TELEPHONE => 't123456789', + OrderAddress::COUNTRY_ID => 'US', + OrderAddress::FIRSTNAME => 'firstname', + OrderAddress::ADDRESS_TYPE => 'billing', + OrderAddress::PARENT_ID => $order->getId(), + OrderAddress::ENTITY_ID => $order->getBillingAddressId(), + OrderAddress::CUSTOMER_ADDRESS_ID => null, + OrderAddress::CUSTOMER_ID => null, + OrderAddress::FAX => null, + OrderAddress::MIDDLENAME => null, + OrderAddress::PREFIX => null, + OrderAddress::QUOTE_ADDRESS_ID => null, + OrderAddress::REGION_ID => null, + OrderAddress::SUFFIX => null, + OrderAddress::VAT_ID => null, + OrderAddress::VAT_IS_VALID => null, + OrderAddress::VAT_REQUEST_DATE => null, + OrderAddress::VAT_REQUEST_ID => null, + OrderAddress::VAT_REQUEST_SUCCESS => null, + ]; + $requestData = ['entity' => $address]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $order->getId(), + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'save', + ], + ]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertGreaterThan(1, count($result)); + + /** @var \Magento\Sales\Model\Order $actualOrder */ + $actualOrder = $objectManager->get('Magento\Sales\Model\Order')->load($order->getId()); + $billingAddress = $actualOrder->getBillingAddress(); + + $validate = [ + OrderAddress::REGION => 'CA', + OrderAddress::POSTCODE => '11111', + OrderAddress::LASTNAME => 'lastname', + OrderAddress::STREET => 'street', + OrderAddress::CITY => 'city', + OrderAddress::EMAIL => 'email@email.com', + OrderAddress::COMPANY => 'company', + OrderAddress::TELEPHONE => 't123456789', + OrderAddress::COUNTRY_ID => 'US', + OrderAddress::FIRSTNAME => 'firstname', + OrderAddress::ADDRESS_TYPE => 'billing', + OrderAddress::PARENT_ID => $order->getId(), + OrderAddress::ENTITY_ID => $order->getBillingAddressId(), + ]; + foreach ($validate as $key => $field) { + $this->assertEquals($validate[$key], $billingAddress->getData($key)); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCancelTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCancelTest.php new file mode 100644 index 0000000000000000000000000000000000000000..39a1efd249f994ac443386cb2a06ba58b8fd379e --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCancelTest.php @@ -0,0 +1,39 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class OrderCancelTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesOrderManagementV1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testOrderCancel() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $order = $objectManager->get('Magento\Sales\Model\Order')->loadByIncrementId('100000001'); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $order->getId() . '/cancel', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'cancel', + ], + ]; + $requestData = ['id' => $order->getId()]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCommentsListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCommentsListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6137432d1634aa1fbdd4ec94869431b261d2ab6c --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCommentsListTest.php @@ -0,0 +1,49 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class OrderCommentsListTest extends WebapiAbstract +{ + const SERVICE_NAME = 'salesOrderManagementV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testOrderCommentsList() + { + $comment = 'Test comment'; + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + /** @var \Magento\Sales\Model\Order $order */ + $order = $objectManager->get('Magento\Sales\Model\Order')->loadByIncrementId('100000001'); + $history = $order->addStatusHistoryComment($comment, $order->getStatus()); + $history->save(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $order->getId() . '/comments', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getCommentsList', + ], + ]; + $requestData = ['id' => $order->getId()]; + $result = $this->_webApiCall($serviceInfo, $requestData); + foreach ($result['items'] as $history) { + $orderHistoryStatus = $objectManager->get('Magento\Sales\Model\Order\Status\History') + ->load($history['entity_id']); + $this->assertEquals($orderHistoryStatus->getComment(), $history['comment']); + $this->assertEquals($orderHistoryStatus->getStatus(), $history['status']); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9e7bd417de67b0830c41a8f81d38ba2a7254c574 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php @@ -0,0 +1,128 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\Sales\Api\Data\OrderInterface; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +class OrderCreateTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/order'; + + const SERVICE_READ_NAME = 'salesOrderRepositoryV1'; + + const SERVICE_VERSION = 'V1'; + + const ORDER_INCREMENT_ID = '100000001'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + protected function prepareOrder() + { + /** @var \Magento\Sales\Model\Order $orderBuilder */ + $orderFactory = $this->objectManager->get('Magento\Sales\Model\OrderFactory'); + /** @var \Magento\Sales\Service\V1\Data\OrderItemBuilder $orderItemBuilder */ + $orderItemFactory = $this->objectManager->get('Magento\Sales\Model\Order\ItemFactory'); + /** @var \Magento\Sales\Service\V1\Data\OrderPaymentBuilder $orderPaymentBuilder */ + $orderPaymentFactory = $this->objectManager->get('Magento\Sales\Model\Order\PaymentFactory'); + /** @var \Magento\Sales\Service\V1\Data\OrderAddressBuilder $orderAddressBuilder */ + $orderAddressFactory = $this->objectManager->get('Magento\Sales\Model\Order\AddressFactory'); + + $order = $orderFactory->create( + ['data' => $this->getDataStructure('Magento\Sales\Api\Data\OrderInterface')] + ); + $orderItem = $orderItemFactory->create( + ['data' => $this->getDataStructure('Magento\Sales\Api\Data\OrderItemInterface')] + ); + $orderPayment = $orderPaymentFactory->create( + ['data' => $this->getDataStructure('Magento\Sales\Api\Data\OrderPaymentInterface')] + ); + $orderAddressBilling = $orderAddressFactory->create( + ['data' => $this->getDataStructure('Magento\Sales\Api\Data\OrderAddressInterface')] + ); + + $email = uniqid() . 'email@example.com'; + $orderItem->setSku('sku#1'); + $orderPayment->setCcLast4('4444'); + $orderPayment->setMethod('checkmo'); + $orderPayment->setAccountStatus('ok'); + $orderPayment->setAdditionalInformation([]); + $order->setCustomerEmail($email); + $order->setBaseGrandTotal(100); + $order->setGrandTotal(100); + $order->setItems([$orderItem->getData()]); + $order->setPayments([$orderPayment->getData()]); + $orderAddressBilling->setCity('City'); + $orderAddressBilling->setPostcode('12345'); + $orderAddressBilling->setLastname('Last Name'); + $orderAddressBilling->setFirstname('First Name'); + $orderAddressBilling->setTelephone('+00(000)-123-45-57'); + $orderAddressBilling->setStreet(['Street']); + $orderAddressBilling->setCountryId(1); + $orderAddressBilling->setAddressType('billing'); + + $orderAddressShipping = $orderAddressFactory->create( + ['data' => $this->getDataStructure('Magento\Sales\Api\Data\OrderAddressInterface')] + ); + $orderAddressShipping->setCity('City'); + $orderAddressShipping->setPostcode('12345'); + $orderAddressShipping->setLastname('Last Name'); + $orderAddressShipping->setFirstname('First Name'); + $orderAddressShipping->setTelephone('+00(000)-123-45-57'); + $orderAddressShipping->setStreet(['Street']); + $orderAddressShipping->setCountryId(1); + $orderAddressShipping->setAddressType('shipping'); + + $orderData = $order->getData(); + $orderData['billing_address'] = $orderAddressBilling->getData(); + $orderData['billing_address']['street'] = ['Street']; + $orderData['shipping_address'] = $orderAddressShipping->getData(); + $orderData['shipping_address']['street'] = ['Street']; + return $orderData; + } + + protected function getDataStructure($className) + { + $refClass = new \ReflectionClass($className); + $constants = $refClass->getConstants(); + $data = array_fill_keys($constants, null); + unset($data['custom_attributes']); + return $data; + } + + public function testOrderCreate() + { + $order = $this->prepareOrder(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'save', + ], + ]; + $this->assertNotEmpty($this->_webApiCall($serviceInfo, ['entity' => $order])); + + /** @var \Magento\Sales\Model\Order $model */ + $model = $this->objectManager->get('Magento\Sales\Model\Order'); + $model->load($order['customer_email'], 'customer_email'); + $this->assertTrue((bool)$model->getId()); + $this->assertEquals($order['base_grand_total'], $model->getBaseGrandTotal()); + $this->assertEquals($order['grand_total'], $model->getGrandTotal()); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderEmailTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderEmailTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3bdb00820ba4a8b0e04114158db4b0b1c08cb56d --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderEmailTest.php @@ -0,0 +1,39 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class OrderEmailTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesOrderManagementV1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testOrderEmail() + { + $order = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create('Magento\Sales\Model\Order'); + $order->loadByIncrementId('100000001'); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $order->getId() . '/email', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'notify', + ], + ]; + $requestData = ['id' => $order->getId()]; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetStatusTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetStatusTest.php new file mode 100644 index 0000000000000000000000000000000000000000..97786a34970d133736c29c08e0651d67853f8b01 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetStatusTest.php @@ -0,0 +1,57 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class OrderGetStatusTest + * @package Magento\Sales\Service\V1 + */ +class OrderGetStatusTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/order/%d/status'; + + const SERVICE_READ_NAME = 'salesOrderManagementV1'; + + const SERVICE_VERSION = 'V1'; + + const ORDER_INCREMENT_ID = '100000001'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testOrderGetStatus() + { + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->objectManager->create('Magento\Sales\Model\Order'); + $order->loadByIncrementId(self::ORDER_INCREMENT_ID); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => sprintf(self::RESOURCE_PATH, $order->getId()), + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'getStatus', + ], + ]; + + $this->assertEquals($order->getStatus(), $this->_webApiCall($serviceInfo, ['id' => $order->getId()])); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d9421a9d4cd50a8e36eec50bb4c683595ee4607c --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php @@ -0,0 +1,89 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +class OrderGetTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/order'; + + const SERVICE_READ_NAME = 'salesOrderRepositoryV1'; + + const SERVICE_VERSION = 'V1'; + + const ORDER_INCREMENT_ID = '100000001'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testOrderGet() + { + $expectedOrderData = [ + 'base_subtotal' => '100.0000', + 'subtotal' => '100.0000', + 'customer_is_guest' => '1', + 'increment_id' => self::ORDER_INCREMENT_ID, + ]; + $expectedPayments = ['method' => 'checkmo']; + $expectedBillingAddressNotEmpty = [ + 'city', + 'postcode', + 'lastname', + 'street', + 'region', + 'telephone', + 'country_id', + 'firstname', + ]; + + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->objectManager->create('Magento\Sales\Model\Order'); + $order->loadByIncrementId(self::ORDER_INCREMENT_ID); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $order->getId(), + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'get', + ], + ]; + $result = $this->_webApiCall($serviceInfo, ['id' => $order->getId()]); + + foreach ($expectedOrderData as $field => $value) { + $this->assertArrayHasKey($field, $result); + $this->assertEquals($value, $result[$field]); + } + + $this->assertArrayHasKey('payments', $result); + foreach ($expectedPayments as $field => $value) { + $paymentsKey = key($result['payments']); + $this->assertArrayHasKey($field, $result['payments'][$paymentsKey]); + $this->assertEquals($value, $result['payments'][$paymentsKey][$field]); + } + + $this->assertArrayHasKey('billing_address', $result); + $this->assertArrayHasKey('shipping_address', $result); + foreach ($expectedBillingAddressNotEmpty as $field) { + $this->assertArrayHasKey($field, $result['billing_address']); + $this->assertArrayHasKey($field, $result['shipping_address']); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderHoldTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderHoldTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a8bdc8e78a42170050fe7299415690abaf88be6a --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderHoldTest.php @@ -0,0 +1,39 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class OrderHoldTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesOrderManagementV1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testOrderHold() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $order = $objectManager->get('Magento\Sales\Model\Order')->loadByIncrementId('100000001'); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $order->getId() . '/hold', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'hold', + ], + ]; + $requestData = ['id' => $order->getId()]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a0d9743fdbc4bca93211cc3bd2d97b6887556895 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderListTest.php @@ -0,0 +1,74 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class OrderListTest + * @package Magento\Sales\Service\V1 + */ +class OrderListTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/orders'; + + const SERVICE_READ_NAME = 'salesOrderRepositoryV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testOrderList() + { + /** @var $searchCriteriaBuilder \Magento\Framework\Api\SearchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + + /** @var $filterBuilder \Magento\Framework\Api\FilterBuilder */ + $filterBuilder = $this->objectManager->create( + 'Magento\Framework\Api\FilterBuilder' + ); + + $searchCriteriaBuilder->addFilter( + [ + $filterBuilder + ->setField('status') + ->setValue('processing') + ->create(), + ] + ); + $searchData = $searchCriteriaBuilder->create()->__toArray(); + + $requestData = ['criteria' => $searchData]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '?' . http_build_query($requestData), + 'httpMethod' => Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'getList', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertArrayHasKey('items', $result); + $this->assertCount(1, $result['items']); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderStatusHistoryAddTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderStatusHistoryAddTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c9a46103a9c033ea8958f4ab373c16bea9519d89 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderStatusHistoryAddTest.php @@ -0,0 +1,83 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\Sales\Api\Data\OrderStatusHistoryInterface; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class OrderCommentAddTest + * @package Magento\Sales\Service\V1 + */ +class OrderStatusHistoryAddTest extends WebapiAbstract +{ + const SERVICE_READ_NAME = 'salesOrderManagementV1'; + + const SERVICE_VERSION = 'V1'; + + const ORDER_INCREMENT_ID = '100000001'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testOrderCommentAdd() + { + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->objectManager->create('Magento\Sales\Model\Order'); + $order->loadByIncrementId(self::ORDER_INCREMENT_ID); + + $commentData = [ + OrderStatusHistoryInterface::COMMENT => 'Hello', + OrderStatusHistoryInterface::ENTITY_ID => null, + OrderStatusHistoryInterface::IS_CUSTOMER_NOTIFIED => true, + OrderStatusHistoryInterface::CREATED_AT => null, + OrderStatusHistoryInterface::PARENT_ID => $order->getId(), + OrderStatusHistoryInterface::ENTITY_NAME => null, + OrderStatusHistoryInterface::STATUS => null, + OrderStatusHistoryInterface::IS_VISIBLE_ON_FRONT => true, + ]; + + $requestData = ['id' => $order->getId(), 'statusHistory' => $commentData]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $order->getId() . '/comment', + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'addComment', + ], + ]; + + $this->_webApiCall($serviceInfo, $requestData); + + //Verification + $comments = $order->load($order->getId())->getAllStatusHistory(); + + $commentData = reset($comments); + foreach ($commentData as $key => $value) { + $this->assertEquals($commentData[OrderStatusHistoryInterface::COMMENT], $statusHistoryComment->getComment()); + $this->assertEquals($commentData[OrderStatusHistoryInterface::PARENT_ID], $statusHistoryComment->getParentId()); + $this->assertEquals( + $commentData[OrderStatusHistoryInterface::IS_CUSTOMER_NOTIFIED], $statusHistoryComment->getIsCustomerNotified() + ); + $this->assertEquals( + $commentData[OrderStatusHistoryInterface::IS_VISIBLE_ON_FRONT], $statusHistoryComment->getIsVisibleOnFront() + ); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderUnHoldTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderUnHoldTest.php new file mode 100644 index 0000000000000000000000000000000000000000..41d877f25b75d03ae86929389cc008c932243e24 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderUnHoldTest.php @@ -0,0 +1,43 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class OrderUnHoldTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesOrderManagementV1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testOrderUnHold() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Sales\Model\Order $order */ + $order = $objectManager->get('Magento\Sales\Model\Order')->loadByIncrementId('100000001'); + if ($order->canHold()) { + $order->hold()->save(); + } + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $order->getId() . '/unhold', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'unHold', + ], + ]; + $requestData = ['id' => $order->getId()]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentAddCommentTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentAddCommentTest.php new file mode 100644 index 0000000000000000000000000000000000000000..dbdd8768fcedf49aa9c13e2c5eb55468c3c3e597 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentAddCommentTest.php @@ -0,0 +1,77 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\Sales\Api\Data\ShipmentCommentInterface; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class ShipmentAddCommentTest + */ +class ShipmentAddCommentTest extends WebapiAbstract +{ + /** + * Service read name + */ + const SERVICE_READ_NAME = 'salesShipmentCommentRepositoryV1'; + + /** + * Service version + */ + const SERVICE_VERSION = 'V1'; + + /** + * Shipment increment id + */ + const SHIPMENT_INCREMENT_ID = '100000001'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Test shipment add comment service + * + * @magentoApiDataFixture Magento/Sales/_files/shipment.php + */ + public function testShipmentAddComment() + { + /** @var \Magento\Sales\Model\Resource\Order\Shipment\Collection $shipmentCollection */ + $shipmentCollection = $this->objectManager->get('Magento\Sales\Model\Resource\Order\Shipment\Collection'); + $shipment = $shipmentCollection->getFirstItem(); + + $commentData = [ + ShipmentCommentInterface::COMMENT => 'Hello world!', + ShipmentCommentInterface::ENTITY_ID => null, + ShipmentCommentInterface::CREATED_AT => null, + ShipmentCommentInterface::PARENT_ID => $shipment->getId(), + ShipmentCommentInterface::IS_VISIBLE_ON_FRONT => true, + ShipmentCommentInterface::IS_CUSTOMER_NOTIFIED => true, + ]; + + $requestData = ['entity' => $commentData]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/shipment/comment', + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'save', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertNotEmpty($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentAddTrackTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentAddTrackTest.php new file mode 100644 index 0000000000000000000000000000000000000000..af1e624793ab4adf4db0d05c5d0ce53efadbfb7a --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentAddTrackTest.php @@ -0,0 +1,83 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\Sales\Api\Data\ShipmentTrackInterface; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class ShipmentAddTrackTest + */ +class ShipmentAddTrackTest extends WebapiAbstract +{ + /** + * Service read name + */ + const SERVICE_READ_NAME = 'salesShipmentTrackRepositoryV1'; + + /** + * Service version + */ + const SERVICE_VERSION = 'V1'; + + /** + * Shipment increment id + */ + const SHIPMENT_INCREMENT_ID = '100000001'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Test shipment add track service + * + * @magentoApiDataFixture Magento/Sales/_files/shipment.php + */ + public function testShipmentAddTrack() + { + /** @var \Magento\Sales\Model\Order\Shipment $shipment */ + $shipmentCollection = $this->objectManager->get('Magento\Sales\Model\Resource\Order\Shipment\Collection'); + $shipment = $shipmentCollection->getFirstItem(); + + $trackData = [ + ShipmentTrackInterface::ENTITY_ID => null, + ShipmentTrackInterface::ORDER_ID => $shipment->getOrderId(), + ShipmentTrackInterface::CREATED_AT => null, + ShipmentTrackInterface::PARENT_ID => $shipment->getId(), + ShipmentTrackInterface::WEIGHT => 20, + ShipmentTrackInterface::QTY => 5, + ShipmentTrackInterface::TRACK_NUMBER => 2, + ShipmentTrackInterface::DESCRIPTION => 'Shipment description', + ShipmentTrackInterface::TITLE => 'Shipment title', + ShipmentTrackInterface::CARRIER_CODE => \Magento\Sales\Model\Order\Shipment\Track::CUSTOM_CARRIER_CODE, + ShipmentTrackInterface::CREATED_AT => null, + ShipmentTrackInterface::UPDATED_AT => null, + ]; + + $requestData = ['entity' => $trackData]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/shipment/track', + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'save', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertNotEmpty($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentCommentsListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentCommentsListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ea79127aee85f7b1a81369f6671c90e2afa7020c --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentCommentsListTest.php @@ -0,0 +1,56 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class ShipmentCommentsListTest + */ +class ShipmentCommentsListTest extends WebapiAbstract +{ + const SERVICE_NAME = 'salesShipmentManagementV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/shipment.php + */ + public function testShipmentCommentsList() + { + $comment = 'Test comment'; + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + /** @var \Magento\Sales\Model\Resource\Order\Shipment\Collection $shipmentCollection */ + $shipmentCollection = $objectManager->get('Magento\Sales\Model\Resource\Order\Shipment\Collection'); + $shipment = $shipmentCollection->getFirstItem(); + $shipmentComment = $objectManager->get('Magento\Sales\Model\Order\Shipment\Comment'); + $shipmentComment->setComment($comment); + $shipmentComment->setParentId($shipment->getId()); + $shipmentComment->save(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/shipment/' . $shipment->getId() . '/comments', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'getCommentsList', + ], + ]; + $requestData = ['id' => $shipment->getId()]; + $result = $this->_webApiCall($serviceInfo, $requestData); + // TODO Test fails, due to the inability of the framework API to handle data collection + foreach ($result['items'] as $item) { + /** @var \Magento\Sales\Model\Order\Shipment\Comment $shipmentHistoryStatus */ + $shipmentHistoryStatus = $objectManager->get('Magento\Sales\Model\Order\Shipment\Comment') + ->load($item['entity_id']); + $this->assertEquals($shipmentHistoryStatus->getComment(), $item['comment']); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentCreateTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentCreateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b73cd43ee8299cdf7e612e755928cf4043315af9 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentCreateTest.php @@ -0,0 +1,88 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class ShipmentCreateTest + */ +class ShipmentCreateTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/shipment'; + + const SERVICE_READ_NAME = 'salesShipmentRepositoryV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + /** + * @magentoApiDataFixture Magento/Sales/_files/order.php + */ + public function testInvoke() + { + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->objectManager->create('Magento\Sales\Model\Order')->loadByIncrementId('100000001'); + $orderItem = current($order->getAllItems()); + $items = [ + [ + 'order_item_id' => $orderItem->getId(), + 'qty' => $orderItem->getQtyOrdered(), + 'additional_data' => null, + 'description' => null, + 'entity_id' => null, + 'name' => null, + 'parent_id' => null, + 'price' => null, + 'product_id' => null, + 'row_total' => null, + 'sku' => null, + 'weight' => null, + ], + ]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'save', + ], + ]; + $data = [ + 'order_id' => $order->getId(), + 'entity_id' => null, + 'store_id' => null, + 'total_weight' => null, + 'total_qty' => null, + 'email_sent' => null, + 'customer_id' => null, + 'shipping_address_id' => null, + 'billing_address_id' => null, + 'shipment_status' => null, + 'increment_id' => null, + 'created_at' => null, + 'updated_at' => null, +// 'packages' => null, + 'shipping_label' => null, + 'tracks' => [], + 'items' => $items, + 'comments' => [], + ]; + $result = $this->_webApiCall($serviceInfo, ['entity' => $data]); + $this->assertNotEmpty($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentEmailTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentEmailTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3329e8addf061b734d575a3a99883897ae1e8d4c --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentEmailTest.php @@ -0,0 +1,43 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class ShipmentEmailTest + */ +class ShipmentEmailTest extends WebapiAbstract +{ + const SERVICE_VERSION = 'V1'; + + const SERVICE_NAME = 'salesShipmentManagementV1'; + + /** + * @magentoApiDataFixture Magento/Sales/_files/shipment.php + */ + public function testShipmentEmail() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $shipmentCollection = $objectManager->get('Magento\Sales\Model\Resource\Order\Shipment\Collection'); + $shipment = $shipmentCollection->getFirstItem(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/shipment/' . $shipment->getId() . '/email', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'notify', + ], + ]; + $requestData = ['id' => $shipment->getId()]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentGetTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentGetTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5bc2a21698d8dedd25c4b0f6100d21bd9d446bef --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentGetTest.php @@ -0,0 +1,76 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class ShipmentGetTest + */ +class ShipmentGetTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/shipment'; + const SERVICE_READ_NAME = 'salesShipmentRepositoryV1'; + const SERVICE_VERSION = 'V1'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/shipment.php + */ + public function testShipmentGet() + { + /** @var \Magento\Sales\Model\Order\Shipment $shipment */ + $shipmentCollection = $this->objectManager->get('Magento\Sales\Model\Resource\Order\Shipment\Collection'); + $shipment = $shipmentCollection->getFirstItem(); + $shipment->load($shipment->getId()); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $shipment->getId(), + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'get', + ], + ]; + $result = $this->_webApiCall($serviceInfo, ['id' => $shipment->getId()]); + $data = $result; + $this->assertArrayHasKey('items', $result); + $this->assertArrayHasKey('tracks', $result); + unset($data['items']); + unset($data['packages']); + unset($data['tracks']); + foreach ($data as $key => $value) { + if (!empty($value)) { + $this->assertEquals($shipment->getData($key), $value, $key); + } + } + $shipmentItem = $this->objectManager->get('Magento\Sales\Model\Order\Shipment\Item'); + foreach ($result['items'] as $item) { + $shipmentItem->load($item['entity_id']); + foreach ($item as $key => $value) { + $this->assertEquals($shipmentItem->getData($key), $value, $key); + } + } + $shipmentTrack = $this->objectManager->get('Magento\Sales\Model\Order\Shipment\Track'); + foreach ($result['tracks'] as $item) { + $shipmentTrack->load($item['entity_id']); + foreach ($item as $key => $value) { + $this->assertEquals($shipmentTrack->getData($key), $value, $key); + } + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentLabelGetTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentLabelGetTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f03bad65a110117b8bdbf1f2e199047862f01ffc --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentLabelGetTest.php @@ -0,0 +1,53 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class ShipmentLabelGetTest + */ +class ShipmentLabelGetTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/shipment'; + const SERVICE_READ_NAME = 'salesShipmentManagementV1'; + const SERVICE_VERSION = 'V1'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/shipment.php + */ + public function testShipmentGet() + { + /** @var \Magento\Sales\Model\Order\Shipment $shipment */ + $shipmentCollection = $this->objectManager->get('Magento\Sales\Model\Resource\Order\Shipment\Collection'); + $shipment = $shipmentCollection->getFirstItem(); + $shipment->setShippingLabel('test_shipping_label'); + $shipment->save(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $shipment->getId() . '/label', + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'getLabel', + ], + ]; + $result = $this->_webApiCall($serviceInfo, ['id' => $shipment->getId()]); + $this->assertEquals($result, 'test_shipping_label'); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentListTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b68d6900eab7879332577843259123c8465b4f2a --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentListTest.php @@ -0,0 +1,67 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class ShipmentListTest + */ +class ShipmentListTest extends WebapiAbstract +{ + const RESOURCE_PATH = '/V1/shipments'; + + const SERVICE_READ_NAME = 'salesShipmentRepositoryV1'; + + const SERVICE_VERSION = 'V1'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/shipment.php + */ + public function testShipmentList() + { + /** @var $searchCriteriaBuilder \Magento\Framework\Api\SearchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + + /** @var $filterBuilder \Magento\Framework\Api\FilterBuilder */ + $filterBuilder = $this->objectManager->create( + 'Magento\Framework\Api\FilterBuilder' + ); + + $searchCriteriaBuilder->addFilter([$filterBuilder->setField('shipment_status')->setValue(1)->create()]); + $searchData = $searchCriteriaBuilder->create()->__toArray(); + + $requestData = ['criteria' => $searchData]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '?' . http_build_query($requestData), + 'httpMethod' => Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'getList', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, $requestData); + // TODO Test fails, due to the inability of the framework API to handle data collection + $this->assertArrayHasKey('items', $result); + $this->assertCount(1, $result['items']); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentRemoveTrackTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentRemoveTrackTest.php new file mode 100644 index 0000000000000000000000000000000000000000..4dc7637b37de6588e998f919d7d1e8c00f6ba0fe --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentRemoveTrackTest.php @@ -0,0 +1,87 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Sales\Service\V1; + +use Magento\Sales\Api\Data\ShipmentTrackInterface; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class ShipmentRemoveTrackTest + */ +class ShipmentRemoveTrackTest extends WebapiAbstract +{ + /** + * Service read name + */ + const SERVICE_READ_NAME = 'salesShipmentTrackRepositoryV1'; + + /** + * Service version + */ + const SERVICE_VERSION = 'V1'; + + /** + * Shipment increment id + */ + const SHIPMENT_INCREMENT_ID = '100000001'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Test shipment remove track service + * + * @magentoApiDataFixture Magento/Sales/_files/shipment.php + */ + public function testShipmentRemoveTrack() + { + /** @var \Magento\Sales\Model\Order\Shipment $shipment */ + $shipmentCollection = $this->objectManager->get('Magento\Sales\Model\Resource\Order\Shipment\Collection'); + $shipment = $shipmentCollection->getFirstItem(); + + /** @var \Magento\Sales\Model\Order\Shipment\Track $track */ + $track = $this->objectManager->create('Magento\Sales\Model\Order\Shipment\TrackFactory')->create(); + $track->addData( + [ + ShipmentTrackInterface::ENTITY_ID => null, + ShipmentTrackInterface::ORDER_ID => 12, + ShipmentTrackInterface::CREATED_AT => null, + ShipmentTrackInterface::PARENT_ID => $shipment->getId(), + ShipmentTrackInterface::WEIGHT => 20, + ShipmentTrackInterface::QTY => 5, + ShipmentTrackInterface::TRACK_NUMBER => 2, + ShipmentTrackInterface::DESCRIPTION => 'Shipment description', + ShipmentTrackInterface::TITLE => 'Shipment title', + ShipmentTrackInterface::CARRIER_CODE => \Magento\Sales\Model\Order\Shipment\Track::CUSTOM_CARRIER_CODE, + ShipmentTrackInterface::CREATED_AT => null, + ShipmentTrackInterface::UPDATED_AT => null, + ] + ); + $track->save(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/shipment/track/' . $track->getId(), + 'httpMethod' => Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'deleteById', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, ['id' => $track->getId()]); + $this->assertNotEmpty($result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/TransactionTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/TransactionTest.php new file mode 100644 index 0000000000000000000000000000000000000000..2138fd6a6afa7ec3085fcdd5d89f80004551d2fa --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/TransactionTest.php @@ -0,0 +1,190 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Sales\Service\V1; + +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Payment; +use Magento\Sales\Model\Order\Payment\Transaction; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config; + +/** + * Class TransactionReadTest + */ +class TransactionTest extends WebapiAbstract +{ + /** + * Service read name + */ + const SERVICE_READ_NAME = 'salesTransactionRepositoryV1'; + + /** + * Resource path for REST + */ + const RESOURCE_PATH = '/V1/transactions'; + + /** + * Service version + */ + const SERVICE_VERSION = 'V1'; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Tests list of order transactions + * + * @magentoApiDataFixture Magento/Sales/_files/transactions_detailed.php + */ + public function testTransactionGet() + { + /** @var Order $order */ + $order = $this->objectManager->create('Magento\Sales\Model\Order'); + $order->loadByIncrementId('100000006'); + + /** @var Payment $payment */ + $payment = $order->getPayment(); + /** @var Transaction $transaction */ + $transaction = $payment->getTransaction('trx_auth'); + + $childTransactions = $transaction->getChildTransactions(); + $childTransaction = reset($childTransactions); + + $expectedData = $this->getPreparedTransactionData($transaction); + $childTransactionData = $this->getPreparedTransactionData($childTransaction); + $expectedData['child_transactions'][] = $childTransactionData; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $transaction->getId(), + 'httpMethod' => Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'get', + ], + ]; + $result = $this->_webApiCall($serviceInfo, ['id' => $transaction->getId()]); + ksort($expectedData); + ksort($result); + $this->assertEquals($expectedData, $result); + } + + /** + * Tests list of order transactions + * @dataProvider filtersDataProvider + */ + public function testTransactionList($filters) + { + /** @var Order $order */ + $order = $this->objectManager->create('Magento\Sales\Model\Order'); + $order->loadByIncrementId('100000006'); + + /** @var Payment $payment */ + $payment = $order->getPayment(); + /** @var Transaction $transaction */ + $transaction = $payment->getTransaction('trx_auth'); + + $childTransactions = $transaction->getChildTransactions(); + + $childTransaction = reset($childTransactions); + + /** @var $searchCriteriaBuilder \Magento\Framework\Api\SearchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + + $searchCriteriaBuilder->addFilter($filters); + $searchData = $searchCriteriaBuilder->create()->__toArray(); + + $requestData = ['criteria' => $searchData]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '?' . http_build_query($requestData), + 'httpMethod' => Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'getList', + ], + ]; + $result = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertArrayHasKey('items', $result); + + $transactionData = $this->getPreparedTransactionData($transaction); + $childTransactionData = $this->getPreparedTransactionData($childTransaction); + $transactionData['child_transactions'][] = $childTransactionData; + $expectedData = [$transactionData, $childTransactionData]; + + $this->assertEquals($expectedData, $result['items']); + } + + /** + * @param Transaction $transaction + * @return array + */ + private function getPreparedTransactionData(Transaction $transaction) + { + $additionalInfo = []; + foreach ($transaction->getAdditionalInformation() as $value) { + $additionalInfo[] = $value; + } + + $expectedData = ['transaction_id' => (int)$transaction->getId()]; + + if (!is_null($transaction->getParentId())) { + $expectedData['parent_id'] = (int)$transaction->getParentId(); + } + + $expectedData = array_merge( + $expectedData, + [ + 'order_id' => (int)$transaction->getOrderId(), + 'payment_id' => (int)$transaction->getPaymentId(), + 'txn_id' => $transaction->getTxnId(), + 'parent_txn_id' => ($transaction->getParentTxnId() ? (string)$transaction->getParentTxnId() : ''), + 'txn_type' => $transaction->getTxnType(), + 'is_closed' => (int)$transaction->getIsClosed(), + 'additional_information' => ['data'], + 'created_at' => $transaction->getCreatedAt(), + 'child_transactions' => [], + ] + ); + + return $expectedData; + } + + /** + * @return array + */ + public function filtersDataProvider() + { + /** @var $filterBuilder \Magento\Framework\Api\FilterBuilder */ + $filterBuilder = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\FilterBuilder' + ); + + return [ + [ + [ + $filterBuilder->setField('created_at')->setValue('2020-12-12 00:00:00') + ->setConditionType('lteq')->create(), + ], + ] + ]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxClassRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxClassRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..4a462cbc3fb321bcc0447c9e4dda6aef70c33633 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxClassRepositoryTest.php @@ -0,0 +1,309 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Tax\Api; + +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Tax\Api\Data\TaxClassDataBuilder; +use Magento\Tax\Model\ClassModelRegistry; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Tests for tax class service. + */ +class TaxClassRepositoryTest extends WebapiAbstract +{ + const SERVICE_NAME = 'taxTaxClassRepositoryV1'; + const SERVICE_VERSION = 'V1'; + const RESOURCE_PATH = '/V1/taxClass'; + + /** @var SearchCriteriaBuilder */ + private $searchCriteriaBuilder; + + /** @var FilterBuilder */ + private $filterBuilder; + + /** @var TaxClassDataBuilder */ + private $taxClassBuilder; + + /** @var TaxClassRepositoryInterface */ + private $taxClassRepository; + + /** @var ClassModelRegistry */ + private $taxClassRegistry; + + const SAMPLE_TAX_CLASS_NAME = 'Wholesale Customer'; + + /** + * Execute per test initialization. + */ + public function setUp() + { + $this->searchCriteriaBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + $this->filterBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\FilterBuilder' + ); + $this->taxClassBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Tax\Api\Data\TaxClassDataBuilder' + ); + $this->taxClassRegistry = Bootstrap::getObjectManager()->create( + 'Magento\Tax\Model\ClassModelRegistry' + ); + $this->taxClassRepository = Bootstrap::getObjectManager()->create( + 'Magento\Tax\Model\TaxClass\Repository', + ['classModelRegistry' => $this->taxClassRegistry] + ); + } + + /** + * Test create Data\TaxClassInterface + */ + public function testCreateTaxClass() + { + $taxClassName = self::SAMPLE_TAX_CLASS_NAME . uniqid(); + /** @var \Magento\Tax\Api\Data\TaxClassInterface $taxClassDataObject */ + $taxClassDataObject = $this->taxClassBuilder->setClassName($taxClassName) + ->setClassType(TaxClassManagementInterface::TYPE_CUSTOMER) + ->create(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $requestData = ['taxClass' => [ + 'class_id' => $taxClassDataObject->getClassId(), + 'class_name' => $taxClassDataObject->getClassName(), + 'class_type' => $taxClassDataObject->getClassType(), + ], + ]; + $taxClassId = $this->_webApiCall($serviceInfo, $requestData); + $this->assertNotNull($taxClassId); + + //Verify by getting the Data\TaxClassInterface + $taxClassData = $this->taxClassRepository->get($taxClassId); + $this->assertEquals($taxClassData->getClassName(), $taxClassName); + $this->assertEquals($taxClassData->getClassType(), TaxClassManagementInterface::TYPE_CUSTOMER); + } + + /** + * Test create Data\TaxClassInterface + */ + public function testUpdateTaxClass() + { + //Create Tax Class + $taxClassDataObject = $this->taxClassBuilder->setClassName(self::SAMPLE_TAX_CLASS_NAME . uniqid()) + ->setClassType(TaxClassManagementInterface::TYPE_CUSTOMER) + ->create(); + $taxClassId = $this->taxClassRepository->save($taxClassDataObject); + $this->assertNotNull($taxClassId); + + //Update Tax Class + $updatedTaxClassName = self::SAMPLE_TAX_CLASS_NAME . uniqid(); + $updatedTaxClassDataObject = $this->taxClassBuilder + ->populate($taxClassDataObject) + ->setClassName($updatedTaxClassName) + ->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $taxClassId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $taxClass = [ + 'class_id' => $updatedTaxClassDataObject->getClassId(), + 'class_name' => $updatedTaxClassDataObject->getClassName(), + 'class_type' => $updatedTaxClassDataObject->getClassType(), + ]; + + $requestData = ['taxClass' => $taxClass, 'ClassId' => $taxClassId]; + + $this->assertEquals($taxClassId, $this->_webApiCall($serviceInfo, $requestData)); + + //Verify by getting the Data\TaxClassInterface + $this->taxClassRegistry->remove($taxClassId); + $taxClassData = $this->taxClassRepository->get($taxClassId); + $this->assertEquals($taxClassData->getClassName(), $updatedTaxClassName); + } + + public function testGetTaxClass() + { + //Create Tax Class + $taxClassName = self::SAMPLE_TAX_CLASS_NAME . uniqid(); + $taxClassDataObject = $this->taxClassBuilder->setClassName($taxClassName) + ->setClassType(TaxClassManagementInterface::TYPE_CUSTOMER) + ->create(); + $taxClassId = $this->taxClassRepository->save($taxClassDataObject); + $this->assertNotNull($taxClassId); + + //Verify by getting the Data\TaxClassInterface + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $taxClassId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + $requestData = ['taxClassId' => $taxClassId]; + $taxClassData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($taxClassData[Data\TaxClassInterface::KEY_NAME], $taxClassName); + $this->assertEquals( + $taxClassData[Data\TaxClassInterface::KEY_TYPE], + TaxClassManagementInterface::TYPE_CUSTOMER + ); + } + + /** + * Test delete Tax class + */ + public function testDeleteTaxClass() + { + $taxClassDataObject = $this->taxClassBuilder->setClassName(self::SAMPLE_TAX_CLASS_NAME . uniqid()) + ->setClassType(TaxClassManagementInterface::TYPE_CUSTOMER) + ->create(); + $taxClassId = $this->taxClassRepository->save($taxClassDataObject); + $this->assertNotNull($taxClassId); + + //Verify by getting the Data\TaxClassInterface + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $taxClassId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ]; + $requestData = ['taxClassId' => $taxClassId]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($result); + + try { + $this->taxClassRegistry->remove($taxClassId); + $this->taxClassRepository->get($taxClassId); + $this->fail("Tax class was not expected to be returned after being deleted."); + } catch (NoSuchEntityException $e) { + $this->assertEquals('No such entity with class_id = ' . $taxClassId, $e->getMessage()); + } + } + + /** + * Test with a single filter + */ + public function testSearchTaxClass() + { + $taxClassName = 'Retail Customer'; + $taxClassNameField = Data\TaxClassInterface::KEY_NAME; + $filter = $this->filterBuilder->setField($taxClassNameField) + ->setValue($taxClassName) + ->create(); + $this->searchCriteriaBuilder->addFilter([$filter]); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + $searchData = $this->searchCriteriaBuilder->create()->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(1, $searchResults['total_count']); + $this->assertEquals($taxClassName, $searchResults['items'][0][$taxClassNameField]); + } + + /** + * Test using multiple filters + */ + public function testSearchTaxClassMultipleFilterGroups() + { + $productTaxClass = [ + Data\TaxClassInterface::KEY_NAME => 'Taxable Goods', + Data\TaxClassInterface::KEY_TYPE => 'PRODUCT', + ]; + $customerTaxClass = [Data\TaxClassInterface::KEY_NAME => 'Retail Customer', + Data\TaxClassInterface::KEY_TYPE => 'CUSTOMER', ]; + + $filter1 = $this->filterBuilder->setField(Data\TaxClassInterface::KEY_NAME) + ->setValue($productTaxClass[Data\TaxClassInterface::KEY_NAME]) + ->create(); + $filter2 = $this->filterBuilder->setField(Data\TaxClassInterface::KEY_NAME) + ->setValue($customerTaxClass[Data\TaxClassInterface::KEY_NAME]) + ->create(); + $filter3 = $this->filterBuilder->setField(Data\TaxClassInterface::KEY_TYPE) + ->setValue($productTaxClass[Data\TaxClassInterface::KEY_TYPE]) + ->create(); + $filter4 = $this->filterBuilder->setField(Data\TaxClassInterface::KEY_TYPE) + ->setValue($customerTaxClass[Data\TaxClassInterface::KEY_TYPE]) + ->create(); + + /** + * (class_name == 'Retail Customer' || class_name == 'Taxable Goods) + * && ( class_type == 'CUSTOMER' || class_type == 'PRODUCT') + */ + $this->searchCriteriaBuilder->addFilter([$filter1, $filter2]); + $this->searchCriteriaBuilder->addFilter([$filter3, $filter4]); + $searchCriteria = $this->searchCriteriaBuilder->setCurrentPage(1)->setPageSize(10)->create(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + $searchData = $searchCriteria->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(2, $searchResults['total_count']); + $this->assertEquals($productTaxClass[Data\TaxClassInterface::KEY_NAME], + $searchResults['items'][0][Data\TaxClassInterface::KEY_NAME]); + $this->assertEquals($customerTaxClass[Data\TaxClassInterface::KEY_NAME], + $searchResults['items'][1][Data\TaxClassInterface::KEY_NAME]); + + /** class_name == 'Retail Customer' && ( class_type == 'CUSTOMER' || class_type == 'PRODUCT') */ + $this->searchCriteriaBuilder->addFilter([$filter2]); + $this->searchCriteriaBuilder->addFilter([$filter3, $filter4]); + $searchCriteria = $this->searchCriteriaBuilder->create(); + $searchData = $searchCriteria->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(1, $searchResults['total_count']); + $this->assertEquals($customerTaxClass[Data\TaxClassInterface::KEY_NAME], + $searchResults['items'][0][Data\TaxClassInterface::KEY_NAME]); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxRateRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxRateRepositoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0122bdfa3d7d1e751f1aa709e35f13f3cdca0639 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxRateRepositoryTest.php @@ -0,0 +1,660 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Tax\Api; + +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SearchCriteria; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Api\SortOrderBuilder; +use Magento\Tax\Api\Data\TaxRateInterface as TaxRate; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; + +class TaxRateRepositoryTest extends WebapiAbstract +{ + const SERVICE_NAME = "taxTaxRateRepositoryV1"; + const SERVICE_VERSION = "V1"; + const RESOURCE_PATH = "/V1/taxRate"; + + /** @var \Magento\Tax\Model\Calculation\Rate[] */ + private $fixtureTaxRates; + + /** @var \Magento\Tax\Model\ClassModel[] */ + private $fixtureTaxClasses; + + /** @var \Magento\Tax\Model\Calculation\Rule[] */ + private $fixtureTaxRules; + + /** + * @var \Magento\Tax\Api\TaxRateRepositoryInterface + */ + private $taxRateService; + + /** @var FilterBuilder */ + private $filterBuilder; + + /** @var SearchCriteriaBuilder */ + private $searchCriteriaBuilder; + + /** @var SortOrderBuilder */ + private $sortOrderBuilder; + + /** + * Other rates created during tests, to be deleted in tearDown() + * + * @var \Magento\Tax\Model\Calculation\Rate[] + */ + private $otherRates = []; + + /** + * Execute per test initialization. + */ + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->taxRateService = $objectManager->get('Magento\Tax\Api\TaxRateRepositoryInterface'); + $this->searchCriteriaBuilder = $objectManager->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + $this->filterBuilder = $objectManager->create( + 'Magento\Framework\Api\FilterBuilder' + ); + $this->sortOrderBuilder = $objectManager->create( + 'Magento\Framework\Api\SortOrderBuilder' + ); + /** Initialize tax classes, tax rates and tax rules defined in fixture Magento/Tax/_files/tax_classes.php */ + $this->getFixtureTaxRates(); + $this->getFixtureTaxClasses(); + $this->getFixtureTaxRules(); + } + + public function tearDown() + { + $taxRules = $this->getFixtureTaxRules(); + if (count($taxRules)) { + $taxRates = $this->getFixtureTaxRates(); + $taxClasses = $this->getFixtureTaxClasses(); + foreach ($taxRules as $taxRule) { + $taxRule->delete(); + } + foreach ($taxRates as $taxRate) { + $taxRate->delete(); + } + foreach ($taxClasses as $taxClass) { + $taxClass->delete(); + } + } + if (count($this->otherRates)) { + foreach ($this->otherRates as $taxRate) { + $taxRate->delete(); + } + } + } + + public function testCreateTaxRateExistingCode() + { + $data = [ + 'tax_rate' => [ + 'tax_country_id' => 'US', + 'tax_region_id' => 12, + 'tax_postcode' => '*', + 'code' => 'US-CA-*-Rate 1', + 'rate' => '8.2501', + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + try { + $this->_webApiCall($serviceInfo, $data); + $this->fail('Expected exception was not raised'); + } catch (\Exception $e) { + $expectedMessage = 'Code already exists.'; + + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + } + + public function testCreateTaxRate() + { + $data = [ + 'tax_rate' => [ + 'tax_country_id' => 'US', + 'tax_region_id' => 12, + 'tax_postcode' => '*', + 'code' => 'Test Tax Rate ' . microtime(), + 'rate' => '8.2501', + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $result = $this->_webApiCall($serviceInfo, $data); + $this->assertArrayHasKey('id', $result); + $taxRateId = $result['id']; + /** Ensure that tax rate was actually created in DB */ + /** @var \Magento\Tax\Model\Calculation\Rate $taxRate */ + $taxRate = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rate'); + $this->assertEquals($taxRateId, $taxRate->load($taxRateId)->getId(), 'Tax rate was not created in DB.'); + $taxRate->delete(); + } + + public function testCreateTaxRateWithZipRange() + { + $data = [ + 'tax_rate' => [ + 'tax_country_id' => 'US', + 'tax_region_id' => 12, + 'code' => 'Test Tax Rate ' . microtime(), + 'rate' => '8.2501', + 'zip_is_range' => 1, + 'zip_from' => 17, + 'zip_to' => 25, + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $result = $this->_webApiCall($serviceInfo, $data); + $this->assertArrayHasKey('id', $result); + $taxRateId = $result['id']; + /** Ensure that tax rate was actually created in DB */ + /** @var \Magento\Tax\Model\Calculation\Rate $taxRate */ + $taxRate = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rate'); + $this->assertEquals($taxRateId, $taxRate->load($taxRateId)->getId(), 'Tax rate was not created in DB.'); + $this->assertEquals('17-25', $taxRate->getTaxPostcode(), 'Zip range is not saved in DB.'); + $taxRate->delete(); + } + + /** + * @magentoApiDataFixture Magento/Tax/_files/tax_classes.php + */ + public function testUpdateTaxRate() + { + $fixtureRate = $this->getFixtureTaxRates()[0]; + + $data = [ + 'tax_rate' => [ + 'id' => $fixtureRate->getId(), + 'tax_region_id' => 43, + 'tax_country_id' => 'US', + 'tax_postcode' => '07400', + 'code' => 'Test Tax Rate ' . microtime(), + 'rate' => 3.456, + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $this->_webApiCall($serviceInfo, $data); + $expectedRateData = $data['tax_rate']; + /** Ensure that tax rate was actually updated in DB */ + /** @var \Magento\Tax\Model\Calculation\Rate $taxRate */ + $taxRate = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rate'); + $taxRateModel = $taxRate->load($fixtureRate->getId()); + $this->assertEquals($expectedRateData['id'], $taxRateModel->getId(), 'Tax rate was not updated in DB.'); + $this->assertEquals( + $expectedRateData['tax_region_id'], + $taxRateModel->getTaxRegionId(), + 'Tax rate was not updated in DB.' + ); + $this->assertEquals( + $expectedRateData['tax_country_id'], + $taxRateModel->getTaxCountryId(), + 'Tax rate was not updated in DB.' + ); + $this->assertEquals( + $expectedRateData['tax_postcode'], + $taxRateModel->getTaxPostcode(), + 'Tax rate was not updated in DB.' + ); + $this->assertEquals($expectedRateData['code'], $taxRateModel->getCode(), 'Tax rate was not updated in DB.'); + $this->assertEquals( + $expectedRateData['rate'], + $taxRateModel->getRate(), + 'Tax rate was not updated in DB.' + ); + } + + public function testUpdateTaxRateNotExisting() + { + $data = [ + 'tax_rate' => [ + 'id' => 555, + 'tax_region_id' => 43, + 'tax_country_id' => 'US', + 'tax_postcode' => '07400', + 'code' => 'Test Tax Rate ' . microtime(), + 'rate' => 3.456, + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + try { + $this->_webApiCall($serviceInfo, $data); + $this->fail('Expected exception was not raised'); + } catch (\Exception $e) { + $expectedMessage = 'No such entity with %fieldName = %fieldValue'; + + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + } + + public function testGetTaxRate() + { + $taxRateId = 2; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$taxRateId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, ['rateId' => $taxRateId]); + $expectedRateData = [ + 'id' => 2, + 'tax_country_id' => 'US', + 'tax_region_id' => 43, + 'tax_postcode' => '*', + 'code' => 'US-NY-*-Rate 1', + 'rate' => 8.375, + 'titles' => [], + 'region_name' => 'NY', + ]; + $this->assertEquals($expectedRateData, $result); + } + + public function testGetTaxRateNotExist() + { + $taxRateId = 37865; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$taxRateId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + try { + $this->_webApiCall($serviceInfo, ['rateId' => $taxRateId]); + $this->fail('Expected exception was not raised'); + } catch (\Exception $e) { + $expectedMessage = 'No such entity with %fieldName = %fieldValue'; + + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + } + + /** + * @magentoApiDataFixture Magento/Tax/_files/tax_classes.php + */ + public function testDeleteTaxRate() + { + /** Tax rules must be deleted since tax rate cannot be deleted if there are any tax rules associated with it */ + $taxRules = $this->getFixtureTaxRules(); + foreach ($taxRules as $taxRule) { + $taxRule->delete(); + } + + $fixtureRate = $this->getFixtureTaxRates()[0]; + $taxRateId = $fixtureRate->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$taxRateId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ]; + + $result = $this->_webApiCall($serviceInfo, ['rateId' => $taxRateId]); + $this->assertTrue($result); + /** Ensure that tax rate was actually removed from DB */ + /** @var \Magento\Tax\Model\Calculation\Rate $taxRate */ + $taxRate = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rate'); + $this->assertNull($taxRate->load($taxRateId)->getId(), 'Tax rate was not deleted from DB.'); + } + + /** + * Insure that tax rate cannot be deleted if it is used for a tax rule. + * + * @magentoApiDataFixture Magento/Tax/_files/tax_classes.php + */ + public function testCannotDeleteTaxRate() + { + $fixtureRate = $this->getFixtureTaxRates()[0]; + $taxRateId = $fixtureRate->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$taxRateId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ]; + try { + $this->_webApiCall($serviceInfo, ['rateId' => $taxRateId]); + $this->fail('Expected exception was not raised'); + } catch (\Exception $e) { + $expectedMessage = 'The tax rate cannot be removed. It exists in a tax rule.'; + + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + } + + public function testSearchTaxRates() + { + $rates = $this->setupTaxRatesForSearch(); + + // Find rates whose code is 'codeUs12' + $filter = $this->filterBuilder->setField(TaxRate::KEY_CODE) + ->setValue('codeUs12') + ->create(); + + $this->searchCriteriaBuilder->addFilter([$filter]); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + $searchData = $this->searchCriteriaBuilder->create()->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + + /** @var \Magento\Framework\Api\SearchResults $searchResults */ + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertEquals(1, $searchResults['total_count']); + + $expectedRuleData = [ + [ + 'id' => (int)$rates['codeUs12']->getId(), + 'tax_country_id' => $rates['codeUs12']->getTaxCountryId(), + 'tax_region_id' => (int)$rates['codeUs12']->getTaxRegionId(), + 'region_name' => 'CA', + 'tax_postcode' => $rates['codeUs12']->getTaxPostcode(), + 'code' => $rates['codeUs12']->getCode(), + 'rate' => ((float) $rates['codeUs12']->getRate()), + 'titles' => [], + ], + ]; + $this->assertEquals($expectedRuleData, $searchResults['items']); + } + + public function testSearchTaxRatesCz() + { + // TODO: This test fails in SOAP, a generic bug searching in SOAP + $this->_markTestAsRestOnly(); + $rates = $this->setupTaxRatesForSearch(); + + // Find rates which country id 'CZ' + $filter = $this->filterBuilder->setField(TaxRate::KEY_COUNTRY_ID) + ->setValue('CZ') + ->create(); + $sortOrder = $this->sortOrderBuilder + ->setField(TaxRate::KEY_POSTCODE) + ->setDirection(SearchCriteria::SORT_DESC) + ->create(); + // Order them by descending postcode (not the default order) + $this->searchCriteriaBuilder->addFilter([$filter]) + ->addSortOrder($sortOrder); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + $searchData = $this->searchCriteriaBuilder->create()->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + + /** @var \Magento\Framework\Api\SearchResults $searchResults */ + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertEquals(2, $searchResults['total_count']); + + $expectedRuleData = [ + [ + 'id' => (int)$rates['codeCz2']->getId(), + 'tax_country_id' => $rates['codeCz2']->getTaxCountryId(), + 'tax_postcode' => $rates['codeCz2']->getTaxPostcode(), + 'code' => $rates['codeCz2']->getCode(), + 'rate' => ((float) $rates['codeCz2']->getRate()), + 'tax_region_id' => 0, + 'titles' => [], + ], + [ + 'id' => (int)$rates['codeCz1']->getId(), + 'tax_country_id' => $rates['codeCz1']->getTaxCountryId(), + 'tax_postcode' => $rates['codeCz1']->getTaxPostcode(), + 'code' => $rates['codeCz1']->getCode(), + 'rate' => ((float) $rates['codeCz1']->getRate()), + 'tax_region_id' => 0, + 'titles' => [], + ], + ]; + $this->assertEquals($expectedRuleData, $searchResults['items']); + } + + /** + * Get tax rates created in Magento\Tax\_files\tax_classes.php + * + * @return \Magento\Tax\Model\Calculation\Rate[] + */ + private function getFixtureTaxRates() + { + if (is_null($this->fixtureTaxRates)) { + $this->fixtureTaxRates = []; + if ($this->getFixtureTaxRules()) { + $taxRateIds = (array)$this->getFixtureTaxRules()[0]->getRates(); + foreach ($taxRateIds as $taxRateId) { + /** @var \Magento\Tax\Model\Calculation\Rate $taxRate */ + $taxRate = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rate'); + $this->fixtureTaxRates[] = $taxRate->load($taxRateId); + } + } + } + return $this->fixtureTaxRates; + } + + /** + * Get tax classes created in Magento\Tax\_files\tax_classes.php + * + * @return \Magento\Tax\Model\ClassModel[] + */ + private function getFixtureTaxClasses() + { + if (is_null($this->fixtureTaxClasses)) { + $this->fixtureTaxClasses = []; + if ($this->getFixtureTaxRules()) { + $taxClassIds = array_merge( + (array)$this->getFixtureTaxRules()[0]->getCustomerTaxClasses(), + (array)$this->getFixtureTaxRules()[0]->getProductTaxClasses() + ); + foreach ($taxClassIds as $taxClassId) { + /** @var \Magento\Tax\Model\ClassModel $taxClass */ + $taxClass = Bootstrap::getObjectManager()->create('Magento\Tax\Model\ClassModel'); + $this->fixtureTaxClasses[] = $taxClass->load($taxClassId); + } + } + } + return $this->fixtureTaxClasses; + } + + /** + * Get tax rule created in Magento\Tax\_files\tax_classes.php + * + * @return \Magento\Tax\Model\Calculation\Rule[] + */ + private function getFixtureTaxRules() + { + if (is_null($this->fixtureTaxRules)) { + $this->fixtureTaxRules = []; + $taxRuleCodes = ['Test Rule Duplicate', 'Test Rule']; + foreach ($taxRuleCodes as $taxRuleCode) { + /** @var \Magento\Tax\Model\Calculation\Rule $taxRule */ + $taxRule = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rule'); + $taxRule->load($taxRuleCode, 'code'); + if ($taxRule->getId()) { + $this->fixtureTaxRules[] = $taxRule; + } + } + } + return $this->fixtureTaxRules; + } + + /** + * Creates rates for search tests. + * + * @return \Magento\Tax\Model\Calculation\Rate[] + */ + private function setupTaxRatesForSearch() + { + $objectManager = Bootstrap::getObjectManager(); + + $taxRateUs12 = [ + 'tax_country_id' => 'US', + 'tax_region_id' => 12, + 'tax_postcode' => '*', + 'code' => 'codeUs12', + 'rate' => 22, + 'region_name' => 'CA', + ]; + $rates['codeUs12'] = $objectManager->create('Magento\Tax\Model\Calculation\Rate') + ->setData($taxRateUs12) + ->save(); + + $taxRateUs14 = [ + 'tax_country_id' => 'US', + 'tax_region_id' => 14, + 'tax_postcode' => '*', + 'code' => 'codeUs14', + 'rate' => 22, + ]; + $rates['codeUs14'] = $objectManager->create('Magento\Tax\Model\Calculation\Rate') + ->setData($taxRateUs14) + ->save(); + $taxRateBr13 = [ + 'tax_country_id' => 'BR', + 'tax_region_id' => 13, + 'tax_postcode' => '*', + 'code' => 'codeBr13', + 'rate' => 7.5, + ]; + $rates['codeBr13'] = $objectManager->create('Magento\Tax\Model\Calculation\Rate') + ->setData($taxRateBr13) + ->save(); + + $taxRateCz1 = [ + 'tax_country_id' => 'CZ', + 'tax_postcode' => '110 00', + 'code' => 'codeCz1', + 'rate' => 1.1, + ]; + $rates['codeCz1'] = $objectManager->create('Magento\Tax\Model\Calculation\Rate') + ->setData($taxRateCz1) + ->save(); + $taxRateCz2 = [ + 'tax_country_id' => 'CZ', + 'tax_postcode' => '250 00', + 'code' => 'codeCz2', + 'rate' => 2.2, + ]; + $rates['codeCz2'] = $objectManager->create('Magento\Tax\Model\Calculation\Rate') + ->setData($taxRateCz2) + ->save(); + + // Set class variable so rates will be deleted on tearDown() + $this->otherRates = $rates; + return $rates; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxRuleRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxRuleRepositoryInterfaceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..277b0611d7acbb12ad62fe8c5763d3eaf088fd4e --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxRuleRepositoryInterfaceTest.php @@ -0,0 +1,606 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Tax\Api; + +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\Webapi\Model\Rest\Config as HttpConstants; + +class TaxRuleRepositoryInterfaceTest extends WebapiAbstract +{ + const SERVICE_NAME = "taxTaxRuleRepositoryV1"; + const SERVICE_VERSION = "V1"; + const RESOURCE_PATH = "/V1/taxRules"; + + /** @var \Magento\Tax\Model\Calculation\Rate[] */ + private $fixtureTaxRates; + + /** @var \Magento\Tax\Model\ClassModel[] */ + private $fixtureTaxClasses; + + /** @var \Magento\Tax\Model\Calculation\Rule[] */ + private $fixtureTaxRules; + + /** @var FilterBuilder */ + private $filterBuilder; + + /** @var SearchCriteriaBuilder */ + private $searchCriteriaBuilder; + + /** + * Execute per test initialization. + */ + public function setUp() + { + $this->searchCriteriaBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + $this->filterBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\FilterBuilder' + ); + $objectManager = Bootstrap::getObjectManager(); + + $this->searchCriteriaBuilder = $objectManager->create( + 'Magento\Framework\Api\SearchCriteriaBuilder' + ); + $this->filterBuilder = $objectManager->create( + 'Magento\Framework\Api\FilterBuilder' + ); + + /** Initialize tax classes, tax rates and tax rules defined in fixture Magento/Tax/_files/tax_classes.php */ + $this->getFixtureTaxRates(); + $this->getFixtureTaxClasses(); + $this->getFixtureTaxRules(); + } + + public function tearDown() + { + $taxRules = $this->getFixtureTaxRules(); + if (count($taxRules)) { + $taxRates = $this->getFixtureTaxRates(); + $taxClasses = $this->getFixtureTaxClasses(); + foreach ($taxRules as $taxRule) { + $taxRule->delete(); + } + foreach ($taxRates as $taxRate) { + $taxRate->delete(); + } + foreach ($taxClasses as $taxClass) { + $taxClass->delete(); + } + } + } + + /** + * @magentoApiDataFixture Magento/Tax/_files/tax_classes.php + */ + public function testDeleteTaxRule() + { + $fixtureRule = $this->getFixtureTaxRules()[0]; + $taxRuleId = $fixtureRule->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$taxRuleId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'DeleteById', + ], + ]; + $requestData = ['ruleId' => $taxRuleId]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($result); + /** Ensure that tax rule was actually removed from DB */ + /** @var \Magento\Tax\Model\Calculation\Rule $taxRule */ + $taxRate = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rate'); + $this->assertNull($taxRate->load($taxRuleId)->getId(), 'Tax rule was not deleted from DB.'); + } + + public function testCreateTaxRule() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => HttpConstants::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $requestData = [ + 'rule' => [ + 'code' => 'Test Rule ' . microtime(), + 'position' => 10, + 'priority' => 5, + 'customer_tax_class_ids' => [3], + 'product_tax_class_ids' => [2], + 'tax_rate_ids' => [1, 2], + 'calculate_subtotal' => 1, + ], + ]; + $taxRuleData = $this->_webApiCall($serviceInfo, $requestData); + $this->assertArrayHasKey('id', $taxRuleData, "Tax rule ID is expected"); + $this->assertGreaterThan(0, $taxRuleData['id']); + $taxRuleId = $taxRuleData['id']; + unset($taxRuleData['id']); + $this->assertEquals($requestData['rule'], $taxRuleData, "Tax rule is created with invalid data."); + /** Ensure that tax rule was actually created in DB */ + /** @var \Magento\Tax\Model\Calculation\Rule $taxRule */ + $taxRule = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rule'); + $this->assertEquals($taxRuleId, $taxRule->load($taxRuleId)->getId(), 'Tax rule was not created in DB.'); + $taxRule->delete(); + } + + public function testCreateTaxRuleInvalidTaxClassIds() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => HttpConstants::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $requestData = [ + 'rule' => [ + 'code' => 'Test Rule ' . microtime(), + 'position' => 10, + 'priority' => 5, + 'customer_tax_class_ids' => [2], + 'product_tax_class_ids' => [3], + 'tax_rate_ids' => [1, 2], + 'calculate_subtotal' => 1, + ], + ]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail('Did not throw expected InputException'); + } catch (\SoapFault $e) { + $this->assertContains('No such entity with customer_tax_class_ids = %fieldValue', $e->getMessage()); + } catch (\Exception $e) { + $this->assertContains('No such entity with customer_tax_class_ids = %fieldValue', $e->getMessage()); + } + } + + public function testCreateTaxRuleExistingCode() + { + $requestData = [ + 'rule' => [ + 'code' => 'Test Rule ' . microtime(), + 'position' => 10, + 'priority' => 5, + 'customer_tax_class_ids' => [3], + 'product_tax_class_ids' => [2], + 'tax_rate_ids' => [1, 2], + 'calculate_subtotal' => 0, + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $newTaxRuleData = $this->_webApiCall($serviceInfo, $requestData); + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail('Expected exception was not raised'); + } catch (\Exception $e) { + $expectedMessage = 'Code already exists.'; + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + + // Clean up the new tax rule so it won't affect other tests + /** @var \Magento\Tax\Model\Calculation\Rule $taxRule */ + $taxRule = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rule'); + $taxRule->load($newTaxRuleData['id']); + $taxRule->delete(); + } + + /** + * @magentoApiDataFixture Magento/Tax/_files/tax_classes.php + */ + public function testGetTaxRule() + { + $fixtureRule = $this->getFixtureTaxRules()[0]; + $taxRuleId = $fixtureRule->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$taxRuleId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + + $expectedRuleData = [ + 'id' => $taxRuleId, + 'code' => 'Test Rule Duplicate', + 'priority' => '0', + 'position' => '0', + 'customer_tax_class_ids' => array_values(array_unique($fixtureRule->getCustomerTaxClasses())), + 'product_tax_class_ids' => array_values(array_unique($fixtureRule->getProductTaxClasses())), + 'tax_rate_ids' => array_values(array_unique($fixtureRule->getRates())), + 'calculate_subtotal' => false, + ]; + $requestData = ['ruleId' => $taxRuleId]; + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($expectedRuleData, $result); + } + /** + * @magentoApiDataFixture Magento/Tax/_files/tax_classes.php + */ + public function testSearchTaxRulesSimple() + { + // Find rules whose code is 'Test Rule' + $filter = $this->filterBuilder->setField('code') + ->setValue('Test Rule') + ->create(); + + $this->searchCriteriaBuilder->addFilter([$filter]); + + $fixtureRule = $this->getFixtureTaxRules()[1]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + $searchData = $this->searchCriteriaBuilder->create()->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + + /** @var \Magento\Framework\Api\SearchResults $searchResults */ + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertEquals(1, $searchResults['total_count']); + + $expectedRuleData = [ + [ + 'id' => $fixtureRule->getId(), + 'code' => 'Test Rule', + 'priority' => 0, + 'position' => 0, + 'calculate_subtotal' => 0, + 'customer_tax_class_ids' => array_values(array_unique($fixtureRule->getCustomerTaxClasses())), + 'product_tax_class_ids' => array_values(array_unique($fixtureRule->getProductTaxClasses())), + 'tax_rate_ids' => array_values(array_unique($fixtureRule->getRates())), + ], + ]; + $this->assertEquals($expectedRuleData, $searchResults['items']); + } + + /** + * @magentoApiDataFixture Magento/Tax/_files/tax_classes.php + */ + public function testSearchTaxRulesCodeLike() + { + // Find rules whose code starts with 'Test Rule' + $filter = $this->filterBuilder + ->setField('code') + ->setValue('Test Rule%') + ->setConditionType('like') + ->create(); + + $sortFilter = $this->filterBuilder + ->setField('position') + ->setValue(0) + ->create(); + + $this->searchCriteriaBuilder->addFilter([$filter, $sortFilter]); + + $fixtureRule = $this->getFixtureTaxRules()[1]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + $searchData = $this->searchCriteriaBuilder->create()->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + + /** @var \Magento\Framework\Api\SearchResults $searchResults */ + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertEquals(2, $searchResults['total_count']); + + $expectedRuleData = [ + [ + 'id' => $fixtureRule->getId(), + 'code' => 'Test Rule', + 'priority' => 0, + 'position' => 0, + 'calculate_subtotal' => 0, + 'customer_tax_class_ids' => array_values(array_unique($fixtureRule->getCustomerTaxClasses())), + 'product_tax_class_ids' => array_values(array_unique($fixtureRule->getProductTaxClasses())), + 'tax_rate_ids' => array_values(array_unique($fixtureRule->getRates())), + ], + [ + 'id' => $this->getFixtureTaxRules()[0]->getId(), + 'code' => 'Test Rule Duplicate', + 'priority' => 0, + 'position' => 0, + 'calculate_subtotal' => 0, + 'customer_tax_class_ids' => array_values(array_unique($fixtureRule->getCustomerTaxClasses())), + 'product_tax_class_ids' => array_values(array_unique($fixtureRule->getProductTaxClasses())), + 'tax_rate_ids' => array_values(array_unique($fixtureRule->getRates())) + ], + ]; + $this->assertEquals($expectedRuleData, $searchResults['items']); + } + + public function testGetTaxRuleNotExist() + { + $taxRuleId = 37865; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . "/$taxRuleId", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + $requestData = ['ruleId' => $taxRuleId]; + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail('Expected exception was not raised'); + } catch (\Exception $e) { + $expectedMessage = 'No such entity with %fieldName = %fieldValue'; + + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + } + /** + * @magentoApiDataFixture Magento/Tax/_files/tax_classes.php + */ + public function testUpdateTaxRule() + { + $fixtureRule = $this->getFixtureTaxRules()[0]; + $requestData = [ + 'rule' => [ + 'id' => $fixtureRule->getId(), + 'code' => 'Test Rule ' . microtime(), + 'position' => 10, + 'priority' => 5, + 'customer_tax_class_ids' => [3], + 'product_tax_class_ids' => [2], + 'tax_rate_ids' => [1, 2], + 'calculate_subtotal' => 1, + ], + ]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $this->_webApiCall($serviceInfo, $requestData); + $expectedRuleData = $requestData['rule']; + /** Ensure that tax rule was actually updated in DB */ + /** @var \Magento\Tax\Model\Calculation $taxCalculation */ + $taxCalculation = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation'); + /** @var \Magento\Tax\Model\Calculation\Rule $taxRule */ + $taxRule = Bootstrap::getObjectManager()->create( + 'Magento\Tax\Model\Calculation\Rule', + ['calculation' => $taxCalculation] + ); + $taxRuleModel = $taxRule->load($fixtureRule->getId()); + $this->assertEquals($expectedRuleData['id'], $taxRuleModel->getId(), 'Tax rule was not updated in DB.'); + $this->assertEquals( + $expectedRuleData['code'], + $taxRuleModel->getCode(), + 'Tax rule code was updated incorrectly.' + ); + $this->assertEquals( + $expectedRuleData['position'], + $taxRuleModel->getPosition(), + 'Tax rule sort order was updated incorrectly.' + ); + $this->assertEquals( + $expectedRuleData['priority'], + $taxRuleModel->getPriority(), + 'Tax rule priority was updated incorrectly.' + ); + $this->assertEquals( + $expectedRuleData['customer_tax_class_ids'], + array_values(array_unique($taxRuleModel->getCustomerTaxClasses())), + 'Customer Tax classes were updated incorrectly' + ); + $this->assertEquals( + $expectedRuleData['product_tax_class_ids'], + array_values(array_unique($taxRuleModel->getProductTaxClasses())), + 'Product Tax classes were updated incorrectly.' + ); + $this->assertEquals( + $expectedRuleData['tax_rate_ids'], + array_values(array_unique($taxRuleModel->getRates())), + 'Tax rates were updated incorrectly.' + ); + } + public function testUpdateTaxRuleNotExisting() + { + $requestData = [ + 'rule' => [ + 'id' => 12345, + 'code' => 'Test Rule ' . microtime(), + 'position' => 10, + 'priority' => 5, + 'customer_tax_class_ids' => [3], + 'product_tax_class_ids' => [2], + 'tax_rate_ids' => [1, 2], + ], + ]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail('Expected exception was not raised'); + } catch (\Exception $e) { + $expectedMessage = 'No such entity with %fieldName = %fieldValue'; + + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Exception does not contain expected message." + ); + } + } + + /** + * @magentoApiDataFixture Magento/Tax/_files/tax_classes.php + */ + public function testSearchTaxRule() + { + $fixtureRule = $this->getFixtureTaxRules()[0]; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/search', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'GetList', + ], + ]; + + $filter = $this->filterBuilder->setField('code') + ->setValue($fixtureRule->getCode()) + ->create(); + $this->searchCriteriaBuilder->addFilter([$filter]); + $searchData = $this->searchCriteriaBuilder->create()->__toArray(); + $requestData = ['searchCriteria' => $searchData]; + $searchResults = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals(1, $searchResults['total_count']); + $this->assertEquals($fixtureRule->getId(), $searchResults['items'][0]["id"]); + $this->assertEquals($fixtureRule->getCode(), $searchResults['items'][0]['code']); + } + + /** + * Get tax rates created in Magento\Tax\_files\tax_classes.php + * + * @return \Magento\Tax\Model\Calculation\Rate[] + */ + private function getFixtureTaxRates() + { + if (is_null($this->fixtureTaxRates)) { + $this->fixtureTaxRates = []; + if ($this->getFixtureTaxRules()) { + $taxRateIds = (array)$this->getFixtureTaxRules()[0]->getRates(); + foreach ($taxRateIds as $taxRateId) { + /** @var \Magento\Tax\Model\Calculation\Rate $taxRate */ + $taxRate = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rate'); + $this->fixtureTaxRates[] = $taxRate->load($taxRateId); + } + } + } + return $this->fixtureTaxRates; + } + + /** + * Get tax classes created in Magento\Tax\_files\tax_classes.php + * + * @return \Magento\Tax\Model\ClassModel[] + */ + private function getFixtureTaxClasses() + { + if (is_null($this->fixtureTaxClasses)) { + $this->fixtureTaxClasses = []; + if ($this->getFixtureTaxRules()) { + $taxClassIds = array_merge( + (array)$this->getFixtureTaxRules()[0]->getCustomerTaxClasses(), + (array)$this->getFixtureTaxRules()[0]->getProductTaxClasses() + ); + foreach ($taxClassIds as $taxClassId) { + /** @var \Magento\Tax\Model\ClassModel $taxClass */ + $taxClass = Bootstrap::getObjectManager()->create('Magento\Tax\Model\ClassModel'); + $this->fixtureTaxClasses[] = $taxClass->load($taxClassId); + } + } + } + return $this->fixtureTaxClasses; + } + + /** + * Get tax rule created in Magento\Tax\_files\tax_classes.php + * + * @return \Magento\Tax\Model\Calculation\Rule[] + */ + private function getFixtureTaxRules() + { + if (is_null($this->fixtureTaxRules)) { + $this->fixtureTaxRules = []; + $taxRuleCodes = ['Test Rule Duplicate', 'Test Rule']; + foreach ($taxRuleCodes as $taxRuleCode) { + /** @var \Magento\Tax\Model\Calculation\Rule $taxRule */ + $taxRule = Bootstrap::getObjectManager()->create('Magento\Tax\Model\Calculation\Rule'); + $taxRule->load($taxRuleCode, 'code'); + if ($taxRule->getId()) { + $this->fixtureTaxRules[] = $taxRule; + } + } + } + return $this->fixtureTaxRules; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Authentication/RestTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Authentication/RestTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3f8bd45445a6e5c43b3969d391bf47920e3245a6 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Authentication/RestTest.php @@ -0,0 +1,203 @@ +<?php +/** + * Test authentication mechanisms in REST. + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Webapi\Authentication; + +/** + * @magentoApiDataFixture consumerFixture + */ +class RestTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + /** @var \Magento\TestFramework\Authentication\Rest\OauthClient[] */ + protected $_oAuthClients = []; + + /** @var \Magento\Integration\Model\Oauth\Consumer */ + protected static $_consumer; + + /** @var \Magento\Integration\Model\Oauth\Token */ + protected static $_token; + + /** @var string */ + protected static $_consumerKey; + + /** @var string */ + protected static $_consumerSecret; + + /** @var string */ + protected static $_verifier; + + protected function setUp() + { + $this->_markTestAsRestOnly(); + parent::setUp(); + } + + /** + * Create a consumer + */ + public static function consumerFixture($date = null) + { + /** Clear the credentials because during the fixture generation, any previous credentials are invalidated */ + \Magento\TestFramework\Authentication\OauthHelper::clearApiAccessCredentials(); + + $consumerCredentials = \Magento\TestFramework\Authentication\OauthHelper::getConsumerCredentials($date); + self::$_consumerKey = $consumerCredentials['key']; + self::$_consumerSecret = $consumerCredentials['secret']; + self::$_verifier = $consumerCredentials['verifier']; + self::$_consumer = $consumerCredentials['consumer']; + self::$_token = $consumerCredentials['token']; + } + + protected function tearDown() + { + parent::tearDown(); + $this->_oAuthClients = []; + if (isset(self::$_consumer)) { + self::$_consumer->delete(); + self::$_token->delete(); + } + } + + public function testGetRequestToken() + { + /** @var $oAuthClient \Magento\TestFramework\Authentication\Rest\OauthClient */ + $oAuthClient = $this->_getOauthClient(self::$_consumerKey, self::$_consumerSecret); + $requestToken = $oAuthClient->requestRequestToken(); + + $this->assertNotEmpty($requestToken->getRequestToken(), "Request token value is not set"); + $this->assertNotEmpty($requestToken->getRequestTokenSecret(), "Request token secret is not set"); + + $this->assertEquals( + \Magento\Framework\Oauth\Helper\Oauth::LENGTH_TOKEN, + strlen($requestToken->getRequestToken()), + "Request token value length should be " . \Magento\Framework\Oauth\Helper\Oauth::LENGTH_TOKEN + ); + $this->assertEquals( + \Magento\Framework\Oauth\Helper\Oauth::LENGTH_TOKEN_SECRET, + strlen($requestToken->getRequestTokenSecret()), + "Request token secret length should be " . \Magento\Framework\Oauth\Helper\Oauth::LENGTH_TOKEN_SECRET + ); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage HTTP/1.1 401 + */ + public function testGetRequestTokenExpiredConsumer() + { + $this::consumerFixture('2012-01-01 00:00:00'); + /** @var $oAuthClient \Magento\TestFramework\Authentication\Rest\OauthClient */ + $oAuthClient = $this->_getOauthClient(self::$_consumerKey, self::$_consumerSecret); + $oAuthClient->requestRequestToken(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage HTTP/1.1 401 + */ + public function testGetRequestTokenInvalidConsumerKey() + { + $oAuthClient = $this->_getOauthClient('invalid_key', self::$_consumerSecret); + $oAuthClient->requestRequestToken(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage HTTP/1.1 401 + */ + public function testGetRequestTokenInvalidConsumerSecret() + { + $oAuthClient = $this->_getOauthClient(self::$_consumerKey, 'invalid_secret'); + $oAuthClient->requestRequestToken(); + } + + public function testGetAccessToken() + { + $oAuthClient = $this->_getOauthClient(self::$_consumerKey, self::$_consumerSecret); + $requestToken = $oAuthClient->requestRequestToken(); + $accessToken = $oAuthClient->requestAccessToken( + $requestToken->getRequestToken(), + self::$_verifier, + $requestToken->getRequestTokenSecret() + ); + $this->assertNotEmpty($accessToken->getAccessToken(), "Access token value is not set."); + $this->assertNotEmpty($accessToken->getAccessTokenSecret(), "Access token secret is not set."); + + $this->assertEquals( + \Magento\Framework\Oauth\Helper\Oauth::LENGTH_TOKEN, + strlen($accessToken->getAccessToken()), + "Access token value length should be " . \Magento\Framework\Oauth\Helper\Oauth::LENGTH_TOKEN + ); + $this->assertEquals( + \Magento\Framework\Oauth\Helper\Oauth::LENGTH_TOKEN_SECRET, + strlen($accessToken->getAccessTokenSecret()), + "Access token secret length should be " . \Magento\Framework\Oauth\Helper\Oauth::LENGTH_TOKEN_SECRET + ); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage HTTP/1.1 401 + */ + public function testGetAccessTokenInvalidVerifier() + { + $oAuthClient = $this->_getOauthClient(self::$_consumerKey, self::$_consumerSecret); + $requestToken = $oAuthClient->requestRequestToken(); + $oAuthClient->requestAccessToken( + $requestToken->getRequestToken(), + 'invalid verifier', + $requestToken->getRequestTokenSecret() + ); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage HTTP/1.1 401 + */ + public function testGetAccessTokenConsumerMismatch() + { + $oAuthClientA = $this->_getOauthClient(self::$_consumerKey, self::$_consumerSecret); + $requestTokenA = $oAuthClientA->requestRequestToken(); + $oauthVerifierA = self::$_verifier; + + self::consumerFixture(); + $oAuthClientB = $this->_getOauthClient(self::$_consumerKey, self::$_consumerSecret); + + $oAuthClientB->requestAccessToken( + $requestTokenA->getRequestToken(), + $oauthVerifierA, + $requestTokenA->getRequestTokenSecret() + ); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage HTTP/1.1 401 + */ + public function testAccessApiInvalidAccessToken() + { + $oAuthClient = $this->_getOauthClient(self::$_consumerKey, self::$_consumerSecret); + $requestToken = $oAuthClient->requestRequestToken(); + $accessToken = $oAuthClient->requestAccessToken( + $requestToken->getRequestToken(), + self::$_verifier, + $requestToken->getRequestTokenSecret() + ); + $accessToken->setAccessToken('invalid'); + $oAuthClient->validateAccessToken($accessToken); + } + + protected function _getOauthClient($consumerKey, $consumerSecret) + { + if (!isset($this->_oAuthClients[$consumerKey])) { + $credentials = new \OAuth\Common\Consumer\Credentials($consumerKey, $consumerSecret, TESTS_BASE_URL); + $this->_oAuthClients[$consumerKey] = new \Magento\TestFramework\Authentication\Rest\OauthClient( + $credentials + ); + } + return $this->_oAuthClients[$consumerKey]; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/DataObjectSerialization/CustomAttributeSerializationMSCTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/DataObjectSerialization/CustomAttributeSerializationMSCTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7b1f33148d999c81ac87d6444edf593408cbe1a1 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/DataObjectSerialization/CustomAttributeSerializationMSCTest.php @@ -0,0 +1,244 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Webapi\DataObjectSerialization; + +use Magento\Framework\Reflection\DataObjectProcessor; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestModuleMSC\Api\Data\ItemDataBuilder; +use Magento\Webapi\Controller\Rest\Response\DataObjectConverter; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * api-functional/testsuite/Magento/Webapi/DataObjectSerialization/CustomAttributeSerializationMSCTest.php + * Class to test if custom attributes are serialized correctly for the new Module Service Contract approach + */ +class CustomAttributeSerializationMSCTest extends \Magento\Webapi\Routing\BaseService +{ + /** + * @var string + */ + protected $_version; + /** + * @var string + */ + protected $_restResourcePath; + /** + * @var string + */ + protected $_soapService = 'testModuleMSCAllSoapAndRest'; + + /** + * @var ItemDataBuilder + */ + protected $itemDataBuilder; + + /** + * @var \Magento\TestModuleMSC\Api\Data\CustomAttributeNestedDataObjectDataBuilder + */ + protected $customAttributeNestedDataObjectDataBuilder; + + /** + * @var \Magento\TestModuleMSC\Api\Data\CustomAttributeDataObjectDataBuilder + */ + protected $customAttributeDataObjectDataBuilder; + + /** + * @var DataObjectProcessor $dataObjectProcessor + */ + protected $dataObjectProcessor; + + /** + * @var DataObjectConverter $dataObjectConverter + */ + protected $dataObjectConverter; + + /** + * Set up custom attribute related data objects + */ + protected function setUp() + { + $this->markTestSkipped('This test become irrelevant according to new API Contract'); + $this->_version = 'V1'; + $this->_soapService = 'testModuleMSCAllSoapAndRestV1'; + $this->_restResourcePath = "/{$this->_version}/testmoduleMSC/"; + + $this->itemDataBuilder = Bootstrap::getObjectManager()->create( + 'Magento\TestModuleMSC\Api\Data\ItemDataBuilder' + ); + + $this->customAttributeNestedDataObjectDataBuilder = Bootstrap::getObjectManager()->create( + 'Magento\TestModuleMSC\Api\Data\CustomAttributeNestedDataObjectDataBuilder' + ); + + $this->customAttributeDataObjectDataBuilder = Bootstrap::getObjectManager()->create( + 'Magento\TestModuleMSC\Api\Data\CustomAttributeDataObjectDataBuilder' + ); + + $this->dataObjectProcessor = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Reflection\DataObjectProcessor' + ); + + $this->dataObjectConverter = Bootstrap::getObjectManager()->create( + 'Magento\Webapi\Controller\Rest\Response\DataObjectConverter' + ); + } + + public function testSimpleAndNonExistentCustomAttributes() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'itemAnyType', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'ItemAnyType'], + ]; + $requestData = [ + 'item_id' => 1, + 'name' => 'testProductAnyType', + 'custom_attributes' => [ + 'non_existent' => [ + 'attribute_code' => 'non_existent', + 'value' => 'test', + ], + 'custom_attribute_string' => [ + 'attribute_code' => 'custom_attribute_string', + 'value' => 'someStringValue', + ], + ], + ]; + $result = $this->_webApiCall($serviceInfo, ['entityItem' => $requestData]); + + //The non_existent custom attribute should be dropped since its not a defined custom attribute + $expectedResponse = [ + 'item_id' => 1, + 'name' => 'testProductAnyType', + 'custom_attributes' => [ + [ + 'attribute_code' => 'custom_attribute_string', + 'value' => 'someStringValue', + ], + ], + ]; + + //\Magento\TestModuleMSC\Api\AllSoapAndRest::itemAnyType just return the input data back as response + $this->assertEquals($expectedResponse, $result); + } + + public function testDataObjectCustomAttributes() + { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->markTestIncomplete('MAGETWO-31016: incompatible with ZF 1.12.9'); + } + $customAttributeDataObject = $this->customAttributeDataObjectDataBuilder + ->setName('nameValue') + ->setCustomAttribute('custom_attribute_int', 1) + ->create(); + + $item = $this->itemDataBuilder + ->setItemId(1) + ->setName('testProductAnyType') + ->setCustomAttribute('custom_attribute_data_object', $customAttributeDataObject) + ->setCustomAttribute('custom_attribute_string', 'someStringValue') + ->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'itemAnyType', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'ItemAnyType'], + ]; + $requestData = $this->dataObjectProcessor->buildOutputDataArray($item, get_class($item)); + $result = $this->_webApiCall($serviceInfo, ['entityItem' => $requestData]); + + $expectedResponse = $this->dataObjectConverter->processServiceOutput( + $item, + '\Magento\TestModuleMSC\Api\AllSoapAndRestInterface', + 'itemAnyType' + ); + //\Magento\TestModuleMSC\Api\AllSoapAndRest::itemAnyType just return the input data back as response + $this->assertEquals($expectedResponse, $result); + } + + public function testDataObjectCustomAttributesPreconfiguredItem() + { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->markTestIncomplete('MAGETWO-31016: incompatible with ZF 1.12.9'); + } + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'itemPreconfigured', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'GetPreconfiguredItem'], + ]; + + $result = $this->_webApiCall($serviceInfo, []); + + $customAttributeDataObject = $this->customAttributeDataObjectDataBuilder + ->setName('nameValue') + ->setCustomAttribute('custom_attribute_int', 1) + ->create(); + + $item = $this->itemDataBuilder + ->setItemId(1) + ->setName('testProductAnyType') + ->setCustomAttribute('custom_attribute_data_object', $customAttributeDataObject) + ->setCustomAttribute('custom_attribute_string', 'someStringValue') + ->create(); + + $expectedResponse = $this->dataObjectConverter->processServiceOutput( + $item, + '\Magento\TestModuleMSC\Api\AllSoapAndRestInterface', + 'getPreconfiguredItem' + ); + $this->assertEquals($expectedResponse, $result); + } + + public function testNestedDataObjectCustomAttributes() + { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->markTestIncomplete('MAGETWO-31016: incompatible with ZF 1.12.9'); + } + $customAttributeNestedDataObject = $this->customAttributeNestedDataObjectDataBuilder + ->setName('nestedNameValue') + ->create(); + + $customAttributeDataObject = $this->customAttributeDataObjectDataBuilder + ->setName('nameValue') + ->setCustomAttribute('custom_attribute_nested', $customAttributeNestedDataObject) + ->setCustomAttribute('custom_attribute_int', 1) + ->create(); + + $item = $this->itemDataBuilder + ->setItemId(1) + ->setName('testProductAnyType') + ->setCustomAttribute('custom_attribute_data_object', $customAttributeDataObject) + ->setCustomAttribute('custom_attribute_string', 'someStringValue') + ->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'itemAnyType', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'ItemAnyType'], + ]; + $requestData = $this->dataObjectProcessor->buildOutputDataArray( + $item, + '\Magento\TestModuleMSC\Api\Data\ItemInterface' + ); + $result = $this->_webApiCall($serviceInfo, ['entityItem' => $requestData]); + + $expectedResponse = $this->dataObjectConverter->processServiceOutput( + $item, + '\Magento\TestModuleMSC\Api\AllSoapAndRestInterface', + 'itemAnyType' + ); + //\Magento\TestModuleMSC\Api\AllSoapAndRest::itemAnyType just return the input data back as response + $this->assertEquals($expectedResponse, $result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/DataObjectSerialization/CustomAttributeSerializationTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/DataObjectSerialization/CustomAttributeSerializationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..4baca07992c41b68ac509b10a5d646550b414d06 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/DataObjectSerialization/CustomAttributeSerializationTest.php @@ -0,0 +1,228 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +/** + * Class to test if custom attributes are serialized correctly + */ +namespace Magento\Webapi\DataObjectSerialization; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestModule1\Service\V1\Entity\ItemBuilder; +use Magento\Webapi\Controller\Rest\Response\DataObjectConverter; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class CustomAttributeSerializationTest extends \Magento\Webapi\Routing\BaseService +{ + /** + * @var string + */ + protected $_version; + /** + * @var string + */ + protected $_restResourcePath; + /** + * @var string + */ + protected $_soapService = 'testModule1AllSoapAndRest'; + + /** + * @var ItemBuilder + */ + protected $itemBuilder; + + /** + * @var \Magento\TestModule1\Service\V1\Entity\CustomAttributeNestedDataObjectBuilder + */ + protected $customAttributeNestedDataObjectBuilder; + + /** + * @var \Magento\TestModule1\Service\V1\Entity\CustomAttributeDataObjectBuilder + */ + protected $customAttributeDataObjectBuilder; + + /** + * @var DataObjectConverter $dataObjectConverter + */ + protected $dataObjectConverter; + + /** + * Set up custom attribute related data objects + */ + protected function setUp() + { + $this->_version = 'V1'; + $this->_soapService = 'testModule1AllSoapAndRestV1'; + $this->_restResourcePath = "/{$this->_version}/testmodule1/"; + + $this->itemBuilder = Bootstrap::getObjectManager()->create( + 'Magento\TestModule1\Service\V1\Entity\ItemBuilder' + ); + + $this->customAttributeNestedDataObjectBuilder = Bootstrap::getObjectManager()->create( + 'Magento\TestModule1\Service\V1\Entity\CustomAttributeNestedDataObjectBuilder' + ); + + $this->customAttributeDataObjectBuilder = Bootstrap::getObjectManager()->create( + 'Magento\TestModule1\Service\V1\Entity\CustomAttributeDataObjectBuilder' + ); + + $this->dataObjectConverter = Bootstrap::getObjectManager()->create( + 'Magento\Webapi\Controller\Rest\Response\DataObjectConverter' + ); + } + + public function testSimpleAndNonExistentCustomAttributes() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'itemAnyType', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'ItemAnyType'], + ]; + $requestData = [ + 'item_id' => 1, + 'name' => 'testProductAnyType', + 'custom_attributes' => [ + 'non_existent' => [ + 'attribute_code' => 'non_existent', + 'value' => 'test', + ], + 'custom_attribute_string' => [ + 'attribute_code' => 'custom_attribute_string', + 'value' => 'someStringValue', + ], + ], + ]; + $result = $this->_webApiCall($serviceInfo, ['entityItem' => $requestData]); + + //The non_existent custom attribute should be dropped since its not a defined custom attribute + $expectedResponse = [ + 'item_id' => 1, + 'name' => 'testProductAnyType', + 'custom_attributes' => [ + [ + 'attribute_code' => 'custom_attribute_string', + 'value' => 'someStringValue', + ], + ], + ]; + + //\Magento\TestModule1\Service\V1\AllSoapAndRest::itemAnyType just return the input data back as response + $this->assertEquals($expectedResponse, $result); + } + + public function testDataObjectCustomAttributes() + { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->markTestIncomplete('MAGETWO-31016: incompatible with ZF 1.12.9'); + } + $customAttributeDataObject = $this->customAttributeDataObjectBuilder + ->setName('nameValue') + ->setCustomAttribute('custom_attribute_int', 1) + ->create(); + + $item = $this->itemBuilder + ->setItemId(1) + ->setName('testProductAnyType') + ->setCustomAttribute('custom_attribute_data_object', $customAttributeDataObject) + ->setCustomAttribute('custom_attribute_string', 'someStringValue') + ->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'itemAnyType', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'ItemAnyType'], + ]; + $requestData = $item->__toArray(); + $result = $this->_webApiCall($serviceInfo, ['entityItem' => $requestData]); + + $expectedResponse = $this->dataObjectConverter->processServiceOutput( + $item, + '\Magento\TestModule1\Service\V1\AllSoapAndRestInterface', + 'itemAnyType' + ); + //\Magento\TestModule1\Service\V1\AllSoapAndRest::itemAnyType just return the input data back as response + $this->assertEquals($expectedResponse, $result); + } + + public function testDataObjectCustomAttributesPreconfiguredItem() + { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->markTestIncomplete('MAGETWO-31016: incompatible with ZF 1.12.9'); + } + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'itemPreconfigured', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'GetPreconfiguredItem'], + ]; + + $result = $this->_webApiCall($serviceInfo, []); + + $customAttributeDataObject = $this->customAttributeDataObjectBuilder + ->setName('nameValue') + ->setCustomAttribute('custom_attribute_int', 1) + ->create(); + + $item = $this->itemBuilder + ->setItemId(1) + ->setName('testProductAnyType') + ->setCustomAttribute('custom_attribute_data_object', $customAttributeDataObject) + ->setCustomAttribute('custom_attribute_string', 'someStringValue') + ->create(); + $expectedResponse = $this->dataObjectConverter->processServiceOutput( + $item, + '\Magento\TestModule1\Service\V1\AllSoapAndRestInterface', + 'getPreconfiguredItem' + ); + $this->assertEquals($expectedResponse, $result); + } + + public function testNestedDataObjectCustomAttributes() + { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->markTestIncomplete('MAGETWO-31016: incompatible with ZF 1.12.9'); + } + $customAttributeNestedDataObject = $this->customAttributeNestedDataObjectBuilder + ->setName('nestedNameValue') + ->create(); + + $customAttributeDataObject = $this->customAttributeDataObjectBuilder + ->setName('nameValue') + ->setCustomAttribute('custom_attribute_nested', $customAttributeNestedDataObject) + ->setCustomAttribute('custom_attribute_int', 1) + ->create(); + + $item = $this->itemBuilder + ->setItemId(1) + ->setName('testProductAnyType') + ->setCustomAttribute('custom_attribute_data_object', $customAttributeDataObject) + ->setCustomAttribute('custom_attribute_string', 'someStringValue') + ->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'itemAnyType', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'ItemAnyType'], + ]; + $requestData = $item->__toArray(); + $result = $this->_webApiCall($serviceInfo, ['entityItem' => $requestData]); + + $expectedResponse = $this->dataObjectConverter->processServiceOutput( + $item, + '\Magento\TestModule1\Service\V1\AllSoapAndRestInterface', + 'itemAnyType' + ); + //\Magento\TestModule1\Service\V1\AllSoapAndRest::itemAnyType just return the input data back as response + $this->assertEquals($expectedResponse, $result); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/DataObjectSerialization/ServiceSerializationTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/DataObjectSerialization/ServiceSerializationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ce7aa7ea452fcb1622e2963a514b182c17b66a31 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/DataObjectSerialization/ServiceSerializationTest.php @@ -0,0 +1,110 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Webapi\DataObjectSerialization; + +class ServiceSerializationTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + /** + * @var string + */ + protected $_version; + + /** + * @var string + */ + protected $_restResourcePath; + + protected function setUp() + { + $this->_markTestAsRestOnly(); + $this->_version = 'V1'; + $this->_restResourcePath = "/{$this->_version}/testmodule4/"; + } + + /** + * Test simple request data + */ + public function testGetServiceCall() + { + $itemId = 1; + $name = 'Test'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + ]; + $item = $this->_webApiCall($serviceInfo, []); + $this->assertEquals($itemId, $item['entity_id'], 'id field returned incorrectly'); + $this->assertEquals($name, $item['name'], 'name field returned incorrectly'); + } + + /** + * Test multiple params with Data Object + */ + public function testUpdateServiceCall() + { + $itemId = 1; + $name = 'Test'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + $item = $this->_webApiCall($serviceInfo, ['request' => ['name' => $name]]); + $this->assertEquals($itemId, $item['entity_id'], 'id field returned incorrectly'); + $this->assertEquals($name, $item['name'], 'name field returned incorrectly'); + } + + /** + * Test nested Data Object + */ + public function testNestedDataObjectCall() + { + $itemId = 1; + $name = 'Test'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId . '/nested', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + $item = $this->_webApiCall($serviceInfo, ['request' => ['details' => ['name' => $name]]]); + $this->assertEquals($itemId, $item['entity_id'], 'id field returned incorrectly'); + $this->assertEquals($name, $item['name'], 'name field returned incorrectly'); + } + + public function testScalarResponse() + { + $id = 2; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => "{$this->_restResourcePath}scalar/{$id}", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + ]; + $this->assertEquals($id, $this->_webApiCall($serviceInfo), 'Scalar service output is serialized incorrectly.'); + } + + public function testExtensibleCall() + { + $id = 2; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => "{$this->_restResourcePath}extensibleDataObject/{$id}", + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_POST, + ], + ]; + + $name = 'Magento'; + $requestData = [ + 'name' => $name, + ]; + $item = $this->_webApiCall($serviceInfo, ['request' => $requestData]); + $this->assertEquals($id, $item['entity_id'], 'id field returned incorrectly'); + $this->assertEquals($name, $item['name'], 'name field returned incorrectly'); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/DeserializationTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/DeserializationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..06a701a2ec6f117789b75b9dc150732c1ec4e6db --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/DeserializationTest.php @@ -0,0 +1,79 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Webapi; + +use Magento\TestFramework\TestCase\Webapi\Adapter\Rest\CurlClient; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class DeserializationTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + /** + * @var string + */ + protected $_version; + + /** + * @var string + */ + protected $_restResourcePath; + + protected function setUp() + { + $this->_version = 'V1'; + $this->_restResourcePath = "/{$this->_version}/TestModule5/"; + } + + /** + * Test POST request with empty body + */ + public function testPostRequestWithEmptyBody() + { + $this->_markTestAsRestOnly(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath, + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + ]; + $expectedMessage = '{"message":"%fieldName is a required field.","parameters":{"fieldName":"item"}}'; + try { + $this->_webApiCall($serviceInfo, CurlClient::EMPTY_REQUEST_BODY); + } catch (\Exception $e) { + $this->assertEquals(\Magento\Webapi\Exception::HTTP_BAD_REQUEST, $e->getCode()); + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Response does not contain expected message." + ); + } + } + + /** + * Test PUT request with empty body + */ + public function testPutRequestWithEmptyBody() + { + $this->_markTestAsRestOnly(); + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + $expectedMessage = '{"message":"%fieldName is a required field.","parameters":{"fieldName":"entityItem"}}'; + try { + $this->_webApiCall($serviceInfo, CurlClient::EMPTY_REQUEST_BODY); + } catch (\Exception $e) { + $this->assertEquals(\Magento\Webapi\Exception::HTTP_BAD_REQUEST, $e->getCode()); + $this->assertContains( + $expectedMessage, + $e->getMessage(), + "Response does not contain expected message." + ); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/PartialResponseTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/PartialResponseTest.php new file mode 100644 index 0000000000000000000000000000000000000000..36b79d9157bf635865c040218576b9339ccb49fb --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/PartialResponseTest.php @@ -0,0 +1,99 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Webapi; + +use Magento\Customer\Api\AccountManagementTest; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Customer as CustomerHelper; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class PartialResponseTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + /** @var CustomerHelper */ + protected $customerHelper; + + /** @var string */ + protected $customerData; + + protected function setUp() + { + $this->_markTestAsRestOnly('Partial response functionality available in REST mode only.'); + + $this->customerHelper = Bootstrap::getObjectManager() + ->get('Magento\TestFramework\Helper\Customer'); + + $this->customerData = $this->customerHelper->createSampleCustomer(); + } + + public function testCustomerWithEmailFilter() + { + $filter = 'email'; + $expected = ['email' => $this->customerData['email']]; + $result = $this->_getCustomerWithFilter($filter, $this->customerData['id']); + $this->assertEquals($expected, $result); + } + + public function testCustomerWithEmailAndAddressFilter() + { + $filter = 'email,addresses[city]'; + $expected = [ + 'email' => $this->customerData['email'], + 'addresses' => [ + ['city' => CustomerHelper::ADDRESS_CITY1], + ['city' => CustomerHelper::ADDRESS_CITY2], + ], + ]; + $result = $this->_getCustomerWithFilter($filter, $this->customerData['id']); + $this->assertEquals($expected, $result); + } + + public function testCustomerWithNestedAddressFilter() + { + $filter = 'addresses[region[region_code]]'; + $expected = [ + 'addresses' => [ + ['region' => ['region_code' => CustomerHelper::ADDRESS_REGION_CODE1]], + ['region' => ['region_code' => CustomerHelper::ADDRESS_REGION_CODE2]], + ], + ]; + $result = $this->_getCustomerWithFilter($filter, $this->customerData['id']); + $this->assertEquals($expected, $result); + } + + public function testCustomerInvalidFilter() + { + // Invalid filter should return an empty result + $result = $this->_getCustomerWithFilter('invalid', $this->customerData['id']); + $this->assertEmpty($result); + } + + public function testFilterForCustomerApiWithSimpleResponse() + { + $result = $this->_getCustomerWithFilter('customers', $this->customerData['id'], '/permissions/readonly'); + // assert if filter is ignored and a normal response is returned + $this->assertFalse($result); + } + + protected function _getCustomerWithFilter($filter, $customerId, $path = '') + { + $resourcePath = sprintf( + '%s/%d%s?fields=%s', + AccountManagementTest::RESOURCE_PATH, + $customerId, + $path, + $filter + ); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $resourcePath, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + ]; + + return $this->_webApiCall($serviceInfo); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/BaseService.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/BaseService.php new file mode 100644 index 0000000000000000000000000000000000000000..5312762a3ae8634e5d0a98a1fcebe27636160f4f --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/BaseService.php @@ -0,0 +1,113 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Webapi\Routing; + +use Magento\Framework\Exception\AuthorizationException; +use Magento\Webapi\Exception as WebapiException; + +/** + * Base class for all Service based routing tests + */ +abstract class BaseService extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + /** + * Check a particular adapter and assert unauthorized access + * + * @param array $serviceInfo + * @param array|null $requestData + */ + protected function assertUnauthorizedException($serviceInfo, $requestData = null) + { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->_assertSoapException($serviceInfo, $requestData, 'Consumer is not authorized to access %resources'); + } elseif (TESTS_WEB_API_ADAPTER == self::ADAPTER_REST) { + $this->_assertRestUnauthorizedException($serviceInfo, $requestData); + } + } + + /** + * Invoke the REST api and assert access is unauthorized + * + * @param array $serviceInfo + * @param array|null $requestData + */ + protected function _assertRestUnauthorizedException($serviceInfo, $requestData = null) + { + try { + $this->_webApiCall($serviceInfo, $requestData); + } catch (\Exception $e) { + $this->assertContains( + '{"message":"' . AuthorizationException::NOT_AUTHORIZED . '"', + $e->getMessage(), + sprintf( + 'REST routing did not fail as expected for the method "%s" of service "%s"', + $serviceInfo['rest']['httpMethod'], + $serviceInfo['rest']['resourcePath'] + ) + ); + $this->assertEquals(WebapiException::HTTP_UNAUTHORIZED, $e->getCode()); + } + } + + /** + * Check a particular adapter and assert the exception + * + * @param array $serviceInfo + * @param array|null $requestData + */ + protected function _assertNoRouteOrOperationException($serviceInfo, $requestData = null) + { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->_assertSoapException($serviceInfo, $requestData); + } elseif (TESTS_WEB_API_ADAPTER == self::ADAPTER_REST) { + $this->_assertNoRestRouteException($serviceInfo, $requestData); + } + } + + /** + * Invoke the REST api and assert for test cases that no such REST route exist + * + * @param array $serviceInfo + * @param array|null $requestData + */ + protected function _assertNoRestRouteException($serviceInfo, $requestData = null) + { + try { + $this->_webApiCall($serviceInfo, $requestData); + } catch (\Exception $e) { + $error = json_decode($e->getMessage(), true); + $this->assertEquals('Request does not match any route.', $error['message']); + $this->assertEquals(WebapiException::HTTP_NOT_FOUND, $e->getCode()); + } + } + + /** + * Invoke the SOAP api and assert for the NoWebApiXmlTestTest test cases that no such SOAP route exists + * + * @param array $serviceInfo + * @param array|null $requestData + * @param string $expectedMessage + */ + protected function _assertSoapException($serviceInfo, $requestData = null, $expectedMessage = '') + { + try { + $this->_webApiCall($serviceInfo, $requestData); + } catch (\Exception $e) { + if (get_class($e) !== 'SoapFault') { + $this->fail( + sprintf( + 'Expected SoapFault exception not generated for Service - "%s" and Operation - "%s"', + $serviceInfo['soap']['service'], + $serviceInfo['soap']['operation'] + ) + ); + } + + if ($expectedMessage) { + $this->assertEquals($expectedMessage, $e->getMessage()); + } + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/CoreRoutingTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/CoreRoutingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e1959e4f59fc9a54e46a4ad472fc8916471f2f4e --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/CoreRoutingTest.php @@ -0,0 +1,75 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +/** + * Class to test Core Web API routing + */ +namespace Magento\Webapi\Routing; + +class CoreRoutingTest extends \Magento\Webapi\Routing\BaseService +{ + public function testBasicRoutingExplicitPath() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/testmodule1/' . $itemId, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'testModule1AllSoapAndRestV1', + 'operation' => 'testModule1AllSoapAndRestV1Item', + ], + ]; + $requestData = ['itemId' => $itemId]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals('testProduct1', $item['name'], "Item was retrieved unsuccessfully"); + } + + public function testDisabledIntegrationAuthorizationException() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/testmodule1/' . $itemId, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'testModule1AllSoapAndRestV1', + 'operation' => 'testModule1AllSoapAndRestV1Item', + ], + ]; + $requestData = ['itemId' => $itemId]; + + /** Disable integration associated with active OAuth credentials. */ + $credentials = \Magento\TestFramework\Authentication\OauthHelper::getApiAccessCredentials(); + /** @var \Magento\Integration\Model\Integration $integration */ + $integration = $credentials['integration']; + $originalStatus = $integration->getStatus(); + $integration->setStatus(\Magento\Integration\Model\Integration::STATUS_INACTIVE)->save(); + + try { + $this->assertUnauthorizedException($serviceInfo, $requestData); + } catch (\Exception $e) { + /** Restore original status of integration associated with active OAuth credentials */ + $integration->setStatus($originalStatus)->save(); + throw $e; + } + $integration->setStatus($originalStatus)->save(); + } + + public function testExceptionSoapInternalError() + { + $this->_markTestAsSoapOnly(); + $serviceInfo = [ + 'soap' => [ + 'service' => 'testModule3ErrorV1', + 'operation' => 'testModule3ErrorV1ServiceException', + ], + ]; + $this->setExpectedException('SoapFault', 'Generic service exception'); + $this->_webApiCall($serviceInfo); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/GettersTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/GettersTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5dfc7fb4a6e240be896190d2319dfb2c943e6299 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/GettersTest.php @@ -0,0 +1,55 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Webapi\Routing; + +use Magento\TestModule5\Service\V1\Entity\AllSoapAndRest; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class GettersTest extends \Magento\Webapi\Routing\BaseService +{ + /** + * @var string + */ + protected $_version; + + /** + * @var string + */ + protected $_restResourcePath; + + /** + * @var string + */ + protected $_soapService = 'testModule5AllSoapAndRest'; + + protected function setUp() + { + $this->_version = 'V1'; + $this->_soapService = "testModule5AllSoapAndRest{$this->_version}"; + $this->_restResourcePath = "/{$this->_version}/TestModule5/"; + } + + public function testGetters() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => $this->_soapService, + 'operation' => $this->_soapService . 'Item', + ], + ]; + $requestData = [AllSoapAndRest::ID => $itemId]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($itemId, $item[AllSoapAndRest::ID], 'Item was retrieved unsuccessfully'); + $isEnabled = isset($item[AllSoapAndRest::ENABLED]) && $item[AllSoapAndRest::ENABLED] === true; + $this->assertTrue($isEnabled, 'Getter with "is" prefix is processed incorrectly.'); + $hasOrder = isset($item[AllSoapAndRest::HAS_ORDERS]) && $item[AllSoapAndRest::HAS_ORDERS] === true; + $this->assertTrue($hasOrder, 'Getter with "has" prefix is processed incorrectly.'); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/NoWebApiXmlTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/NoWebApiXmlTest.php new file mode 100644 index 0000000000000000000000000000000000000000..819429fb00302902ff55d6960ff64b5ee9218705 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/NoWebApiXmlTest.php @@ -0,0 +1,106 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Webapi\Routing; + +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class to test routing with a service that has no webapi.xml + */ +class NoWebApiXmlTest extends \Magento\Webapi\Routing\BaseService +{ + /** + * @var string + */ + private $_version; + + /** + * @var string + */ + private $_restResourcePath; + + protected function setUp() + { + $this->_version = 'V1'; + $this->_restResourcePath = "/{$this->_version}/testModule2NoWebApiXml/"; + } + + /** + * Test get item + */ + public function testItem() + { + $this->_markTestAsRestOnly(); + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + ]; + $requestData = ['id' => $itemId]; + $this->_assertNoRestRouteException($serviceInfo, $requestData); + } + + /** + * Test fetching all items + */ + public function testItems() + { + $this->_markTestAsRestOnly(); + $serviceInfo = [ + 'rest' => ['resourcePath' => $this->_restResourcePath, 'httpMethod' => RestConfig::HTTP_METHOD_GET], + ]; + $this->_assertNoRestRouteException($serviceInfo); + } + + /** + * Test create item + */ + public function testCreate() + { + $this->_markTestAsRestOnly(); + $createdItemName = 'createdItemName'; + $serviceInfo = [ + 'rest' => ['resourcePath' => $this->_restResourcePath, 'httpMethod' => RestConfig::HTTP_METHOD_POST], + ]; + $requestData = ['name' => $createdItemName]; + $this->_assertNoRestRouteException($serviceInfo, $requestData); + } + + /** + * Test update item + */ + public function testUpdate() + { + $this->_markTestAsRestOnly(); + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + $requestData = ['id' => $itemId]; + $this->_assertNoRestRouteException($serviceInfo, $requestData); + } + + /** + * Test remove item + */ + public function testRemove() + { + $this->_markTestAsRestOnly(); + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + ]; + $requestData = ['id' => $itemId]; + $this->_assertNoRestRouteException($serviceInfo, $requestData); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RequestIdOverrideTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RequestIdOverrideTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6ed32b0349fe1a14417e294732777634d0553431 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RequestIdOverrideTest.php @@ -0,0 +1,160 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Webapi\Routing; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +/** + * Class to test overriding request body identifier property with id passed in url path parameter + * + * Refer to \Magento\Webapi\Controller\Rest\Request::overrideRequestBodyIdWithPathParam + */ +class RequestIdOverrideTest extends \Magento\Webapi\Routing\BaseService +{ + /** + * @var string + */ + protected $_version; + + /** + * @var string + */ + protected $_restResourcePath; + + /** + * @var \Magento\TestModule5\Service\V1\Entity\AllSoapAndRestBuilder + */ + protected $itemBuilder; + + /** + * @var string + */ + protected $_soapService = 'testModule5AllSoapAndRest'; + + protected function setUp() + { + $this->_markTestAsRestOnly('Request Id overriding is a REST based feature.'); + $this->_version = 'V1'; + $this->_restResourcePath = "/{$this->_version}/TestModule5/"; + $this->itemBuilder = Bootstrap::getObjectManager() + ->create('Magento\TestModule5\Service\V1\Entity\AllSoapAndRestBuilder'); + } + + public function testOverride() + { + $itemId = 1; + $incorrectItemId = 2; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + $item = $this->itemBuilder + ->setEntityId($incorrectItemId) + ->setName('test') + ->create(); + $requestData = ['entityItem' => $item->__toArray()]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals( + $itemId, + $item[\Magento\TestModule5\Service\V1\Entity\AllSoapAndRest::ID], + 'Identifier overriding failed.' + ); + } + + public function testOverrideNested() + { + $firstItemId = 1; + $secondItemId = 11; + $incorrectItemId = 2; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $firstItemId . '/nestedResource/' . $secondItemId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + $item = $this->itemBuilder + ->setEntityId($incorrectItemId) + ->setName('test') + ->create(); + $requestData = ['entityItem' => $item->__toArray()]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals( + $secondItemId, + $item[\Magento\TestModule5\Service\V1\Entity\AllSoapAndRest::ID], + 'Identifier overriding failed for nested resource request.' + ); + } + + public function testOverrideAdd() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + $item = $this->itemBuilder + ->setName('test') + ->create(); + $requestData = ['entityItem' => $item->__toArray()]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals( + $itemId, + $item[\Magento\TestModule5\Service\V1\Entity\AllSoapAndRest::ID], + 'Identifier replacing failed.' + ); + } + + /** + * Test if the framework works if camelCase path parameters are provided instead of valid snake case ones. + * Webapi Framework currently accepts both cases due to shortcoming in Serialization (MAGETWO-29833). + * Unless it is fixed this use case is valid. + */ + public function testAddCaseMismatch() + { + $itemId = 1; + $incorrectItemId = 2; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + $requestData = ['entityItem' => ['entityId' => $incorrectItemId, 'name' => 'test']]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals( + $itemId, + $item[\Magento\TestModule5\Service\V1\Entity\AllSoapAndRest::ID], + 'Identifier overriding failed.' + ); + } + + public function testOverrideWithScalarValues() + { + $firstItemId = 1; + $secondItemId = 11; + $incorrectItemId = 2; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => "/{$this->_version}/TestModule5/OverrideService/" . $firstItemId + . '/nestedResource/' . $secondItemId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + ]; + + $requestData = ['entity_id' => $incorrectItemId, 'name' => 'test', 'orders' => true]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals( + $secondItemId, + $item[\Magento\TestModule5\Service\V1\Entity\AllSoapAndRest::ID], + 'Identifier overriding failed.' + ); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..18d169911f9fd95a5112de353d85d9fcb5565073 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php @@ -0,0 +1,160 @@ +<?php +/** + * Test Web API error codes. + * + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Webapi\Routing; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Webapi\Exception as WebapiException; + +class RestErrorHandlingTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + /** + * @var string + */ + protected $mode; + + protected function setUp() + { + $this->_markTestAsRestOnly(); + $this->mode = Bootstrap::getObjectManager()->get('Magento\Framework\App\State')->getMode(); + parent::setUp(); + } + + public function testSuccess() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/errortest/success', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + ]; + + $item = $this->_webApiCall($serviceInfo); + + // TODO: check Http Status = 200, cannot do yet due to missing header info returned + + $this->assertEquals('a good id', $item['value'], 'Success case is correct'); + } + + public function testNotFound() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/errortest/notfound', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + ]; + + // \Magento\Framework\Api\ResourceNotFoundException + $this->_errorTest( + $serviceInfo, + ['resource_id' => 'resourceY'], + WebapiException::HTTP_NOT_FOUND, + 'Resource with ID "%resource_id" not found.' + ); + } + + public function testUnauthorized() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/errortest/unauthorized', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + ]; + + // \Magento\Framework\Api\AuthorizationException + $this->_errorTest( + $serviceInfo, + [], + WebapiException::HTTP_UNAUTHORIZED, + 'Consumer is not authorized to access %resources', + ['resources' => 'resourceN'] + ); + } + + public function testOtherException() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/errortest/otherexception', + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + ]; + + /* TODO : Fix as part MAGETWO-31330 + $expectedMessage = $this->mode == \Magento\Framework\App\State::MODE_DEVELOPER + ? 'Non service exception' + : 'Internal Error. Details are available in Magento log file. Report ID: webapi-XXX'; + */ + $expectedMessage = 'Internal Error. Details are available in Magento log file. Report ID: webapi-XXX'; + $this->_errorTest( + $serviceInfo, + [], + WebapiException::HTTP_INTERNAL_ERROR, + $expectedMessage, + null, + 'Magento\TestModule3\Service\V1\Error->otherException()' // Check if trace contains proper error source + ); + } + + /** + * Perform a negative REST api call test case and compare the results with expected values. + * + * @param string $serviceInfo - REST Service information (i.e. resource path and HTTP method) + * @param array $data - Data for the cal + * @param int $httpStatus - Expected HTTP status + * @param string|array $errorMessage - \Exception error message + * @param array $parameters - Optional parameters array, or null if no parameters + * @param string $traceString - Optional trace string to verify + */ + protected function _errorTest( + $serviceInfo, + $data, + $httpStatus, + $errorMessage, + $parameters = [], + $traceString = null + ) { + try { + $this->_webApiCall($serviceInfo, $data); + } catch (\Exception $e) { + $this->assertEquals($httpStatus, $e->getCode(), 'Checking HTTP status code'); + + $body = json_decode($e->getMessage(), true); + + $errorMessages = is_array($errorMessage) ? $errorMessage : [$errorMessage]; + $actualMessage = $body['message']; + $matches = []; + //Report ID was created dynamically, so we need to replace it with some static value in order to test + if (preg_match('/.*Report\sID\:\s([a-zA-Z0-9\-]*)/', $actualMessage, $matches)) { + $actualMessage = str_replace($matches[1], 'webapi-XXX', $actualMessage); + } + //make sure that the match for a report with an id is found if Internal error was reported + //Refer : \Magento\Webapi\Controller\ErrorProcessor::INTERNAL_SERVER_ERROR_MSG + if (count($matches) > 1) { + $this->assertTrue(!empty($matches[1]), 'Report id missing for internal error.'); + } + $this->assertContains( + $actualMessage, + $errorMessages, + "Message is invalid. Actual: '{$actualMessage}'. Expected one of: {'" . implode( + "', '", + $errorMessages + ) . "'}" + ); + + if ($parameters) { + $this->assertEquals($parameters, $body['parameters'], 'Checking body parameters'); + } + + if ($this->mode == \Magento\Framework\App\State::MODE_DEVELOPER && $traceString) { + // TODO : Fix as part MAGETWO-31330 + //$this->assertContains($traceString, $body['trace'], 'Trace information is incorrect.'); + } + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/ServiceVersionV1Test.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/ServiceVersionV1Test.php new file mode 100644 index 0000000000000000000000000000000000000000..d0e97d268f3473b8464dc1a6925e8d99bc773215 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/ServiceVersionV1Test.php @@ -0,0 +1,267 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +/** + * Class to test routing based on Service Versioning(for V1 version of a service) + */ +namespace Magento\Webapi\Routing; + +use Magento\Framework\Api\AttributeValue; +use Magento\TestFramework\Authentication\OauthHelper; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestModule1\Service\V1\Entity\ItemBuilder; +use Magento\Webapi\Model\Rest\Config as RestConfig; + +class ServiceVersionV1Test extends \Magento\Webapi\Routing\BaseService +{ + /** + * @var string + */ + protected $_version; + /** + * @var string + */ + protected $_restResourcePath; + /** + * @var string + */ + protected $_soapService = 'testModule1AllSoapAndRest'; + + /** @var \Magento\Framework\Api\AttributeDataBuilder */ + protected $valueBuilder; + + /** @var ItemBuilder */ + protected $itemBuilder; + + protected function setUp() + { + $this->_version = 'V1'; + $this->_soapService = 'testModule1AllSoapAndRestV1'; + $this->_restResourcePath = "/{$this->_version}/testmodule1/"; + + $this->valueBuilder = Bootstrap::getObjectManager()->create( + 'Magento\Framework\Api\AttributeDataBuilder' + ); + + $this->itemBuilder = Bootstrap::getObjectManager()->create( + 'Magento\TestModule1\Service\V1\Entity\ItemBuilder' + ); + } + + /** + * Test get item + */ + public function testItem() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Item'], + ]; + $requestData = ['itemId' => $itemId]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals('testProduct1', $item['name'], 'Item was retrieved unsuccessfully'); + } + + /** + * Test get item with any type + */ + public function testItemAnyType() + { + $this->_markTestAsRestOnly('Test will fail for SOAP because attribute values get converted to strings.'); + $customerAttributes = [ + ItemBuilder::CUSTOM_ATTRIBUTE_1 => [ + AttributeValue::ATTRIBUTE_CODE => ItemBuilder::CUSTOM_ATTRIBUTE_1, + AttributeValue::VALUE => '12345', + ], + ItemBuilder::CUSTOM_ATTRIBUTE_2 => [ + AttributeValue::ATTRIBUTE_CODE => ItemBuilder::CUSTOM_ATTRIBUTE_2, + AttributeValue::VALUE => 12345, + ], + ItemBuilder::CUSTOM_ATTRIBUTE_3 => [ + AttributeValue::ATTRIBUTE_CODE => ItemBuilder::CUSTOM_ATTRIBUTE_3, + AttributeValue::VALUE => true, + ], + ]; + + $attributeValue1 = $this->valueBuilder + ->setAttributeCode(ItemBuilder::CUSTOM_ATTRIBUTE_1) + ->setValue('12345') + ->create(); + $attributeValue2 = $this->valueBuilder + ->setAttributeCode(ItemBuilder::CUSTOM_ATTRIBUTE_2) + ->setValue(12345) + ->create(); + $attributeValue3 = $this->valueBuilder + ->setAttributeCode(ItemBuilder::CUSTOM_ATTRIBUTE_3) + ->setValue(true) + ->create(); + + $item = $this->itemBuilder + ->setItemId(1) + ->setName('testProductAnyType') + ->setCustomAttributes([$attributeValue1, $attributeValue2, $attributeValue3]) + ->create(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'itemAnyType', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'ItemAnyType'], + ]; + $requestData = $item->__toArray(); + $item = $this->_webApiCall($serviceInfo, ['entityItem' => $requestData]); + + $this->assertSame( + $attributeValue1->getValue(), + $item['custom_attributes'][0]['value'], + 'Serialized attribute value type does\'t match pre-defined type.' + ); // string '12345' is expected + + $this->assertSame( + $attributeValue2->getValue(), + $item['custom_attributes'][1]['value'], + 'Serialized attribute value type does\'t match pre-defined type.' + ); // integer 12345 is expected + + $this->assertSame( + $attributeValue3->getValue(), + $item['custom_attributes'][2]['value'], + 'Serialized attribute value type does\'t match pre-defined type.' + ); // boolean true is expected + } + + /** + * Test fetching all items + */ + public function testItems() + { + $itemArr = [['item_id' => 1, 'name' => 'testProduct1'], ['item_id' => 2, 'name' => 'testProduct2']]; + $serviceInfo = [ + 'rest' => ['resourcePath' => $this->_restResourcePath, 'httpMethod' => RestConfig::HTTP_METHOD_GET], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Items'], + ]; + $item = $this->_webApiCall($serviceInfo); + $this->assertEquals($itemArr, $item, 'Items were not retrieved'); + } + + /** + * Test create item + */ + public function testCreate() + { + $createdItemName = 'createdItemName'; + $serviceInfo = [ + 'rest' => ['resourcePath' => $this->_restResourcePath, 'httpMethod' => RestConfig::HTTP_METHOD_POST], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Create'], + ]; + $requestData = ['name' => $createdItemName]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($createdItemName, $item['name'], 'Item creation failed'); + } + + /** + * Test create item with missing proper resources + */ + public function testCreateWithoutResources() + { + $createdItemName = 'createdItemName'; + $serviceInfo = [ + 'rest' => ['resourcePath' => $this->_restResourcePath, 'httpMethod' => RestConfig::HTTP_METHOD_POST], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Create'], + ]; + $requestData = ['name' => $createdItemName]; + + // getting new credentials that do not match the api resources + OauthHelper::clearApiAccessCredentials(); + OauthHelper::getApiAccessCredentials([]); + try { + $this->assertUnauthorizedException($serviceInfo, $requestData); + } catch (\Exception $e) { + OauthHelper::clearApiAccessCredentials(); + throw $e; + } + // to allow good credentials to be restored (this is statically stored on OauthHelper) + OauthHelper::clearApiAccessCredentials(); + } + + /** + * Test update item + */ + public function testUpdate() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_PUT, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Update'], + ]; + $requestData = ['entityItem' => ['itemId' => $itemId, 'name' => 'testName']]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals('Updated' . $requestData['entityItem']['name'], $item['name'], 'Item update failed'); + } + + /** + * Negative Test: Invoking non-existent delete api which is only available in V2 + */ + public function testDelete() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => RestConfig::HTTP_METHOD_DELETE, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Delete'], + ]; + $requestData = ['itemId' => $itemId, 'name' => 'testName']; + $this->_assertNoRouteOrOperationException($serviceInfo, $requestData); + } + + public function testOverwritten() + { + $this->_markTestAsRestOnly(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'overwritten', + 'httpMethod' => RestConfig::HTTP_METHOD_GET, + ], + ]; + $item = $this->_webApiCall($serviceInfo, []); + $this->assertEquals(['item_id' => -55, 'name' => 'testProduct1'], $item); + } + + public function testDefaulted() + { + $this->_markTestAsRestOnly(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'testOptionalParam', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + ]; + $item = $this->_webApiCall($serviceInfo, []); + $this->assertEquals(['item_id' => 3, 'name' => 'Default Name'], $item); + } + + public function testDefaultedWithValue() + { + $this->_markTestAsRestOnly(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . 'testOptionalParam', + 'httpMethod' => RestConfig::HTTP_METHOD_POST, + ], + ]; + $item = $this->_webApiCall($serviceInfo, ['name' => 'Ms. LaGrange']); + $this->assertEquals(['item_id' => 3, 'name' => 'Ms. LaGrange'], $item); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/ServiceVersionV2Test.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/ServiceVersionV2Test.php new file mode 100644 index 0000000000000000000000000000000000000000..44707fb779da6960c671bb81e0d9fab78fee2a85 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/ServiceVersionV2Test.php @@ -0,0 +1,142 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ +namespace Magento\Webapi\Routing; + +class ServiceVersionV2Test extends \Magento\Webapi\Routing\BaseService +{ + protected function setUp() + { + $this->_version = 'V2'; + $this->_soapService = 'testModule1AllSoapAndRestV2'; + $this->_restResourcePath = "/{$this->_version}/testmodule1/"; + } + + /** + * Test to assert overriding of the existing 'Item' api in V2 version of the same service + */ + public function testItem() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Item'], + ]; + $requestData = ['id' => $itemId]; + $item = $this->_webApiCall($serviceInfo, $requestData); + // Asserting for additional attribute returned by the V2 api + $this->assertEquals(1, $item['price'], 'Item was retrieved unsuccessfully from V2'); + } + + /** + * Test fetching all items + */ + public function testItems() + { + $itemArr = [ + ['id' => 1, 'name' => 'testProduct1', 'price' => '1'], + ['id' => 2, 'name' => 'testProduct2', 'price' => '2'], + ]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Items'], + ]; + $item = $this->_webApiCall($serviceInfo); + $this->assertEquals($itemArr, $item, 'Items were not retrieved'); + } + + /** + * Test fetching items when filters are applied + * + * @param string[] $filters + * @param array $expectedResult + * @dataProvider itemsWithFiltersDataProvider + */ + public function testItemsWithFilters($filters, $expectedResult) + { + $restFilter = ''; + foreach ($filters as $filterItemKey => $filterMetadata) { + foreach ($filterMetadata as $filterMetaKey => $filterMetaValue) { + $paramsDelimiter = empty($restFilter) ? '?' : '&'; + $restFilter .= "{$paramsDelimiter}filters[{$filterItemKey}][{$filterMetaKey}]={$filterMetaValue}"; + } + } + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $restFilter, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => $this->_soapService, + 'operation' => $this->_soapService . 'Items', + ], + ]; + $requestData = []; + if (!empty($filters)) { + $requestData['filters'] = $filters; + } + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($expectedResult, $item, 'Filtration does not seem to work correctly.'); + } + + public function itemsWithFiltersDataProvider() + { + $firstItem = ['id' => 1, 'name' => 'testProduct1', 'price' => 1]; + $secondItem = ['id' => 2, 'name' => 'testProduct2', 'price' => 2]; + return [ + 'Both items filter' => [ + [ + ['field' => 'id', 'conditionType' => 'eq','value' => 1], + ['field' => 'id', 'conditionType' => 'eq','value' => 2], + ], + [$firstItem, $secondItem], + ], + 'First item filter' => [[['field' => 'id', 'conditionType' => 'eq','value' => 1]], [$firstItem]], + 'Second item filter' => [[['field' => 'id', 'conditionType' => 'eq','value' => 2]], [$secondItem]], + 'Empty filter' => [[], [$firstItem, $secondItem]], + ]; + } + + /** + * Test update item + */ + public function testUpdate() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_PUT, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Update'], + ]; + $requestData = ['entityItem' => ['id' => $itemId, 'name' => 'testName', 'price' => '4']]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals('Updated' . $requestData['entityItem']['name'], $item['name'], 'Item update failed'); + } + + /** + * Test to assert presence of new 'delete' api added in V2 version of the same service + */ + public function testDelete() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_DELETE, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Delete'], + ]; + $requestData = ['id' => $itemId, 'name' => 'testName']; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($itemId, $item['id'], "Item delete failed"); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/SoapErrorHandlingTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/SoapErrorHandlingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d84f5fe8198b26cf1913e59d06e678ed0d93898e --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/SoapErrorHandlingTest.php @@ -0,0 +1,163 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Webapi\Routing; + +use Magento\Framework\Exception\AuthorizationException; + +/** + * SOAP error handling test. + */ +class SoapErrorHandlingTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + protected function setUp() + { + $this->_markTestAsSoapOnly(); + parent::setUp(); + } + + public function testWebapiException() + { + $serviceInfo = [ + 'soap' => [ + 'service' => 'testModule3ErrorV1', + 'operation' => 'testModule3ErrorV1WebapiException', + ], + ]; + try { + $this->_webApiCall($serviceInfo); + $this->fail("SoapFault was not raised as expected."); + } catch (\SoapFault $e) { + $this->checkSoapFault( + $e, + 'Service not found', + 'env:Sender' + ); + } + } + + public function testUnknownException() + { + $serviceInfo = [ + 'soap' => [ + 'service' => 'testModule3ErrorV1', + 'operation' => 'testModule3ErrorV1OtherException', + ], + ]; + try { + $this->_webApiCall($serviceInfo); + $this->fail("SoapFault was not raised as expected."); + } catch (\SoapFault $e) { + /** In developer mode message is masked, so checks should be different in two modes */ + if (strpos($e->getMessage(), 'Internal Error') === false) { + $this->checkSoapFault( + $e, + 'Non service exception', + 'env:Receiver', + null, + null, + 'Magento\TestModule3\Service\V1\Error->otherException()' + ); + } else { + $this->checkSoapFault( + $e, + 'Internal Error. Details are available in Magento log file. Report ID:', + 'env:Receiver' + ); + } + } + } + + public function testEmptyInputException() + { + $parameters = []; + $this->_testWrappedError($parameters); + } + + public function testSingleWrappedErrorException() + { + $parameters = [ + ['fieldName' => 'key1', 'value' => 'value1'], + ]; + $this->_testWrappedError($parameters); + } + + public function testMultipleWrappedErrorException() + { + $parameters = [ + ['fieldName' => 'key1', 'value' => 'value1'], + ['fieldName' => 'key2', 'value' => 'value2'], + ]; + $this->_testWrappedError($parameters); + } + + public function testUnauthorized() + { + $serviceInfo = [ + 'soap' => [ + 'service' => 'testModule3ErrorV1', + 'operation' => 'testModule3ErrorV1AuthorizationException', + 'token' => 'invalidToken', + ], + ]; + + $expectedException = new AuthorizationException( + AuthorizationException::NOT_AUTHORIZED, + ['resources' => 'Magento_TestModule3::resource1, Magento_TestModule3::resource2'] + ); + + try { + $this->_webApiCall($serviceInfo); + $this->fail("SoapFault was not raised as expected."); + } catch (\SoapFault $e) { + $this->checkSoapFault( + $e, + $expectedException->getRawMessage(), + 'env:Sender', + $expectedException->getParameters() // expected error parameters + ); + } + } + + protected function _testWrappedError($parameters) + { + $serviceInfo = [ + 'soap' => [ + 'service' => 'testModule3ErrorV1', + 'operation' => 'testModule3ErrorV1InputException', + ], + ]; + + $expectedException = new \Magento\Framework\Exception\InputException(); + foreach ($parameters as $error) { + $expectedException->addError(\Magento\Framework\Exception\InputException::INVALID_FIELD_VALUE, $error); + } + + $arguments = [ + 'wrappedErrorParameters' => $parameters, + ]; + + $expectedErrors = []; + foreach ($expectedException->getErrors() as $key => $error) { + $expectedErrors[$key] = [ + 'message' => $error->getRawMessage(), + 'params' => $error->getParameters(), + ]; + } + + try { + $this->_webApiCall($serviceInfo, $arguments); + $this->fail("SoapFault was not raised as expected."); + } catch (\SoapFault $e) { + $this->checkSoapFault( + $e, + $expectedException->getRawMessage(), + 'env:Sender', + $expectedException->getParameters(), // expected error parameters + $expectedErrors // expected wrapped errors + ); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/SubsetTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/SubsetTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e9b3aac72be7cab13a84317d72235c88c4b2c625 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/SubsetTest.php @@ -0,0 +1,75 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +/** + * Class to test routing based on a Service that exposes subset of operations + */ +namespace Magento\Webapi\Routing; + +class SubsetTest extends \Magento\Webapi\Routing\BaseService +{ + /** + * @var string + */ + protected $_version; + + /** + * @var string + */ + protected $_restResourcePath; + + /** + * @var string + */ + protected $_soapService; + + /** + * @Override + */ + protected function setUp() + { + $this->_version = 'V1'; + $this->_restResourcePath = "/{$this->_version}/testModule2SubsetRest/"; + $this->_soapService = 'testModule2SubsetRestV1'; + } + + /** + * @Override + * Test get item + */ + public function testItem() + { + $itemId = 1; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath . $itemId, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Item'], + ]; + $requestData = ['id' => $itemId]; + $item = $this->_webApiCall($serviceInfo, $requestData); + $this->assertEquals($itemId, $item['id'], 'Item was retrieved unsuccessfully'); + } + + /** + * @Override + * Test fetching all items + */ + public function testItems() + { + $itemArr = [['id' => 1, 'name' => 'testItem1'], ['id' => 2, 'name' => 'testItem2']]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => $this->_restResourcePath, + 'httpMethod' => \Magento\Webapi\Model\Rest\Config::HTTP_METHOD_GET, + ], + 'soap' => ['service' => $this->_soapService, 'operation' => $this->_soapService . 'Items'], + ]; + + $item = $this->_webApiCall($serviceInfo); + $this->assertEquals($itemArr, $item, 'Items were not retrieved'); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/WsdlGenerationFromDataObjectTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/WsdlGenerationFromDataObjectTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3f27b6179ec55ddb06d290b61c6e6ded4dc1c943 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/WsdlGenerationFromDataObjectTest.php @@ -0,0 +1,735 @@ +<?php +/** + * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com) + */ + +namespace Magento\Webapi; + +use Magento\TestFramework\Helper\Bootstrap; + +/** + * Test WSDL generation mechanisms. + */ +class WsdlGenerationFromDataObjectTest extends \Magento\TestFramework\TestCase\WebapiAbstract +{ + /** @var string */ + protected $_baseUrl = TESTS_BASE_URL; + + /** @var string */ + protected $_storeCode; + + /** @var string */ + protected $_soapUrl; + + protected function setUp() + { + $this->_markTestAsSoapOnly("WSDL generation tests are intended to be executed for SOAP adapter only."); + $this->_storeCode = Bootstrap::getObjectManager()->get('Magento\Store\Model\StoreManagerInterface') + ->getStore()->getCode(); + $this->_soapUrl = "{$this->_baseUrl}/soap/{$this->_storeCode}?services%3DtestModule5AllSoapAndRestV1%2CtestModule5AllSoapAndRestV2"; + parent::setUp(); + } + + public function testMultiServiceWsdl() + { + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + $this->markTestIncomplete('MAGETWO-31016: incompatible with ZF 1.12.9'); + } + $wsdlUrl = $this->_getBaseWsdlUrl() . 'testModule5AllSoapAndRestV1,testModule5AllSoapAndRestV2'; + $wsdlContent = $this->_convertXmlToString($this->_getWsdlContent($wsdlUrl)); + + $this->_checkTypesDeclaration($wsdlContent); + $this->_checkPortTypeDeclaration($wsdlContent); + $this->_checkBindingDeclaration($wsdlContent); + $this->_checkServiceDeclaration($wsdlContent); + $this->_checkMessagesDeclaration($wsdlContent); + $this->_checkFaultsDeclaration($wsdlContent); + } + + public function testInvalidWsdlUrlNoServices() + { + $responseContent = $this->_getWsdlContent($this->_getBaseWsdlUrl()); + $this->assertContains("Requested services are missing.", $responseContent); + } + + public function testInvalidWsdlUrlInvalidParameter() + { + $wsdlUrl = $this->_getBaseWsdlUrl() . '&invalid'; + $responseContent = $this->_getWsdlContent($wsdlUrl); + $this->assertContains("Not allowed parameters", $responseContent); + } + + /** + * Remove unnecessary spaces and line breaks from xml string. + * + * @param string $xml + * @return string + */ + protected function _convertXmlToString($xml) + { + return str_replace([' ', "\n", "\r", " ", " "], '', $xml); + } + + /** + * Retrieve WSDL content. + * + * @param string $wsdlUrl + * @return string|boolean + */ + protected function _getWsdlContent($wsdlUrl) + { + $connection = curl_init($wsdlUrl); + curl_setopt($connection, CURLOPT_RETURNTRANSFER, 1); + $responseContent = curl_exec($connection); + $responseDom = new \DOMDocument(); + $this->assertTrue( + $responseDom->loadXML($responseContent), + "Valid XML is always expected as a response for WSDL request." + ); + return $responseContent; + } + + /** + * Generate base WSDL URL (without any services specified) + * + * @return string + */ + protected function _getBaseWsdlUrl() + { + /** @var \Magento\TestFramework\TestCase\Webapi\Adapter\Soap $soapAdapter */ + $soapAdapter = $this->_getWebApiAdapter(self::ADAPTER_SOAP); + $wsdlUrl = $soapAdapter->generateWsdlUrl([]); + return $wsdlUrl; + } + + /** + * Ensure that types section has correct structure. + * + * @param string $wsdlContent + */ + protected function _checkTypesDeclaration($wsdlContent) + { + // @codingStandardsIgnoreStart + $typesSectionDeclaration = <<< TYPES_SECTION_DECLARATION +<types> + <xsd:schema targetNamespace="{$this->_soapUrl}"> +TYPES_SECTION_DECLARATION; + // @codingStandardsIgnoreEnd + $this->assertContains( + $this->_convertXmlToString($typesSectionDeclaration), + $wsdlContent, + 'Types section declaration is invalid' + ); + $this->_checkElementsDeclaration($wsdlContent); + $this->_checkComplexTypesDeclaration($wsdlContent); + } + + /** + * @param string $wsdlContent + */ + protected function _checkElementsDeclaration($wsdlContent) + { + $requestElement = <<< REQUEST_ELEMENT +<xsd:element name="testModule5AllSoapAndRestV1ItemRequest" type="tns:TestModule5AllSoapAndRestV1ItemRequest"/> +REQUEST_ELEMENT; + $this->assertContains( + $this->_convertXmlToString($requestElement), + $wsdlContent, + 'Request element declaration in types section is invalid' + ); + $responseElement = <<< RESPONSE_ELEMENT +<xsd:element name="testModule5AllSoapAndRestV1ItemResponse" type="tns:TestModule5AllSoapAndRestV1ItemResponse"/> +RESPONSE_ELEMENT; + $this->assertContains( + $this->_convertXmlToString($responseElement), + $wsdlContent, + 'Response element declaration in types section is invalid' + ); + } + + /** + * @param string $wsdlContent + */ + protected function _checkComplexTypesDeclaration($wsdlContent) + { + // @codingStandardsIgnoreStart + $requestType = <<< REQUEST_TYPE +<xsd:complexType name="TestModule5AllSoapAndRestV1ItemRequest"> + <xsd:annotation> + <xsd:documentation>Retrieve an item.</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="entityId" minOccurs="1" maxOccurs="1" type="xsd:int"> + <xsd:annotation> + <xsd:documentation></xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Item</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> +</xsd:complexType> +REQUEST_TYPE; + // @codingStandardsIgnoreEnd + $this->assertContains( + $this->_convertXmlToString($requestType), + $wsdlContent, + 'Request type declaration in types section is invalid' + ); + // @codingStandardsIgnoreStart + $responseType = <<< RESPONSE_TYPE +<xsd:complexType name="TestModule5AllSoapAndRestV1ItemResponse"> + <xsd:annotation> + <xsd:documentation> + Response container for the testModule5AllSoapAndRestV1Item call. + </xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="result" minOccurs="1" maxOccurs="1" type="tns:TestModule5V1EntityAllSoapAndRest"> + <xsd:annotation> + <xsd:documentation></xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Item</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> +</xsd:complexType> +RESPONSE_TYPE; + // @codingStandardsIgnoreEnd + $this->assertContains( + $this->_convertXmlToString($responseType), + $wsdlContent, + 'Response type declaration in types section is invalid' + ); + $this->_checkReferencedTypeDeclaration($wsdlContent); + } + + /** + * Ensure that complex type generated from Data Object is correct. + * + * @param string $wsdlContent + */ + protected function _checkReferencedTypeDeclaration($wsdlContent) + { + // @codingStandardsIgnoreStart + $referencedType = <<< RESPONSE_TYPE +<xsd:complexType name="TestModule5V1EntityAllSoapAndRest"> + <xsd:annotation> + <xsd:documentation>Some Data Object short description. Data Object long multi line description.</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="entityId" minOccurs="1" maxOccurs="1" type="xsd:int"> + <xsd:annotation> + <xsd:documentation>Item ID</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:min/> + <inf:max/> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Item</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Create</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Update</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1NestedUpdate</inf:callName> + <inf:returned>Always</inf:returned> + </inf:callInfo> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Create</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Update</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1NestedUpdate</inf:callName> + <inf:requiredInput>Yes</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="name" minOccurs="0" maxOccurs="1" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Item name</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:maxLength/> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Item</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Create</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Update</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1NestedUpdate</inf:callName> + <inf:returned>Conditionally</inf:returned> + </inf:callInfo> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Create</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Update</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1NestedUpdate</inf:callName> + <inf:requiredInput>No</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="enabled" minOccurs="1" maxOccurs="1" type="xsd:boolean"> + <xsd:annotation> + <xsd:documentation></xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:default>false</inf:default> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Item</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Create</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Update</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1NestedUpdate</inf:callName> + <inf:returned>Conditionally</inf:returned> + </inf:callInfo> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Create</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Update</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1NestedUpdate</inf:callName> + <inf:requiredInput>No</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="orders" minOccurs="1" maxOccurs="1" type="xsd:boolean"> + <xsd:annotation> + <xsd:documentation></xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:default>false</inf:default> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Item</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Create</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Update</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1NestedUpdate</inf:callName> + <inf:returned>Conditionally</inf:returned> + </inf:callInfo> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Create</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Update</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1NestedUpdate</inf:callName> + <inf:requiredInput>No</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="customAttributes" type="tns:ArrayOfFrameworkAttributeInterface" minOccurs="0"> + <xsd:annotation> + <xsd:documentation></xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:natureOfType>array</inf:natureOfType> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Item</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Create</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Update</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1NestedUpdate</inf:callName> + <inf:returned>Conditionally</inf:returned> + </inf:callInfo> + <inf:callInfo> + <inf:callName>testModule5AllSoapAndRestV1Create</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1Update</inf:callName> + <inf:callName>testModule5AllSoapAndRestV1NestedUpdate</inf:callName> + <inf:requiredInput>No</inf:requiredInput> + </inf:callInfo> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> +</xsd:complexType> +RESPONSE_TYPE; + // @codingStandardsIgnoreEnd + $this->assertContains( + $this->_convertXmlToString($referencedType), + $wsdlContent, + 'Declaration of complex type generated from Data Object, which is referenced in response, is invalid' + ); + } + + /** + * Ensure that port type sections have correct structure. + * + * @param string $wsdlContent + */ + protected function _checkPortTypeDeclaration($wsdlContent) + { + $firstPortType = <<< FIRST_PORT_TYPE +<portType name="testModule5AllSoapAndRestV1PortType"> +FIRST_PORT_TYPE; + $this->assertContains( + $this->_convertXmlToString($firstPortType), + $wsdlContent, + 'Port type declaration is missing or invalid' + ); + $secondPortType = <<< SECOND_PORT_TYPE +<portType name="testModule5AllSoapAndRestV2PortType"> +SECOND_PORT_TYPE; + $this->assertContains( + $this->_convertXmlToString($secondPortType), + $wsdlContent, + 'Port type declaration is missing or invalid' + ); + $operationDeclaration = <<< OPERATION_DECLARATION +<operation name="testModule5AllSoapAndRestV2Item"> + <input message="tns:testModule5AllSoapAndRestV2ItemRequest"/> + <output message="tns:testModule5AllSoapAndRestV2ItemResponse"/> + <fault name="GenericFault" message="tns:GenericFault"/> +</operation> +<operation name="testModule5AllSoapAndRestV2Items"> + <input message="tns:testModule5AllSoapAndRestV2ItemsRequest"/> + <output message="tns:testModule5AllSoapAndRestV2ItemsResponse"/> + <fault name="GenericFault" message="tns:GenericFault"/> +</operation> +OPERATION_DECLARATION; + $this->assertContains( + $this->_convertXmlToString($operationDeclaration), + $wsdlContent, + 'Operation in port type is invalid' + ); + } + + /** + * Ensure that binding sections have correct structure. + * + * @param string $wsdlContent + */ + protected function _checkBindingDeclaration($wsdlContent) + { + $firstBinding = <<< FIRST_BINDING +<binding name="testModule5AllSoapAndRestV1Binding" type="tns:testModule5AllSoapAndRestV1PortType"> + <soap12:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> +FIRST_BINDING; + $this->assertContains( + $this->_convertXmlToString($firstBinding), + $wsdlContent, + 'Binding declaration is missing or invalid' + ); + $secondBinding = <<< SECOND_BINDING +<binding name="testModule5AllSoapAndRestV2Binding" type="tns:testModule5AllSoapAndRestV2PortType"> + <soap12:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> +SECOND_BINDING; + $this->assertContains( + $this->_convertXmlToString($secondBinding), + $wsdlContent, + 'Binding declaration is missing or invalid' + ); + $operationDeclaration = <<< OPERATION_DECLARATION +<operation name="testModule5AllSoapAndRestV1Item"> + <soap:operation soapAction="testModule5AllSoapAndRestV1Item"/> + <input> + <soap12:body use="literal"/> + </input> + <output> + <soap12:body use="literal"/> + </output> + <fault name="GenericFault"> + <soap12:fault use="literal" name="GenericFault"/> + </fault> +</operation> +<operation name="testModule5AllSoapAndRestV1Items"> + <soap:operation soapAction="testModule5AllSoapAndRestV1Items"/> + <input> + <soap12:body use="literal"/> + </input> + <output> + <soap12:body use="literal"/> + </output> + <fault name="GenericFault"> + <soap12:fault use="literal" name="GenericFault"/> + </fault> +</operation> +OPERATION_DECLARATION; + $this->assertContains( + $this->_convertXmlToString($operationDeclaration), + $wsdlContent, + 'Operation in binding is invalid' + ); + } + + /** + * Ensure that service sections have correct structure. + * + * @param string $wsdlContent + */ + protected function _checkServiceDeclaration($wsdlContent) + { + // @codingStandardsIgnoreStart + $firstServiceDeclaration = <<< FIRST_SERVICE_DECLARATION +<service name="testModule5AllSoapAndRestV1Service"> + <port name="testModule5AllSoapAndRestV1Port" binding="tns:testModule5AllSoapAndRestV1Binding"> + <soap:address location="{$this->_baseUrl}/soap/{$this->_storeCode}?services=testModule5AllSoapAndRestV1%2CtestModule5AllSoapAndRestV2"/> + </port> +</service> +FIRST_SERVICE_DECLARATION; + // @codingStandardsIgnoreEnd + $this->assertContains( + $this->_convertXmlToString($firstServiceDeclaration), + $wsdlContent, + 'First service section is invalid' + ); + + // @codingStandardsIgnoreStart + $secondServiceDeclaration = <<< SECOND_SERVICE_DECLARATION +<service name="testModule5AllSoapAndRestV2Service"> + <port name="testModule5AllSoapAndRestV2Port" binding="tns:testModule5AllSoapAndRestV2Binding"> + <soap:address location="{$this->_baseUrl}/soap/{$this->_storeCode}?services=testModule5AllSoapAndRestV1%2CtestModule5AllSoapAndRestV2"/> + </port> +</service> +SECOND_SERVICE_DECLARATION; + // @codingStandardsIgnoreEnd + $this->assertContains( + $this->_convertXmlToString($secondServiceDeclaration), + $wsdlContent, + 'Second service section is invalid' + ); + } + + /** + * Ensure that messages sections have correct structure. + * + * @param string $wsdlContent + */ + protected function _checkMessagesDeclaration($wsdlContent) + { + $itemMessagesDeclaration = <<< MESSAGES_DECLARATION +<message name="testModule5AllSoapAndRestV2ItemRequest"> + <part name="messageParameters" element="tns:testModule5AllSoapAndRestV2ItemRequest"/> +</message> +<message name="testModule5AllSoapAndRestV2ItemResponse"> + <part name="messageParameters" element="tns:testModule5AllSoapAndRestV2ItemResponse"/> +</message> +MESSAGES_DECLARATION; + $this->assertContains( + $this->_convertXmlToString($itemMessagesDeclaration), + $wsdlContent, + 'Messages section for "item" operation is invalid' + ); + $itemsMessagesDeclaration = <<< MESSAGES_DECLARATION +<message name="testModule5AllSoapAndRestV2ItemsRequest"> + <part name="messageParameters" element="tns:testModule5AllSoapAndRestV2ItemsRequest"/> +</message> +<message name="testModule5AllSoapAndRestV2ItemsResponse"> + <part name="messageParameters" element="tns:testModule5AllSoapAndRestV2ItemsResponse"/> +</message> +MESSAGES_DECLARATION; + $this->assertContains( + $this->_convertXmlToString($itemsMessagesDeclaration), + $wsdlContent, + 'Messages section for "items" operation is invalid' + ); + } + + /** + * Ensure that SOAP faults are declared properly. + * + * @param string $wsdlContent + */ + protected function _checkFaultsDeclaration($wsdlContent) + { + $this->_checkFaultsPortTypeSection($wsdlContent); + $this->_checkFaultsBindingSection($wsdlContent); + $this->_checkFaultsMessagesSection($wsdlContent); + $this->_checkFaultsComplexTypeSection($wsdlContent); + } + + /** + * @param string $wsdlContent + */ + protected function _checkFaultsPortTypeSection($wsdlContent) + { + $faultsInPortType = <<< FAULT_IN_PORT_TYPE +<fault name="GenericFault" message="tns:GenericFault"/> +FAULT_IN_PORT_TYPE; + $this->assertContains( + $this->_convertXmlToString($faultsInPortType), + $wsdlContent, + 'SOAP Fault section in port type section is invalid' + ); + } + + /** + * @param string $wsdlContent + */ + protected function _checkFaultsBindingSection($wsdlContent) + { + $faultsInBinding = <<< FAULT_IN_BINDING +<fault name="GenericFault"> + <soap12:fault use="literal" name="GenericFault"/> +</fault> +FAULT_IN_BINDING; + $this->assertContains( + $this->_convertXmlToString($faultsInBinding), + $wsdlContent, + 'SOAP Fault section in binding section is invalid' + ); + } + + /** + * @param string $wsdlContent + */ + protected function _checkFaultsMessagesSection($wsdlContent) + { + $genericFaultMessage = <<< GENERIC_FAULT_IN_MESSAGES +<message name="GenericFault"> + <part name="messageParameters" element="tns:GenericFault"/> +</message> +GENERIC_FAULT_IN_MESSAGES; + $this->assertContains( + $this->_convertXmlToString($genericFaultMessage), + $wsdlContent, + 'Generic SOAP Fault declaration in messages section is invalid' + ); + } + + /** + * @param string $wsdlContent + */ + protected function _checkFaultsComplexTypeSection($wsdlContent) + { + $this->assertContains( + $this->_convertXmlToString('<xsd:element name="GenericFault" type="tns:GenericFault"/>'), + $wsdlContent, + 'Default SOAP Fault complex type element declaration is invalid' + ); + + // @codingStandardsIgnoreStart + $genericFaultType = <<< GENERIC_FAULT_COMPLEX_TYPE +<xsd:complexType name="GenericFault"> + <xsd:sequence> + <xsd:element name="Trace" minOccurs="0" maxOccurs="1" type="xsd:string"> + <xsd:annotation> + <xsd:documentation>Exception calls stack trace.</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:maxLength/> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="Parameters" type="tns:ArrayOfGenericFaultParameter" minOccurs="0"> + <xsd:annotation> + <xsd:documentation>Additional exception parameters.</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:natureOfType>array</inf:natureOfType> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="WrappedErrors" type="tns:ArrayOfWrappedError" minOccurs="0"> + <xsd:annotation> + <xsd:documentation>Additional wrapped errors.</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:natureOfType>array</inf:natureOfType> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> +</xsd:complexType> +GENERIC_FAULT_COMPLEX_TYPE; + $this->assertContains( + $this->_convertXmlToString($genericFaultType), + $wsdlContent, + 'Default SOAP Fault complex types declaration is invalid' + ); + + $detailsParameterType = <<< PARAM_COMPLEX_TYPE +<xsd:complexType name="GenericFaultParameter"> + <xsd:sequence> + <xsd:element name="key" minOccurs="1" maxOccurs="1" type="xsd:string"> + <xsd:annotation> + <xsd:documentation></xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:maxLength/> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="value" minOccurs="1" maxOccurs="1" type="xsd:string"> + <xsd:annotation> + <xsd:documentation></xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"> + <inf:maxLength/> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> +</xsd:complexType> +PARAM_COMPLEX_TYPE; + $this->assertContains( + $this->_convertXmlToString($detailsParameterType), + $wsdlContent, + 'Details parameter complex types declaration is invalid.' + ); + + $detailsWrappedErrorType = <<< WRAPPED_ERROR_COMPLEX_TYPE +<xsd:complexType name="WrappedError"> + <xsd:sequence> + <xsd:element name="message" minOccurs="1" maxOccurs="1" type="xsd:string"> + <xsd:annotation> + <xsd:documentation></xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_baseUrl}/soap/{$this->_storeCode}?services%3DtestModule5AllSoapAndRestV1%2CtestModule5AllSoapAndRestV2"> + <inf:maxLength/> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + <xsd:element name="parameters" type="tns:ArrayOfGenericFaultParameter" minOccurs="0"> + <xsd:annotation> + <xsd:documentation>Message parameters.</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_baseUrl}/soap/{$this->_storeCode}?services%3DtestModule5AllSoapAndRestV1%2CtestModule5AllSoapAndRestV2"> + <inf:natureOfType>array</inf:natureOfType> + </xsd:appinfo> + </xsd:annotation> + </xsd:element> + </xsd:sequence> +</xsd:complexType> +WRAPPED_ERROR_COMPLEX_TYPE; + $this->assertContains( + $this->_convertXmlToString($detailsWrappedErrorType), + $wsdlContent, + 'Details wrapped error complex types declaration is invalid.' + ); + + $detailsParametersType = <<< PARAMETERS_COMPLEX_TYPE +<xsd:complexType name="ArrayOfGenericFaultParameter"> + <xsd:annotation> + <xsd:documentation>An array of GenericFaultParameter items.</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="item" minOccurs="0" maxOccurs="unbounded" type="tns:GenericFaultParameter"> + <xsd:annotation> + <xsd:documentation>An item of ArrayOfGenericFaultParameter.</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_soapUrl}"/> + </xsd:annotation> + </xsd:element> + </xsd:sequence> +</xsd:complexType> +PARAMETERS_COMPLEX_TYPE; + // @codingStandardsIgnoreEnd + $this->assertContains( + $this->_convertXmlToString($detailsParametersType), + $wsdlContent, + 'Details parameters (array of parameters) complex types declaration is invalid.' + ); + + $detailsWrappedErrorsType = <<< WRAPPED_ERRORS_COMPLEX_TYPE +<xsd:complexType name="ArrayOfWrappedError"> + <xsd:annotation> + <xsd:documentation>An array of WrappedError items.</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_baseUrl}/soap/{$this->_storeCode}?services%3DtestModule5AllSoapAndRestV1%2CtestModule5AllSoapAndRestV2"/> + </xsd:annotation> + <xsd:sequence> + <xsd:element name="item" minOccurs="0" maxOccurs="unbounded" type="tns:WrappedError"> + <xsd:annotation> + <xsd:documentation>An item of ArrayOfWrappedError.</xsd:documentation> + <xsd:appinfo xmlns:inf="{$this->_baseUrl}/soap/{$this->_storeCode}?services%3DtestModule5AllSoapAndRestV1%2CtestModule5AllSoapAndRestV2"/> + </xsd:annotation> + </xsd:element> + </xsd:sequence> +</xsd:complexType> +WRAPPED_ERRORS_COMPLEX_TYPE; + // @codingStandardsIgnoreEnd + $this->assertContains( + $this->_convertXmlToString($detailsWrappedErrorsType), + $wsdlContent, + 'Details wrapped errors (array of wrapped errors) complex types declaration is invalid.' + ); + } +} diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt index 1d55de7b2756da549f1f0657a43e5146a24b7ea3..c6bac2ba9f3b3dd5970b717f88acea5427bb38bb 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/reference.txt @@ -37,3 +37,17 @@ Model3 \Magento\Wonderland\Model\Data\FakeRegion \Magento\Wonderland\Model\Data\FakeAddress \Magento\Framework\Error\Processor +\Magento\TestModule3\Service\V1\Entity\Parameter +\Magento\TestModule3\Service\V1\Entity\ParameterBuilder +\Magento\TestModuleMSC\Api\Data\ItemInterface +\Magento\TestModule5\Service\V1\Entity\AllSoapAndRest +\Magento\TestModule5\Service\V2\Entity\AllSoapAndRest +\Magento\TestModule5\Service\V2\Entity\AllSoapAndRestBuilder +\Magento\TestModule1\Service\V1\Entity\Item +\Magento\TestModule1\Service\V1\Entity\ItemBuilder +\Magento\TestModule1\Service\V2\Entity\Item +\Magento\TestModule1\Service\V2\Entity\ItemBuilder +\Magento\TestModule2\Service\V1\Entity\Item +\Magento\TestModule2\Service\V1\Entity\ItemBuilder +\Magento\TestModule4\Service\V1\Entity\DataObjectResponse +\Magento\TestModule4\Service\V1\Entity\DataObjectRequest