diff --git a/etc/di.xml b/etc/di.xml
index 081b324fc..c07bfe127 100644
--- a/etc/di.xml
+++ b/etc/di.xml
@@ -49,24 +49,6 @@
-
-
- Magento\FunctionalTestingFramework\Page\Config\Data
-
-
-
-
- Magento\FunctionalTestingFramework\Block\Config\Data
-
-
-
-
-
- - Magento\FunctionalTestingFramework\Generate\GeneratePage
- - Magento\FunctionalTestingFramework\Generate\GenerateBlock
-
-
-
-
+
Magento\FunctionalTestingFramework\DataProfile\Config\Metadata
@@ -198,7 +180,7 @@
Magento\FunctionalTestingFramework\Config\SchemaLocator\Metadata
- name
- - key
+ - key
- key
- key
@@ -222,11 +204,9 @@
- name
- name
- - key
- - key
- name
- - name
- - mergeKey
+ - persistedKey
+ - mergeKey
*Cest.xml
Cest
@@ -236,20 +216,14 @@
- - mergeKey
- - mergeKey
- - mergeKey
+ - mergeKey
+ - mergeKey
+ - mergeKey
- name
- name
- - key
- - key
- - name
- - key
- - key
- - name
- - key
- - key
- - name
+ - persistedKey
+ - persistedKey
+ - persistedKey
- name
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Api/ApiExecutor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Api/ApiExecutor.php
deleted file mode 100644
index 2cad2bf16..000000000
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/Api/ApiExecutor.php
+++ /dev/null
@@ -1,368 +0,0 @@
-operation = $operation;
- $this->entityObject = $entityObject;
- if ($dependentEntities != null) {
- foreach ($dependentEntities as $entity) {
- $this->dependentEntities[$entity->getName()] = $entity;
- }
- }
-
- $this->jsonDefinition = JsonDefinitionObjectHandler::getInstance()->getJsonDefinition(
- $this->operation,
- $this->entityObject->getType()
- );
- }
-
- /**
- * Executes an api request based on parameters given by constructor.
- *
- * @return string | null
- */
- public function executeRequest()
- {
- $apiClientUrl = $this->jsonDefinition->getApiUrl();
-
- $matchedParams = [];
- preg_match_all("/[{](.+?)[}]/", $apiClientUrl, $matchedParams);
-
- if (!empty($matchedParams)) {
- foreach ($matchedParams[0] as $paramKey => $paramValue) {
- $param = $this->entityObject->getDataByName(
- $matchedParams[1][$paramKey],
- EntityDataObject::CEST_UNIQUE_VALUE
- );
- $apiClientUrl = str_replace($paramValue, $param, $apiClientUrl);
- }
- }
-
- $authorization = $this->jsonDefinition->getAuth();
- $headers = $this->jsonDefinition->getHeaders();
-
- if ($authorization) {
- $headers[] = $this->getAuthorizationHeader($authorization);
- }
-
- $jsonBody = $this->getEncodedJsonString();
-
- $apiClientUtil = new ApiClientUtil(
- $apiClientUrl,
- $headers,
- $this->jsonDefinition->getApiMethod(),
- empty($jsonBody) ? null : $jsonBody
- );
-
- return $apiClientUtil->submit();
- }
-
- /**
- * Returns the authorization token needed for some requests via REST call.
- *
- * @param string $authUrl
- * @return string
- */
- private function getAuthorizationHeader($authUrl)
- {
- $headers = ['Content-Type: application/json'];
- $authCreds = [
- 'username' => getenv('MAGENTO_ADMIN_USERNAME'),
- 'password' => getenv('MAGENTO_ADMIN_PASSWORD')
- ];
-
- $apiClientUtil = new ApiClientUtil($authUrl, $headers, 'POST', json_encode($authCreds));
- $token = $apiClientUtil->submit();
- $authHeader = 'Authorization: Bearer ' . str_replace('"', "", $token);
-
- return $authHeader;
- }
-
- /**
- * This function returns an array which is structurally equal to the json which is needed by the web api for
- * entity creation. The function retrieves an array describing the json metadata and traverses any dependencies
- * recursively forming an array which represents the json structure for the api of the desired type.
- *
- * @param EntityDataObject $entityObject
- * @param array $jsonArrayMetadata
- * @return array
- * @throws \Exception
- */
- private function convertJsonArray($entityObject, $jsonArrayMetadata)
- {
- $jsonArray = [];
- self::incrementSequence($entityObject->getName());
-
- foreach ($jsonArrayMetadata as $jsonElement) {
- if ($jsonElement->getType() == JsonObjectExtractor::JSON_OBJECT_OBJ_NAME) {
- $entityObj = $this->resolveJsonObjectAndEntityData($entityObject, $jsonElement->getValue());
- $jsonArray[$jsonElement->getValue()] =
- $this->convertJsonArray($entityObj, $jsonElement->getNestedMetadata());
- continue;
- }
-
- $jsonElementType = $jsonElement->getValue();
-
- if (in_array($jsonElementType, ApiExecutor::PRIMITIVE_TYPES)) {
- $elementData = $entityObject->getDataByName(
- $jsonElement->getKey(),
- EntityDataObject::CEST_UNIQUE_VALUE
- );
-
- // If data was defined at all, attempt to put it into JSON body
- // If data was not defined, and element is required, throw exception
- // If no data is defined, don't input defaults per primitive into JSON for the data
- if ($elementData != null) {
- if (array_key_exists($jsonElement->getKey(), $entityObject->getUniquenessData())) {
- $uniqueData = $entityObject->getUniquenessDataByName($jsonElement->getKey());
- if ($uniqueData === 'suffix') {
- $elementData .= (string)self::getSequence($entityObject->getName());
- } else {
- $elementData = (string)self::getSequence($entityObject->getName()) . $elementData;
- }
- }
- $jsonArray[$jsonElement->getKey()] = $this->castValue($jsonElementType, $elementData);
-
- } elseif ($jsonElement->getRequired()) {
- throw new \Exception(sprintf(
- ApiExecutor::EXCEPTION_REQUIRED_DATA,
- $jsonElement->getType(),
- $jsonElement->getKey(),
- $this->entityObject->getName()
- ));
- }
- } else {
- $entityNamesOfType = $entityObject->getLinkedEntitiesOfType($jsonElementType);
-
- // If an element is required by metadata, but was not provided in the entity, throw an exception
- if ($jsonElement->getRequired() && $entityNamesOfType == null) {
- throw new \Exception(sprintf(
- ApiExecutor::EXCEPTION_REQUIRED_DATA,
- $jsonElement->getType(),
- $jsonElement->getKey(),
- $this->entityObject->getName()
- ));
- }
- foreach ($entityNamesOfType as $entityName) {
- $jsonDataSubArray = $this->resolveNonPrimitiveElement($entityName, $jsonElement);
-
- if ($jsonElement->getType() == 'array') {
- $jsonArray[$jsonElement->getKey()][] = $jsonDataSubArray;
- } else {
- $jsonArray[$jsonElement->getKey()] = $jsonDataSubArray;
- }
- }
- }
- }
-
- return $jsonArray;
- }
-
- /**
- * This function does a comparison of the entity object being matched to the json element. If there is a mismatch in
- * type we attempt to use a nested entity, if the entities are properly matched, we simply return the object.
- *
- * @param EntityDataObject $entityObject
- * @param string $jsonElementValue
- * @return EntityDataObject|null
- */
- private function resolveJsonObjectAndEntityData($entityObject, $jsonElementValue)
- {
- if ($jsonElementValue != $entityObject->getType()) {
- // if we have a mismatch attempt to retrieve linked data and return just the first linkage
- $linkName = $entityObject->getLinkedEntitiesOfType($jsonElementValue)[0];
- return DataObjectHandler::getInstance()->getObject($linkName);
- }
-
- return $entityObject;
- }
-
- /**
- * Resolves JsonObjects and pre-defined metadata (in other operation.xml file) referenced by the json metadata
- *
- * @param string $entityName
- * @param JsonElement $jsonElement
- * @return array
- */
- private function resolveNonPrimitiveElement($entityName, $jsonElement)
- {
- $linkedEntityObj = $this->resolveLinkedEntityObject($entityName);
-
- // in array case
- if (!empty($jsonElement->getNestedJsonElement($jsonElement->getValue()))
- && $jsonElement->getType() == 'array'
- ) {
- $jsonSubArray = $this->convertJsonArray(
- $linkedEntityObj,
- [$jsonElement->getNestedJsonElement($jsonElement->getValue())]
- );
-
- return $jsonSubArray[$jsonElement->getValue()];
- }
-
- $jsonMetadata = JsonDefinitionObjectHandler::getInstance()->getJsonDefinition(
- $this->operation,
- $linkedEntityObj->getType()
- )->getJsonMetadata();
-
- return $this->convertJsonArray($linkedEntityObj, $jsonMetadata);
- }
-
- /**
- * Method to wrap entity resolution, checks locally defined dependent entities first
- *
- * @param string $entityName
- * @return EntityDataObject
- */
- private function resolveLinkedEntityObject($entityName)
- {
- // check our dependent entity list to see if we have this defined
- if (array_key_exists($entityName, $this->dependentEntities)) {
- return $this->dependentEntities[$entityName];
- }
-
- return DataObjectHandler::getInstance()->getObject($entityName);
- }
-
- /**
- * This function retrieves an array representative of json body for a request and returns it encoded as a string.
- *
- * @return string
- */
- public function getEncodedJsonString()
- {
- $jsonMetadataArray = $this->convertJsonArray($this->entityObject, $this->jsonDefinition->getJsonMetadata());
-
- return json_encode($jsonMetadataArray, JSON_PRETTY_PRINT);
- }
-
- /**
- * Increment an entity's sequence number by 1.
- *
- * @param string $entityName
- * @return void
- */
- private static function incrementSequence($entityName)
- {
- if (array_key_exists($entityName, self::$entitySequences)) {
- self::$entitySequences[$entityName]++;
- } else {
- self::$entitySequences[$entityName] = 1;
- }
- }
-
- /**
- * Get the current sequence number for an entity.
- *
- * @param string $entityName
- * @return int
- */
- private static function getSequence($entityName)
- {
- if (array_key_exists($entityName, self::$entitySequences)) {
- return self::$entitySequences[$entityName];
- }
- return 0;
- }
-
- // @codingStandardsIgnoreStart
-
- /**
- * This function takes a string value and its corresponding type and returns the string cast
- * into its the type passed.
- *
- * @param string $type
- * @param string $value
- * @return mixed
- */
- private function castValue($type, $value)
- {
- $newVal = $value;
-
- switch ($type) {
- case 'string':
- break;
- case 'integer':
- $newVal = (integer)$value;
- break;
- case 'boolean':
- if (strtolower($newVal) === 'false') {
- return false;
- }
- $newVal = (boolean)$value;
- break;
- case 'double':
- $newVal = (double)$value;
- break;
- }
-
- return $newVal;
- }
- // @codingStandardsIgnoreEnd
-}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Api/EntityApiHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Api/EntityApiHandler.php
deleted file mode 100644
index 8116dbd87..000000000
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/Api/EntityApiHandler.php
+++ /dev/null
@@ -1,107 +0,0 @@
-entityObject = clone $entityObject;
- $this->dependentObjects = $dependentObjects;
- }
-
- /**
- * Function which executes a create request based on specific operation metadata
- * @return void
- */
- public function createEntity()
- {
- $apiExecutor = new ApiExecutor('create', $this->entityObject, $this->dependentObjects);
- $result = $apiExecutor->executeRequest();
-
- $this->createdObject = new EntityDataObject(
- $this->entityObject->getName(),
- $this->entityObject->getType(),
- json_decode($result, true),
- null,
- null // No uniqueness data is needed to be further processed.
- );
- }
-
- /**
- * Function which executes a delete request based on specific operation metadata
- *
- * @return string | false
- */
- public function deleteEntity()
- {
- $apiExecutor = new ApiExecutor('delete', $this->createdObject);
- $result = $apiExecutor->executeRequest();
-
- return $result;
- }
-
- /**
- * Returns the createdDataObject, instantiated when the entity is created via API.
- * @return EntityDataObject
- */
- public function getCreatedObject()
- {
- return $this->createdObject;
- }
-
- /**
- * Returns a specific data value based on the CreatedObject's definition.
- * @param string $dataName
- * @return string
- */
- public function getCreatedDataByName($dataName)
- {
- $data = $this->createdObject->getDataByName($dataName, EntityDataObject::NO_UNIQUE_PROCESS);
- if (empty($data)) {
- $data = $this->entityObject->getDataByName($dataName, EntityDataObject::CEST_UNIQUE_VALUE);
- }
- return $data;
- }
-
- // TODO add update function
- /* public function updateEntity()
- {
-
- }*/
-}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php
index 633028538..f52659b34 100644
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php
@@ -43,6 +43,12 @@ class DataObjectHandler implements ObjectHandlerInterface
const ARRAY_ELEMENT_ITEM = 'item';
const ARRAY_ELEMENT_ITEM_VALUE = 'value';
+ const VAR_VALUES = 'var';
+ const VAR_KEY = 'key';
+ const VAR_ENTITY = 'entityType';
+ const VAR_FIELD = 'entityKey';
+ const VAR_ENTITY_FIELD_SEPARATOR = '->';
+
const REQUIRED_ENTITY = 'required-entity';
const REQUIRED_ENTITY_TYPE = 'type';
const REQUIRED_ENTITY_VALUE = 'value';
@@ -150,6 +156,7 @@ private function parseDataEntities()
$dataValues = [];
$linkedEntities = [];
$arrayValues = [];
+ $vars = [];
$uniquenessValues = [];
if (array_key_exists(self::DATA_VALUES, $entity)) {
@@ -186,12 +193,21 @@ private function parseDataEntities()
}
}
+ if (array_key_exists(self::VAR_VALUES, $entity)) {
+ foreach ($entity[self::VAR_VALUES] as $varElement) {
+ $varKey = $varElement[self::VAR_KEY];
+ $varValue = $varElement[self::VAR_ENTITY] . self::VAR_ENTITY_FIELD_SEPARATOR . $varElement[self::VAR_FIELD];
+ $vars[$varKey] = $varValue;
+ }
+ }
+
$entityDataObject = new EntityDataObject(
$entityName,
$entityType,
$dataValues,
$linkedEntities,
- $uniquenessValues
+ $uniquenessValues,
+ $vars
);
$this->data[$entityDataObject->getName()] = $entityDataObject;
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/JsonDefinitionObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/JsonDefinitionObjectHandler.php
deleted file mode 100644
index 9243ff46e..000000000
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/JsonDefinitionObjectHandler.php
+++ /dev/null
@@ -1,216 +0,0 @@
-initJsonDefinitions();
- }
-
- return self::$JSON_DEFINITION_OBJECT_HANDLER;
- }
-
- /**
- * Returns a JsonDefinition object based on name
- *
- * @param string $jsonDefinitionName
- * @return JsonDefinition
- */
- public function getObject($jsonDefinitionName)
- {
- return $this->jsonDefinitions[$jsonDefinitionName];
- }
-
- /**
- * Returns all Json Definition objects
- *
- * @return array
- */
- public function getAllObjects()
- {
- return $this->jsonDefinitions;
- }
-
- /**
- * JsonDefintionArrayProcessor constructor.
- */
- private function __construct()
- {
- $this->jsonDefExtractor = new JsonObjectExtractor();
- }
-
- /**
- * This method takes an operation such as create and a data type such as 'customer' and returns the corresponding
- * json definition defined in metadata.xml
- *
- * @param string $operation
- * @param string $dataType
- * @return JsonDefinition
- */
- public function getJsonDefinition($operation, $dataType)
- {
- return $this->getObject($operation . $dataType);
- }
-
- /**
- * This method reads all jsonDefinitions from metadata xml into memory.
- * @return void
- */
- private function initJsonDefinitions()
- {
- $objectManager = ObjectManagerFactory::getObjectManager();
- $metadataParser = $objectManager->create(OperationMetadataParser::class);
- foreach ($metadataParser->readOperationMetadata()[JsonDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG] as
- $jsonDefName => $jsonDefArray) {
- $operation = $jsonDefArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_TYPE];
- $dataType = $jsonDefArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE];
- $url = $jsonDefArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_URL] ?? null;
- $method = $jsonDefArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_METHOD] ?? null;
- $auth = $jsonDefArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_AUTH] ?? null;
- $headers = [];
- $params = [];
- $jsonMetadata = [];
-
- if (array_key_exists(JsonDefinitionObjectHandler::ENTITY_OPERATION_HEADER, $jsonDefArray)) {
- foreach ($jsonDefArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_HEADER] as $headerEntry) {
- $headers[] = $headerEntry[JsonDefinitionObjectHandler::ENTITY_OPERATION_HEADER_PARAM] . ': ' .
- $headerEntry[JsonDefinitionObjectHandler::ENTITY_OPERATION_HEADER_VALUE];
- }
- }
-
- if (array_key_exists(JsonDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM, $jsonDefArray)) {
- foreach ($jsonDefArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM] as $paramEntry) {
- $params[$paramEntry[JsonDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_TYPE]]
- [$paramEntry[JsonDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_KEY]] =
- $paramEntry[JsonDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_VALUE];
- }
- }
-
- // extract relevant jsonObjects as JsonElements
- if (array_key_exists(JsonDefinitionObjectHandler::ENTITY_OPERATION_JSON_OBJECT, $jsonDefArray)) {
- foreach ($jsonDefArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_JSON_OBJECT] as $jsonObjectArray) {
- $jsonMetadata[] = $this->jsonDefExtractor->extractJsonObject($jsonObjectArray);
- }
- }
-
- //handle loose entries
-
- if (array_key_exists(JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY, $jsonDefArray)) {
- foreach ($jsonDefArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY] as $jsonEntryType) {
- $jsonMetadata[] = new JsonElement(
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY],
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE],
- JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY,
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null
- );
- }
- }
-
- if (array_key_exists(JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY, $jsonDefArray)) {
- foreach ($jsonDefArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY] as $jsonEntryType) {
- $jsonSubMetadata = [];
- $value = null;
- $type = null;
-
- if (array_key_exists('jsonObject', $jsonEntryType)) {
- $jsonNestedElement = $this->jsonDefExtractor->extractJsonObject(
- $jsonEntryType['jsonObject'][0]
- );
- $jsonSubMetadata[$jsonNestedElement->getKey()] = $jsonNestedElement;
- $value = $jsonNestedElement->getValue();
- $type = $jsonNestedElement->getKey();
- } else {
- $value = $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE][0]
- [JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE];
- $type = [JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE];
- }
-
- $jsonMetadata[] = new JsonElement(
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_KEY],
- $value,
- $type,
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null,
- $jsonSubMetadata
- );
- }
- }
-
- $this->jsonDefinitions[$operation . $dataType] = new JsonDefinition(
- $jsonDefName,
- $operation,
- $dataType,
- $method,
- $url,
- $auth,
- $headers,
- $params,
- $jsonMetadata
- );
- }
- }
-}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php
new file mode 100644
index 000000000..9dda26324
--- /dev/null
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php
@@ -0,0 +1,233 @@
+initDataDefinitions();
+ }
+
+ return self::$DATA_DEFINITION_OBJECT_HANDLER;
+ }
+
+ /**
+ * Returns a OperationDefinitionObject object based on name
+ *
+ * @param string $operationDefinitionName
+ * @return OperationDefinitionObject
+ */
+ public function getObject($operationDefinitionName)
+ {
+ return $this->operationDefinitions[$operationDefinitionName];
+ }
+
+ /**
+ * Returns all data Definition objects
+ *
+ * @return array
+ */
+ public function getAllObjects()
+ {
+ return $this->operationDefinitions;
+ }
+
+ /**
+ * DataDefintionArrayProcessor constructor.
+ */
+ private function __construct()
+ {
+ $this->dataDefExtractor = new OperationElementExtractor();
+ }
+
+ /**
+ * This method takes an operation such as create and a data type such as 'customer' and returns the corresponding
+ * data definition defined in metadata.xml
+ *
+ * @param string $operation
+ * @param string $dataType
+ * @return OperationDefinitionObject
+ */
+ public function getOperationDefinition($operation, $dataType)
+ {
+ return $this->getObject($operation . $dataType);
+ }
+
+ /**
+ * This method reads all dataDefinitions from metadata xml into memory.
+ * @return void
+ */
+ private function initDataDefinitions()
+ {
+ $objectManager = ObjectManagerFactory::getObjectManager();
+ $metadataParser = $objectManager->create(OperationDefinitionParser::class);
+ foreach ($metadataParser->readOperationMetadata()
+ [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG] as $dataDefName => $opDefArray) {
+ $operation = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE];
+ $dataType = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE];
+ $url = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL] ?? null;
+ $method = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD] ?? null;
+ $auth = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH] ?? null;
+ $successRegex = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_SUCCESS_REGEX] ?? null;
+ $returnRegex = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_RETURN_REGEX] ?? null;
+ $contentType = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_CONTENT_TYPE][0]['value']
+ ?? null;
+ $headers = [];
+ $params = [];
+ $operationElements = [];
+
+ if (array_key_exists(OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER, $opDefArray)) {
+ foreach ($opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER] as $headerEntry) {
+ if (isset($headerEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER_VALUE])
+ && $headerEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER_VALUE] !== 'none') {
+ $headers[] = $headerEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER_PARAM]
+ . ': '
+ . $headerEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER_VALUE];
+ }
+ }
+ }
+
+ if (array_key_exists(OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM, $opDefArray)) {
+ foreach ($opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM] as $paramEntry) {
+ $params[$paramEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_TYPE]]
+ [$paramEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_KEY]] =
+ $paramEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_VALUE];
+ }
+ }
+
+ // extract relevant OperationObjects as OperationElements
+ if (array_key_exists(OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT, $opDefArray)) {
+ foreach ($opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT] as $opElementArray) {
+ $operationElements[] = $this->dataDefExtractor->extractOperationElement($opElementArray);
+ }
+ }
+
+ //handle loose operation fields
+ if (array_key_exists(OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY, $opDefArray)) {
+ foreach ($opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY] as $operationField) {
+ $operationElements[] = new OperationElement(
+ $operationField[OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY],
+ $operationField[OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE],
+ OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY,
+ $operationField[OperationDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null
+ );
+ }
+ }
+
+ // handle loose json arrays
+ if (array_key_exists(OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY, $opDefArray)) {
+ foreach ($opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY] as $operationField) {
+ $subOperationElements = [];
+ $value = null;
+ $type = null;
+
+ if (array_key_exists(
+ OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT,
+ $operationField
+ )) {
+ $nestedDataElement = $this->dataDefExtractor->extractOperationElement(
+ $operationField[OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT][0]
+ );
+ $subOperationElements[$nestedDataElement->getKey()] = $nestedDataElement;
+ $value = $nestedDataElement->getValue();
+ $type = $nestedDataElement->getKey();
+ } else {
+ $value = $operationField[OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE][0]
+ [OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE];
+ $type = OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY;
+ }
+
+ $operationElements[] = new OperationElement(
+ $operationField[OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_KEY],
+ $value,
+ $type,
+ $operationField[OperationDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null,
+ $subOperationElements
+ );
+ }
+ }
+
+ $this->operationDefinitions[$operation . $dataType] = new OperationDefinitionObject(
+ $dataDefName,
+ $operation,
+ $dataType,
+ $method,
+ $url,
+ $auth,
+ $headers,
+ $params,
+ $operationElements,
+ $contentType,
+ $successRegex,
+ $returnRegex
+ );
+ }
+ }
+}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php
index db602ad07..41730f3aa 100644
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php
@@ -34,6 +34,13 @@ class EntityDataObject
*/
private $linkedEntities = [];
+ /**
+ * An array of variable mappings for static data
+ *
+ * @var array
+ */
+ private $vars;
+
/**
* An array of Data Name to Data Value
*
@@ -63,8 +70,9 @@ class EntityDataObject
* @param array $data
* @param array $linkedEntities
* @param array $uniquenessData
+ * @param array $vars
*/
- public function __construct($entityName, $entityType, $data, $linkedEntities, $uniquenessData)
+ public function __construct($entityName, $entityType, $data, $linkedEntities, $uniquenessData, $vars = [])
{
$this->name = $entityName;
$this->type = $entityType;
@@ -73,6 +81,8 @@ public function __construct($entityName, $entityType, $data, $linkedEntities, $u
if ($uniquenessData) {
$this->uniquenessData = $uniquenessData;
}
+
+ $this->vars = $vars;
}
/**
@@ -189,6 +199,22 @@ public function getDataByName($dataName, $uniDataFormat)
return null;
}
+ /**
+ * Function which returns a reference to another entity (e.g. a var with entity="category" field="id" returns as
+ * category->id)
+ *
+ * @param string $dataKey
+ * @return array|null
+ */
+ public function getVarReference($dataKey)
+ {
+ if (array_key_exists($dataKey, $this->vars)) {
+ return $this->vars[$dataKey];
+ }
+
+ return null;
+ }
+
/**
* This function takes an array of entityTypes indexed by name and a string that represents the type of interest.
* The function returns an array of entityNames relevant to the specified type.
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/JsonDefinition.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php
similarity index 54%
rename from src/Magento/FunctionalTestingFramework/DataGenerator/Objects/JsonDefinition.php
rename to src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php
index f19a2e51e..8f9ac19a4 100644
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/JsonDefinition.php
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php
@@ -7,26 +7,28 @@
namespace Magento\FunctionalTestingFramework\DataGenerator\Objects;
/**
- * Class JsonDefinition
+ * Class OperationDefinitionObject
*/
-class JsonDefinition
+class OperationDefinitionObject
{
+ const HTTP_CONTENT_TYPE_HEADER = 'Content-Type';
+
/**
- * Json Definitions Name
+ * Data Definitions Name
*
* @var string
*/
private $name;
/**
- * Operation which the json defintion describes
+ * Operation which the data defintion describes
*
* @var string
*/
private $operation;
/**
- * Data type for which the json defintiion is used
+ * Data type for which the data defintiion is used
*
* @var string
*/
@@ -40,18 +42,18 @@ class JsonDefinition
private $apiMethod;
/**
- * Base URL for the request
+ * Api request url.
*
* @var string
*/
- private $baseUrl;
+ private $apiUrl;
/**
* Resource specific URI for the request
*
* @var string
*/
- private $apiUrl;
+ private $apiUri;
/**
* Authorization path for retrieving a token
@@ -60,6 +62,13 @@ class JsonDefinition
*/
private $auth;
+ /**
+ * Content type of body
+ *
+ * @var string
+ */
+ private $contentType;
+
/**
* Relevant headers for the request
*
@@ -75,48 +84,79 @@ class JsonDefinition
private $params = [];
/**
- * The metadata describing the json fields and values themselves
+ * The metadata describing the data fields and values themselves
*
* @var array
*/
- private $jsonMetadata = [];
+ private $operationMetadata = [];
+
+ /**
+ * Regex to check for request success.
+ *
+ * @var string
+ */
+ private $successRegex;
/**
- * JsonDefinition constructor.
+ * Regex to grab return value from response.
+ *
+ * @var string
+ */
+ private $returnRegex;
+
+ /**
+ * OperationDefinitionObject constructor.
* @param string $name
* @param string $operation
* @param string $dataType
* @param string $apiMethod
- * @param string $apiUrl
+ * @param string $apiUri
* @param string $auth
* @param array $headers
* @param array $params
- * @param array $jsonMetadata
+ * @param array $metaData
+ * @param string $contentType
+ * @param string $successRegex
+ * @param string $returnRegex
*/
public function __construct(
$name,
$operation,
$dataType,
$apiMethod,
- $apiUrl,
+ $apiUri,
$auth,
$headers,
$params,
- $jsonMetadata
+ $metaData,
+ $contentType,
+ $successRegex = null,
+ $returnRegex = null
) {
$this->name = $name;
$this->operation = $operation;
$this->dataType = $dataType;
$this->apiMethod = $apiMethod;
- $this->baseUrl = $apiUrl;
+ $this->apiUri = trim($apiUri, '/');
$this->auth = $auth;
$this->headers = $headers;
$this->params = $params;
- $this->jsonMetadata = $jsonMetadata;
+ $this->operationMetadata = $metaData;
+ $this->successRegex = $successRegex;
+ $this->returnRegex = $returnRegex;
+ $this->apiUrl = null;
+
+ if (!empty($contentType)) {
+ $this->contentType = $contentType;
+ } else {
+ $this->contentType = 'application/x-www-form-urlencoded';
+ }
+ // add content type as a header
+ $this->headers[] = self::HTTP_CONTENT_TYPE_HEADER . ': ' . $this->contentType;
}
/**
- * Getter for json data type
+ * Getter for data's data type
*
* @return string
*/
@@ -126,7 +166,7 @@ public function getDataType()
}
/**
- * Getter for json operation
+ * Getter for data operation
*
* @return string
*/
@@ -146,20 +186,22 @@ public function getApiMethod()
}
/**
- * Getter for api url
+ * Getter for api url for a store.
*
* @return string
*/
public function getApiUrl()
{
- $this->cleanApiUrl();
+ if (!$this->apiUrl) {
+ $this->apiUrl = $this->apiUri;
- if (array_key_exists('path', $this->params)) {
- $this->addPathParam();
- }
+ if (array_key_exists('path', $this->params)) {
+ $this->addPathParam();
+ }
- if (array_key_exists('query', $this->params)) {
- $this->addQueryParams();
+ if (array_key_exists('query', $this->params)) {
+ $this->addQueryParams();
+ }
}
return $this->apiUrl;
@@ -186,27 +228,43 @@ public function getHeaders()
}
/**
- * Getter for json metadata
+ * Getter for Content-type
+ *
+ * @return string
+ */
+ public function getContentType()
+ {
+ return $this->contentType;
+ }
+
+ /**
+ * Getter for data metadata
*
* @return array
*/
- public function getJsonMetadata()
+ public function getOperationMetadata()
{
- return $this->jsonMetadata;
+ return $this->operationMetadata;
}
/**
- * Function to validate api format and add "/" char where necessary
+ * Getter for success regex.
*
- * @return void
+ * @return string
*/
- private function cleanApiUrl()
+ public function getSuccessRegex()
{
- if (substr($this->baseUrl, -1) == "/") {
- $this->apiUrl = rtrim($this->baseUrl, "/");
- } else {
- $this->apiUrl = $this->baseUrl;
- }
+ return $this->successRegex;
+ }
+
+ /**
+ * Getter for return regex.
+ *
+ * @return string
+ */
+ public function getReturnRegex()
+ {
+ return $this->returnRegex;
}
/**
@@ -222,21 +280,19 @@ private function addPathParam()
}
/**
- * Function to append query params where necessary
+ * Function to append or add query parameters
*
* @return void
*/
- private function addQueryParams()
+ public function addQueryParams()
{
-
foreach ($this->params['query'] as $paramName => $paramValue) {
- if (!stringContains("?", $this->apiUrl)) {
+ if (strpos($this->apiUrl, '?') === false) {
$this->apiUrl = $this->apiUrl . "?";
} else {
$this->apiUrl = $this->apiUrl . "&";
}
-
- $this->apiUrl = $paramName . "=" . $paramValue;
+ $this->apiUrl = $this->apiUrl . $paramName . "=" . $paramValue;
}
}
}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/JsonElement.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationElement.php
similarity index 76%
rename from src/Magento/FunctionalTestingFramework/DataGenerator/Objects/JsonElement.php
rename to src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationElement.php
index a2af57341..0580018fd 100644
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/JsonElement.php
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationElement.php
@@ -6,51 +6,51 @@
namespace Magento\FunctionalTestingFramework\DataGenerator\Objects;
-class JsonElement
+class OperationElement
{
/**
- * Json parameter name
+ * Data parameter name
*
* @var string
*/
private $key;
/**
- * Json parameter metadata value (e.g. string, bool)
+ * Data parameter metadata value (e.g. string, bool)
*
* @var string
*/
private $value;
/**
- * Json type such as array or entry
+ * Data type such as array or entry
*
* @var string
*/
private $type;
/**
- * Nested Json Objects defined within the same operation.xml file
+ * Nested data Objects defined within the same operation.xml file
*
* @var array
*/
private $nestedElements = [];
/**
- * Nested Metadata which must be included for a jsonElement of type jsonObject
+ * Nested Metadata which must be included for a dataElement of type dataObject
*
* @var array|null
*/
private $nestedMetadata = [];
/**
- * Json required attribute, used to determine if values need to be cast before insertion.
+ * Required attribute, used to determine if values need to be cast before insertion.
* @var bool
*/
private $required;
/**
- * JsonElement constructor.
+ * OperationElement constructor.
* @param string $key
* @param string $value
* @param string $type
@@ -73,7 +73,7 @@ public function __construct($key, $value, $type, $required, $nestedElements = []
}
/**
- * Getter for json parameter name
+ * Getter for data parameter name
*
* @return string
*/
@@ -113,12 +113,12 @@ public function getRequired()
}
/**
- * Returns the nested json element based on the type of entity passed
+ * Returns the nested data element based on the type of entity passed
*
* @param string $type
* @return array
*/
- public function getNestedJsonElement($type)
+ public function getNestedOperationElement($type)
{
if (array_key_exists($type, $this->nestedElements)) {
return $this->nestedElements[$type];
@@ -128,7 +128,7 @@ public function getNestedJsonElement($type)
}
/**
- * Returns relevant nested json metadata for a json element which is a json object
+ * Returns relevant nested data metadata for a data element which is a data object
*
* @return array|null
*/
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Parsers/DataProfileSchemaParser.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Parsers/DataProfileSchemaParser.php
index c9ac3dda2..0a40afe09 100644
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/Parsers/DataProfileSchemaParser.php
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Parsers/DataProfileSchemaParser.php
@@ -13,6 +13,13 @@
*/
class DataProfileSchemaParser
{
+ /**
+ * Data Profiles.
+ *
+ * @var DataInterface
+ */
+ private $dataProfiles;
+
/**
* DataProfileSchemaParser constructor.
* @param DataInterface $dataProfiles
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Parsers/OperationMetadataParser.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Parsers/OperationDefinitionParser.php
similarity index 80%
rename from src/Magento/FunctionalTestingFramework/DataGenerator/Parsers/OperationMetadataParser.php
rename to src/Magento/FunctionalTestingFramework/DataGenerator/Parsers/OperationDefinitionParser.php
index b3c6cc514..e7a68435c 100644
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/Parsers/OperationMetadataParser.php
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Parsers/OperationDefinitionParser.php
@@ -9,10 +9,17 @@
use Magento\FunctionalTestingFramework\Config\DataInterface;
/**
- * Class OperationMetadataParser
+ * Class OperationDefinitionParser
*/
-class OperationMetadataParser
+class OperationDefinitionParser
{
+ /**
+ * Meta Data.
+ *
+ * @var DataInterface
+ */
+ private $metadata;
+
/**
* MetadataParser constructor.
* @param DataInterface $metadata
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php
new file mode 100644
index 000000000..6adf87892
--- /dev/null
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php
@@ -0,0 +1,45 @@
+transport = new CurlTransport();
+ $this->authorize();
+ }
+
+ /**
+ * Authorize customer on backend.
+ *
+ * @return void
+ * @throws TestFrameworkException
+ */
+ public function authorize()
+ {
+ // Perform GET to backend url so form_key is set
+ $this->transport->write(self::$adminUrl, [], CurlInterface::GET);
+ $this->read();
+
+ // Authenticate admin user
+ $authUrl = self::$adminUrl . 'admin/auth/login/';
+ $data = [
+ 'login[username]' => getenv('MAGENTO_ADMIN_USERNAME'),
+ 'login[password]' => getenv('MAGENTO_ADMIN_PASSWORD'),
+ 'form_key' => $this->formKey,
+ ];
+ $this->transport->write($authUrl, $data, CurlInterface::POST);
+ $response = $this->read();
+ if (strpos($response, 'login-form')) {
+ throw new TestFrameworkException('Admin user authentication failed!');
+ }
+ }
+
+ /**
+ * Init Form Key from response.
+ *
+ * @return void
+ */
+ private function setFormKey()
+ {
+ preg_match('!var FORM_KEY = \'(\w+)\';!', $this->response, $matches);
+ if (!empty($matches[1])) {
+ $this->formKey = $matches[1];
+ }
+ }
+
+ /**
+ * Send request to the remote server.
+ *
+ * @param string $url
+ * @param array $data
+ * @param string $method
+ * @param array $headers
+ * @return void
+ * @throws TestFrameworkException
+ */
+ public function write($url, $data = [], $method = CurlInterface::POST, $headers = [])
+ {
+ $apiUrl = self::$adminUrl . $url;
+ if ($this->formKey) {
+ $data['form_key'] = $this->formKey;
+ } else {
+ throw new TestFrameworkException(
+ sprintf('Form key is absent! Url: "%s" Response: "%s"', $url, $this->response)
+ );
+ }
+
+ $this->transport->write($apiUrl, str_replace('null', '', http_build_query($data)), $method, $headers);
+ }
+
+ /**
+ * Read response from server.
+ *
+ * @param string $successRegex
+ * @param string $returnRegex
+ * @return string|array
+ * @throws TestFrameworkException
+ */
+ public function read($successRegex = null, $returnRegex = null)
+ {
+ $this->response = $this->transport->read();
+ $this->setFormKey();
+
+ if (!empty($successRegex)) {
+ preg_match(
+ '/' . preg_quote($successRegex, '/') . '/',
+ $this->response,
+ $successMatches
+ );
+ if (empty($successMatches)) {
+ throw new TestFrameworkException("Entity creation was not successful! Response: $this->response");
+ }
+ }
+
+ if (!empty($returnRegex)) {
+ preg_match(
+ '/' . preg_quote($returnRegex, '/') . '/',
+ $this->response,
+ $returnMatches
+ );
+ if (!empty($returnMatches)) {
+ return $returnMatches;
+ }
+ }
+ return $this->response;
+ }
+
+ /**
+ * Add additional option to cURL.
+ *
+ * @param int $option the CURLOPT_* constants
+ * @param int|string|bool|array $value
+ * @return void
+ */
+ public function addOption($option, $value)
+ {
+ $this->transport->addOption($option, $value);
+ }
+
+ /**
+ * Close the connection to the server.
+ *
+ * @return void
+ */
+ public function close()
+ {
+ $this->transport->close();
+ }
+}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php
new file mode 100644
index 000000000..652f620b4
--- /dev/null
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php
@@ -0,0 +1,141 @@
+storeCode = $storeCode;
+ $this->transport = new CurlTransport();
+ $this->authorize();
+ }
+
+ /**
+ * Returns the authorization token needed for some requests via REST call.
+ *
+ * @return void
+ */
+ private function authorize()
+ {
+ $authUrl = parent::$baseUrl . 'rest/' . $this->storeCode . self::ADMIN_AUTH_URL;
+ $authCreds = [
+ 'username' => getenv('MAGENTO_ADMIN_USERNAME'),
+ 'password' => getenv('MAGENTO_ADMIN_PASSWORD')
+ ];
+
+ $this->transport->write($authUrl, json_encode($authCreds), CurlInterface::POST, $this->headers);
+ $this->headers = array_merge(
+ ['Authorization: Bearer ' . str_replace('"', "", $this->read())],
+ $this->headers
+ );
+ }
+
+ /**
+ * Send request to the remote server.
+ *
+ * @param string $url
+ * @param array $data
+ * @param string $method
+ * @param array $headers
+ * @return void
+ */
+ public function write($url, $data = [], $method = CurlInterface::POST, $headers = [])
+ {
+ $this->transport->write(
+ parent::$baseUrl . 'rest/' . $this->storeCode . '/' . trim($url, '/'),
+ json_encode($data, JSON_PRETTY_PRINT),
+ $method,
+ array_unique(array_merge($headers, $this->headers))
+ );
+ }
+
+ /**
+ * Read response from server.
+ *
+ * @param string $successRegex
+ * @param string $returnRegex
+ * @return string
+ */
+ public function read($successRegex = null, $returnRegex = null)
+ {
+ $this->response = $this->transport->read();
+ return $this->response;
+ }
+
+ /**
+ * Add additional option to cURL.
+ *
+ * @param int $option the CURLOPT_* constants
+ * @param int|string|bool|array $value
+ * @return void
+ */
+ public function addOption($option, $value)
+ {
+ $this->transport->addOption($option, $value);
+ }
+
+ /**
+ * Close the connection to the server.
+ *
+ * @return void
+ */
+ public function close()
+ {
+ $this->transport->close();
+ }
+}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php
new file mode 100644
index 000000000..e7d73676e
--- /dev/null
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php
@@ -0,0 +1,196 @@
+ CurlInterface::POST,
+ 'delete' => CurlInterface::DELETE,
+ 'update' => CurlInterface::PUT,
+ 'get' => CurlInterface::GET,
+ ];
+
+ /**
+ * ApiSubObject constructor.
+ * @param string $operation
+ * @param EntityDataObject $entityObject
+ * @param string $storeCode
+ */
+ public function __construct($operation, $entityObject, $storeCode = 'default')
+ {
+ $this->operation = $operation;
+ $this->entityObject = $entityObject;
+ $this->storeCode = $storeCode;
+
+ $this->operationDefinition = OperationDefinitionObjectHandler::getInstance()->getOperationDefinition(
+ $this->operation,
+ $this->entityObject->getType()
+ );
+ $this->isJson = false;
+ }
+
+ /**
+ * Executes an api request based on parameters given by constructor.
+ *
+ * @param array $dependentEntities
+ * @return array | null
+ * @throws TestFrameworkException
+ */
+ public function executeRequest($dependentEntities)
+ {
+ $executor = null;
+ $successRegex = null;
+ $returnRegex = null;
+
+ $apiUrl = $this->resolveUrlReference($this->operationDefinition->getApiUrl());
+ $headers = $this->operationDefinition->getHeaders();
+ $authorization = $this->operationDefinition->getAuth();
+ $contentType = $this->operationDefinition->getContentType();
+ $successRegex = $this->operationDefinition->getSuccessRegex();
+ $returnRegex = $this->operationDefinition->getReturnRegex();
+
+ $operationDataResolver = new OperationDataArrayResolver($dependentEntities);
+ $this->requestData = $operationDataResolver->resolveOperationDataArray(
+ $this->entityObject,
+ $this->operationDefinition->getOperationMetadata(),
+ $this->operationDefinition->getOperation()
+ );
+
+ if (($contentType === 'application/json') && ($authorization === 'adminOauth')) {
+ $this->isJson = true;
+ $executor = new WebapiExecutor($this->storeCode);
+ } elseif ($authorization === 'adminFormKey') {
+ $executor = new AdminExecutor();
+ //TODO: add frontend request executor
+ //} elseif ($authorization === 'customFromKey') {
+ }
+
+ if (!$executor) {
+ throw new TestFrameworkException(
+ sprintf(
+ "Invalid content type and/or auth type. content type = %s, auth type = %s\n",
+ $contentType,
+ $authorization
+ )
+ );
+ }
+
+ $executor->write(
+ $apiUrl,
+ $this->requestData,
+ self::$curlMethodMapping[$this->operation],
+ $headers
+ );
+
+ $response = $executor->read($successRegex, $returnRegex);
+ $executor->close();
+
+ return $response;
+ }
+
+ /**
+ * Getter for request data in array.
+ *
+ * @return array
+ */
+ public function getRequestDataArray()
+ {
+ return $this->requestData;
+ }
+
+ /**
+ * If content type of a request is Json.
+ *
+ * @return bool
+ */
+ public function isContentTypeJson()
+ {
+ return $this->isJson;
+ }
+
+ /**
+ * Resolve rul reference from entity data.
+ *
+ * @param string $urlIn
+ * @return string
+ */
+ private function resolveUrlReference($urlIn)
+ {
+ $urlOut = $urlIn;
+ $matchedParams = [];
+ preg_match_all("/[{](.+?)[}]/", $urlIn, $matchedParams);
+
+ if (!empty($matchedParams)) {
+ foreach ($matchedParams[0] as $paramKey => $paramValue) {
+ $param = $this->entityObject->getDataByName(
+ $matchedParams[1][$paramKey],
+ EntityDataObject::CEST_UNIQUE_VALUE
+ );
+ $urlOut = str_replace($paramValue, $param, $urlIn);
+ }
+ }
+ return $urlOut;
+ }
+}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php
new file mode 100644
index 000000000..7c80765b7
--- /dev/null
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php
@@ -0,0 +1,173 @@
+entityObject = clone $entityObject;
+ $this->storeCode = 'default';
+
+ foreach ($dependentObjects as $dependentObject) {
+ $this->dependentObjects[] = $dependentObject->getCreatedObject();
+ }
+ }
+
+ /**
+ * Function which executes a create request based on specific operation metadata
+ *
+ * @param string $storeCode
+ * @return void
+ */
+ public function createEntity($storeCode = null)
+ {
+ if (!empty($storeCode)) {
+ $this->storeCode = $storeCode;
+ }
+ $curlHandler = new CurlHandler('create', $this->entityObject, $this->storeCode);
+ $result = $curlHandler->executeRequest($this->dependentObjects);
+ $this->setCreatedEntity(
+ $result,
+ $curlHandler->getRequestDataArray(),
+ $curlHandler->isContentTypeJson()
+ );
+ }
+
+ /**
+ * Function which executes a delete request based on specific operation metadata
+ *
+ * @param string $storeCode
+ * @return void
+ */
+ public function deleteEntity($storeCode = null)
+ {
+ if (!empty($storeCode)) {
+ $this->storeCode = $storeCode;
+ }
+ $curlHandler = new CurlHandler('delete', $this->createdObject, $this->storeCode);
+ $result = $curlHandler->executeRequest($this->dependentObjects);
+ }
+
+ /**
+ * Returns the createdDataObject, instantiated when the entity is created via API.
+ * @return EntityDataObject
+ */
+ public function getCreatedObject()
+ {
+ return $this->createdObject;
+ }
+
+ /**
+ * Returns a specific data value based on the CreatedObject's definition.
+ * @param string $dataName
+ * @return string
+ */
+ public function getCreatedDataByName($dataName)
+ {
+ return $this->createdObject->getDataByName($dataName, EntityDataObject::NO_UNIQUE_PROCESS);
+ }
+
+ // TODO add update function
+ /* public function updateEntity()
+ {
+
+ }*/
+
+ /**
+ * Save created entity.
+ *
+ * @param string|array $response
+ * @param array $requestDataArray
+ * @param bool $isJson
+ * @return void
+ */
+ private function setCreatedEntity($response, $requestDataArray, $isJson)
+ {
+ if ($isJson) {
+ $persistedData = array_merge($requestDataArray, json_decode($response, true));
+ } else {
+ $persistedData = array_merge(
+ $this->convertToFlatArray($requestDataArray),
+ ['return' => $response]
+ );
+ }
+
+ $this->createdObject = new EntityDataObject(
+ $this->entityObject->getName(),
+ $this->entityObject->getType(),
+ $persistedData,
+ null,
+ null
+ );
+ }
+
+ /**
+ * Convert an multi-dimensional array to flat array.
+ *
+ * @param array $arrayIn
+ * @param string $rootKey
+ * @return array
+ */
+ private function convertToFlatArray($arrayIn, $rootKey = '')
+ {
+ $arrayOut = [];
+ foreach ($arrayIn as $key => $value) {
+ if (is_array($value)) {
+ if (!empty($rootKey)) {
+ $newRootKey = $rootKey . '[' . $key . ']';
+ } else {
+ $newRootKey = $key;
+ }
+ $arrayOut = array_merge($arrayOut, $this->convertToFlatArray($value, $newRootKey));
+ } elseif (!empty($rootKey)) {
+ $arrayOut[$rootKey . '[' . $key . ']'] = $value;
+ } else {
+ $arrayOut[$key] = $value;
+ }
+ }
+ return $arrayOut;
+ }
+}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php
new file mode 100644
index 000000000..49cb535a8
--- /dev/null
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php
@@ -0,0 +1,347 @@
+dependentEntities[$entity->getName()] = $entity;
+ }
+ }
+ }
+
+ /**
+ * This function returns an array which is structurally equal to the data which is needed by the magento web api,
+ * magento backend / frontend requests for entity creation. The function retrieves an array describing the entity's
+ * operation metadata and traverses any dependencies recursively forming an array which represents the data
+ * structure for the request of the desired entity type.
+ *
+ * @param EntityDataObject $entityObject
+ * @param array $operationMetadata
+ * @param string $operation
+ * @return array
+ * @throws \Exception
+ */
+ public function resolveOperationDataArray($entityObject, $operationMetadata, $operation)
+ {
+ $operationDataArray = [];
+ self::incrementSequence($entityObject->getName());
+
+ foreach ($operationMetadata as $operationElement) {
+ if ($operationElement->getType() == OperationElementExtractor::OPERATION_OBJECT_OBJ_NAME) {
+ $entityObj = $this->resolveOperationObjectAndEntityData($entityObject, $operationElement->getValue());
+ $operationDataArray[$operationElement->getValue()] =
+ $this->resolveOperationDataArray($entityObj, $operationElement->getNestedMetadata(), $operation);
+ continue;
+ }
+
+ $operationElementType = $operationElement->getValue();
+
+ if (in_array($operationElementType, self::PRIMITIVE_TYPES)) {
+ $elementData = $this->resolvePrimitiveReference(
+ $entityObject,
+ $operationElement->getKey(),
+ $operationElement->getType()
+ );
+
+ // If data was defined at all, attempt to put it into operation data array
+ // If data was not defined, and element is required, throw exception
+ // If no data is defined, don't input defaults per primitive into operation data array
+ if ($elementData != null) {
+ if (array_key_exists($operationElement->getKey(), $entityObject->getUniquenessData())) {
+ $uniqueData = $entityObject->getUniquenessDataByName($operationElement->getKey());
+ if ($uniqueData === 'suffix') {
+ $elementData .= (string)self::getSequence($entityObject->getName());
+ } else {
+ $elementData = (string)self::getSequence($entityObject->getName()) . $elementData;
+ }
+ }
+ $operationDataArray[$operationElement->getKey()] = $this->castValue(
+ $operationElementType,
+ $elementData
+ );
+
+ } elseif ($operationElement->getRequired()) {
+ throw new \Exception(sprintf(
+ self::EXCEPTION_REQUIRED_DATA,
+ $operationElement->getType(),
+ $operationElement->getKey(),
+ $entityObject->getName()
+ ));
+ }
+ } else {
+ $entityNamesOfType = $entityObject->getLinkedEntitiesOfType($operationElementType);
+
+ // If an element is required by metadata, but was not provided in the entity, throw an exception
+ if ($operationElement->getRequired() && $entityNamesOfType == null) {
+ throw new \Exception(sprintf(
+ self::EXCEPTION_REQUIRED_DATA,
+ $operationElement->getType(),
+ $operationElement->getKey(),
+ $entityObject->getName()
+ ));
+ }
+ foreach ($entityNamesOfType as $entityName) {
+ $operationDataSubArray = $this->resolveNonPrimitiveElement(
+ $entityName,
+ $operationElement,
+ $operation
+ );
+
+ if ($operationElement->getType() == OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY) {
+ $operationDataArray[$operationElement->getKey()][] = $operationDataSubArray;
+ } else {
+ $operationDataArray[$operationElement->getKey()] = $operationDataSubArray;
+ }
+ }
+ }
+ }
+
+ return $operationDataArray;
+ }
+
+ /**
+ * Resolves a reference for a primitive piece of data, if the data cannot be found as a defined field, the method
+ * looks to see if any vars have been declared with the same operationKey and resolves based on defined dependent
+ * entities.
+ *
+ * @param EntityDataObject $entityObject
+ * @param string $operationKey
+ * @param string $operationElementType
+ * @return array|string
+ */
+ private function resolvePrimitiveReference($entityObject, $operationKey, $operationElementType)
+ {
+ $elementData = $entityObject->getDataByName(
+ $operationKey,
+ EntityDataObject::CEST_UNIQUE_VALUE
+ );
+
+ if ($elementData == null && $entityObject->getVarReference($operationKey) != null) {
+ list($type, $field) = explode(
+ DataObjectHandler::VAR_ENTITY_FIELD_SEPARATOR,
+ $entityObject->getVarReference($operationKey)
+ );
+
+ if ($operationElementType == OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY) {
+ $elementDatas = [];
+ $entities = $this->getDependentEntitiesOfType($type);
+ foreach ($entities as $entity) {
+ $elementDatas[] = $entity->getDataByName($field, EntityDataObject::CEST_UNIQUE_VALUE);
+ }
+
+ return $elementDatas;
+
+ }
+
+ $entity = $this->getDependentEntitiesOfType($type)[0];
+ $elementData = $entity->getDataByName($field, EntityDataObject::CEST_UNIQUE_VALUE);
+ }
+
+ return $elementData;
+ }
+
+ /**
+ * Returns all dependent entities of the type passed in as an arg (the dependent entities are given at runtime,
+ * and are not statically defined).
+ *
+ * @param string $type
+ * @return array
+ */
+ private function getDependentEntitiesOfType($type)
+ {
+ $entitiesOfType = [];
+
+ foreach ($this->dependentEntities as $dependentEntity) {
+ if ($dependentEntity->getType() == $type) {
+ $entitiesOfType[] = $dependentEntity;
+ }
+ }
+
+ return $entitiesOfType;
+ }
+
+ /**
+ * This function does a comparison of the entity object being matched to the operation element. If there is a
+ * mismatch in type we attempt to use a nested entity, if the entities are properly matched, we simply return
+ * the object.
+ *
+ * @param EntityDataObject $entityObject
+ * @param string $operationElementValue
+ * @return EntityDataObject|null
+ */
+ private function resolveOperationObjectAndEntityData($entityObject, $operationElementValue)
+ {
+ if ($operationElementValue != $entityObject->getType()) {
+ // if we have a mismatch attempt to retrieve linked data and return just the first linkage
+ $linkName = $entityObject->getLinkedEntitiesOfType($operationElementValue)[0];
+ return DataObjectHandler::getInstance()->getObject($linkName);
+ }
+
+ return $entityObject;
+ }
+
+ /**
+ * Resolves DataObjects and pre-defined metadata (in other operation.xml file) referenced by the operation
+ *
+ * @param string $entityName
+ * @param OperationElement $operationElement
+ * @param string $operation
+ * @return array
+ */
+ private function resolveNonPrimitiveElement($entityName, $operationElement, $operation)
+ {
+ $linkedEntityObj = $this->resolveLinkedEntityObject($entityName);
+
+ // in array case
+ if (!empty($operationElement->getNestedOperationElement($operationElement->getValue()))
+ && $operationElement->getType() == OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY
+ ) {
+ $operationSubArray = $this->resolveOperationDataArray(
+ $linkedEntityObj,
+ [$operationElement->getNestedOperationElement($operationElement->getValue())],
+ $operation
+ );
+
+ return $operationSubArray[$operationElement->getValue()];
+ }
+
+ $operationMetadata = OperationDefinitionObjectHandler::getInstance()->getOperationDefinition(
+ $operation,
+ $linkedEntityObj->getType()
+ )->getOperationMetadata();
+
+ return $this->resolveOperationDataArray($linkedEntityObj, $operationMetadata, $operation);
+ }
+
+ /**
+ * Method to wrap entity resolution, checks locally defined dependent entities first
+ *
+ * @param string $entityName
+ * @return EntityDataObject
+ */
+ private function resolveLinkedEntityObject($entityName)
+ {
+ // check our dependent entity list to see if we have this defined
+ if (array_key_exists($entityName, $this->dependentEntities)) {
+ return $this->dependentEntities[$entityName];
+ }
+
+ return DataObjectHandler::getInstance()->getObject($entityName);
+ }
+
+ /**
+ * Increment an entity's sequence number by 1.
+ *
+ * @param string $entityName
+ * @return void
+ */
+ private static function incrementSequence($entityName)
+ {
+ if (array_key_exists($entityName, self::$entitySequences)) {
+ self::$entitySequences[$entityName]++;
+ } else {
+ self::$entitySequences[$entityName] = 1;
+ }
+ }
+
+ /**
+ * Get the current sequence number for an entity.
+ *
+ * @param string $entityName
+ * @return int
+ */
+ private static function getSequence($entityName)
+ {
+ if (array_key_exists($entityName, self::$entitySequences)) {
+ return self::$entitySequences[$entityName];
+ }
+ return 0;
+ }
+
+ // @codingStandardsIgnoreStart
+ /**
+ * This function takes a string value and its corresponding type and returns the string cast
+ * into its the type passed.
+ *
+ * @param string $type
+ * @param string $value
+ * @return mixed
+ */
+ private function castValue($type, $value)
+ {
+ $newVal = $value;
+
+ if (is_array($value)) {
+ $newVals = [];
+ foreach($value as $val) {
+ $newVals[] = $this->castValue($type, $val);
+ }
+
+ return $newVals;
+ }
+
+ switch ($type) {
+ case 'string':
+ break;
+ case 'integer':
+ $newVal = (integer)$value;
+ break;
+ case 'boolean':
+ if (strtolower($newVal) === 'false') {
+ return false;
+ }
+ $newVal = (boolean)$value;
+ break;
+ case 'double':
+ $newVal = (double)$value;
+ break;
+ }
+
+ return $newVal;
+ }
+ // @codingStandardsIgnoreEnd
+}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/JsonObjectExtractor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/JsonObjectExtractor.php
deleted file mode 100644
index f5c80065a..000000000
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/JsonObjectExtractor.php
+++ /dev/null
@@ -1,132 +0,0 @@
-extractJsonEntries($jsonMetadata, $jsonObjectArray[JsonObjectExtractor::JSON_OBJECT_ENTRY]);
- }
-
- // extract nested arrays
- if (array_key_exists(JsonObjectExtractor::JSON_OBJECT_ARRAY, $jsonObjectArray)) {
- $this->extractJsonArrays($jsonMetadata, $jsonObjectArray[JsonObjectExtractor::JSON_OBJECT_ARRAY]);
- }
-
- // extract nested
- if (array_key_exists(JsonObjectExtractor::JSON_OBJECT_OBJ_NAME, $jsonObjectArray)) {
- foreach ($jsonObjectArray[JsonObjectExtractor::JSON_OBJECT_OBJ_NAME] as $jsonObject) {
- $nestedJsonElement = $this->extractJsonObject($jsonObject);
- $jsonMetadata[] = $nestedJsonElement;
- }
- }
-
- // a jsonObject specified in xml must contain corresponding metadata for the object
- if (empty($jsonMetadata)) {
- throw new \Exception("must specificy jsonObject metadata if declaration is used");
- }
-
- return new JsonElement(
- $jsonDefKey,
- $dataType,
- JsonObjectExtractor::JSON_OBJECT_OBJ_NAME,
- $jsonObjectArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null,
- $nestedJsonElements,
- $jsonMetadata
- );
- }
-
- /**
- * Creates and Adds relevant JsonElements from json entries defined within jsonObject array
- *
- * @param array &$jsonMetadata
- * @param array $jsonEntryArray
- * @return void
- */
- private function extractJsonEntries(&$jsonMetadata, $jsonEntryArray)
- {
- foreach ($jsonEntryArray as $jsonEntryType) {
- $jsonMetadata[] = new JsonElement(
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY],
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE],
- JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY,
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null
- );
- }
- }
-
- /**
- * Creates and Adds relevant JsonElements from json arrays defined within jsonObject array
- *
- * @param array &$jsonArrayData
- * @param array $jsonArrayArray
- * @return void
- */
- private function extractJsonArrays(&$jsonArrayData, $jsonArrayArray)
- {
- foreach ($jsonArrayArray as $jsonEntryType) {
- $jsonElementValue =
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE][0]
- [JsonObjectExtractor::JSON_OBJECT_ARRAY_VALUE] ?? null;
-
- $nestedJsonElements = [];
- if (array_key_exists(JsonObjectExtractor::JSON_OBJECT_OBJ_NAME, $jsonEntryType)) {
- //add the key to reference this object later
- $jsonObjectKeyedArray = $jsonEntryType[JsonObjectExtractor::JSON_OBJECT_OBJ_NAME][0];
- $jsonObjectKeyedArray[JsonObjectExtractor::JSON_OBJECT_KEY] =
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_KEY];
- $jsonElement = $this->extractJsonObject($jsonObjectKeyedArray);
- $jsonElementValue = $jsonElement->getValue();
- $nestedJsonElements[$jsonElement->getValue()] = $jsonElement;
- }
- $jsonArrayData[] = new JsonElement(
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_KEY],
- $jsonElementValue,
- JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY,
- $jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null,
- $nestedJsonElements
- );
- }
- }
-}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/OperationElementExtractor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/OperationElementExtractor.php
new file mode 100644
index 000000000..6f2e3e447
--- /dev/null
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/OperationElementExtractor.php
@@ -0,0 +1,139 @@
+extractOperationField(
+ $operationElements,
+ $operationElementArray[OperationElementExtractor::OPERATION_OBJECT_ENTRY]
+ );
+ }
+
+ // extract nested arrays
+ if (array_key_exists(OperationElementExtractor::OPERATION_OBJECT_ARRAY, $operationElementArray)) {
+ $this->extractOperationArray(
+ $operationElements,
+ $operationElementArray[OperationElementExtractor::OPERATION_OBJECT_ARRAY]
+ );
+ }
+
+ // extract nested
+ if (array_key_exists(OperationElementExtractor::OPERATION_OBJECT_OBJ_NAME, $operationElementArray)) {
+ foreach ($operationElementArray[OperationElementExtractor::OPERATION_OBJECT_OBJ_NAME] as $operationObject) {
+ $nestedOperationElement = $this->extractOperationElement($operationObject);
+ $operationElements[] = $nestedOperationElement;
+ }
+ }
+
+ // a dataObject specified in xml must contain corresponding metadata for the object
+ if (empty($operationElements)) {
+ throw new \Exception("must specify dataObject metadata if declaration is used");
+ }
+
+ return new OperationElement(
+ $operationDefKey,
+ $dataType,
+ OperationElementExtractor::OPERATION_OBJECT_OBJ_NAME,
+ $operationElementArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null,
+ $nestedOperationElements,
+ $operationElements
+ );
+ }
+
+ /**
+ * Creates and Adds relevant DataElements from data entries defined within dataObject array
+ *
+ * @param array &$operationElements
+ * @param array $operationFieldArray
+ * @return void
+ */
+ private function extractOperationField(&$operationElements, $operationFieldArray)
+ {
+ foreach ($operationFieldArray as $operationFieldType) {
+ $operationElements[] = new OperationElement(
+ $operationFieldType[OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY],
+ $operationFieldType[OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE],
+ OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY,
+ $operationFieldType[OperationDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null
+ );
+ }
+ }
+
+ /**
+ * Creates and Adds relevant DataElements from data arrays defined within dataObject array
+ *
+ * @param array &$operationArrayData
+ * @param array $operationArrayArray
+ * @return void
+ */
+ private function extractOperationArray(&$operationArrayData, $operationArrayArray)
+ {
+ foreach ($operationArrayArray as $operationFieldType) {
+ $operationElementValue =
+ $operationFieldType[OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE][0]
+ [OperationElementExtractor::OPERATION_OBJECT_ARRAY_VALUE] ?? null;
+
+ $nestedOperationElements = [];
+ if (array_key_exists(OperationElementExtractor::OPERATION_OBJECT_OBJ_NAME, $operationFieldType)) {
+ //add the key to reference this object later
+ $operationObjectKeyedArray = $operationFieldType
+ [OperationElementExtractor::OPERATION_OBJECT_OBJ_NAME][0];
+ $operationObjectKeyedArray[OperationElementExtractor::OPERATION_OBJECT_KEY] =
+ $operationFieldType[OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_KEY];
+ $operationElement = $this->extractOperationElement($operationObjectKeyedArray);
+ $operationElementValue = $operationElement->getValue();
+ $nestedOperationElements[$operationElement->getValue()] = $operationElement;
+ }
+ $operationArrayData[] = new OperationElement(
+ $operationFieldType[OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_KEY],
+ $operationElementValue,
+ OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY,
+ $operationFieldType[OperationDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null,
+ $nestedOperationElements
+ );
+ }
+ }
+}
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd
index 2c4fcabc7..eadc0e396 100644
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd
@@ -6,28 +6,31 @@
-
-
+
+
+
-
+
+
+
-
+
-
+
-
+
@@ -44,7 +47,7 @@
-
+
@@ -73,4 +76,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd
index 24a7eed6b..c0494c911 100644
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd
+++ b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd
@@ -30,6 +30,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/sample.xml b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/sample.xml
deleted file mode 100644
index 722e5e6e7..000000000
--- a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/sample.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
- simpleConfiguration
- regressionConfiguration
-
- asdf
-
-
-
- AssertNumberOne
- AssertNumberTwo
-
-
- FirstNameData
-
-
- AssertNumberOne
- AssertNumberTwo
- AssertNumberThree
-
-
-
\ No newline at end of file
diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php
index e51117e36..a88bcae61 100644
--- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php
+++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php
@@ -54,9 +54,10 @@ public function __construct($name, $arguments, $actions)
* Gets the ordered steps including merged waits
*
* @param array $arguments
+ * @param string $actionReferenceKey
* @return array
*/
- public function getSteps($arguments)
+ public function getSteps($arguments, $actionReferenceKey)
{
$mergeUtil = new ActionMergeUtil();
$args = $this->arguments;
@@ -65,7 +66,7 @@ public function getSteps($arguments)
$args = array_merge($args, $arguments);
}
- return $mergeUtil->resolveActionSteps($this->getResolvedActionsWithArgs($args), true);
+ return $mergeUtil->resolveActionSteps($this->getResolvedActionsWithArgs($args, $actionReferenceKey), true);
}
/**
@@ -73,17 +74,18 @@ public function getSteps($arguments)
* action objects with proper argument.field references.
*
* @param array $arguments
+ * @param string $actionReferenceKey
* @return array
*/
- private function getResolvedActionsWithArgs($arguments)
+ private function getResolvedActionsWithArgs($arguments, $actionReferenceKey)
{
$resolvedActions = [];
$regexPattern = '/{{([\w]+)/';
foreach ($this->parsedActions as $action) {
$varAttributes = array_intersect(self::VAR_ATTRIBUTES, array_keys($action->getCustomActionAttributes()));
+ $newActionAttributes = [];
if (!empty($varAttributes)) {
- $newActionAttributes = [];
// 1 check to see if we have pertinent var
foreach ($varAttributes as $varAttribute) {
$attributeValue = $action->getCustomActionAttributes()[$varAttribute];
@@ -98,18 +100,14 @@ private function getResolvedActionsWithArgs($arguments)
$matches
);
}
-
- $resolvedActions[$action->getMergeKey()] = new ActionObject(
- $action->getMergeKey(),
- $action->getType(),
- array_merge($action->getCustomActionAttributes(), $newActionAttributes),
- $action->getLinkedAction(),
- $action->getOrderOffset()
- );
- } else {
- // add action here if we do not see any userInput in this particular action
- $resolvedActions[$action->getMergeKey()] = $action;
}
+ $resolvedActions[$action->getMergeKey() . $actionReferenceKey] = new ActionObject(
+ $action->getMergeKey() . $actionReferenceKey,
+ $action->getType(),
+ array_merge($action->getCustomActionAttributes(), $newActionAttributes),
+ $action->getLinkedAction(),
+ $action->getOrderOffset()
+ );
}
return $resolvedActions;
diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php
index 767012694..cc473075e 100644
--- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php
+++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php
@@ -392,11 +392,12 @@ private function matchParameterReferences($reference, $parameters)
);
}
- //Attempt to Resolve {{data}} references to actual output.
+ //Attempt to Resolve {{data}} references to actual output. Trim parameter for whitespace before processing it.
//If regex matched it means that it's either a 'StringLiteral' or $key.data$/$$key.data$$ reference.
//Else assume it's a normal {{data.key}} reference and recurse through findAndReplace
$resolvedParameters = [];
foreach ($parameters as $parameter) {
+ $parameter = trim($parameter);
preg_match_all("/[$'][\w.$]+[$']/", $parameter, $match);
if (!empty($match[0])) {
$resolvedParameters[] = ltrim(rtrim($parameter, "'"), "'");
diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php
index 133ace223..ad38df07f 100644
--- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php
+++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php
@@ -77,7 +77,7 @@ private function resolveActionGroups($mergedSteps)
$mergedStep->getCustomActionAttributes()[ActionObjectExtractor::ACTION_GROUP_REF]
);
$args = $mergedStep->getCustomActionAttributes()[ActionObjectExtractor::ACTION_GROUP_ARGUMENTS] ?? null;
- $actionsToMerge = $actionGroup->getSteps($args);
+ $actionsToMerge = $actionGroup->getSteps($args, $key);
$newOrderedList = $newOrderedList + $actionsToMerge;
} else {
$newOrderedList[$key] = $mergedStep;
diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd
index 94d6d5a7a..edabbcbea 100644
--- a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd
+++ b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd
@@ -105,7 +105,6 @@
-
@@ -375,11 +374,12 @@
+
-
+
@@ -394,6 +394,7 @@
+
@@ -616,38 +617,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Magento/FunctionalTestingFramework/Util/ApiClientUtil.php b/src/Magento/FunctionalTestingFramework/Util/ApiClientUtil.php
deleted file mode 100644
index 0db7075b8..000000000
--- a/src/Magento/FunctionalTestingFramework/Util/ApiClientUtil.php
+++ /dev/null
@@ -1,117 +0,0 @@
-apiPath = $apiPath;
- $this->headers = $headers;
- $this->apiOperation = $apiOperation;
- $this->jsonBody = $jsonBody;
-
- $this->curl = curl_init();
- }
-
- /**
- * Submits the request based on object properties
- *
- * @param bool $verbose
- * @return string|bool
- * @throws \Exception
- */
- public function submit($verbose = false)
- {
- $url = null;
-
- if ($this->jsonBody) {
- curl_setopt($this->curl, CURLOPT_POSTFIELDS, $this->jsonBody);
- }
-
- curl_setopt($this->curl, CURLOPT_VERBOSE, $verbose);
-
- if ((getenv('MAGENTO_RESTAPI_SERVER_HOST') !== false)
- && (getenv('MAGENTO_RESTAPI_SERVER_HOST') !== '') ) {
- $url = getenv('MAGENTO_RESTAPI_SERVER_HOST');
- } else {
- $url = getenv('MAGENTO_BASE_URL');
- }
-
- if ((getenv('MAGENTO_RESTAPI_SERVER_PORT') !== false)
- && (getenv('MAGENTO_RESTAPI_SERVER_PORT') !== '')) {
- $url .= ':' . getenv('MAGENTO_RESTAPI_SERVER_PORT');
- }
-
- curl_setopt_array($this->curl, [
- CURLOPT_RETURNTRANSFER => 1,
- CURLOPT_HTTPHEADER => $this->headers,
- CURLOPT_CUSTOMREQUEST => $this->apiOperation,
- CURLOPT_URL => $url . $this->apiPath
- ]);
-
- $response = curl_exec($this->curl);
- $http_code = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
-
- if ($response === false || !in_array($http_code, ApiClientUtil::SUCCESSFUL_HTTP_CODES)) {
- throw new \Exception('API returned response code: ' . $http_code . ' Response:' . $response);
- }
-
- curl_close($this->curl);
-
- return $response;
- }
-}
diff --git a/src/Magento/FunctionalTestingFramework/Util/Protocol/CurlInterface.php b/src/Magento/FunctionalTestingFramework/Util/Protocol/CurlInterface.php
new file mode 100644
index 000000000..792e0c6d4
--- /dev/null
+++ b/src/Magento/FunctionalTestingFramework/Util/Protocol/CurlInterface.php
@@ -0,0 +1,57 @@
+ CURLOPT_TIMEOUT,
+ 'maxredirects' => CURLOPT_MAXREDIRS,
+ 'proxy' => CURLOPT_PROXY,
+ 'ssl_cert' => CURLOPT_SSLCERT,
+ 'userpwd' => CURLOPT_USERPWD,
+ ];
+
+ /**
+ * Array of CURL options.
+ *
+ * @var array
+ */
+ protected $options = [];
+
+ /**
+ * A list of successful HTTP responses that will not trigger an exception.
+ *
+ * @var int[] SUCCESSFUL_HTTP_CODES
+ */
+ const SUCCESSFUL_HTTP_CODES = [200, 201, 202, 203, 204, 205];
+
+ /**
+ * Apply current configuration array to curl resource.
+ *
+ * @return $this
+ */
+ protected function applyConfig()
+ {
+ // apply additional options to cURL
+ foreach ($this->options as $option => $value) {
+ curl_setopt($this->getResource(), $option, $value);
+ }
+
+ if (empty($this->config)) {
+ return $this;
+ }
+ foreach (array_keys($this->config) as $param) {
+ if (array_key_exists($param, $this->allowedParams)) {
+ curl_setopt($this->getResource(), $this->allowedParams[$param], $this->config[$param]);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Set array of additional cURL options.
+ *
+ * @param array $options
+ * @return $this
+ */
+ public function setOptions(array $options = [])
+ {
+ $this->options = $options;
+ return $this;
+ }
+
+ /**
+ * Add additional option to cURL.
+ *
+ * @param int $option
+ * @param int|string|bool|array $value
+ * @return $this
+ */
+ public function addOption($option, $value)
+ {
+ $this->options[$option] = $value;
+ return $this;
+ }
+
+ /**
+ * Set the configuration array for the adapter.
+ *
+ * @param array $config
+ * @return $this
+ */
+ public function setConfig(array $config = [])
+ {
+ $this->config = $config;
+ return $this;
+ }
+
+ /**
+ * Send request to the remote server.
+ *
+ * @param string $url
+ * @param array $body
+ * @param string $method
+ * @param array $headers
+ * @return void
+ * @throws TestFrameworkException
+ */
+ public function write($url, $body = [], $method = CurlInterface::POST, $headers = [])
+ {
+ $this->applyConfig();
+ $options = [
+ CURLOPT_URL => $url,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_FOLLOWLOCATION => true,
+ CURLOPT_COOKIEFILE => '',
+ CURLOPT_HTTPHEADER => $headers,
+ CURLOPT_SSL_VERIFYPEER => false,
+ ];
+ switch ($method) {
+ case CurlInterface::POST:
+ $options[CURLOPT_POST] = true;
+ $options[CURLOPT_POSTFIELDS] = $body;
+ break;
+ case CurlInterface::PUT:
+ $options[CURLOPT_CUSTOMREQUEST] = self::PUT;
+ $options[CURLOPT_POSTFIELDS] = $body;
+ break;
+ case CurlInterface::DELETE:
+ $options[CURLOPT_CUSTOMREQUEST] = self::DELETE;
+ break;
+ case CurlInterface::GET:
+ $options[CURLOPT_HTTPGET] = true;
+ break;
+ default:
+ throw new TestFrameworkException("Undefined curl method: $method");
+ }
+
+ curl_setopt_array($this->getResource(), $options);
+ }
+
+ /**
+ * Read response from server.
+ *
+ * @param string $successRegex
+ * @param string $returnRegex
+ * @return string
+ * @throws TestFrameworkException
+ */
+ public function read($successRegex = null, $returnRegex = null)
+ {
+ $response = curl_exec($this->getResource());
+
+ if ($response === false) {
+ throw new TestFrameworkException(curl_error($this->getResource()));
+ }
+ $http_code = $this->getInfo(CURLINFO_HTTP_CODE);
+ if (!in_array($http_code, self::SUCCESSFUL_HTTP_CODES)) {
+ throw new TestFrameworkException('Error HTTP response code: ' . $http_code . ' Response:' . $response);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Close the connection to the server.
+ *
+ * @return void
+ */
+ public function close()
+ {
+ curl_close($this->getResource());
+ $this->resource = null;
+ }
+
+ /**
+ * Returns a cURL handle on success.
+ *
+ * @return resource
+ */
+ protected function getResource()
+ {
+ if ($this->resource === null) {
+ $this->resource = curl_init();
+ }
+ return $this->resource;
+ }
+
+ /**
+ * Get last error number.
+ *
+ * @return int
+ */
+ public function getErrno()
+ {
+ return curl_errno($this->getResource());
+ }
+
+ /**
+ * Get string with last error for the current session.
+ *
+ * @return string
+ */
+ public function getError()
+ {
+ return curl_error($this->getResource());
+ }
+
+ /**
+ * Get information regarding a specific transfer.
+ *
+ * @param int $opt CURLINFO option
+ * @return string|array
+ */
+ public function getInfo($opt = 0)
+ {
+ return curl_getinfo($this->getResource(), $opt);
+ }
+
+ /**
+ * Provide curl_multi_* requests support.
+ *
+ * @param array $urls
+ * @param array $options
+ * @return array
+ */
+ public function multiRequest(array $urls, array $options = [])
+ {
+ $handles = [];
+ $result = [];
+
+ $multiHandle = curl_multi_init();
+
+ foreach ($urls as $key => $url) {
+ $handles[$key] = curl_init();
+ curl_setopt($handles[$key], CURLOPT_URL, $url);
+ curl_setopt($handles[$key], CURLOPT_HEADER, 0);
+ curl_setopt($handles[$key], CURLOPT_RETURNTRANSFER, 1);
+ if (!empty($options)) {
+ curl_setopt_array($handles[$key], $options);
+ }
+ curl_multi_add_handle($multiHandle, $handles[$key]);
+ }
+ $process = null;
+ do {
+ curl_multi_exec($multiHandle, $process);
+ usleep(100);
+ } while ($process > 0);
+
+ foreach ($handles as $key => $handle) {
+ $result[$key] = curl_multi_getcontent($handle);
+ curl_multi_remove_handle($multiHandle, $handle);
+ }
+ curl_multi_close($multiHandle);
+ return $result;
+ }
+
+ /**
+ * Extract the response code from a response string.
+ *
+ * @param string $responseStr
+ * @return int
+ */
+ public static function extractCode($responseStr)
+ {
+ preg_match("|^HTTP/[\d\.x]+ (\d+)|", $responseStr, $m);
+
+ if (isset($m[1])) {
+ return (int)$m[1];
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php
index 2798329bc..971688fcf 100644
--- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php
+++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php
@@ -18,6 +18,8 @@
class TestGenerator
{
+ const REQUIRED_ENTITY_REFERENCE = 'persistedKey';
+
/**
* Path to the export dir.
*
@@ -212,7 +214,7 @@ private function generateUseStatementsPhp()
$useStatementsPhp = "use Magento\FunctionalTestingFramework\AcceptanceTester;\n";
$useStatementsPhp .= "use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler;\n";
- $useStatementsPhp .= "use Magento\FunctionalTestingFramework\DataGenerator\Api\EntityApiHandler;\n";
+ $useStatementsPhp .= "use Magento\FunctionalTestingFramework\DataGenerator\Persist\DataPersistenceHandler;\n";
$useStatementsPhp .= "use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject;\n";
$allureStatements = [
@@ -395,7 +397,7 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false)
if (isset($customActionAttributes['selectorArray'])) {
$selector = $customActionAttributes['selectorArray'];
} elseif (isset($customActionAttributes['selector'])) {
- $selector = $this->wrapWithDoubleQuotes($customActionAttributes['selector']);
+ $selector = $this->addUniquenessFunctionCall($customActionAttributes['selector']);
}
if (isset($customActionAttributes['selector1'])) {
@@ -487,62 +489,54 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false)
foreach ($customActionAttributes as $customAttribute) {
if (is_array($customAttribute) && $customAttribute['nodeName'] = 'required-entity') {
if ($hookObject) {
- $requiredEntities [] = "\$this->" . $customAttribute['name'] . "->getName() => " .
- "\$this->" . $customAttribute['name'] . "->getType()";
- $requiredEntityObjects [] = '$this->' . $customAttribute['name'];
+ $requiredEntities [] = "\$this->" . $customAttribute[self::REQUIRED_ENTITY_REFERENCE] .
+ "->getName() => " . "\$this->" . $customAttribute[self::REQUIRED_ENTITY_REFERENCE] .
+ "->getType()";
+ $requiredEntityObjects [] = '$this->' . $customAttribute
+ [self::REQUIRED_ENTITY_REFERENCE];
} else {
- $requiredEntities [] = "\$" . $customAttribute['name'] . "->getName() => "
- . "\$" . $customAttribute['name'] . "->getType()";
- $requiredEntityObjects [] = '$' . $customAttribute['name'];
+ $requiredEntities [] = "\$" . $customAttribute[self::REQUIRED_ENTITY_REFERENCE]
+ . "->getName() => " . "\$" . $customAttribute[self::REQUIRED_ENTITY_REFERENCE] .
+ "->getType()";
+ $requiredEntityObjects [] = '$' . $customAttribute[self::REQUIRED_ENTITY_REFERENCE];
}
}
}
- //If required-entities are defined, reassign dataObject to not overwrite the static definition.
- //Also, EntityApiHandler needs to be defined with customData array.
- if (!empty($requiredEntities)) {
- $testSteps .= sprintf(
- "\t\t$%s = new EntityDataObject($%s->getName(), $%s->getType(), $%s->getData()
- , array_merge($%s->getLinkedEntities(), [%s]), $%s->getUniquenessData());\n",
- $entity,
- $entity,
- $entity,
- $entity,
- $entity,
- implode(", ", $requiredEntities),
+
+ if ($hookObject) {
+ $createEntityFunctionCall = sprintf("\t\t\$this->%s->createEntity(", $key);
+ $dataPersistenceHandlerFunctionCall = sprintf(
+ "\t\t\$this->%s = new DataPersistenceHandler($%s",
+ $key,
+ $entity
+ );
+ } else {
+ $createEntityFunctionCall = sprintf("\t\t\$%s->createEntity(", $key);
+ $dataPersistenceHandlerFunctionCall = sprintf(
+ "\t\t$%s = new DataPersistenceHandler($%s",
+ $key,
$entity
);
+ }
- if ($hookObject) {
- $testSteps .= sprintf(
- "\t\t\$this->%s = new EntityApiHandler($%s, [%s]);\n",
- $key,
- $entity,
- implode(', ', $requiredEntityObjects)
- );
- $testSteps .= sprintf("\t\t\$this->%s->createEntity();\n", $key);
- } else {
- $testSteps .= sprintf(
- "\t\t$%s = new EntityApiHandler($%s, [%s]);\n",
- $key,
- $entity,
- implode(', ', $requiredEntityObjects)
- );
- $testSteps .= sprintf("\t\t$%s->createEntity();\n", $key);
- }
+ if (isset($customActionAttributes['storeCode'])) {
+ $createEntityFunctionCall .= sprintf("\"%s\");\n", $customActionAttributes['storeCode']);
} else {
- if ($hookObject) {
- $testSteps .= sprintf(
- "\t\t\$this->%s = new EntityApiHandler($%s);\n",
- $key,
- $entity
- );
- $testSteps .= sprintf("\t\t\$this->%s->createEntity();\n", $key);
- } else {
- $testSteps .= sprintf("\t\t$%s = new EntityApiHandler($%s);\n", $key, $entity);
- $testSteps .= sprintf("\t\t$%s->createEntity();\n", $key);
- }
+ $createEntityFunctionCall .= ");\n";
}
+ //If required-entities are defined, reassign dataObject to not overwrite the static definition.
+ //Also, DataPersistenceHandler needs to be defined with customData array.
+ if (!empty($requiredEntities)) {
+ $dataPersistenceHandlerFunctionCall .= sprintf(
+ ", [%s]);\n",
+ implode(', ', $requiredEntityObjects)
+ );
+ } else {
+ $dataPersistenceHandlerFunctionCall .= ");\n";
+ }
+ $testSteps .= $dataPersistenceHandlerFunctionCall;
+ $testSteps .= $createEntityFunctionCall;
break;
case "deleteData":
$key = $customActionAttributes['createDataKey'];
@@ -559,33 +553,6 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false)
$testSteps .= sprintf("\t\t$%s->deleteEntity();\n", $key);
}
break;
- case "entity":
- $entityData = '[';
- foreach ($stepsData[$customActionAttributes['name']] as $dataKey => $dataValue) {
- $variableReplace = $this->resolveTestVariable($dataValue, true);
- $entityData .= sprintf("\"%s\" => \"%s\", ", $dataKey, $variableReplace);
- }
- $entityData .= ']';
- if ($hookObject) {
- // no uniqueness attributes for data allowed within entity defined in cest.
- $testSteps .= sprintf(
- "\t\t\$this->%s = new EntityDataObject(\"%s\",\"%s\",%s,null,null);\n",
- $customActionAttributes['name'],
- $customActionAttributes['name'],
- $customActionAttributes['type'],
- $entityData
- );
- } else {
- // no uniqueness attributes for data allowed within entity defined in cest.
- $testSteps .= sprintf(
- "\t\t$%s = new EntityDataObject(\"%s\",\"%s\",%s,null,null);\n",
- $customActionAttributes['name'],
- $customActionAttributes['name'],
- $customActionAttributes['type'],
- $entityData
- );
- }
- break;
case "dontSeeCurrentUrlEquals":
case "dontSeeCurrentUrlMatches":
case "seeInPopup":
@@ -805,7 +772,7 @@ private function resolveTestVariable($inputString, $quoteBreak = false)
$replaced = false;
// Check for Cest-scope variables first, stricter regex match.
- preg_match_all("/\\$\\$[\w.]+\\$\\$/", $outputString, $matches);
+ preg_match_all("/\\$\\$[\w.\[\]]+\\$\\$/", $outputString, $matches);
foreach ($matches[0] as $match) {
$replacement = null;
$variable = $this->stripAndSplitReference($match, '$$');
@@ -824,7 +791,7 @@ private function resolveTestVariable($inputString, $quoteBreak = false)
}
// Check Test-scope variables
- preg_match_all("/\\$[\w.]+\\$/", $outputString, $matches);
+ preg_match_all("/\\$[\w.\[\]]+\\$/", $outputString, $matches);
foreach ($matches[0] as $match) {
$replacement = null;
$variable = $this->stripAndSplitReference($match, '$');
@@ -873,7 +840,7 @@ private function generateHooksPhp($hookObjects)
foreach ($hookObject->getActions() as $step) {
if ($step->getType() == "createData") {
$hooks .= "\t/**\n";
- $hooks .= sprintf("\t * @var EntityApiHandler $%s;\n", $step->getMergeKey());
+ $hooks .= sprintf("\t * @var DataPersistenceHandler $%s;\n", $step->getMergeKey());
$hooks .= "\t */\n";
$hooks .= sprintf("\tprotected $%s;\n\n", $step->getMergeKey());
$createData = true;
@@ -1083,7 +1050,7 @@ private function wrapWithDoubleQuotes($input)
}
/**
- * Strip beginning and ending quotes of input string.
+ * Strip beginning and ending double quotes of input string.
*
* @param string $input
* @return string
@@ -1093,10 +1060,10 @@ private function stripWrappedQuotes($input)
if (empty($input)) {
return '';
}
- if (substr($input, 0, 1) === '"' || substr($input, 0, 1) === "'") {
+ if (substr($input, 0, 1) === '"') {
$input = substr($input, 1);
}
- if (substr($input, -1, 1) === '"' || substr($input, -1, 1) === "'") {
+ if (substr($input, -1, 1) === '"') {
$input = substr($input, 0, -1);
}
return $input;