diff --git a/src/ploigos_step_runner/step_implementers/package/maven.py b/src/ploigos_step_runner/step_implementers/package/maven.py index 1a0ac90b..4e7c4fd5 100644 --- a/src/ploigos_step_runner/step_implementers/package/maven.py +++ b/src/ploigos_step_runner/step_implementers/package/maven.py @@ -3,12 +3,6 @@ Notes ----- -.. WARNING:: - - This can currently only handle POMs that generate a single artifact. - See https://github.com/ploigos/ploigos-step-runner/issues/99 for RFE - to handle multiple artifacts. - .. Important:: If package not specified in pom will default to jar in result. @@ -22,17 +16,31 @@ * runtime configuration * previous step results -Configuration Key | Required? | Default | Description -----------------------|-----------|-------------------------|----------- -`pom-file` | True | `'pom.xml'` | Maven pom file to build -`artifact-extensions` | True | `["jar", "war", "ear"]` | Extensions to look for in the \ - `artifact-parent-dir` for built \ - artifacts. -`artifact-parent-dir` | True | `'target'` | Parent directory to look for built \ - artifacts in ending in \ - `artifact-extensions`. -`tls-verify` | No | True | Disables TLS Verification if set to \ - False +Configuration Key | Required? | Default | Description +-----------------------------|-----------|---------|----------- +`pom-file` | Yes | `'pom.xml'` | pom used when executing maven. +`tls-verify` | No | `True` | Disables TLS Verification if set to False +`maven-profiles` | No | `[]` | List of maven profiles to use. +`maven-no-transfer-progress` | No | `True` | \ + `True` to suppress the transfer progress of packages maven downloads. + `False` to have the transfer progress printed.\ + See https://maven.apache.org/ref/current/maven-embedder/cli.html +`maven-additional-arguments` | No | `['-Dmaven.test.skip=true']` \ + | List of additional arguments to use. \ + Skipping tests by default because assuming \ + a previous step already ran them. +`maven-servers` | No | | Dictionary of dictionaries of \ + id, username, password +`maven-repositories` | No | | Dictionary of dictionaries of \ + id, url, snapshots, releases +`maven-mirrors` | No | | Dictionary of dictionaries of \ + id, url, mirror_of +`artifact-extensions` | Yes | `["jar", "war", "ear"]` \ + | Extensions to look for in the `artifact-parent-dir` \ + for built artifacts. +`artifact-parent-dir` | Yes | `'target'` \ + | Parent directory to look for built artifacts in \ + ending in `artifact-extensions`. Result Artifacts ---------------- @@ -40,7 +48,8 @@ Result Artifact Key | Description --------------------|------------ -`package-artifacts` | An array of dictionaries with information on the built artifacts. +`maven-output` | Path to Stdout and Stderr from invoking Maven. +`packages` | An array of dictionaries with information on the built artifacts. ## package-artifacts @@ -49,58 +58,18 @@ | Key | Description |-----------------|------------ | `path` | Absolute path to the built artifact. -| `artifact-id` | Maven artifact ID. -| `group-id` | Maven group ID. -| `package-type` | Package type. -| `pom-path` | Absolute path to the pom that built the artifact. - -Examples --------- - -**Example 1** - -*Given POM* - - - 4.0.0 - com.mycompany.app - my-app - 1.0-SNAPSHOT - - 1.8 - 1.8 - - - -**Example 2** - -*Given POM* - - - 4.0.0 - com.mycompany.app - my-app - 1.0-SNAPSHOT - war - - 1.8 - 1.8 - - """ import os -import sys -import sh -from ploigos_step_runner import StepResult -from ploigos_step_runner.step_implementers.shared.maven_generic import MavenGeneric -from ploigos_step_runner.utils.io import create_sh_redirect_to_multiple_streams_fn_callback -from ploigos_step_runner.utils.xml import get_xml_element +from ploigos_step_runner import StepResult, StepRunnerException +from ploigos_step_runner.step_implementers.shared.maven_generic import \ + MavenGeneric DEFAULT_CONFIG = { - 'tls-verify': True, - 'pom-file': 'pom.xml', + 'maven-additional-arguments': [ + '-Dmaven.test.skip=true' + ], 'artifact-extensions': ["jar", "war", "ear"], 'artifact-parent-dir': 'target' } @@ -109,10 +78,23 @@ 'pom-file' ] - class Maven(MavenGeneric): """`StepImplementer` for the `package` step using Maven. """ + def __init__( # pylint: disable=too-many-arguments + self, + workflow_result, + parent_work_dir_path, + config, + environment=None + ): + super().__init__( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=environment, + maven_phases_and_goals=['package'] + ) @staticmethod def step_implementer_config_defaults(): @@ -126,9 +108,8 @@ def step_implementer_config_defaults(): Notes ----- These are the lowest precedence configuration values. - """ - return DEFAULT_CONFIG + return {**MavenGeneric.step_implementer_config_defaults(), **DEFAULT_CONFIG} @staticmethod def _required_config_or_result_keys(): @@ -157,106 +138,48 @@ def _run_step(self): # pylint: disable=too-many-locals """ step_result = StepResult.from_step_implementer(self) - tls_verify = self.get_value('tls-verify') pom_file = self.get_value('pom-file') artifact_extensions = self.get_value('artifact-extensions') artifact_parent_dir = self.get_value('artifact-parent-dir') - if not os.path.exists(pom_file): - step_result.success = False - step_result.message = f'Given pom file does not exist: {pom_file}' - return step_result - - mvn_additional_options = [] - if not tls_verify: - mvn_additional_options += [ - '-Dmaven.wagon.http.ssl.insecure=true', - '-Dmaven.wagon.http.ssl.allowall=true', - '-Dmaven.wagon.http.ssl.ignore.validity.dates=true', - ] - - settings_file = self._generate_maven_settings() - mvn_output_file_path = self.write_working_file('mvn_test_output.txt') + # package the artifacts + mvn_output_file_path = self.write_working_file('mvn_output.txt') try: - with open(mvn_output_file_path, 'w') as mvn_output_file: - out_callback = create_sh_redirect_to_multiple_streams_fn_callback([ - sys.stdout, - mvn_output_file - ]) - err_callback = create_sh_redirect_to_multiple_streams_fn_callback([ - sys.stderr, - mvn_output_file - ]) + # execute maven step (params come from config) + self._run_maven_step( + mvn_output_file_path=mvn_output_file_path + ) + + # find the artifacts + packages = [] + pom_file_dir_name = os.path.dirname(os.path.abspath(pom_file)) + artifact_parent_dir_full_path = \ + os.listdir(os.path.join( + pom_file_dir_name, + artifact_parent_dir)) + for filename in artifact_parent_dir_full_path: + if any(filename.endswith(ext) for ext in artifact_extensions): + packages += [{ + 'path': os.path.join( + pom_file_dir_name, + artifact_parent_dir, + filename + ) + }] - sh.mvn( # pylint: disable=no-member - 'clean', - 'install', - '-f', pom_file, - '-s', settings_file, - *mvn_additional_options, - _out=out_callback, - _err=err_callback - ) - except sh.ErrorReturnCode as error: + step_result.add_artifact( + name='packages', + value=packages + ) + except StepRunnerException as error: step_result.success = False - step_result.message = "Package failures. See 'maven-output' report artifacts " \ - f"for details: {error}" - return step_result + step_result.message = "Error running 'maven package' to package artifacts. " \ + f"More details maybe found in 'maven-output' report artifact: {error}" finally: step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", + description="Standard out and standard error from maven.", name='maven-output', value=mvn_output_file_path ) - # find the artifacts - artifact_file_names = [] - artifact_parent_dir_full_path = \ - os.listdir(os.path.join( - os.path.dirname(os.path.abspath(pom_file)), - artifact_parent_dir)) - for filename in artifact_parent_dir_full_path: - if any(filename.endswith(ext) for ext in artifact_extensions): - artifact_file_names.append(filename) - - # error if we find more then one artifact - # see https://projects.engineering.redhat.com/browse/NAPSSPO-546 - if len(artifact_file_names) > 1: - step_result.success = False - step_result.message = 'pom resulted in multiple artifacts with expected artifact ' \ - f'extensions ({artifact_extensions}), this is unsupported' - return step_result - - if len(artifact_file_names) < 1: - step_result.success = False - step_result.message = 'pom resulted in 0 with expected artifact extensions ' \ - f'({artifact_extensions}), this is unsupported' - return step_result - - artifact_id = get_xml_element(pom_file, 'artifactId').text - group_id = get_xml_element(pom_file, 'groupId').text - try: - package_type = get_xml_element(pom_file, 'package').text - except ValueError: - package_type = 'jar' - - package_artifacts = { - 'path': os.path.join( - os.path.dirname(os.path.abspath(pom_file)), - artifact_parent_dir, - artifact_file_names[0] - ), - 'artifact-id': artifact_id, - 'group-id': group_id, - 'package-type': package_type, - 'pom-path': pom_file - } - - # Currently, package returns ONE 'artifact', eg: one war file - # However, in the future, an ARRAY could be returned, eg: several jar files - step_result.add_artifact( - name='package-artifacts', - value=[package_artifacts] - ) - return step_result diff --git a/src/ploigos_step_runner/step_implementers/push_artifacts/maven.py b/src/ploigos_step_runner/step_implementers/push_artifacts/maven.py index bdfebc8a..3061f3e7 100644 --- a/src/ploigos_step_runner/step_implementers/push_artifacts/maven.py +++ b/src/ploigos_step_runner/step_implementers/push_artifacts/maven.py @@ -9,19 +9,34 @@ * runtime configuration * previous step results -Configuration Key | Required | Default | Description --------------------------------|----------|---------|------------------------------------------ -`maven-push-artifact-repo-url` | yes | | id for the maven servers and mirrors -`maven-push-artifact-repo-id` | Yes | | url for the maven servers and mirrors -`version` | Yes | | version to push -`package-artifacts` | Yes | | Artifacts is dictionary \ - Each element of an `artifact` will be used \ - as a parameter to deploy to repository:
\ - * artifact.group-id
\ - * artifact.artifact-id
\ - * artifact.path
\ - * artifact.package-type -`tls-verify` | No | True | Disables TLS Verification if set to False +Configuration Key | Required? | Default | Description +-----------------------------|-----------|---------|----------- +`pom-file` | Yes | `'pom.xml'` | pom used when executing maven. +`tls-verify` | No | `True` | Disables TLS Verification if set to False +`maven-profiles` | No | `[]` | List of maven profiles to use. +`maven-no-transfer-progress` | No | `True` | \ + `True` to suppress the transfer progress of packages maven downloads. + `False` to have the transfer progress printed.\ + See https://maven.apache.org/ref/current/maven-embedder/cli.html +`maven-additional-arguments` | No | `['-Dmaven.test.skip=true', \ + '-Dmaven.install.skip=true']` \ + | List of additional arguments to use. \ + Skipping tests by default because assuming \ + a previous step already ran them. \ + Skipping install backs assuming this is \ + running in an ephermal environment where \ + that would be a waist of time, and also \ + that a previous step ran `package` \ + and `push-artifacts` steps. +`maven-servers` | No | | Dictionary of dictionaries of \ + id, username, password +`maven-repositories` | No | | Dictionary of dictionaries of \ + id, url, snapshots, releases +`maven-mirrors` | No | | Dictionary of dictionaries of \ + id, url, mirror_of +`version` | Yes | | version to push +`maven-push-artifact-repo-url` | yes | | id for the maven servers and mirrors +`maven-push-artifact-repo-id` | Yes | | url for the maven servers and mirrors Result Artifacts ---------------- @@ -29,68 +44,49 @@ Result Artifact Key | Description --------------------|------------ -`push-artifacts` | An array of dictionaries with information on the built artifacts. - -## push-artifacts -Keys in the dictionary elements in the `push-artifacts` array in the step results. - -| Key | Description -|-----------------|------------ -| `path` | Absolute path to the artifact pushed to the artifact repository -| `artifact-id` | Maven artifact ID pushed to the artifact repository -| `group-id` | Maven group ID pushed to the artifact repository -| `version` | Version pushed to the artifact repository -| `packaging` | Type of package (eg: jar, war) - -Examples --------- - -**Example: Step Configuration (minimal)** - - push-artifacts: - - implementer: Maven - config: - maven-push-artifact-repo-id: internal-id-name - maven-push-artifact-repo-url: url-to server - -**Example: Generated Maven Deploy (uses both step configuration and previous results)** - - mvn - deploy:deploy-file' - -Durl=maven-push-artifact-repo-url - -Dversion=package.artifact.version - -DgroupId=package.artifact.group-id - -DartifactId=package.artifact.artifact-id - -Dfile=package.artifact.path - -Dpackaging=package.artifact.package-type - -DrepositoryId=maven-push-artifact-repo-id - -s settings.xml +`push-artifacts` | An array of dictionaries with information on the pushed artifacts """ -import sys -import sh -from ploigos_step_runner import StepResult -from ploigos_step_runner.step_implementers.shared.maven_generic import MavenGeneric -from ploigos_step_runner.utils.io import create_sh_redirect_to_multiple_streams_fn_callback +from ploigos_step_runner import StepResult, StepRunnerException +from ploigos_step_runner.step_implementers.shared.maven_generic import \ + MavenGeneric +from ploigos_step_runner.utils.maven import run_maven DEFAULT_CONFIG = { - 'tls-verify': True + 'maven-additional-arguments': [ + '-Dmaven.install.skip=true', + '-Dmaven.test.skip=true' + ] } + REQUIRED_CONFIG_OR_PREVIOUS_STEP_RESULT_ARTIFACT_KEYS = [ + 'pom-file', 'maven-push-artifact-repo-url', 'maven-push-artifact-repo-id', - 'version', - 'package-artifacts' + 'version' ] class Maven(MavenGeneric): - """`StepImplementer` for the `package` step using Maven. + """`StepImplementer` for the `push-artifacts` step using Maven. """ + def __init__( # pylint: disable=too-many-arguments + self, + workflow_result, + parent_work_dir_path, + config, + environment=None + ): + super().__init__( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=environment, + maven_phases_and_goals=['deploy'] + ) @staticmethod def step_implementer_config_defaults(): - """ - Getter for the StepImplementer's configuration defaults. + """Getter for the StepImplementer's configuration defaults. Returns ------- @@ -101,7 +97,7 @@ def step_implementer_config_defaults(): ----- These are the lowest precedence configuration values. """ - return DEFAULT_CONFIG + return {**MavenGeneric.step_implementer_config_defaults(), **DEFAULT_CONFIG} @staticmethod def _required_config_or_result_keys(): @@ -134,76 +130,56 @@ def _run_step(self): # pylint: disable=too-many-locals maven_push_artifact_repo_id = self.get_value('maven-push-artifact-repo-id') maven_push_artifact_repo_url = self.get_value('maven-push-artifact-repo-url') version = self.get_value('version') - package_artifacts = self.get_value('package-artifacts') - tls_verify = self.get_value('tls-verify') - - # disable tls verification - mvn_additional_options = [] - if not tls_verify: - mvn_additional_options += [ - '-Dmaven.wagon.http.ssl.insecure=true', - '-Dmaven.wagon.http.ssl.allowall=true', - '-Dmaven.wagon.http.ssl.ignore.validity.dates=true', - ] - - # Create settings.xml - settings_file = self._generate_maven_settings() # push the artifacts - push_artifacts = [] - mvn_output_file_path = self.write_working_file('mvn_test_output.txt') + mvn_update_version_output_file_path = self.write_working_file('mvn_versions_set_output.txt') + mvn_push_artifacts_output_file_path = self.write_working_file('mvn_deploy_output.txt') try: - for package in package_artifacts: - artifact_path = package['path'] - group_id = package['group-id'] - artifact_id = package['artifact-id'] - package_type = package['package-type'] - - # push the artifact - with open(mvn_output_file_path, 'a') as mvn_output_file: - out_callback = create_sh_redirect_to_multiple_streams_fn_callback([ - sys.stdout, - mvn_output_file - ]) - err_callback = create_sh_redirect_to_multiple_streams_fn_callback([ - sys.stderr, - mvn_output_file - ]) - sh.mvn( # pylint: disable=no-member - 'deploy:deploy-file', - '-Dversion=' + version, - '-Dfile=' + artifact_path, - '-DgroupId=' + group_id, - '-DartifactId=' + artifact_id, - '-Dpackaging=' + package_type, - '-Durl=' + maven_push_artifact_repo_url, - '-DrepositoryId=' + maven_push_artifact_repo_id, - '-s' + settings_file, - *mvn_additional_options, - _out=out_callback, - _err=err_callback - ) - - # record the pushed artifact - push_artifacts.append({ - 'artifact-id': artifact_id, - 'group-id': group_id, - 'version': version, - 'path': artifact_path, - 'packaging': package_type, - }) - except sh.ErrorReturnCode as error: + # update the version before pushing + # NOTE 1: we know this is weird. But the version in the pom isn't necessarily + # the version that was calculated as part of the release and so we need + # to update that before doing the maven deploy so the maven deploy will + # use the new version. + # + # NOTE 2: we tried doing this in the same command as the deploy, + # but the pom was already loaded so even though the xml was updated + # the deploy still used the old version, hence having to run this + # first and independently. + print("Update maven package version") + run_maven( + mvn_output_file_path=mvn_update_version_output_file_path, + settings_file=self.maven_settings_file, + pom_file=self.get_value('pom-file'), + phases_and_goals=['versions:set'], + additional_arguments=[ + f'-DnewVersion={version}' + ] + ) + + # execute maven step (params come from config) + print("Push packaged maven artifacts") + self._run_maven_step( + mvn_output_file_path=mvn_push_artifacts_output_file_path, + step_implementer_additional_arguments=[ + '-DaltDeploymentRepository=' \ + f'{maven_push_artifact_repo_id}::default::{maven_push_artifact_repo_url}' + ] + ) + except StepRunnerException as error: step_result.success = False - step_result.message = "Push artifacts failures. See 'maven-output' report artifacts " \ - f"for details: {error}" + step_result.message = "Error running 'maven deploy' to push artifacts. " \ + f"More details maybe found in 'maven-output' report artifact: {error}" + finally: + step_result.add_artifact( + description="Standard out and standard error from running maven to update version.", + name='maven-update-version-output', + value=mvn_update_version_output_file_path + ) + step_result.add_artifact( + description="Standard out and standard error from running maven to " \ + "push artifacts to repository.", + name='maven-push-artifacts-output', + value=mvn_push_artifacts_output_file_path + ) - step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", - name='maven-output', - value=mvn_output_file_path - ) - step_result.add_artifact( - name='push-artifacts', - value=push_artifacts - ) return step_result diff --git a/src/ploigos_step_runner/step_implementers/shared/maven_generic.py b/src/ploigos_step_runner/step_implementers/shared/maven_generic.py index 3d02c393..f493f075 100644 --- a/src/ploigos_step_runner/step_implementers/shared/maven_generic.py +++ b/src/ploigos_step_runner/step_implementers/shared/maven_generic.py @@ -1,13 +1,53 @@ """Abstract parent class for StepImplementers that use Maven. + +Step Configuration +------------------ +Step configuration expected as input to this step. +Could come from: +* static configuration +* runtime configuration +* previous step results + +Configuration Key | Required? | Default | Description +-----------------------------|-----------|---------|----------- +`pom-file` | Yes | `'pom.xml'` | pom used when executing maven. +`tls-verify` | No | `True` | Disables TLS Verification if set to False +`maven-phases-and-goals` | Yes | | List of maven phases and/or goals to execute. +`maven-profiles` | No | `[]` | List of maven profiles to use. +`maven-no-transfer-progress` | No | `True` | \ + `True` to suppress the transfer progress of packages maven downloads. + `False` to have the transfer progress printed.\ + See https://maven.apache.org/ref/current/maven-embedder/cli.html +`maven-additional-arguments` | No | `[]` | List of additional arguments to use. +`maven-servers` | No | | Dictionary of dictionaries of \ + id, username, password +`maven-repositories` | No | | Dictionary of dictionaries of \ + id, url, snapshots, releases +`maven-mirrors` | No | | Dictionary of dictionaries of \ + id, url, mirror_of """ import os +from ploigos_step_runner import StepResult, StepRunnerException from ploigos_step_runner.config.config_value import ConfigValue from ploigos_step_runner.step_implementer import StepImplementer -from ploigos_step_runner.utils.maven import generate_maven_settings, write_effective_pom +from ploigos_step_runner.utils.maven import (generate_maven_settings, + run_maven, write_effective_pom) from ploigos_step_runner.utils.xml import get_xml_element_by_path +DEFAULT_CONFIG = { + 'pom-file': 'pom.xml', + 'tls-verify': True, + 'maven-profiles': [], + 'maven-additional-arguments': [], + 'maven-no-transfer-progress': True +} + +REQUIRED_CONFIG_OR_PREVIOUS_STEP_RESULT_ARTIFACT_KEYS = [ + 'pom-file', + 'maven-phases-and-goals' +] class MavenGeneric(StepImplementer): """Abstract parent class for StepImplementers that use Maven. @@ -19,6 +59,56 @@ class MavenGeneric(StepImplementer): f'{SUREFIRE_PLUGIN_XML_ELEMENT_PATH}/mvn:configuration/mvn:reportsDirectory' DEFAULT_SUREFIRE_PLUGIN_REPORTS_DIR = 'target/surefire-reports' + def __init__( # pylint: disable=too-many-arguments + self, + workflow_result, + parent_work_dir_path, + config, + environment=None, + maven_phases_and_goals=None + ): + self.__maven_settings_file = None + self.__maven_phases_and_goals = maven_phases_and_goals + + super().__init__( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=environment + ) + + @staticmethod + def step_implementer_config_defaults(): + """Getter for the StepImplementer's configuration defaults. + + Returns + ------- + dict + Default values to use for step configuration values. + + Notes + ----- + These are the lowest precedence configuration values. + """ + return DEFAULT_CONFIG + + @staticmethod + def _required_config_or_result_keys(): + """Getter for step configuration or previous step result artifacts that are required before + running this step. + + See Also + -------- + _validate_required_config_or_previous_step_result_artifact_keys + + Returns + ------- + array_list + Array of configuration keys or previous step result artifacts + that are required before running the step. + """ + return REQUIRED_CONFIG_OR_PREVIOUS_STEP_RESULT_ARTIFACT_KEYS + def _validate_required_config_or_previous_step_result_artifact_keys(self): """Validates that the required configuration keys or previous step result artifacts are set and have valid values. @@ -41,23 +131,50 @@ def _validate_required_config_or_previous_step_result_artifact_keys(self): assert os.path.exists(pom_file), \ f'Given maven pom file (pom-file) does not exist: {pom_file}' - def _generate_maven_settings(self): - maven_servers = ConfigValue.convert_leaves_to_values( - self.get_value('maven-servers') - ) - maven_repositories = ConfigValue.convert_leaves_to_values( - self.get_value('maven-repositories') - ) - maven_mirrors = ConfigValue.convert_leaves_to_values( - self.get_value('maven-mirrors') - ) + @property + def maven_phases_and_goals(self): + """Property for getting the maven phases and goals to execute which can either come + from field set on this class via constructor, intended for use by sub classes that want + to hard code the phases and goals for convenience, or comes from config value + `maven-phases-and-goals` set by the user. - return generate_maven_settings( - working_dir=self.work_dir_path, - maven_servers=maven_servers, - maven_repositories=maven_repositories, - maven_mirrors=maven_mirrors - ) + Returns + ------- + str + Maven phases and/or goals to execute. + """ + maven_phases_and_goals = None + if self.__maven_phases_and_goals: + maven_phases_and_goals = self.__maven_phases_and_goals + else: + maven_phases_and_goals = self.get_value('maven-phases-and-goals') + + return maven_phases_and_goals + + @property + def maven_settings_file(self): + """Gets the maven settings file for this step. + """ + + if not self.__maven_settings_file: + maven_servers = ConfigValue.convert_leaves_to_values( + self.get_value('maven-servers') + ) + maven_repositories = ConfigValue.convert_leaves_to_values( + self.get_value('maven-repositories') + ) + maven_mirrors = ConfigValue.convert_leaves_to_values( + self.get_value('maven-mirrors') + ) + + self.__maven_settings_file = generate_maven_settings( + working_dir=self.work_dir_path, + maven_servers=maven_servers, + maven_repositories=maven_repositories, + maven_mirrors=maven_mirrors + ) + + return self.__maven_settings_file def _get_effective_pom(self): """Writes the effective pom to a file and returns the path. @@ -78,8 +195,94 @@ def _get_effective_pom(self): return effective_pom_path def _get_effective_pom_element(self, element_path): + """Get an XML element from the effective pom. + + Parameters + ---------- + element_path : str + XML path of element to to get from effective pom. + + Returns + ------- + str + Value of the element from the effective pom. + """ return get_xml_element_by_path( self._get_effective_pom(), element_path, default_namespace='mvn' ) + + def _run_maven_step( + self, + mvn_output_file_path, + step_implementer_additional_arguments=None + ): + """Runs maven using the configuration given to this step runner. + + Parameters + ---------- + mvn_output_file_path : str + Path to file containing the maven stdout and stderr output. + step_implementer_additional_arguments : [] + Additional arguments hard coded by the step implementer. + + Raises + ------ + StepRunnerException + If maven returns a none 0 exit code. + """ + + phases_and_goals = self.maven_phases_and_goals + pom_file = self.get_value('pom-file') + tls_verify = self.get_value('tls-verify') + profiles = self.get_value('maven-profiles') + no_transfer_progress = self.get_value('maven-no-transfer-progress') + + additional_arguments = [] + if step_implementer_additional_arguments: + additional_arguments = \ + step_implementer_additional_arguments + self.get_value('maven-additional-arguments') + else: + additional_arguments = self.get_value('maven-additional-arguments') + + run_maven( + mvn_output_file_path=mvn_output_file_path, + phases_and_goals=phases_and_goals, + additional_arguments=additional_arguments, + pom_file=pom_file, + tls_verify=tls_verify, + profiles=profiles, + no_transfer_progress=no_transfer_progress, + settings_file=self.maven_settings_file + ) + + def _run_step(self): # pylint: disable=too-many-locals + """Runs the step implemented by this StepImplementer. + + Returns + ------- + StepResult + Object containing the dictionary results of this step. + """ + step_result = StepResult.from_step_implementer(self) + + # package the artifacts + mvn_output_file_path = self.write_working_file('mvn_output.txt') + try: + # execute maven step (params come from config) + self._run_maven_step( + mvn_output_file_path=mvn_output_file_path + ) + except StepRunnerException as error: + step_result.success = False + step_result.message = "Error running maven. " \ + f"More details maybe found in 'maven-output' report artifact: {error}" + finally: + step_result.add_artifact( + description="Standard out and standard error from maven.", + name='maven-output', + value=mvn_output_file_path + ) + + return step_result diff --git a/src/ploigos_step_runner/step_implementers/uat/maven_selenium_cucumber.py b/src/ploigos_step_runner/step_implementers/uat/maven_selenium_cucumber.py index 1f8c97dc..36f44272 100644 --- a/src/ploigos_step_runner/step_implementers/uat/maven_selenium_cucumber.py +++ b/src/ploigos_step_runner/step_implementers/uat/maven_selenium_cucumber.py @@ -8,24 +8,41 @@ * runtime configuration * previous step results -Configuration Key | Required? | Default | Description ----------------------|-----------|--------------------|------------ -`fail-on-no-tests` | Yes | True | Value to specify whether unit-test \ - step can succeed when no tests are defined -`pom-file` | Yes | `pom.xml` | pom used to run tests and check \ - for existence of custom reportsDirectory -`selenium-hub-url` | Yes | | URL where the Selenium Hub is running -`target-host-url` | Maybe | | Target host URL for UAT. \ -
\ - If not given then use first host url from \ - `deployed-host-urls`. -`deployed-host-urls` | Maybe | | Deployed host URLs. If `target-host-url` \ - is not given then use first URL from this \ - list. If `target-host-url` is given then \ - ignore this value. -`uat-maven-profile` | Yes | `integration-test` | Maven profile to use to invoke \ - Selenium tests. -`tls-verify` | No | True | Disables TLS Verification if set to False +Configuration Key | Required? | Default | Description +-----------------------------|-----------|---------|------------ +`pom-file` | Yes | `'pom.xml'` | pom used when executing maven. +`tls-verify` | No | `True` | Disables TLS Verification if set to False +`maven-profiles` | No | `['integration-test']` \ + | \ + List of maven profiles to use. \ + Typically user acceptance tests are executed \ + using a specific profile using `maven test`. \ + If your user acceptance tests are run \ + differently look to use \ + `ploigos_step_runner.step_implementers.shared.MavenGeneric` \ + instead. +`maven-no-transfer-progress` | No | `True` | \ + `True` to suppress the transfer progress of packages maven downloads. + `False` to have the transfer progress printed.\ + See https://maven.apache.org/ref/current/maven-embedder/cli.html +`maven-additional-arguments` | No | `[]` | List of additional arguments to use. +`maven-servers` | No | | Dictionary of dictionaries of \ + id, username, password +`maven-repositories` | No | | Dictionary of dictionaries of \ + id, url, snapshots, releases +`maven-mirrors` | No | | Dictionary of dictionaries of \ + id, url, mirror_of +`fail-on-no-tests` | Yes | `True ` | `True` to fail if there are not tests to run. \ + `False` to ignore if there are no tests to run. +`selenium-hub-url` | Yes | | URL where the Selenium Hub is running +`target-host-url` | Maybe | | Target host URL for UAT. \ +
\ + If not given then use first host url from \ + `deployed-host-urls`. +`deployed-host-urls` | Maybe | | Deployed host URLs. If `target-host-url` \ + is not given then use first URL from this \ + list. If `target-host-url` is given then \ + ignore this value. Result Artifacts ---------------- @@ -40,35 +57,43 @@ """ import os -import sys -import sh -from ploigos_step_runner.config.config_value import ConfigValue -from ploigos_step_runner.exceptions import StepRunnerException -from ploigos_step_runner.step_implementers.shared.maven_generic import MavenGeneric from ploigos_step_runner import StepResult -from ploigos_step_runner.utils.io import create_sh_redirect_to_multiple_streams_fn_callback -from ploigos_step_runner.utils.xml import aggregate_xml_element_attribute_values +from ploigos_step_runner.exceptions import StepRunnerException +from ploigos_step_runner.step_implementers.shared.maven_generic import \ + MavenGeneric +from ploigos_step_runner.utils.xml import \ + aggregate_xml_element_attribute_values DEFAULT_CONFIG = { - 'tls-verify': True, - 'fail-on-no-tests': True, - 'pom-file': 'pom.xml', - 'uat-maven-profile': 'integration-test' + 'maven-profiles': ['integration-test'], + 'fail-on-no-tests': True } REQUIRED_CONFIG_OR_PREVIOUS_STEP_RESULT_ARTIFACT_KEYS = [ - 'fail-on-no-tests', 'pom-file', + 'fail-on-no-tests', 'selenium-hub-url', - 'uat-maven-profile' ] - class MavenSeleniumCucumber(MavenGeneric): """`StepImplementer` for the `uat` step using Maven driving Selenium generating Cucumber reports. """ + def __init__( # pylint: disable=too-many-arguments + self, + workflow_result, + parent_work_dir_path, + config, + environment=None + ): + super().__init__( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=environment, + maven_phases_and_goals=['test'] + ) @staticmethod def step_implementer_config_defaults(): @@ -83,7 +108,7 @@ def step_implementer_config_defaults(): ----- These are the lowest precedence configuration values. """ - return DEFAULT_CONFIG + return {**MavenGeneric.step_implementer_config_defaults(), **DEFAULT_CONFIG} @staticmethod def _required_config_or_result_keys(): @@ -136,15 +161,11 @@ def _run_step(self): # pylint: disable=too-many-locals,too-many-statements,too-m """ step_result = StepResult.from_step_implementer(self) - settings_file = self._generate_maven_settings() pom_file = self.get_value('pom-file') fail_on_no_tests = self.get_value('fail-on-no-tests') selenium_hub_url = self.get_value('selenium-hub-url') - deployed_host_urls = ConfigValue.convert_leaves_to_values( - self.get_value('deployed-host-urls') - ) - uat_maven_profile = self.get_value('uat-maven-profile') - tls_verify = self.get_value('tls-verify') + deployed_host_urls = self.get_value('deployed-host-urls') + maven_profiles = self.get_value('maven-profiles') # NOTE: # at some point may need to do smarter logic if a deployable has more then one deployed @@ -161,7 +182,6 @@ def _run_step(self): # pylint: disable=too-many-locals,too-many-statements,too-m else: target_base_url = self.get_value('target-host-url') - # ensure surefire plugin enabled maven_surefire_plugin = self._get_effective_pom_element( element_path=MavenGeneric.SUREFIRE_PLUGIN_XML_ELEMENT_PATH @@ -177,60 +197,45 @@ def _run_step(self): # pylint: disable=too-many-locals,too-many-statements,too-m element_path=MavenGeneric.SUREFIRE_PLUGIN_REPORTS_DIR_XML_ELEMENT_PATH ) if reports_dir is not None: - test_results_dir = reports_dir.text + if os.path.isabs(reports_dir.text): + test_results_dir = reports_dir.text + else: + test_results_dir = os.path.join( + os.path.dirname(os.path.abspath(pom_file)), + reports_dir.text + ) else: test_results_dir = os.path.join( os.path.dirname(os.path.abspath(pom_file)), MavenGeneric.DEFAULT_SUREFIRE_PLUGIN_REPORTS_DIR ) - mvn_additional_options = [] - if not tls_verify: - mvn_additional_options += [ - '-Dmaven.wagon.http.ssl.insecure=true', - '-Dmaven.wagon.http.ssl.allowall=true', - '-Dmaven.wagon.http.ssl.ignore.validity.dates=true', - ] - cucumber_html_report_path = os.path.join(self.work_dir_path, 'cucumber.html') cucumber_json_report_path = os.path.join(self.work_dir_path, 'cucumber.json') mvn_output_file_path = self.write_working_file('mvn_test_output.txt') try: - with open(mvn_output_file_path, 'w') as mvn_output_file: - out_callback = create_sh_redirect_to_multiple_streams_fn_callback([ - sys.stdout, - mvn_output_file - ]) - err_callback = create_sh_redirect_to_multiple_streams_fn_callback([ - sys.stderr, - mvn_output_file - ]) - sh.mvn( # pylint: disable=no-member - 'clean', - 'test', - f'-P{uat_maven_profile}', + # execute maven step (params come from config) + self._run_maven_step( + mvn_output_file_path=mvn_output_file_path, + step_implementer_additional_arguments=[ f'-Dselenium.hub.url={selenium_hub_url}', f'-Dtarget.base.url={target_base_url}', f'-Dcucumber.plugin=' \ f'html:{cucumber_html_report_path},' \ f'json:{cucumber_json_report_path}', - '-f', pom_file, - '-s', settings_file, - *mvn_additional_options, - _out=out_callback, - _err=err_callback - ) + ] + ) # if not results # else add evidence of results if not os.path.isdir(test_results_dir) or len(os.listdir(test_results_dir)) == 0: if fail_on_no_tests: step_result.message = "No user acceptance tests defined" \ - f" using maven profile ({uat_maven_profile})." + f" using maven profile ({maven_profiles})." step_result.success = False else: step_result.message = "No user acceptance tests defined" \ - f" using maven profile ({uat_maven_profile})," \ + f" using maven profile ({maven_profiles})," \ " but 'fail-on-no-tests' is False." else: attribs = ["time", "tests", "errors", "skipped", "failures"] @@ -239,48 +244,57 @@ def _run_step(self): # pylint: disable=too-many-locals,too-many-statements,too-m report_results = aggregate_xml_element_attribute_values( test_results_dir, xml_element, - attribs) + attribs + ) + not_found_attribs = [] for attrib in attribs: if attrib in report_results: step_result.add_evidence( - description="Surefire report value for " + attrib, - name="uat-evidence-" + attrib, - value=report_results[attrib] - ) + description="Surefire report value for " + attrib, + name="uat-evidence-" + attrib, + value=report_results[attrib] + ) else: - raise ValueError("Error gathering evidence from "\ - "surefire report, expected attribute " + attrib +" "\ - "not found in report " + test_results_dir) - - except sh.ErrorReturnCode: - step_result.message = "User acceptance test failures. See 'maven-output'" \ - ", 'surefire-reports', 'cucumber-report-html', and 'cucumber-report-json'" \ - " report artifacts for details." + not_found_attribs.append(attrib) + + if not_found_attribs: + #NOTE: not sure if this should be a failure or just a warning... + raise ValueError( + "Error gathering evidence from "\ + f"surefire report, expected attribute(s) ({not_found_attribs}) "\ + f"not found in report ({test_results_dir})" + ) + + except StepRunnerException as error: step_result.success = False + step_result.message = "Error running 'maven test' to run user acceptance tests. " \ + "More details maybe found in 'maven-output', `surefire-reports`, " \ + "`cucumber-report-html`, and `cucumber-report-json` " \ + f"report artifact: {error}" except ValueError as error: step_result.message = str(error) step_result.success = False - - step_result.add_artifact( - description=f"Standard out and standard error by 'mvn -P{uat_maven_profile} test'.", - name='maven-output', - value=mvn_output_file_path - ) - step_result.add_artifact( - description=f"Surefire reports generated by 'mvn -P{uat_maven_profile} test'.", - name='surefire-reports', - value=test_results_dir - ) - step_result.add_artifact( - description=f"Cucumber (HTML) report generated by 'mvn -P{uat_maven_profile} test'.", - name='cucumber-report-html', - value=cucumber_html_report_path - ) - step_result.add_artifact( - description=f"Cucumber (JSON) report generated by 'mvn -P{uat_maven_profile} test'.", - name='cucumber-report-json', - value=cucumber_json_report_path - ) + finally: + step_result.add_artifact( + description="Standard out and standard error from maven.", + name='maven-output', + value=mvn_output_file_path + ) + step_result.add_artifact( + description="Surefire reports generated by maven.", + name='surefire-reports', + value=test_results_dir + ) + step_result.add_artifact( + description="Cucumber (HTML) report generated by maven.", + name='cucumber-report-html', + value=cucumber_html_report_path + ) + step_result.add_artifact( + description="Cucumber (JSON) report generated by maven.", + name='cucumber-report-json', + value=cucumber_json_report_path + ) return step_result diff --git a/src/ploigos_step_runner/step_implementers/unit_test/maven.py b/src/ploigos_step_runner/step_implementers/unit_test/maven.py index c829abee..f5f5879b 100644 --- a/src/ploigos_step_runner/step_implementers/unit_test/maven.py +++ b/src/ploigos_step_runner/step_implementers/unit_test/maven.py @@ -8,13 +8,24 @@ * runtime configuration * previous step results -Configuration Key | Required? | Default | Description --------------------|-----------|-------------|----------- -`fail-on-no-tests` | True | True | Value to specify whether unit-test \ - step can succeed when no tests are defined -`pom-file` | True | `'pom.xml'` | pom used to run tests and check \ - for existence of custom reportsDirectory -`tls-verify` | No | True | Disables TLS Verification if set to False +Configuration Key | Required? | Default | Description +-----------------------------|-----------|---------|----------- +`pom-file` | Yes | `'pom.xml'` | pom used when executing maven. +`tls-verify` | No | `True` | Disables TLS Verification if set to False +`maven-profiles` | No | `[]` | List of maven profiles to use. +`maven-no-transfer-progress` | No | `True` | \ + `True` to suppress the transfer progress of packages maven downloads. + `False` to have the transfer progress printed.\ + See https://maven.apache.org/ref/current/maven-embedder/cli.html +`maven-additional-arguments` | No | `[]` | List of additional arguments to use. +`maven-servers` | No | | Dictionary of dictionaries of \ + id, username, password +`maven-repositories` | No | | Dictionary of dictionaries of \ + id, url, snapshots, releases +`maven-mirrors` | No | | Dictionary of dictionaries of \ + id, url, mirror_of +`fail-on-no-tests` | Yes | `True ` | `True` to fail if there are not tests to run. \ + `False` to ignore if there are no tests to run. Result Artifacts ---------------- @@ -26,28 +37,37 @@ `surefile-reports` | Path to Surefire reports generated from invoking Maven. """ import os -import sys -import sh -from ploigos_step_runner import StepResult -from ploigos_step_runner.step_implementers.shared.maven_generic import MavenGeneric -from ploigos_step_runner.utils.io import create_sh_redirect_to_multiple_streams_fn_callback +from ploigos_step_runner import StepResult, StepRunnerException +from ploigos_step_runner.step_implementers.shared.maven_generic import \ + MavenGeneric DEFAULT_CONFIG = { - 'tls-verify': True, - 'fail-on-no-tests': True, - 'pom-file': 'pom.xml' + 'fail-on-no-tests': True } REQUIRED_CONFIG_OR_PREVIOUS_STEP_RESULT_ARTIFACT_KEYS = [ - 'fail-on-no-tests', - 'pom-file' + 'pom-file', + 'fail-on-no-tests' ] - class Maven(MavenGeneric): """`StepImplementer` for the `unit-test` step using Maven with Surefire plugin. """ + def __init__( # pylint: disable=too-many-arguments + self, + workflow_result, + parent_work_dir_path, + config, + environment=None + ): + super().__init__( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=environment, + maven_phases_and_goals=['test'] + ) @staticmethod def step_implementer_config_defaults(): @@ -61,9 +81,8 @@ def step_implementer_config_defaults(): Notes ----- These are the lowest precedence configuration values. - """ - return DEFAULT_CONFIG + return {**MavenGeneric.step_implementer_config_defaults(), **DEFAULT_CONFIG} @staticmethod def _required_config_or_result_keys(): @@ -92,11 +111,11 @@ def _run_step(self): """ step_result = StepResult.from_step_implementer(self) - tls_verify = self.get_value('tls-verify') pom_file = self.get_value('pom-file') fail_on_no_tests = self.get_value('fail-on-no-tests') # ensure surefire plugin enabled + # NOTE: should this really be hard requirement? maven_surefire_plugin = self._get_effective_pom_element( element_path=MavenGeneric.SUREFIRE_PLUGIN_XML_ELEMENT_PATH ) @@ -111,62 +130,47 @@ def _run_step(self): element_path=MavenGeneric.SUREFIRE_PLUGIN_REPORTS_DIR_XML_ELEMENT_PATH ) if reports_dir is not None: - test_results_dir = reports_dir.text + if os.path.isabs(reports_dir.text): + test_results_dir = reports_dir.text + else: + test_results_dir = os.path.join( + os.path.dirname(os.path.abspath(pom_file)), + reports_dir.text + ) else: test_results_dir = os.path.join( os.path.dirname(os.path.abspath(pom_file)), MavenGeneric.DEFAULT_SUREFIRE_PLUGIN_REPORTS_DIR ) - mvn_additional_options = [] - if not tls_verify: - mvn_additional_options += [ - '-Dmaven.wagon.http.ssl.insecure=true', - '-Dmaven.wagon.http.ssl.allowall=true', - '-Dmaven.wagon.http.ssl.ignore.validity.dates=true', - ] - - settings_file = self._generate_maven_settings() - mvn_output_file_path = self.write_working_file('mvn_test_output.txt') + # run the tests + mvn_output_file_path = self.write_working_file('mvn_output.txt') try: - with open(mvn_output_file_path, 'w') as mvn_output_file: - out_callback = create_sh_redirect_to_multiple_streams_fn_callback([ - sys.stdout, - mvn_output_file - ]) - err_callback = create_sh_redirect_to_multiple_streams_fn_callback([ - sys.stderr, - mvn_output_file - ]) - - sh.mvn( # pylint: disable=no-member - 'clean', - 'test', - '-f', pom_file, - '-s', settings_file, - *mvn_additional_options, - _out=out_callback, - _err=err_callback - ) + # execute maven step (params come from config) + self._run_maven_step( + mvn_output_file_path=mvn_output_file_path + ) + # check if any tests were run if not os.path.isdir(test_results_dir) or len(os.listdir(test_results_dir)) == 0: if fail_on_no_tests: step_result.message = 'No unit tests defined.' step_result.success = False else: step_result.message = "No unit tests defined, but 'fail-on-no-tests' is False." - except sh.ErrorReturnCode as error: - step_result.message = "Unit test failures. See 'maven-output'" \ - f" and 'surefire-reports' report artifacts for details: {error}" + except StepRunnerException as error: step_result.success = False + step_result.message = "Error running 'maven test' to run unit tests. " \ + "More details maybe found in 'maven-output' and `surefire-reports` " \ + f"report artifact: {error}" finally: step_result.add_artifact( - description="Standard out and standard error from 'mvn test'.", + description="Standard out and standard error from maven.", name='maven-output', value=mvn_output_file_path ) step_result.add_artifact( - description="Surefire reports generated from 'mvn test'.", + description="Surefire reports generated by maven.", name='surefire-reports', value=test_results_dir ) diff --git a/src/ploigos_step_runner/utils/maven.py b/src/ploigos_step_runner/utils/maven.py index 490c338d..390e776b 100644 --- a/src/ploigos_step_runner/utils/maven.py +++ b/src/ploigos_step_runner/utils/maven.py @@ -1,11 +1,13 @@ """Shared utils for maven operations. """ - import os +import sys import xml.etree.ElementTree as ET import sh from ploigos_step_runner.exceptions import StepRunnerException +from ploigos_step_runner.utils.io import \ + create_sh_redirect_to_multiple_streams_fn_callback def generate_maven_settings(working_dir, maven_servers, maven_repositories, maven_mirrors): @@ -442,3 +444,95 @@ def write_effective_pom( ) from error return output_path + +def run_maven( #pylint: disable=too-many-arguments + mvn_output_file_path, + settings_file, + pom_file, + phases_and_goals, + tls_verify=True, + additional_arguments=None, + profiles=None, + no_transfer_progress=True +): + """Runs maven using the given configuration. + + Parameters + ---------- + mvn_output_file_path : str + Path to file containing the maven stdout and stderr output. + phases_and_goals : [str] + List of maven phases and/or goals to execute. + additional_arguments : [str] + List of additional arguments to use. + pom_file : str (path) + pom used when executing maven. + tls_verify : boolean + Disables TLS Verification if set to False + profiles : [str] + List of maven profiles to use. + no_transfer_progress : boolean + `True` to suppress the transfer progress of packages maven downloads. + `False` to have the transfer progress printed.\ + See https://maven.apache.org/ref/current/maven-embedder/cli.html + settings_file : str (path) + Maven settings file to use. + + Raises + ------ + StepRunnerException + If maven returns a none 0 exit code. + """ + + if not isinstance(phases_and_goals, list): + phases_and_goals = [phases_and_goals] + + # create profile argument + profiles_arguments = "" + if profiles: + profiles_arguments = ['-P', f"{','.join(profiles)}"] + + # create no transfer progress argument + no_transfer_progress_argument = None + if no_transfer_progress: + no_transfer_progress_argument = '--no-transfer-progress' + + # create tls arguments + tls_arguments = [] + if not tls_verify: + tls_arguments += [ + '-Dmaven.wagon.http.ssl.insecure=true', + '-Dmaven.wagon.http.ssl.allowall=true', + '-Dmaven.wagon.http.ssl.ignore.validity.dates=true', + ] + + if not additional_arguments: + additional_arguments = [] + + # run maven + try: + with open(mvn_output_file_path, 'w') as mvn_output_file: + out_callback = create_sh_redirect_to_multiple_streams_fn_callback([ + sys.stdout, + mvn_output_file + ]) + err_callback = create_sh_redirect_to_multiple_streams_fn_callback([ + sys.stderr, + mvn_output_file + ]) + + sh.mvn( # pylint: disable=no-member + *phases_and_goals, + '-f', pom_file, + '-s', settings_file, + *profiles_arguments, + no_transfer_progress_argument, + *tls_arguments, + *additional_arguments, + _out=out_callback, + _err=err_callback + ) + except sh.ErrorReturnCode as error: + raise StepRunnerException( + f"Error running maven. {error}" + ) from error diff --git a/tests/config/test_config_value.py b/tests/config/test_config_value.py index 93cc6551..ee819b3e 100644 --- a/tests/config/test_config_value.py +++ b/tests/config/test_config_value.py @@ -1,8 +1,6 @@ from io import StringIO import os.path -import unittest -from testfixtures import TempDirectory from unittest.mock import patch from tests.helpers.base_test_case import BaseTestCase diff --git a/tests/helpers/maven_step_implementer_test_case.py b/tests/helpers/maven_step_implementer_test_case.py deleted file mode 100644 index 97b8e3a5..00000000 --- a/tests/helpers/maven_step_implementer_test_case.py +++ /dev/null @@ -1,58 +0,0 @@ -import os -from pathlib import Path - -import sh -from tests.helpers.base_step_implementer_test_case import \ - BaseStepImplementerTestCase - - -class MaveStepImplementerTestCase(BaseStepImplementerTestCase): - @staticmethod - def create_mvn_side_effect( - pom_file, - artifact_parent_dir, - artifact_names, - raise_error_on_tests=False - ): - """simulates what mvn does by touching files. - - Notes - ----- - Supports - - mvn clean - - mvn install - - mvn test - """ - target_dir_path = os.path.join( - os.path.dirname(os.path.abspath(pom_file)), - artifact_parent_dir) - - def mvn_side_effect(*args, **kwargs): - if 'clean' in args: - if os.path.exists(target_dir_path): - os.rmdir(target_dir_path) - - if 'install' in args: - os.mkdir(target_dir_path) - - for artifact_name in artifact_names: - artifact_path = os.path.join( - target_dir_path, - artifact_name - ) - Path(artifact_path).touch() - - if 'test' in args: - if raise_error_on_tests: - raise sh.ErrorReturnCode('mvn', b'mock out', b'mock error') - - os.makedirs(target_dir_path, exist_ok=True) - - for artifact_name in artifact_names: - artifact_path = os.path.join( - target_dir_path, - artifact_name - ) - Path(artifact_path).touch() - - return mvn_side_effect diff --git a/tests/step_implementers/package/test_maven_package.py b/tests/step_implementers/package/test_maven_package.py index 73ebea2a..02058a9d 100644 --- a/tests/step_implementers/package/test_maven_package.py +++ b/tests/step_implementers/package/test_maven_package.py @@ -1,432 +1,287 @@ -# pylint: disable=missing-module-docstring -# pylint: disable=missing-class-docstring -# pylint: disable=missing-function-docstring import os -import re from pathlib import Path from unittest.mock import patch -import sh -from ploigos_step_runner import StepResult +from ploigos_step_runner import StepResult, StepRunnerException, WorkflowResult from ploigos_step_runner.step_implementers.package import Maven from testfixtures import TempDirectory from tests.helpers.base_step_implementer_test_case import \ BaseStepImplementerTestCase -class TestStepImplementerMavenPackageBase(BaseStepImplementerTestCase): +@patch("ploigos_step_runner.step_implementers.shared.MavenGeneric.__init__") +class TestStepImplementerMavenPackage___init__(BaseStepImplementerTestCase): + def test_defaults(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} + + Maven( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config + ) + + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=None, + maven_phases_and_goals=['package'] + ) + + def test_given_environment(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} + + Maven( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment='mock-env' + ) + + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment='mock-env', + maven_phases_and_goals=['package'] + ) + +class TestStepImplementerMavenPackage_step_implementer_config_defaults( + BaseStepImplementerTestCase +): + def test_result(self): + self.assertEqual( + Maven.step_implementer_config_defaults(), + { + 'pom-file': 'pom.xml', + 'tls-verify': True, + 'maven-profiles': [], + 'maven-additional-arguments': [], + 'maven-no-transfer-progress': True, + 'maven-additional-arguments': [ + '-Dmaven.test.skip=true' + ], + 'artifact-extensions': ["jar", "war", "ear"], + 'artifact-parent-dir': 'target' + } + ) + +class TestStepImplementerMavenPackage__required_config_or_result_keys( + BaseStepImplementerTestCase +): + def test_result(self): + self.assertEqual( + Maven._required_config_or_result_keys(), + [ + 'pom-file' + ] + ) + +@patch.object(Maven, '_run_maven_step') +@patch.object(Maven, 'write_working_file', return_value='/mock/mvn_output.txt') +class TestStepImplementerMavenPackage__run_step( + BaseStepImplementerTestCase +): def create_step_implementer( self, step_config={}, - step_name='', - implementer='', workflow_result=None, parent_work_dir_path='' ): return self.create_given_step_implementer( step_implementer=Maven, step_config=step_config, - step_name=step_name, - implementer=implementer, + step_name='package', + implementer='Maven', workflow_result=workflow_result, parent_work_dir_path=parent_work_dir_path ) - # TESTS FOR configuration checks - def test_step_implementer_config_defaults(self): - defaults = Maven.step_implementer_config_defaults() - expected_defaults = { - 'tls-verify': True, - 'pom-file': 'pom.xml', - 'artifact-extensions': ["jar", "war", "ear"], - 'artifact-parent-dir': 'target' - } - self.assertEqual(defaults, expected_defaults) - - def test__required_config_or_result_keys(self): - required_keys = Maven._required_config_or_result_keys() - expected_required_keys = [ - 'pom-file' - ] - self.assertEqual(required_keys, expected_required_keys) - - def create_mvn_side_effect(pom_file, artifact_parent_dir, artifact_names): - """simulates what mvn does by touching files. - Notes - ----- - Supports - - mvn clean - - mvn install - """ - target_dir_path = os.path.join( - os.path.dirname(os.path.abspath(pom_file)), - artifact_parent_dir) - - def mvn_side_effect(*args, **kwargs): - if 'clean' in args: - if os.path.exists(target_dir_path): - os.rmdir(target_dir_path) - - if 'install' in args: - os.mkdir(target_dir_path) - - for artifact_name in artifact_names: - artifact_path = os.path.join( - target_dir_path, - artifact_name - ) - Path(artifact_path).touch() - - return mvn_side_effect - - @patch('sh.mvn', create=True) - def test_run_step_pass(self, mvn_mock): - with TempDirectory() as temp_dir: - artifact_id = 'my-app' - version = '1.0' - package = 'war' - parent_work_dir_path = os.path.join(temp_dir.path, 'working') - temp_dir.write('pom.xml', b''' - 4.0.0 - com.mycompany.app - my-app - 1.0 - war - ''') - pom_file_path = os.path.join(temp_dir.path, 'pom.xml') - - step_config = {'pom-file': pom_file_path} - - artifact_file_name = f'{artifact_id}-{version}.{package}' + def test_success_single_packaged_artifact( + self, + mock_write_working_file, + mock_run_maven_step + ): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + step_config = { + 'pom-file': pom_file + } step_implementer = self.create_step_implementer( step_config=step_config, - step_name='package', - implementer='Maven', parent_work_dir_path=parent_work_dir_path, ) - mvn_mock.side_effect = TestStepImplementerMavenPackageBase.create_mvn_side_effect( - pom_file_path, - 'target', - [artifact_file_name]) + # setup sideeffects + artifact_parent_dir = os.path.join(test_dir.path, 'target') + package_artifact_names = [ + f'my-app.jar' + ] + def run_maven_side_effect(mvn_output_file_path): + os.makedirs(artifact_parent_dir, exist_ok=True) + for artifact_name in package_artifact_names: + artifact_path = os.path.join( + artifact_parent_dir, + artifact_name + ) + Path(artifact_path).touch() - result = step_implementer._run_step() + mock_run_maven_step.side_effect = run_maven_side_effect - package_artifacts = { - 'path': temp_dir.path + '/target/my-app-1.0.war', - 'artifact-id': 'my-app', - 'group-id': 'com.mycompany.app', - 'package-type': 'war', - 'pom-path': pom_file_path - } + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result expected_step_result = StepResult( step_name='package', sub_step_name='Maven', sub_step_implementer_name='Maven' ) - expected_step_result.add_artifact(name='package-artifacts', value=[package_artifacts]) - mvn_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' - ) expected_step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", + description="Standard out and standard error from maven.", name='maven-output', - value=mvn_output_file_path - ) - - self.assertEqual(expected_step_result, result) - - @patch('sh.mvn', create=True) - def test_run_step_pass_no_package_in_pom(self, mvn_mock): - with TempDirectory() as temp_dir: - artifact_id = 'my-app' - version = '1.0' - package = 'jar' - parent_work_dir_path = os.path.join(temp_dir.path, 'working') - temp_dir.write('pom.xml',b''' - 4.0.0 - com.mycompany.app - my-app - 1.0 - ''') - pom_file_path = os.path.join(temp_dir.path, 'pom.xml') - - step_config = {'pom-file': pom_file_path} - - artifact_file_name = f'{artifact_id}-{version}.{package}' - - step_implementer = self.create_step_implementer( - step_config=step_config, - step_name='package', - implementer='Maven', - parent_work_dir_path=parent_work_dir_path, - ) - - mvn_mock.side_effect = TestStepImplementerMavenPackageBase.create_mvn_side_effect( - pom_file_path, - 'target', - [artifact_file_name]) - - result = step_implementer._run_step() - - package_artifacts = { - 'path': temp_dir.path + '/target/my-app-1.0.jar', - 'artifact-id': 'my-app', - 'group-id': 'com.mycompany.app', - 'package-type': 'jar', - 'pom-path': pom_file_path - } - expected_step_result = StepResult(step_name='package', sub_step_name='Maven', sub_step_implementer_name='Maven') - expected_step_result.add_artifact(name='package-artifacts', value=[package_artifacts]) - mvn_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' + value='/mock/mvn_output.txt' ) expected_step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", - name='maven-output', - value=mvn_output_file_path + name='packages', + value=[{ + 'path': os.path.join(artifact_parent_dir, 'my-app.jar') + }] ) - self.assertEqual(result, expected_step_result) - - - @patch('sh.mvn', create=True) - def test_run_step_fail_no_pom(self, mvn_mock): - with TempDirectory() as temp_dir: - parent_work_dir_path = os.path.join(temp_dir.path, 'working') - - step_config = {} - - step_implementer = self.create_step_implementer( - step_config=step_config, - step_name='package', - implementer='Maven', - parent_work_dir_path=parent_work_dir_path, + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - result = step_implementer._run_step() - - expected_step_result = StepResult(step_name='package', sub_step_name='Maven', sub_step_implementer_name='Maven') - expected_step_result.success = False - expected_step_result.message = 'Given pom file does not exist: pom.xml' - - self.assertEqual(result, expected_step_result) - - @patch('sh.mvn', create=True) - def test_run_step_fail_mvn_error(self, mvn_mock): - with TempDirectory() as temp_dir: - parent_work_dir_path = os.path.join(temp_dir.path, 'working') - temp_dir.write('pom.xml',b''' - 4.0.0 - com.mycompany.app - my-app - 1.0 - ''') - pom_file_path = os.path.join(temp_dir.path, 'pom.xml') + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' + ) - step_config = {'pom-file': pom_file_path} + def test_success_multiple_packaged_artifact( + self, + mock_write_working_file, + mock_run_maven_step + ): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + step_config = { + 'pom-file': pom_file + } step_implementer = self.create_step_implementer( step_config=step_config, - step_name='package', - implementer='Maven', parent_work_dir_path=parent_work_dir_path, ) - mvn_mock.side_effect = sh.ErrorReturnCode('mvn', b'mock out', b'mock error') + # setup sideeffects + artifact_parent_dir = os.path.join(test_dir.path, 'target') + package_artifact_names = [ + f'my-app.jar', + f'my-app.war' + ] + def run_maven_side_effect(mvn_output_file_path): + os.makedirs(artifact_parent_dir, exist_ok=True) + for artifact_name in package_artifact_names: + artifact_path = os.path.join( + artifact_parent_dir, + artifact_name + ) + Path(artifact_path).touch() + mock_run_maven_step.side_effect = run_maven_side_effect - result = step_implementer._run_step() + # run step + actual_step_result = step_implementer._run_step() + # create expected step result expected_step_result = StepResult( step_name='package', sub_step_name='Maven', sub_step_implementer_name='Maven' ) - mvn_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' - ) expected_step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", + description="Standard out and standard error from maven.", name='maven-output', - value=mvn_output_file_path - ) - expected_step_result.success = False - - self.assertEqual(result.success, expected_step_result.success) - self.assertRegex(result.message, re.compile( - r"Package failures. See 'maven-output' report artifacts for details:" - r".*RAN: mvn" - r".*STDOUT:" - r".*mock out" - r".*STDERR:" - r".*mock error", - re.DOTALL - )) - self.assertEqual(result.artifacts, expected_step_result.artifacts) - - @patch('sh.mvn', create=True) - def test_run_step_fail_multiple_artifacts(self, mvn_mock): - with TempDirectory() as temp_dir: - artifact_id = 'my-app' - version = '1.0' - package = 'jar' - parent_work_dir_path = os.path.join(temp_dir.path, 'working') - temp_dir.write('pom.xml',b''' - 4.0.0 - com.mycompany.app - my-app - 1.0 - ''') - pom_file_path = os.path.join(temp_dir.path, 'pom.xml') - - step_config = {'pom-file': pom_file_path} - - artifact_file_name = f'{artifact_id}-{version}.{package}' - - step_implementer = self.create_step_implementer( - step_config=step_config, - step_name='package', - implementer='Maven', - parent_work_dir_path=parent_work_dir_path, - ) - - mvn_mock.side_effect = TestStepImplementerMavenPackageBase.create_mvn_side_effect( - pom_file_path, - 'target', - [ - f'{artifact_id}-{version}.war', - artifact_file_name - ] - ) - - result = step_implementer._run_step() - - expected_step_result = StepResult(step_name='package', sub_step_name='Maven', sub_step_implementer_name='Maven') - expected_step_result.success = False - expected_step_result.message = "pom resulted in multiple artifacts with expected artifact extensions (['jar', 'war', 'ear']), this is unsupported" - mvn_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' + value='/mock/mvn_output.txt' ) expected_step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", - name='maven-output', - value=mvn_output_file_path + name='packages', + value=[ + { + 'path': os.path.join(artifact_parent_dir, 'my-app.jar') + }, + { + 'path': os.path.join(artifact_parent_dir, 'my-app.war') + } + ] ) - self.assertEqual(result, expected_step_result) - - @patch('sh.mvn', create=True) - def test_run_step_fail_no_artifacts(self, mvn_mock): - with TempDirectory() as temp_dir: - artifact_id = '' - version = '' - package = '' - parent_work_dir_path = os.path.join(temp_dir.path, 'working') - temp_dir.write('pom.xml',b''' - 4.0.0 - com.mycompany.app - my-app - 1.0 - ''') - pom_file_path = os.path.join(temp_dir.path, 'pom.xml') - - step_config = {'pom-file': pom_file_path} - - artifact_file_name = f'{artifact_id}-{version}.{package}' - step_implementer = self.create_step_implementer( - step_config=step_config, - step_name='package', - implementer='Maven', - parent_work_dir_path=parent_work_dir_path, + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - mvn_mock.side_effect = TestStepImplementerMavenPackageBase.create_mvn_side_effect( - pom_file_path, - 'target', - [artifact_file_name] + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' ) - result = step_implementer._run_step() - - expected_step_result = StepResult(step_name='package', sub_step_name='Maven', sub_step_implementer_name='Maven') - expected_step_result.success = False - expected_step_result.message = "pom resulted in 0 with expected artifact extensions (['jar', 'war', 'ear']), this is unsupported" - mvn_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' - ) - expected_step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", - name='maven-output', - value=mvn_output_file_path - ) - - self.assertEqual(result, expected_step_result) - - @patch('sh.mvn', create=True) - def test_run_step_tls_verify_false(self, mvn_mock): - with TempDirectory() as temp_dir: - artifact_id = 'my-app' - version = '1.0' - package = 'war' - parent_work_dir_path = os.path.join(temp_dir.path, 'working') - temp_dir.write('pom.xml', b''' - 4.0.0 - com.mycompany.app - my-app - 1.0 - war - ''') - pom_file_path = os.path.join(temp_dir.path, 'pom.xml') + def test_fail_maven_run( + self, + mock_write_working_file, + mock_run_maven_step + ): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') step_config = { - 'pom-file': pom_file_path, - 'tls-verify': False + 'pom-file': pom_file } - - artifact_file_name = f'{artifact_id}-{version}.{package}' - step_implementer = self.create_step_implementer( step_config=step_config, - step_name='package', - implementer='Maven', parent_work_dir_path=parent_work_dir_path, ) - mvn_mock.side_effect = TestStepImplementerMavenPackageBase.create_mvn_side_effect( - pom_file_path, - 'target', - [artifact_file_name]) + # run step with mock failure + mock_run_maven_step.side_effect = StepRunnerException('Mock error running maven') + actual_step_result = step_implementer._run_step() - result = step_implementer._run_step() - - package_artifacts = { - 'path': temp_dir.path + '/target/my-app-1.0.war', - 'artifact-id': 'my-app', - 'group-id': 'com.mycompany.app', - 'package-type': 'war', - 'pom-path': pom_file_path - } + # create expected step result + surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') expected_step_result = StepResult( step_name='package', sub_step_name='Maven', sub_step_implementer_name='Maven' ) - expected_step_result.add_artifact(name='package-artifacts', value=[package_artifacts]) - mvn_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' - ) + expected_step_result.success = False + expected_step_result.message = "Error running 'maven package' to package artifacts. " \ + "More details maybe found in 'maven-output' report artifact: " \ + "Mock error running maven" expected_step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", + description="Standard out and standard error from maven.", name='maven-output', - value=mvn_output_file_path + value='/mock/mvn_output.txt' ) - self.assertEqual(expected_step_result, result) + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' + ) diff --git a/tests/step_implementers/push_artifacts/test_maven_push_artifacts.py b/tests/step_implementers/push_artifacts/test_maven_push_artifacts.py index 3768d03e..54fe1896 100644 --- a/tests/step_implementers/push_artifacts/test_maven_push_artifacts.py +++ b/tests/step_implementers/push_artifacts/test_maven_push_artifacts.py @@ -1,235 +1,329 @@ -# pylint: disable=missing-module-docstring -# pylint: disable=missing-class-docstring -# pylint: disable=missing-function-docstring + import os -import re -from unittest.mock import patch +from unittest.mock import PropertyMock, patch -import sh +from ploigos_step_runner import StepResult, WorkflowResult, StepRunnerException +from ploigos_step_runner.step_implementers.push_artifacts import Maven from testfixtures import TempDirectory from tests.helpers.base_step_implementer_test_case import \ BaseStepImplementerTestCase -from ploigos_step_runner import StepResult -from ploigos_step_runner.step_implementers.push_artifacts import Maven -class TestStepImplementerMavenPushArtifacts(BaseStepImplementerTestCase): +@patch("ploigos_step_runner.step_implementers.shared.MavenGeneric.__init__") +class TestStepImplementerMavenDeploy___init__(BaseStepImplementerTestCase): + def test_defaults(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} + + Maven( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config + ) + + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=None, + maven_phases_and_goals=['deploy'] + ) + + def test_given_environment(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} + + Maven( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment='mock-env' + ) + + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment='mock-env', + maven_phases_and_goals=['deploy'] + ) + +class TestStepImplementerMavenDeploy_step_implementer_config_defaults( + BaseStepImplementerTestCase +): + def test_result(self): + self.assertEqual( + Maven.step_implementer_config_defaults(), + { + 'pom-file': 'pom.xml', + 'tls-verify': True, + 'maven-profiles': [], + 'maven-additional-arguments': [], + 'maven-no-transfer-progress': True, + 'maven-additional-arguments': [ + '-Dmaven.install.skip=true', + '-Dmaven.test.skip=true' + ] + } + ) + +class TestStepImplementerMavenDeploy__required_config_or_result_keys( + BaseStepImplementerTestCase +): + def test_result(self): + self.assertEqual( + Maven._required_config_or_result_keys(), + [ + 'pom-file', + 'maven-push-artifact-repo-url', + 'maven-push-artifact-repo-id', + 'version' + ] + ) + +@patch('ploigos_step_runner.step_implementers.push_artifacts.maven.run_maven') +@patch.object(Maven, '_run_maven_step') +@patch.object( + Maven, + 'write_working_file', + side_effect=['/mock/mvn_versions_set_output.txt', '/mock/mvn_deploy_output.txt'] +) +@patch.object( + Maven, + 'maven_settings_file', + new_callable=PropertyMock, + return_value='/fake/settings.xml' +) +class TestStepImplementerMavenDeploy__run_step( + BaseStepImplementerTestCase +): def create_step_implementer( self, step_config={}, - step_name='', - implementer='', workflow_result=None, parent_work_dir_path='' ): return self.create_given_step_implementer( step_implementer=Maven, step_config=step_config, - step_name=step_name, - implementer=implementer, + step_name='deploy', + implementer='Maven', workflow_result=workflow_result, parent_work_dir_path=parent_work_dir_path ) - def test_step_implementer_config_defaults(self): - actual_defaults = Maven.step_implementer_config_defaults() - expected_defaults = { - 'tls-verify': True - } - self.assertEqual(expected_defaults, actual_defaults) - - def test__required_config_or_result_keys(self): - actual_required_keys = Maven._required_config_or_result_keys() - expected_required_keys = [ - 'maven-push-artifact-repo-url', - 'maven-push-artifact-repo-id', - 'version', - 'package-artifacts' - ] - self.assertEqual(expected_required_keys, actual_required_keys) - - @patch('sh.mvn', create=True) - def test_run_step_pass(self, mvn_mock): - with TempDirectory() as temp_dir: - parent_work_dir_path = os.path.join(temp_dir.path, 'working') + def test_success( + self, + mock_settings_file, + mock_write_working_file, + mock_run_maven_step, + mock_run_maven + ): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + maven_push_artifact_repo_id = 'mock-repo-id' + maven_push_artifact_repo_url = 'https://mock-repo.ploigos.com' + version = '0.42.0-mock' step_config = { - 'maven-push-artifact-repo-url': 'pass', - 'maven-push-artifact-repo-id': 'pass' - } - - # Previous (fake) results - package_artifacts = [{ - 'path': 'test-path', - 'group-id': 'test-group-id', - 'artifact-id': 'test-artifact-id', - 'package-type': 'test-package-type' - }] - artifact_config = { - 'package-artifacts': {'value': package_artifacts}, - 'version': {'value': 'test-version'} + 'pom-file': pom_file, + 'maven-push-artifact-repo-id': maven_push_artifact_repo_id, + 'maven-push-artifact-repo-url': maven_push_artifact_repo_url, + 'version': version } - workflow_result = self.setup_previous_result(parent_work_dir_path, artifact_config) - - # Actual results step_implementer = self.create_step_implementer( step_config=step_config, - step_name='push-artifacts', - implementer='Maven', - workflow_result=workflow_result, - parent_work_dir_path=parent_work_dir_path - ) - result = step_implementer._run_step() - - # Expected results - push_artifacts = [{ - 'artifact-id': 'test-artifact-id', - 'group-id': 'test-group-id', - 'version': 'test-version', - 'path': 'test-path', - 'packaging': 'test-package-type', - }] + parent_work_dir_path=parent_work_dir_path, + ) + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result expected_step_result = StepResult( - step_name='push-artifacts', + step_name='deploy', sub_step_name='Maven', sub_step_implementer_name='Maven' ) - expected_step_result.add_artifact(name='push-artifacts', value=push_artifacts) - mvn_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' + expected_step_result.add_artifact( + description="Standard out and standard error from running maven to update version.", + name='maven-update-version-output', + value='/mock/mvn_versions_set_output.txt' ) expected_step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", - name='maven-output', - value=mvn_output_file_path + description="Standard out and standard error from running maven to " \ + "push artifacts to repository.", + name='maven-push-artifacts-output', + value='/mock/mvn_deploy_output.txt' ) - self.assertEqual(expected_step_result, result) - @patch('sh.mvn', create=True) - def test_run_step_fail(self, mvn_mock): - with TempDirectory() as temp_dir: - parent_work_dir_path = os.path.join(temp_dir.path, 'working') + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) - # config - step_config = { - 'maven-push-artifact-repo-url': 'pass', - 'maven-push-artifact-repo-id': 'pass' - } + mock_write_working_file.assert_called() + mock_run_maven.assert_called_with( + mvn_output_file_path='/mock/mvn_versions_set_output.txt', + settings_file='/fake/settings.xml', + pom_file=pom_file, + phases_and_goals=['versions:set'], + additional_arguments=[ + f'-DnewVersion={version}' + ] + ) + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_deploy_output.txt', + step_implementer_additional_arguments=[ + '-DaltDeploymentRepository=' \ + f'{maven_push_artifact_repo_id}::default::{maven_push_artifact_repo_url}' + ] + ) - # Previous (fake) results - package_artifacts = [{ - 'path': 'test-path', - 'group-id': 'test-group-id', - 'artifact-id': 'test-artifact-id', - 'package-type': 'test-package-type' - }] - artifact_config = { - 'package-artifacts': {'value': package_artifacts}, - 'version': {'value': 'test-version'} - } - workflow_result = self.setup_previous_result(parent_work_dir_path, artifact_config) + def test_fail_set_version( + self, + mock_settings_file, + mock_write_working_file, + mock_run_maven_step, + mock_run_maven + ): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') - # Actual results + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + maven_push_artifact_repo_id = 'mock-repo-id' + maven_push_artifact_repo_url = 'https://mock-repo.ploigos.com' + version = '0.42.0-mock' + step_config = { + 'pom-file': pom_file, + 'maven-push-artifact-repo-id': maven_push_artifact_repo_id, + 'maven-push-artifact-repo-url': maven_push_artifact_repo_url, + 'version': version + } step_implementer = self.create_step_implementer( step_config=step_config, - step_name='push-artifacts', - implementer='Maven', - workflow_result=workflow_result, - parent_work_dir_path=parent_work_dir_path + parent_work_dir_path=parent_work_dir_path, ) - sh.mvn.side_effect = sh.ErrorReturnCode('mvn', b'mock out', b'mock error') - result = step_implementer._run_step() + # run step with mvn version:set failure + mock_run_maven.side_effect = StepRunnerException('mock error setting new pom version') + actual_step_result = step_implementer._run_step() + # create expected step result expected_step_result = StepResult( - step_name='push-artifacts', + step_name='deploy', sub_step_name='Maven', sub_step_implementer_name='Maven' ) + expected_step_result.success = False + expected_step_result.message = "Error running 'maven deploy' to push artifacts. " \ + "More details maybe found in 'maven-output' report artifact: " \ + "mock error setting new pom version" expected_step_result.add_artifact( - name='push-artifacts', - value=[] - ) - mvn_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' + description="Standard out and standard error from running maven to update version.", + name='maven-update-version-output', + value='/mock/mvn_versions_set_output.txt' ) expected_step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", - name='maven-output', - value=mvn_output_file_path + description="Standard out and standard error from running maven to " \ + "push artifacts to repository.", + name='maven-push-artifacts-output', + value='/mock/mvn_deploy_output.txt' ) - expected_step_result.success = False - self.assertEqual(result.success, expected_step_result.success) - self.assertRegex(result.message, re.compile( - r"Push artifacts failures. See 'maven-output' report artifacts for details:" - r".*RAN: mvn" - r".*STDOUT:" - r".*mock out" - r".*STDERR:" - r".*mock error", - re.DOTALL - )) - self.assertEqual(result.artifacts, expected_step_result.artifacts) - - @patch('sh.mvn', create=True) - def test_run_step_tls_verify_false(self, mvn_mock): - with TempDirectory() as temp_dir: - parent_work_dir_path = os.path.join(temp_dir.path, 'working') + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) - step_config = { - 'maven-push-artifact-repo-url': 'pass', - 'maven-push-artifact-repo-id': 'pass', - 'tls-verify': False - } + mock_write_working_file.assert_called() + mock_run_maven.assert_called_with( + mvn_output_file_path='/mock/mvn_versions_set_output.txt', + settings_file='/fake/settings.xml', + pom_file=pom_file, + phases_and_goals=['versions:set'], + additional_arguments=[ + f'-DnewVersion={version}' + ] + ) + mock_run_maven_step.assert_not_called() - # Previous (fake) results - package_artifacts = [{ - 'path': 'test-path', - 'group-id': 'test-group-id', - 'artifact-id': 'test-artifact-id', - 'package-type': 'test-package-type' - }] - artifact_config = { - 'package-artifacts': {'value': package_artifacts}, - 'version': {'value': 'test-version'} - } - workflow_result = self.setup_previous_result(parent_work_dir_path, artifact_config) + def test_fail_mvn_depoy( + self, + mock_settings_file, + mock_write_working_file, + mock_run_maven_step, + mock_run_maven + ): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') - # Actual results + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + maven_push_artifact_repo_id = 'mock-repo-id' + maven_push_artifact_repo_url = 'https://mock-repo.ploigos.com' + version = '0.42.0-mock' + step_config = { + 'pom-file': pom_file, + 'maven-push-artifact-repo-id': maven_push_artifact_repo_id, + 'maven-push-artifact-repo-url': maven_push_artifact_repo_url, + 'version': version + } step_implementer = self.create_step_implementer( step_config=step_config, - step_name='push-artifacts', - implementer='Maven', - workflow_result=workflow_result, - parent_work_dir_path=parent_work_dir_path - ) - result = step_implementer._run_step() - - # Expected results - push_artifacts = [{ - 'artifact-id': 'test-artifact-id', - 'group-id': 'test-group-id', - 'version': 'test-version', - 'path': 'test-path', - 'packaging': 'test-package-type', - }] + parent_work_dir_path=parent_work_dir_path, + ) + + # run step with mvn deploy failure + mock_run_maven_step.side_effect = StepRunnerException('mock error running mvn deploy') + actual_step_result = step_implementer._run_step() + + # create expected step result expected_step_result = StepResult( - step_name='push-artifacts', + step_name='deploy', sub_step_name='Maven', sub_step_implementer_name='Maven' ) - expected_step_result.add_artifact(name='push-artifacts', value=push_artifacts) - mvn_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' + expected_step_result.success = False + expected_step_result.message = "Error running 'maven deploy' to push artifacts. " \ + "More details maybe found in 'maven-output' report artifact: " \ + "mock error running mvn deploy" + expected_step_result.add_artifact( + description="Standard out and standard error from running maven to update version.", + name='maven-update-version-output', + value='/mock/mvn_versions_set_output.txt' ) expected_step_result.add_artifact( - description="Standard out and standard error from 'mvn install'.", - name='maven-output', - value=mvn_output_file_path + description="Standard out and standard error from running maven to " \ + "push artifacts to repository.", + name='maven-push-artifacts-output', + value='/mock/mvn_deploy_output.txt' ) - self.assertEqual(expected_step_result, result) + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_write_working_file.assert_called() + mock_run_maven.assert_called_with( + mvn_output_file_path='/mock/mvn_versions_set_output.txt', + settings_file='/fake/settings.xml', + pom_file=pom_file, + phases_and_goals=['versions:set'], + additional_arguments=[ + f'-DnewVersion={version}' + ] + ) + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_deploy_output.txt', + step_implementer_additional_arguments=[ + '-DaltDeploymentRepository=' \ + f'{maven_push_artifact_repo_id}::default::{maven_push_artifact_repo_url}' + ] + ) diff --git a/tests/step_implementers/shared/test_maven_generic.py b/tests/step_implementers/shared/test_maven_generic.py index 7970ad49..59e5ea3d 100644 --- a/tests/step_implementers/shared/test_maven_generic.py +++ b/tests/step_implementers/shared/test_maven_generic.py @@ -1,30 +1,114 @@ import os from pathlib import Path from shutil import copyfile -from unittest.mock import patch +from unittest.mock import PropertyMock, patch +from ploigos_step_runner import StepResult, StepRunnerException, WorkflowResult +from ploigos_step_runner.config.config import Config +from ploigos_step_runner.step_implementers.shared.maven_generic import \ + MavenGeneric +from ploigos_step_runner.utils.file import create_parent_dir from testfixtures import TempDirectory from tests.helpers.base_step_implementer_test_case import \ BaseStepImplementerTestCase -from ploigos_step_runner.step_implementers.shared.maven_generic import MavenGeneric -from ploigos_step_runner import StepResult -from ploigos_step_runner.utils.file import create_parent_dir -class SampleMavenStepImplementer(MavenGeneric): - @staticmethod - def step_implementer_config_defaults(): - return {} +@patch("ploigos_step_runner.StepImplementer.__init__") +class TestStepImplementerSharedMavenGeneric___init__(BaseStepImplementerTestCase): + + def test_no_environment_no_maven_phases_and_goals(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} + + step_implementer = MavenGeneric( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config + ) + + self.assertIsNone(step_implementer._MavenGeneric__maven_settings_file) + self.assertIsNone(step_implementer._MavenGeneric__maven_phases_and_goals) + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=None + ) + + def test_with_environment_no_maven_phases_and_goals(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} + + step_implementer = MavenGeneric( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment='test-env' + ) - @staticmethod - def _required_config_or_result_keys(): - return [] + self.assertIsNone(step_implementer._MavenGeneric__maven_settings_file) + self.assertIsNone(step_implementer._MavenGeneric__maven_phases_and_goals) + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment='test-env' + ) + + def test_no_environment_with_maven_phases_and_goals(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} - def _run_step(self): - step_result = StepResult.from_step_implementer(self) - return step_result + step_implementer = MavenGeneric( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + maven_phases_and_goals=['fake-phase'] + ) -class TestStepImplementerSharedMavenGeneric(BaseStepImplementerTestCase): + self.assertIsNone(step_implementer._MavenGeneric__maven_settings_file) + self.assertEqual( + step_implementer._MavenGeneric__maven_phases_and_goals, + ['fake-phase'] + ) + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=None + ) + +class TestStepImplementerSharedMavenGeneric_step_implementer_config_defaults( + BaseStepImplementerTestCase +): + def test_result(self): + self.assertEqual( + MavenGeneric.step_implementer_config_defaults(), + { + 'pom-file': 'pom.xml', + 'tls-verify': True, + 'maven-profiles': [], + 'maven-additional-arguments': [], + 'maven-no-transfer-progress': True + } + ) + +class TestStepImplementerSharedMavenGeneric__required_config_or_result_keys( + BaseStepImplementerTestCase +): + def test_result(self): + self.assertEqual( + MavenGeneric._required_config_or_result_keys(), + [ + 'pom-file', + 'maven-phases-and-goals' + ] + ) + +class BaseTestStepImplementerSharedMavenGeneric(BaseStepImplementerTestCase): def create_step_implementer( self, step_config={}, @@ -32,80 +116,141 @@ def create_step_implementer( parent_work_dir_path='' ): return self.create_given_step_implementer( - step_implementer=SampleMavenStepImplementer, + step_implementer=MavenGeneric, step_config=step_config, step_name='foo', - implementer='SampleMavenStepImplementer', + implementer='MavenGeneric', workflow_result=workflow_result, parent_work_dir_path=parent_work_dir_path ) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.generate_maven_settings') - def test__generate_maven_settings(self, utils_generate_maven_settings_mock): +@patch("ploigos_step_runner.StepImplementer._validate_required_config_or_previous_step_result_artifact_keys") +class TestStepImplementerSharedMavenGeneric__validate_required_config_or_previous_step_result_artifact_keys( + BaseTestStepImplementerSharedMavenGeneric +): + def test_valid(self, mock_super_validate): with TempDirectory() as test_dir: parent_work_dir_path = os.path.join(test_dir.path, 'working') - maven_servers = { - "internal-mirror": { - "id": "internal-server", - "username": "ploigos" - } - } - maven_repositories = { - 'internal-mirror-1': { - 'id': 'internal-server', - 'url': 'https://foo.example.xyz', - 'snapshots': 'true', - 'releases': 'false' - } - } - maven_mirrors = { - "internal-mirror": { - "id": "internal-mirror", - "url": "https://artifacts.example.xyz/artifactory/release/", - "mirror-of": "*" - } + + pom_file_path = os.path.join(test_dir.path, 'pom.xml') + step_config = { + 'pom-file': pom_file_path, + 'maven-phases-and-goals': 'fake-phase' } + + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + Path(pom_file_path).touch() + step_implementer._validate_required_config_or_previous_step_result_artifact_keys() + + mock_super_validate.assert_called_once_with() + + def test_pom_file_does_not_exist(self, mock_super_validate): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file_path = '/does/not/exist/pom.xml' step_config = { - 'maven-servers' : maven_servers, - 'maven-repositories' : maven_repositories, - 'maven-mirrors': maven_mirrors + 'pom-file': pom_file_path, + 'maven-phases-and-goals': 'fake-phase' } + step_implementer = self.create_step_implementer( step_config=step_config, parent_work_dir_path=parent_work_dir_path, ) - expected_settings_xml_path = '/does/not/matter/settings.xml' - def utils_generate_maven_settings_mock_side_effect( - working_dir, - maven_servers, - maven_repositories, - maven_mirrors + with self.assertRaisesRegex( + AssertionError, + rf'Given maven pom file \(pom-file\) does not exist: {pom_file_path}' ): - return expected_settings_xml_path - utils_generate_maven_settings_mock.side_effect = \ - utils_generate_maven_settings_mock_side_effect + step_implementer._validate_required_config_or_previous_step_result_artifact_keys() + mock_super_validate.assert_called_once_with() - actual_settings_xml_path = step_implementer._generate_maven_settings() - self.assertEqual(expected_settings_xml_path, actual_settings_xml_path) +class TestStepImplementerSharedMavenGeneric_maven_phases_and_goals( + BaseTestStepImplementerSharedMavenGeneric +): + def test_use_object_property_no_config_value(self): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = None - utils_generate_maven_settings_mock.assert_called_once_with( - working_dir=step_implementer.work_dir_path, - maven_servers=maven_servers, - maven_repositories=maven_repositories, - maven_mirrors=maven_mirrors - ) + step_implementer = MavenGeneric( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + maven_phases_and_goals=['fake-phase'] + ) - def test__validate_required_config_or_previous_step_result_artifact_keys_valid(self): + self.assertEqual( + step_implementer.maven_phases_and_goals, + ['fake-phase'] + ) + + def test_use_object_property_with_config_value(self): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + step_config = { + 'maven-phases-and-goals': ['config-value-fake-phase'] + } + config = Config({ + Config.CONFIG_KEY: { + 'foo': [ + { + 'implementer': 'MavenGeneric', + 'config': step_config + } + ] + + } + }) + + step_implementer = MavenGeneric( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + maven_phases_and_goals=['object-property-fake-phase'] + ) + + self.assertEqual( + step_implementer.maven_phases_and_goals, + ['object-property-fake-phase'] + ) + + def test_use_config_value(self): + parent_work_dir_path = '/fake/path' + step_config = { + 'maven-phases-and-goals': ['config-value-fake-phase'] + } + + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + self.assertEqual( + step_implementer.maven_phases_and_goals, + ['config-value-fake-phase'] + ) + +@patch( + "ploigos_step_runner.step_implementers.shared.maven_generic.generate_maven_settings", + return_value='/mock/settings.xml' +) +class TestStepImplementerSharedMavenGeneric_maven_settings_file( + BaseTestStepImplementerSharedMavenGeneric +): + def test_no_config(self, mock_gen_mvn_settings): with TempDirectory() as test_dir: - results_dir_path = os.path.join(test_dir.path, 'step-runner-results') - results_file_name = 'step-runner-results.yml' parent_work_dir_path = os.path.join(test_dir.path, 'working') pom_file_path = os.path.join(test_dir.path, 'pom.xml') step_config = { - 'fail-on-no-tests': True, - 'pom-file': pom_file_path + 'pom-file': pom_file_path, + 'maven-phases-and-goals': 'fake-phase' } step_implementer = self.create_step_implementer( @@ -113,19 +258,62 @@ def test__validate_required_config_or_previous_step_result_artifact_keys_valid(s parent_work_dir_path=parent_work_dir_path, ) - Path(pom_file_path).touch() - step_implementer._validate_required_config_or_previous_step_result_artifact_keys() + # call first time + maven_settings_file = step_implementer.maven_settings_file + self.assertEqual( + maven_settings_file, + '/mock/settings.xml' + ) + mock_gen_mvn_settings.assert_called_once_with( + working_dir=step_implementer.work_dir_path, + maven_servers=None, + maven_repositories=None, + maven_mirrors=None + ) - def test__validate_required_config_or_previous_step_result_artifact_keys_pom_file_does_not_exist(self): + # call second time + mock_gen_mvn_settings.reset_mock() + maven_settings_file = step_implementer.maven_settings_file + self.assertEqual( + maven_settings_file, + '/mock/settings.xml' + ) + mock_gen_mvn_settings.assert_not_called() + + def test_given_config_maven_servers_maven_repos_and_maven_mirrors(self, mock_gen_mvn_settings): with TempDirectory() as test_dir: - results_dir_path = os.path.join(test_dir.path, 'step-runner-results') - results_file_name = 'step-runner-results.yml' parent_work_dir_path = os.path.join(test_dir.path, 'working') pom_file_path = os.path.join(test_dir.path, 'pom.xml') + maven_servers = { + 'internal-mirror-1': { + 'id': 'internal-server', + 'password': 'you-wish', + 'username': 'team-a' + } + } + maven_repositories = { + 'internal-mirror-1': { + 'id': 'internal-mirror-1', + 'url': 'https://nexus.apps.ploigos.com/repository/maven-public/', + 'snapshots': 'true', + 'releases': 'true' + } + } + maven_mirrors = { + 'internal-mirror-1': { + 'id': 'internal-mirror', + 'mirror-of': '*', + 'url': 'https://nexus.apps.ploigos.com/repository/maven-public/' + } + } + step_config = { - 'fail-on-no-tests': True, - 'pom-file': pom_file_path + 'pom-file': pom_file_path, + 'maven-phases-and-goals': 'fake-phase', + 'maven-servers': maven_servers, + 'maven-repositories': maven_repositories, + 'maven-mirrors': maven_mirrors } step_implementer = self.create_step_implementer( @@ -133,14 +321,33 @@ def test__validate_required_config_or_previous_step_result_artifact_keys_pom_fil parent_work_dir_path=parent_work_dir_path, ) - with self.assertRaisesRegex( - AssertionError, - rf'Given maven pom file \(pom-file\) does not exist: {pom_file_path}' - ): - step_implementer._validate_required_config_or_previous_step_result_artifact_keys() + # call first time + maven_settings_file = step_implementer.maven_settings_file + self.assertEqual( + maven_settings_file, + '/mock/settings.xml' + ) + mock_gen_mvn_settings.assert_called_once_with( + working_dir=step_implementer.work_dir_path, + maven_servers=maven_servers, + maven_repositories=maven_repositories, + maven_mirrors=maven_mirrors + ) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__get_effective_pom_call_once(self, write_effective_pom_mock): + # call second time + mock_gen_mvn_settings.reset_mock() + maven_settings_file = step_implementer.maven_settings_file + self.assertEqual( + maven_settings_file, + '/mock/settings.xml' + ) + mock_gen_mvn_settings.assert_not_called() + +@patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +class TestStepImplementerSharedMavenGeneric__get_effective_pom( + BaseTestStepImplementerSharedMavenGeneric +): + def test_call_once(self, write_effective_pom_mock): with TempDirectory() as test_dir: parent_work_dir_path = os.path.join(test_dir.path, 'working') @@ -162,7 +369,10 @@ def write_effective_pom_mock_side_effect(pom_file_path, output_path): write_effective_pom_mock.side_effect = write_effective_pom_mock_side_effect # first call - expected_effective_pom_path = os.path.join(step_implementer.work_dir_path, 'effective-pom.xml') + expected_effective_pom_path = os.path.join( + step_implementer.work_dir_path, + 'effective-pom.xml' + ) actual_effective_pom_path = step_implementer._get_effective_pom() self.assertEqual(actual_effective_pom_path, expected_effective_pom_path) write_effective_pom_mock.assert_called_once_with( @@ -170,7 +380,6 @@ def write_effective_pom_mock_side_effect(pom_file_path, output_path): output_path=expected_effective_pom_path ) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') def test__get_effective_pom_call_twice(self, write_effective_pom_mock): with TempDirectory() as test_dir: parent_work_dir_path = os.path.join(test_dir.path, 'working') @@ -193,7 +402,10 @@ def write_effective_pom_mock_side_effect(pom_file_path, output_path): write_effective_pom_mock.side_effect = write_effective_pom_mock_side_effect # first call - expected_effective_pom_path = os.path.join(step_implementer.work_dir_path, 'effective-pom.xml') + expected_effective_pom_path = os.path.join( + step_implementer.work_dir_path, + 'effective-pom.xml' + ) actual_effective_pom_path = step_implementer._get_effective_pom() self.assertEqual(actual_effective_pom_path, expected_effective_pom_path) write_effective_pom_mock.assert_called_once_with( @@ -203,17 +415,21 @@ def write_effective_pom_mock_side_effect(pom_file_path, output_path): # second call write_effective_pom_mock.reset_mock() - expected_effective_pom_path = os.path.join(step_implementer.work_dir_path, 'effective-pom.xml') + expected_effective_pom_path = os.path.join( + step_implementer.work_dir_path, + 'effective-pom.xml' + ) actual_effective_pom_path = step_implementer._get_effective_pom() self.assertEqual(actual_effective_pom_path, expected_effective_pom_path) write_effective_pom_mock.assert_not_called() - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.get_xml_element_by_path') - @patch.object(MavenGeneric, '_get_effective_pom') - def test__get_effective_pom_element(self, get_effective_pom_mock, get_xml_element_by_path_mock): +@patch('ploigos_step_runner.step_implementers.shared.maven_generic.get_xml_element_by_path') +@patch.object(MavenGeneric, '_get_effective_pom') +class TestStepImplementerSharedMavenGeneric__get_effective_pom_element( + BaseTestStepImplementerSharedMavenGeneric +): + def test_result(self, get_effective_pom_mock, get_xml_element_by_path_mock): with TempDirectory() as test_dir: - results_dir_path = os.path.join(test_dir.path, 'step-runner-results') - results_file_name = 'step-runner-results.yml' parent_work_dir_path = os.path.join(test_dir.path, 'working') pom_file_path = os.path.join(test_dir.path, 'pom.xml') @@ -237,3 +453,334 @@ def get_effective_pom_side_effect(): 'foo', default_namespace='mvn' ) + +@patch('ploigos_step_runner.step_implementers.shared.maven_generic.run_maven') +@patch.object( + MavenGeneric, + 'maven_phases_and_goals', + new_callable=PropertyMock, + return_value=['fake-phase'] +) +@patch.object( + MavenGeneric, + 'maven_settings_file', + new_callable=PropertyMock, + return_value='/fake/settings.xml' +) +class TestStepImplementerSharedMavenGeneric__run_maven_step( + BaseTestStepImplementerSharedMavenGeneric +): + def test_defaults(self, mock_settings_file, mock_phases_and_goals, mock_run_maven): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file_path = os.path.join(test_dir.path, 'pom.xml') + step_config = { + 'pom-file': pom_file_path + } + + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + mvn_output_file_path = os.path.join(test_dir.path, 'maven-output.txt') + step_implementer._run_maven_step( + mvn_output_file_path=mvn_output_file_path + ) + + mock_run_maven.assert_called_with( + mvn_output_file_path=mvn_output_file_path, + phases_and_goals=['fake-phase'], + additional_arguments=[], + pom_file=pom_file_path, + tls_verify=True, + profiles=[], + no_transfer_progress=True, + settings_file='/fake/settings.xml' + ) + + + def test_custom_profile(self, mock_settings_file, mock_phases_and_goals, mock_run_maven): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file_path = os.path.join(test_dir.path, 'pom.xml') + step_config = { + 'pom-file': pom_file_path, + 'maven-profiles': ['fake-profile-1', 'fakse-profile-2'] + } + + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + mvn_output_file_path = os.path.join(test_dir.path, 'maven-output.txt') + step_implementer._run_maven_step( + mvn_output_file_path=mvn_output_file_path + ) + + mock_run_maven.assert_called_with( + mvn_output_file_path=mvn_output_file_path, + phases_and_goals=['fake-phase'], + additional_arguments=[], + pom_file=pom_file_path, + tls_verify=True, + profiles=['fake-profile-1', 'fakse-profile-2'], + no_transfer_progress=True, + settings_file='/fake/settings.xml' + ) + + def test_no_tls_verify(self, mock_settings_file, mock_phases_and_goals, mock_run_maven): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file_path = os.path.join(test_dir.path, 'pom.xml') + step_config = { + 'pom-file': pom_file_path, + 'tls-verify': False + } + + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + mvn_output_file_path = os.path.join(test_dir.path, 'maven-output.txt') + step_implementer._run_maven_step( + mvn_output_file_path=mvn_output_file_path + ) + + mock_run_maven.assert_called_with( + mvn_output_file_path=mvn_output_file_path, + phases_and_goals=['fake-phase'], + additional_arguments=[], + pom_file=pom_file_path, + tls_verify=False, + profiles=[], + no_transfer_progress=True, + settings_file='/fake/settings.xml' + ) + + def test_yes_transfer_progress(self, mock_settings_file, mock_phases_and_goals, mock_run_maven): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file_path = os.path.join(test_dir.path, 'pom.xml') + step_config = { + 'pom-file': pom_file_path, + 'maven-no-transfer-progress': False + } + + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + mvn_output_file_path = os.path.join(test_dir.path, 'maven-output.txt') + step_implementer._run_maven_step( + mvn_output_file_path=mvn_output_file_path + ) + + mock_run_maven.assert_called_with( + mvn_output_file_path=mvn_output_file_path, + phases_and_goals=['fake-phase'], + additional_arguments=[], + pom_file=pom_file_path, + tls_verify=True, + profiles=[], + no_transfer_progress=False, + settings_file='/fake/settings.xml' + ) + + def test_config_additional_arguments( + self, + mock_settings_file, + mock_phases_and_goals, + mock_run_maven + ): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file_path = os.path.join(test_dir.path, 'pom.xml') + step_config = { + 'pom-file': pom_file_path, + 'maven-additional-arguments': ['-Dfake.config.arg=True'] + } + + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + mvn_output_file_path = os.path.join(test_dir.path, 'maven-output.txt') + step_implementer._run_maven_step( + mvn_output_file_path=mvn_output_file_path + ) + + mock_run_maven.assert_called_with( + mvn_output_file_path=mvn_output_file_path, + phases_and_goals=['fake-phase'], + additional_arguments=['-Dfake.config.arg=True'], + pom_file=pom_file_path, + tls_verify=True, + profiles=[], + no_transfer_progress=True, + settings_file='/fake/settings.xml' + ) + + def test_step_implementer_additional_arguments( + self, + mock_settings_file, + mock_phases_and_goals, + mock_run_maven + ): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file_path = os.path.join(test_dir.path, 'pom.xml') + step_config = { + 'pom-file': pom_file_path + } + + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + mvn_output_file_path = os.path.join(test_dir.path, 'maven-output.txt') + step_implementer._run_maven_step( + mvn_output_file_path=mvn_output_file_path, + step_implementer_additional_arguments=['-Dfake.step_implementer.arg=True'] + ) + + mock_run_maven.assert_called_with( + mvn_output_file_path=mvn_output_file_path, + phases_and_goals=['fake-phase'], + additional_arguments=['-Dfake.step_implementer.arg=True'], + pom_file=pom_file_path, + tls_verify=True, + profiles=[], + no_transfer_progress=True, + settings_file='/fake/settings.xml' + ) + + def test_step_implementer_additional_arguments_and_config_additional_arguments( + self, + mock_settings_file, + mock_phases_and_goals, + mock_run_maven + ): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file_path = os.path.join(test_dir.path, 'pom.xml') + step_config = { + 'pom-file': pom_file_path, + 'maven-additional-arguments': ['-Dfake.config.arg=True'] + } + + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + mvn_output_file_path = os.path.join(test_dir.path, 'maven-output.txt') + step_implementer._run_maven_step( + mvn_output_file_path=mvn_output_file_path, + step_implementer_additional_arguments=['-Dfake.step_implementer.arg=True'] + ) + + mock_run_maven.assert_called_with( + mvn_output_file_path=mvn_output_file_path, + phases_and_goals=['fake-phase'], + additional_arguments=['-Dfake.step_implementer.arg=True', '-Dfake.config.arg=True'], + pom_file=pom_file_path, + tls_verify=True, + profiles=[], + no_transfer_progress=True, + settings_file='/fake/settings.xml' + ) + +@patch.object(MavenGeneric, '_run_maven_step') +@patch.object(MavenGeneric, 'write_working_file', return_value='/mock/mvn_output.txt') +class TestStepImplementerSharedMavenGeneric__run_step( + BaseTestStepImplementerSharedMavenGeneric +): + def test_success(self, mock_write_working_file, mock_run_maven_step): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + step_config = {} + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + expected_step_result = StepResult( + step_name='foo', + sub_step_name='MavenGeneric', + sub_step_implementer_name='MavenGeneric' + ) + expected_step_result.add_artifact( + description="Standard out and standard error from maven.", + name='maven-output', + value='/mock/mvn_output.txt' + ) + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' + ) + + def test_fail(self, mock_write_working_file, mock_run_maven_step): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + step_config = {} + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # run step with mock failure + mock_run_maven_step.side_effect = StepRunnerException('Mock error running maven') + actual_step_result = step_implementer._run_step() + + # create expected step result + expected_step_result = StepResult( + step_name='foo', + sub_step_name='MavenGeneric', + sub_step_implementer_name='MavenGeneric' + ) + expected_step_result.add_artifact( + description="Standard out and standard error from maven.", + name='maven-output', + value='/mock/mvn_output.txt' + ) + expected_step_result.message = "Error running maven. " \ + "More details maybe found in 'maven-output' report artifact: "\ + "Mock error running maven" + expected_step_result.success = False + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' + ) diff --git a/tests/step_implementers/uat/test_maven_selenium_cucumber.py b/tests/step_implementers/uat/test_maven_selenium_cucumber.py index 997128be..241b8c73 100644 --- a/tests/step_implementers/uat/test_maven_selenium_cucumber.py +++ b/tests/step_implementers/uat/test_maven_selenium_cucumber.py @@ -1,24 +1,20 @@ import os -from io import IOBase from pathlib import Path -from shutil import copyfile -from unittest.mock import patch +from unittest.mock import Mock, patch -import sh -from testfixtures import TempDirectory -from tests.helpers.maven_step_implementer_test_case import \ - MaveStepImplementerTestCase -from tests.helpers.test_utils import Any +from ploigos_step_runner import StepResult, StepRunnerException, WorkflowResult from ploigos_step_runner.exceptions import StepRunnerException from ploigos_step_runner.step_implementers.uat import MavenSeleniumCucumber -from ploigos_step_runner import StepResult -from ploigos_step_runner.utils.file import create_parent_dir +from testfixtures import TempDirectory +from tests.helpers.base_step_implementer_test_case import \ + BaseStepImplementerTestCase -class TestStepImplementerMavenSeleniumCucumberBase(MaveStepImplementerTestCase): +class BaseTestStepImplementerSharedMavenSeleniumCucumber(BaseStepImplementerTestCase): def create_step_implementer( self, step_config={}, + workflow_result=None, parent_work_dir_path='' ): return self.create_given_step_implementer( @@ -26,40 +22,91 @@ def create_step_implementer( step_config=step_config, step_name='uat', implementer='MavenSeleniumCucumber', + workflow_result=workflow_result, parent_work_dir_path=parent_work_dir_path ) -class TestStepImplementerDeployMavenSeleniumCucumber_validate_required_config_or_previous_step_result_artifact_keys( - TestStepImplementerMavenSeleniumCucumberBase -): - def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_artifact_keys_success_target_host_url(self): - with TempDirectory() as temp_dir: - parent_work_dir_path = os.path.join(temp_dir.path, 'working') +@patch("ploigos_step_runner.step_implementers.shared.MavenGeneric.__init__") +class TestStepImplementerMavenTestMavenSeleniumCucumber___init__(BaseStepImplementerTestCase): + def test_defaults(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} - pom_file_path = os.path.join(temp_dir.path, 'pom.xml') - Path(pom_file_path).touch() - step_config = { - 'selenium-hub-url': 'https://selenium.ploigos.xyz', - 'pom-file': pom_file_path, - 'target-host-url': 'https://foo.test.ploigos.xyz' + MavenSeleniumCucumber( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config + ) + + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=None, + maven_phases_and_goals=['test'] + ) + + def test_given_environment(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} + + MavenSeleniumCucumber( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment='mock-env' + ) + + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment='mock-env', + maven_phases_and_goals=['test'] + ) + +class TestStepImplementerMavenTestMavenSeleniumCucumber_step_implementer_config_defaults( + BaseStepImplementerTestCase +): + def test_result(self): + self.assertEqual( + MavenSeleniumCucumber.step_implementer_config_defaults(), + { + 'pom-file': 'pom.xml', + 'tls-verify': True, + 'maven-profiles': [], + 'maven-additional-arguments': [], + 'maven-no-transfer-progress': True, + 'maven-profiles': ['integration-test'], + 'fail-on-no-tests': True } - step_implementer = self.create_step_implementer( - step_config=step_config, - parent_work_dir_path=parent_work_dir_path, - ) + ) - step_implementer._validate_required_config_or_previous_step_result_artifact_keys() +class TestStepImplementerMavenTestMavenSeleniumCucumber__required_config_or_result_keys( + BaseStepImplementerTestCase +): + def test_result(self): + self.assertEqual( + MavenSeleniumCucumber._required_config_or_result_keys(), + [ + 'pom-file', + 'fail-on-no-tests', + 'selenium-hub-url', + ] + ) - def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_artifact_keys_success_deployed_host_urls_1(self): - with TempDirectory() as temp_dir: - parent_work_dir_path = os.path.join(temp_dir.path, 'working') +@patch("ploigos_step_runner.step_implementers.shared.MavenGeneric._validate_required_config_or_previous_step_result_artifact_keys") +class TestStepImplementerSharedMavenGeneric__validate_required_config_or_previous_step_result_artifact_keys( + BaseTestStepImplementerSharedMavenSeleniumCucumber +): + def test_valid_target_host_url(self, mock_super_validate): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') - pom_file_path = os.path.join(temp_dir.path, 'pom.xml') - Path(pom_file_path).touch() step_config = { - 'selenium-hub-url': 'https://selenium.ploigos.xyz', - 'pom-file': pom_file_path, - 'deployed-host-urls': ['https://foo.test.ploigos.xyz'] + 'target-host-url': 'https://mock-target-host-url.ploigos.com' } step_implementer = self.create_step_implementer( step_config=step_config, @@ -67,17 +114,14 @@ def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_ ) step_implementer._validate_required_config_or_previous_step_result_artifact_keys() + mock_super_validate.assert_called_once_with() - def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_artifact_keys_success_deployed_host_urls_2(self): - with TempDirectory() as temp_dir: - parent_work_dir_path = os.path.join(temp_dir.path, 'working') + def test_valid_deployed_host_urls(self, mock_super_validate): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') - pom_file_path = os.path.join(temp_dir.path, 'pom.xml') - Path(pom_file_path).touch() step_config = { - 'selenium-hub-url': 'https://selenium.ploigos.xyz', - 'pom-file': pom_file_path, - 'deployed-host-urls': ['https://foo.test.ploigos.xyz', 'https://bar.test.ploigos.xyz'] + 'deployed-host-urls': ['https://mock-deployed-host-url1.ploigos.com'] } step_implementer = self.create_step_implementer( step_config=step_config, @@ -85,17 +129,13 @@ def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_ ) step_implementer._validate_required_config_or_previous_step_result_artifact_keys() + mock_super_validate.assert_called_once_with() - def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_artifact_keys_fail_no_target_urls(self): - with TempDirectory() as temp_dir: - parent_work_dir_path = os.path.join(temp_dir.path, 'working') + def test_fail_no_target_host_url_or_deployed_host_urls(self, mock_super_validate): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') - pom_file_path = os.path.join(temp_dir.path, 'pom.xml') - Path(pom_file_path).touch() - step_config = { - 'selenium-hub-url': 'https://selenium.ploigos.xyz', - 'pom-file': pom_file_path - } + step_config = {} step_implementer = self.create_step_implementer( step_config=step_config, parent_work_dir_path=parent_work_dir_path, @@ -103,1074 +143,1902 @@ def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_ with self.assertRaisesRegex( StepRunnerException, - rf"Either 'target-host-url' or 'deployed-host-urls' needs to be supplied but" - " neither were." + "Either 'target-host-url' or 'deployed-host-urls' needs " \ + "to be supplied but neither were." ): step_implementer._validate_required_config_or_previous_step_result_artifact_keys() -class TestStepImplementerMavenSeleniumCucumber_Other(TestStepImplementerMavenSeleniumCucumberBase): - def test_step_implementer_config_defaults(self): - actual_defaults = MavenSeleniumCucumber.step_implementer_config_defaults() - expected_defaults = { - 'fail-on-no-tests': True, - 'pom-file': 'pom.xml', - 'tls-verify': True, - 'uat-maven-profile': 'integration-test' - } - self.assertEqual(expected_defaults, actual_defaults) - - def test__required_config_or_result_keys(self): - actual_required_keys = MavenSeleniumCucumber._required_config_or_result_keys() - expected_required_keys = [ - 'fail-on-no-tests', - 'pom-file', - 'selenium-hub-url', - 'uat-maven-profile' - ] - self.assertEqual(expected_required_keys, actual_required_keys) + mock_super_validate.assert_called_once_with() - def __run__run_step_test( - self, - test_dir, - mvn_mock, - write_effective_pom_mock, - generate_maven_settings_mock, - pom_content, - group_id, - artifact_id, - surefire_reports_dir, - selenium_hub_url, - target_host_url=None, - deployed_host_urls=None, - write_mock_test_results=True, - assert_mvn_called=True, - assert_report_artifact=True, - assert_evidence=True, - expected_result_success=True, - expected_result_message='', - fail_on_no_tests=None, - uat_maven_profile=None, - pom_file_name='pom.xml', - raise_error_on_tests=False, - set_tls_verify_false=False, - aggregate_xml_element_attribute_values_mock=False, - aggregate_xml_element_attribute_values_mock_fail=False - ): - parent_work_dir_path = os.path.join(test_dir.path, 'working') +@patch.object(MavenSeleniumCucumber, '_run_maven_step') +@patch.object(MavenSeleniumCucumber, 'write_working_file', return_value='/mock/mvn_output.txt') +@patch( + 'ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values', + return_value={ + 'time': '42', + 'tests': '42', + 'errors': '0', + 'skipped': '0', + 'failures': '0' + }) +class TestStepImplementerMavenTestMavenSeleniumCucumber__run_step( + BaseTestStepImplementerSharedMavenSeleniumCucumber +): + def __expected_step_result_base(self): + expected_step_result = StepResult( + step_name='uat', + sub_step_name='MavenSeleniumCucumber', + sub_step_implementer_name='MavenSeleniumCucumber' + ) + + return expected_step_result + def __expected_step_result_with_artifacts(self, parent_work_dir_path, surefire_reports_dir): cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + expected_step_result = self.__expected_step_result_base() + expected_step_result.add_artifact( + description="Standard out and standard error from maven.", + name='maven-output', + value='/mock/mvn_output.txt' + ) + expected_step_result.add_artifact( + description="Surefire reports generated by maven.", + name='surefire-reports', + value=surefire_reports_dir + ) + expected_step_result.add_artifact( + description="Cucumber (HTML) report generated by maven.", + name='cucumber-report-html', + value=cucumber_html_report_path + ) + expected_step_result.add_artifact( + description="Cucumber (JSON) report generated by maven.", + name='cucumber-report-json', + value=cucumber_json_report_path + ) - test_dir.write(pom_file_name, pom_content) - - pom_file_path = os.path.join(test_dir.path, pom_file_name) - step_config = { - 'pom-file': pom_file_path, - 'selenium-hub-url': selenium_hub_url, - 'tls-verify': True - } - - if set_tls_verify_false: - step_config['tls-verify'] = False - - target_base_url = None - if deployed_host_urls: - step_config['deployed-host-urls'] = deployed_host_urls - if isinstance(deployed_host_urls, list): - target_base_url = deployed_host_urls[0] - else: - target_base_url = deployed_host_urls - if target_host_url: - step_config['target-host-url'] = target_host_url - target_base_url = target_host_url - - if fail_on_no_tests is not None: - step_config['fail-on-no-tests'] = fail_on_no_tests - if uat_maven_profile is not None: - step_config['uat-maven-profile'] = uat_maven_profile - else: - uat_maven_profile = 'integration-test' - step_implementer = self.create_step_implementer( - step_config=step_config, + return expected_step_result + + def __expected_step_result_with_artifacts_and_evidence( + self, + parent_work_dir_path, + surefire_reports_dir + ): + expected_step_result = self.__expected_step_result_with_artifacts( parent_work_dir_path=parent_work_dir_path, + surefire_reports_dir=surefire_reports_dir + ) + expected_step_result.add_evidence( + name='uat-evidence-time', + description='Surefire report value for time', + value='42' + ) + expected_step_result.add_evidence( + name='uat-evidence-tests', + description='Surefire report value for tests', + value='42' + ) + expected_step_result.add_evidence( + name='uat-evidence-errors', + description='Surefire report value for errors', + value='0' + ) + expected_step_result.add_evidence( + name='uat-evidence-skipped', + description='Surefire report value for skipped', + value='0' + ) + expected_step_result.add_evidence( + name='uat-evidence-failures', + description='Surefire report value for failures', + value='0' ) - # mock generating settings - settings_file_path = "/does/not/matter/settings.xml" - def generate_maven_settings_side_effect(): - return settings_file_path - generate_maven_settings_mock.side_effect = generate_maven_settings_side_effect - - # mock effective pom - def write_effective_pom_mock_side_effect(pom_file_path, output_path): - create_parent_dir(pom_file_path) - copyfile(pom_file_path, output_path) - write_effective_pom_mock.side_effect = write_effective_pom_mock_side_effect - - # mock test results - if write_mock_test_results: - mvn_mock.side_effect = MaveStepImplementerTestCase.create_mvn_side_effect( - pom_file=pom_file_path, - artifact_parent_dir=surefire_reports_dir, - artifact_names=[ - f'{group_id}.{artifact_id}.CucumberTest.txt', - f'TEST-{group_id}.{artifact_id}.CucumberTest.xml' - ], - raise_error_on_tests=raise_error_on_tests - ) + return expected_step_result - # mock evidence - if aggregate_xml_element_attribute_values_mock and not aggregate_xml_element_attribute_values_mock_fail: - aggregate_xml_element_attribute_values_mock.return_value = { - 'time': '42', - 'tests': '42', - 'errors': '0', - 'skipped': '0', - 'failures': '0' - } - elif aggregate_xml_element_attribute_values_mock_fail: - aggregate_xml_element_attribute_values_mock.return_value = { - 'time': '42' - } - - result = step_implementer._run_step() - if assert_mvn_called: - if not set_tls_verify_false: - mvn_mock.assert_called_once_with( - 'clean', - 'test', - f'-P{uat_maven_profile}', - f'-Dselenium.hub.url={selenium_hub_url}', - f'-Dtarget.base.url={target_base_url}', - f'-Dcucumber.plugin=' \ - f'html:{cucumber_html_report_path},' \ - f'json:{cucumber_json_report_path}', - '-f', pom_file_path, - '-s', settings_file_path, - _out=Any(IOBase), - _err=Any(IOBase) - ) - else: - mvn_mock.assert_called_once_with( - 'clean', - 'test', - f'-P{uat_maven_profile}', - f'-Dselenium.hub.url={selenium_hub_url}', - f'-Dtarget.base.url={target_base_url}', - f'-Dcucumber.plugin=' \ - f'html:{cucumber_html_report_path},' \ - f'json:{cucumber_json_report_path}', - '-f', pom_file_path, - '-s', settings_file_path, - '-Dmaven.wagon.http.ssl.insecure=true', - '-Dmaven.wagon.http.ssl.allowall=true', - '-Dmaven.wagon.http.ssl.ignore.validity.dates=true', - _out=Any(IOBase), - _err=Any(IOBase) + + def __create_run_maven_side_effect(self, surefire_reports_dir): + group_id = 'com.ploigos.app' + artifact_id = 'my-app' + surefire_artifact_names = [ + f'{group_id}.{artifact_id}.ClassNameTest.txt', + f'TEST-{group_id}.{artifact_id}.ClassNameTest.xml' + ] + def run_maven_side_effect(**kargs): + os.makedirs(surefire_reports_dir, exist_ok=True) + + for artifact_name in surefire_artifact_names: + artifact_path = os.path.join( + surefire_reports_dir, + artifact_name ) + Path(artifact_path).touch() - expected_step_result = StepResult( - step_name='uat', - sub_step_name='MavenSeleniumCucumber', - sub_step_implementer_name='MavenSeleniumCucumber' - ) - expected_step_result.success = expected_result_success - expected_step_result.message = expected_result_message + return run_maven_side_effect - if assert_report_artifact: - mvn_test_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' - ) - expected_step_result.add_artifact( - description=f"Standard out and standard error by 'mvn -P{uat_maven_profile} test'.", - name='maven-output', - value=mvn_test_output_file_path - ) - expected_step_result.add_artifact( - description=f"Surefire reports generated by 'mvn -P{uat_maven_profile} test'.", - name='surefire-reports', - value=surefire_reports_dir - ) - expected_step_result.add_artifact( - description=f"Cucumber (HTML) report generated by 'mvn -P{uat_maven_profile} test'.", - name='cucumber-report-html', - value=cucumber_html_report_path - ) - expected_step_result.add_artifact( - description=f"Cucumber (JSON) report generated by 'mvn -P{uat_maven_profile} test'.", - name='cucumber-report-json', - value=cucumber_json_report_path - ) - - if assert_evidence and not aggregate_xml_element_attribute_values_mock_fail: - expected_step_result.add_evidence( - name='uat-evidence-time', - description='Surefire report value for time', - value='42' - ) - expected_step_result.add_evidence( - name='uat-evidence-tests', - description='Surefire report value for tests', - value='42' - ) - expected_step_result.add_evidence( - name='uat-evidence-errors', - description='Surefire report value for errors', - value='0' + @patch.object( + MavenSeleniumCucumber, + '_get_effective_pom_element', + side_effect=['mock surefire element', None] + ) + def test_success_target_host_url_default_reports_dir( + self, + mock_effective_pom_element, + mock_aggregate_xml_element_attribute_values, + mock_write_working_file, + mock_run_maven_step + ): + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + selenium_hub_url = 'https://mock-selenium-hub.ploigos.com' + target_base_url = 'https://mock-app.ploigos.com' + step_config = { + 'pom-file': pom_file, + 'selenium-hub-url': selenium_hub_url, + 'target-host-url': target_base_url + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, ) - expected_step_result.add_evidence( - name='uat-evidence-skipped', - description='Surefire report value for skipped', - value='0' + + # setup sideeffects + surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') + mock_run_maven_step.side_effect = self.__create_run_maven_side_effect( + surefire_reports_dir=surefire_reports_dir ) - expected_step_result.add_evidence( - name='uat-evidence-failures', - description='Surefire report value for failures', - value='0' + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') + cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + expected_step_result = self.__expected_step_result_with_artifacts_and_evidence( + parent_work_dir_path=parent_work_dir_path, + surefire_reports_dir=surefire_reports_dir ) - elif assert_evidence and aggregate_xml_element_attribute_values_mock_fail: - expected_step_result.add_evidence( - name='uat-evidence-time', - description='Surefire report value for time', - value='42' + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - print(result) - self.assertEqual(expected_step_result, result) + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt', + step_implementer_additional_arguments=[ + f'-Dselenium.hub.url={selenium_hub_url}', + f'-Dtarget.base.url={target_base_url}', + f'-Dcucumber.plugin=' \ + f'html:{cucumber_html_report_path},' \ + f'json:{cucumber_json_report_path}', + ] + ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success_defaults( + @patch.object( + MavenSeleniumCucumber, + '_get_effective_pom_element', + side_effect=['mock surefire element', None] + ) + def test_success_single_deployed_host_url_default_reports_dir( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock + mock_effective_pom_element, + mock_aggregate_xml_element_attribute_values, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + selenium_hub_url = 'https://mock-selenium-hub.ploigos.com' + target_base_url = 'https://mock-app.ploigos.com' + step_config = { + 'pom-file': pom_file, + 'selenium-hub-url': selenium_hub_url, + 'deployed-host-urls': target_base_url + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # setup sideeffects surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + mock_run_maven_step.side_effect = self.__create_run_maven_side_effect( + surefire_reports_dir=surefire_reports_dir ) - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') + cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + expected_step_result = self.__expected_step_result_with_artifacts_and_evidence( + parent_work_dir_path=parent_work_dir_path, surefire_reports_dir=surefire_reports_dir ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_tls_verify_false( - self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock - ): - with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - set_tls_verify_false=True + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt', + step_implementer_additional_arguments=[ + f'-Dselenium.hub.url={selenium_hub_url}', + f'-Dtarget.base.url={target_base_url}', + f'-Dcucumber.plugin=' \ + f'html:{cucumber_html_report_path},' \ + f'json:{cucumber_json_report_path}', + ] ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success__deployed_host_urls_str( + @patch.object( + MavenSeleniumCucumber, + '_get_effective_pom_element', + side_effect=['mock surefire element', None] + ) + def test_success_multiple_deployed_host_url_default_reports_dir( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock + mock_effective_pom_element, + mock_aggregate_xml_element_attribute_values, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + selenium_hub_url = 'https://mock-selenium-hub.ploigos.com' + target_base_url = 'https://mock-app.ploigos.com' + deployed_host_urls = [target_base_url, 'https://mock-app-ignored.ploigos.com'] + step_config = { + 'pom-file': pom_file, + 'selenium-hub-url': selenium_hub_url, + 'deployed-host-urls': deployed_host_urls + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # setup sideeffects surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + mock_run_maven_step.side_effect = self.__create_run_maven_side_effect( + surefire_reports_dir=surefire_reports_dir ) - deployed_host_urls = 'https://foo.ploigos.xyz' - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - deployed_host_urls=deployed_host_urls + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') + cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + expected_step_result = self.__expected_step_result_with_artifacts_and_evidence( + parent_work_dir_path=parent_work_dir_path, + surefire_reports_dir=surefire_reports_dir ) + expected_step_result.message = \ + f"Given more then one deployed host URL ({deployed_host_urls})," \ + f" targeting first one ({target_base_url}) for user acceptance test (UAT)." - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success__deployed_host_urls_array_1( - self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock - ): - with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - deployed_host_urls = ['https://foo.ploigos.xyz'] - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - deployed_host_urls=deployed_host_urls + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt', + step_implementer_additional_arguments=[ + f'-Dselenium.hub.url={selenium_hub_url}', + f'-Dtarget.base.url={target_base_url}', + f'-Dcucumber.plugin=' \ + f'html:{cucumber_html_report_path},' \ + f'json:{cucumber_json_report_path}', + ] ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success__deployed_host_urls_array_2( + @patch.object( + MavenSeleniumCucumber, + '_get_effective_pom_element', + side_effect=['mock surefire element', Mock(text='mock/fake/reports')] + ) + def test_success_target_host_url_pom_specified_relative_reports_dir( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock, + mock_effective_pom_element, + mock_aggregate_xml_element_attribute_values, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + selenium_hub_url = 'https://mock-selenium-hub.ploigos.com' + target_base_url = 'https://mock-app.ploigos.com' + step_config = { + 'pom-file': pom_file, + 'selenium-hub-url': selenium_hub_url, + 'target-host-url': target_base_url + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, ) - deployed_host_urls = ['https://foo.ploigos.xyz', 'https://foo.ploigos.xyz'] - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - deployed_host_urls=deployed_host_urls, - expected_result_message=\ - f"Given more then one deployed host URL ({deployed_host_urls})," \ - f" targeting first one (https://foo.ploigos.xyz) for user acceptance test (UAT)." + # setup sideeffects + surefire_reports_dir = os.path.join(test_dir.path, 'mock/fake/reports') + mock_run_maven_step.side_effect = self.__create_run_maven_side_effect( + surefire_reports_dir=surefire_reports_dir ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success_provided_profile_override( - self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock - ): - with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') + cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + expected_step_result = self.__expected_step_result_with_artifacts_and_evidence( + parent_work_dir_path=parent_work_dir_path, + surefire_reports_dir=surefire_reports_dir + ) + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - uat_maven_profile='custom-uat-profile' + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt', + step_implementer_additional_arguments=[ + f'-Dselenium.hub.url={selenium_hub_url}', + f'-Dtarget.base.url={target_base_url}', + f'-Dcucumber.plugin=' \ + f'html:{cucumber_html_report_path},' \ + f'json:{cucumber_json_report_path}', + ] ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success_provided_pom_file_override( + @patch.object(MavenSeleniumCucumber, '_get_effective_pom_element') + def test_success_target_host_url_pom_specified_absolute_reports_dir( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock + mock_effective_pom_element, + mock_aggregate_xml_element_attribute_values, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + selenium_hub_url = 'https://mock-selenium-hub.ploigos.com' + target_base_url = 'https://mock-app.ploigos.com' + step_config = { + 'pom-file': pom_file, + 'selenium-hub-url': selenium_hub_url, + 'target-host-url': target_base_url + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, ) - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - pom_file_name='custom-pom.xml' + # setup sideeffects + surefire_reports_dir = os.path.join(test_dir.path, 'mock-abs/fake/reports') + mock_effective_pom_element.side_effect = [ + 'mock surefire element', + Mock(text=surefire_reports_dir) + ] + mock_run_maven_step.side_effect = self.__create_run_maven_side_effect( + surefire_reports_dir=surefire_reports_dir ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success_provided_fail_on_no_tests_false_with_tests( - self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock - ): - with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') + cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + expected_step_result = self.__expected_step_result_with_artifacts_and_evidence( + parent_work_dir_path=parent_work_dir_path, + surefire_reports_dir=surefire_reports_dir + ) + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - fail_on_no_tests=False, - write_mock_test_results=True, - expected_result_success=True + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt', + step_implementer_additional_arguments=[ + f'-Dselenium.hub.url={selenium_hub_url}', + f'-Dtarget.base.url={target_base_url}', + f'-Dcucumber.plugin=' \ + f'html:{cucumber_html_report_path},' \ + f'json:{cucumber_json_report_path}', + ] ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success_provided_fail_on_no_tests_false_with_no_tests( + @patch.object(MavenSeleniumCucumber, '_get_effective_pom_element', side_effect=[None, None]) + @patch.object(MavenSeleniumCucumber, '_get_effective_pom', return_value='mock-effective-pom.xml') + def test_fail_no_surefire_plugin( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock + mock_effective_pom, + mock_effective_pom_element, + mock_aggregate_xml_element_attribute_values, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + selenium_hub_url = 'https://mock-selenium-hub.ploigos.com' + target_base_url = 'https://mock-app.ploigos.com' + step_config = { + 'pom-file': pom_file, + 'selenium-hub-url': selenium_hub_url, + 'target-host-url': target_base_url + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # setup sideeffects surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + mock_run_maven_step.side_effect = self.__create_run_maven_side_effect( + surefire_reports_dir=surefire_reports_dir ) - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - assert_evidence=False, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - fail_on_no_tests=False, - write_mock_test_results=False, - expected_result_success=True, - expected_result_message="No user acceptance tests defined" \ - " using maven profile (integration-test)," \ - " but 'fail-on-no-tests' is False." + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + expected_step_result = self.__expected_step_result_base() + expected_step_result.success = False + expected_step_result.message = 'Unit test dependency "maven-surefire-plugin" ' \ + 'missing from effective pom (mock-effective-pom.xml).' + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_fail_provided_fail_on_no_tests_true_with_no_tests( + mock_run_maven_step.assert_not_called() + + @patch.object( + MavenSeleniumCucumber, + '_get_effective_pom_element', + side_effect=['mock surefire element', None] + ) + def test_fail_no_tests( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock + mock_effective_pom_element, + mock_aggregate_xml_element_attribute_values, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + selenium_hub_url = 'https://mock-selenium-hub.ploigos.com' + target_base_url = 'https://mock-app.ploigos.com' + step_config = { + 'pom-file': pom_file, + 'selenium-hub-url': selenium_hub_url, + 'target-host-url': target_base_url + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') + cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + expected_step_result = self.__expected_step_result_with_artifacts( + parent_work_dir_path=parent_work_dir_path, + surefire_reports_dir=surefire_reports_dir ) + expected_step_result.success = False + expected_step_result.message = "No user acceptance tests defined" \ + f" using maven profile (['integration-test'])." - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - assert_evidence=False, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - fail_on_no_tests=True, - write_mock_test_results=False, - expected_result_success=False, - expected_result_message="No user acceptance tests defined" \ - " using maven profile (integration-test)." + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_fail_no_surefire_plugin( + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt', + step_implementer_additional_arguments=[ + f'-Dselenium.hub.url={selenium_hub_url}', + f'-Dtarget.base.url={target_base_url}', + f'-Dcucumber.plugin=' \ + f'html:{cucumber_html_report_path},' \ + f'json:{cucumber_json_report_path}', + ] + ) + + @patch.object( + MavenSeleniumCucumber, + '_get_effective_pom_element', + side_effect=['mock surefire element', None] + ) + def test_success_but_no_tests( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock + mock_effective_pom_element, + mock_aggregate_xml_element_attribute_values, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + selenium_hub_url = 'https://mock-selenium-hub.ploigos.com' + target_base_url = 'https://mock-app.ploigos.com' + step_config = { + 'pom-file': pom_file, + 'selenium-hub-url': selenium_hub_url, + 'target-host-url': target_base_url, + 'fail-on-no-tests': False + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') + cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + expected_step_result = self.__expected_step_result_with_artifacts( + parent_work_dir_path=parent_work_dir_path, + surefire_reports_dir=surefire_reports_dir ) + expected_step_result.message = "No user acceptance tests defined" \ + " using maven profile (['integration-test'])," \ + " but 'fail-on-no-tests' is False." - effective_pom_path = os.path.join( - test_dir.path, - 'working', - 'uat', - 'effective-pom.xml' + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - assert_evidence=False, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - expected_result_success=False, - expected_result_message='Unit test dependency "maven-surefire-plugin" ' \ - f'missing from effective pom ({effective_pom_path}).', - assert_mvn_called=False, - assert_report_artifact=False + + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt', + step_implementer_additional_arguments=[ + f'-Dselenium.hub.url={selenium_hub_url}', + f'-Dtarget.base.url={target_base_url}', + f'-Dcucumber.plugin=' \ + f'html:{cucumber_html_report_path},' \ + f'json:{cucumber_json_report_path}', + ] ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success_pom_specified_reports_dir( + @patch.object( + MavenSeleniumCucumber, + '_get_effective_pom_element', + side_effect=['mock surefire element', None] + ) + def test_could_not_find_expected_evidence( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock + mock_effective_pom_element, + mock_aggregate_xml_element_attribute_values, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + selenium_hub_url = 'https://mock-selenium-hub.ploigos.com' + target_base_url = 'https://mock-app.ploigos.com' + step_config = { + 'pom-file': pom_file, + 'selenium-hub-url': selenium_hub_url, + 'target-host-url': target_base_url + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # setup sideeffects surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - {surefire_reports_dir} - - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version, - surefire_reports_dir=surefire_reports_dir - ), 'utf-8' + mock_run_maven_step.side_effect = self.__create_run_maven_side_effect( + surefire_reports_dir=surefire_reports_dir ) + mock_aggregate_xml_element_attribute_values.return_value = {} + + # run step + actual_step_result = step_implementer._run_step() - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - assert_evidence=True, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, + # create expected step result + cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') + cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + expected_step_result = self.__expected_step_result_with_artifacts( + parent_work_dir_path=parent_work_dir_path, surefire_reports_dir=surefire_reports_dir ) + expected_step_result.success = False + attribs = ["time", "tests", "errors", "skipped", "failures"] + expected_step_result.message = "Error gathering evidence from "\ + f"surefire report, expected attribute(s) ({attribs}) "\ + f"not found in report ({surefire_reports_dir})" - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_fail_mvn_test_failure( - self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock - ): - with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result ) - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=None, - assert_evidence=False, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - raise_error_on_tests=True, - expected_result_success=False, - expected_result_message="User acceptance test failures. See 'maven-output'" \ - ", 'surefire-reports', 'cucumber-report-html', and 'cucumber-report-json'" \ - " report artifacts for details." + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt', + step_implementer_additional_arguments=[ + f'-Dselenium.hub.url={selenium_hub_url}', + f'-Dtarget.base.url={target_base_url}', + f'-Dcucumber.plugin=' \ + f'html:{cucumber_html_report_path},' \ + f'json:{cucumber_json_report_path}', + ] ) - @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') - @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_failure_missing_evidence_attribute( + @patch.object( + MavenSeleniumCucumber, + '_get_effective_pom_element', + side_effect=['mock surefire element', None] + ) + def test_fail_maven_error( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock + mock_effective_pom_element, + mock_aggregate_xml_element_attribute_values, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + selenium_hub_url = 'https://mock-selenium-hub.ploigos.com' + target_base_url = 'https://mock-app.ploigos.com' + step_config = { + 'pom-file': pom_file, + 'selenium-hub-url': selenium_hub_url, + 'target-host-url': target_base_url + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # setup sideeffects surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' + mock_run_maven_step.side_effect = StepRunnerException('mock maven error') + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') + cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + expected_step_result = self.__expected_step_result_with_artifacts( + parent_work_dir_path=parent_work_dir_path, + surefire_reports_dir=surefire_reports_dir + ) + expected_step_result.success = False + expected_step_result.message = "Error running 'maven test' to run user acceptance tests. " \ + "More details maybe found in 'maven-output', `surefire-reports`, " \ + "`cucumber-report-html`, and `cucumber-report-json` " \ + "report artifact: mock maven error" + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt', + step_implementer_additional_arguments=[ + f'-Dselenium.hub.url={selenium_hub_url}', + f'-Dtarget.base.url={target_base_url}', + f'-Dcucumber.plugin=' \ + f'html:{cucumber_html_report_path},' \ + f'json:{cucumber_json_report_path}', + ] ) - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - selenium_hub_url='https://test.xyz:4444', - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, - aggregate_xml_element_attribute_values_mock_fail=True, - assert_evidence=True, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - expected_result_success=False, - expected_result_message="Error gathering evidence from "\ - "surefire report, expected attribute tests "\ - "not found in report " + surefire_reports_dir) +# class TestStepImplementerMavenSeleniumCucumberBase(MaveStepImplementerTestCase): +# def create_step_implementer( +# self, +# step_config={}, +# parent_work_dir_path='' +# ): +# return self.create_given_step_implementer( +# step_implementer=MavenSeleniumCucumber, +# step_config=step_config, +# step_name='uat', +# implementer='MavenSeleniumCucumber', +# parent_work_dir_path=parent_work_dir_path +# ) + +# class TestStepImplementerDeployMavenSeleniumCucumber_validate_required_config_or_previous_step_result_artifact_keys( +# TestStepImplementerMavenSeleniumCucumberBase +# ): +# def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_artifact_keys_success_target_host_url(self): +# with TempDirectory() as temp_dir: +# parent_work_dir_path = os.path.join(temp_dir.path, 'working') + +# pom_file_path = os.path.join(temp_dir.path, 'pom.xml') +# Path(pom_file_path).touch() +# step_config = { +# 'selenium-hub-url': 'https://selenium.ploigos.xyz', +# 'pom-file': pom_file_path, +# 'target-host-url': 'https://foo.test.ploigos.xyz' +# } +# step_implementer = self.create_step_implementer( +# step_config=step_config, +# parent_work_dir_path=parent_work_dir_path, +# ) + +# step_implementer._validate_required_config_or_previous_step_result_artifact_keys() + +# def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_artifact_keys_success_deployed_host_urls_1(self): +# with TempDirectory() as temp_dir: +# parent_work_dir_path = os.path.join(temp_dir.path, 'working') + +# pom_file_path = os.path.join(temp_dir.path, 'pom.xml') +# Path(pom_file_path).touch() +# step_config = { +# 'selenium-hub-url': 'https://selenium.ploigos.xyz', +# 'pom-file': pom_file_path, +# 'deployed-host-urls': ['https://foo.test.ploigos.xyz'] +# } +# step_implementer = self.create_step_implementer( +# step_config=step_config, +# parent_work_dir_path=parent_work_dir_path, +# ) + +# step_implementer._validate_required_config_or_previous_step_result_artifact_keys() + +# def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_artifact_keys_success_deployed_host_urls_2(self): +# with TempDirectory() as temp_dir: +# parent_work_dir_path = os.path.join(temp_dir.path, 'working') + +# pom_file_path = os.path.join(temp_dir.path, 'pom.xml') +# Path(pom_file_path).touch() +# step_config = { +# 'selenium-hub-url': 'https://selenium.ploigos.xyz', +# 'pom-file': pom_file_path, +# 'deployed-host-urls': ['https://foo.test.ploigos.xyz', 'https://bar.test.ploigos.xyz'] +# } +# step_implementer = self.create_step_implementer( +# step_config=step_config, +# parent_work_dir_path=parent_work_dir_path, +# ) + +# step_implementer._validate_required_config_or_previous_step_result_artifact_keys() + +# def test_MavenSeleniumCucumber_validate_required_config_or_previous_step_result_artifact_keys_fail_no_target_urls(self): +# with TempDirectory() as temp_dir: +# parent_work_dir_path = os.path.join(temp_dir.path, 'working') + +# pom_file_path = os.path.join(temp_dir.path, 'pom.xml') +# Path(pom_file_path).touch() +# step_config = { +# 'selenium-hub-url': 'https://selenium.ploigos.xyz', +# 'pom-file': pom_file_path +# } +# step_implementer = self.create_step_implementer( +# step_config=step_config, +# parent_work_dir_path=parent_work_dir_path, +# ) + +# with self.assertRaisesRegex( +# StepRunnerException, +# rf"Either 'target-host-url' or 'deployed-host-urls' needs to be supplied but" +# " neither were." +# ): +# step_implementer._validate_required_config_or_previous_step_result_artifact_keys() + +# class TestStepImplementerMavenSeleniumCucumber_Other(TestStepImplementerMavenSeleniumCucumberBase): +# def test_step_implementer_config_defaults(self): +# actual_defaults = MavenSeleniumCucumber.step_implementer_config_defaults() +# expected_defaults = { +# 'fail-on-no-tests': True, +# 'pom-file': 'pom.xml', +# 'tls-verify': True, +# 'uat-maven-profile': 'integration-test' +# } +# self.assertEqual(expected_defaults, actual_defaults) + +# def test__required_config_or_result_keys(self): +# actual_required_keys = MavenSeleniumCucumber._required_config_or_result_keys() +# expected_required_keys = [ +# 'fail-on-no-tests', +# 'pom-file', +# 'selenium-hub-url', +# 'uat-maven-profile' +# ] +# self.assertEqual(expected_required_keys, actual_required_keys) + +# def __run__run_step_test( +# self, +# test_dir, +# mvn_mock, +# write_effective_pom_mock, +# generate_maven_settings_mock, +# pom_content, +# group_id, +# artifact_id, +# surefire_reports_dir, +# selenium_hub_url, +# target_host_url=None, +# deployed_host_urls=None, +# write_mock_test_results=True, +# assert_mvn_called=True, +# assert_report_artifact=True, +# assert_evidence=True, +# expected_result_success=True, +# expected_result_message='', +# fail_on_no_tests=None, +# uat_maven_profile=None, +# pom_file_name='pom.xml', +# raise_error_on_tests=False, +# set_tls_verify_false=False, +# aggregate_xml_element_attribute_values_mock=False, +# aggregate_xml_element_attribute_values_mock_fail=False +# ): +# parent_work_dir_path = os.path.join(test_dir.path, 'working') + +# cucumber_html_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.html') +# cucumber_json_report_path = os.path.join(parent_work_dir_path, 'uat', 'cucumber.json') + +# test_dir.write(pom_file_name, pom_content) + +# pom_file_path = os.path.join(test_dir.path, pom_file_name) +# step_config = { +# 'pom-file': pom_file_path, +# 'selenium-hub-url': selenium_hub_url, +# 'tls-verify': True +# } + +# if set_tls_verify_false: +# step_config['tls-verify'] = False + +# target_base_url = None +# if deployed_host_urls: +# step_config['deployed-host-urls'] = deployed_host_urls +# if isinstance(deployed_host_urls, list): +# target_base_url = deployed_host_urls[0] +# else: +# target_base_url = deployed_host_urls +# if target_host_url: +# step_config['target-host-url'] = target_host_url +# target_base_url = target_host_url + +# if fail_on_no_tests is not None: +# step_config['fail-on-no-tests'] = fail_on_no_tests +# if uat_maven_profile is not None: +# step_config['uat-maven-profile'] = uat_maven_profile +# else: +# uat_maven_profile = 'integration-test' +# step_implementer = self.create_step_implementer( +# step_config=step_config, +# parent_work_dir_path=parent_work_dir_path, +# ) + +# # mock generating settings +# settings_file_path = "/does/not/matter/settings.xml" +# def generate_maven_settings_side_effect(): +# return settings_file_path +# generate_maven_settings_mock.side_effect = generate_maven_settings_side_effect + +# # mock effective pom +# def write_effective_pom_mock_side_effect(pom_file_path, output_path): +# create_parent_dir(pom_file_path) +# copyfile(pom_file_path, output_path) +# write_effective_pom_mock.side_effect = write_effective_pom_mock_side_effect + +# # mock test results +# if write_mock_test_results: +# mvn_mock.side_effect = MaveStepImplementerTestCase.create_mvn_side_effect( +# pom_file=pom_file_path, +# artifact_parent_dir=surefire_reports_dir, +# artifact_names=[ +# f'{group_id}.{artifact_id}.CucumberTest.txt', +# f'TEST-{group_id}.{artifact_id}.CucumberTest.xml' +# ], +# raise_error_on_tests=raise_error_on_tests +# ) + +# # mock evidence +# if aggregate_xml_element_attribute_values_mock and not aggregate_xml_element_attribute_values_mock_fail: +# aggregate_xml_element_attribute_values_mock.return_value = { +# 'time': '42', +# 'tests': '42', +# 'errors': '0', +# 'skipped': '0', +# 'failures': '0' +# } +# elif aggregate_xml_element_attribute_values_mock_fail: +# aggregate_xml_element_attribute_values_mock.return_value = { +# 'time': '42' +# } + +# result = step_implementer._run_step() +# if assert_mvn_called: +# if not set_tls_verify_false: +# mvn_mock.assert_called_once_with( +# 'clean', +# 'test', +# f'-P{uat_maven_profile}', +# f'-Dselenium.hub.url={selenium_hub_url}', +# f'-Dtarget.base.url={target_base_url}', +# f'-Dcucumber.plugin=' \ +# f'html:{cucumber_html_report_path},' \ +# f'json:{cucumber_json_report_path}', +# '-f', pom_file_path, +# '-s', settings_file_path, +# _out=Any(IOBase), +# _err=Any(IOBase) +# ) +# else: +# mvn_mock.assert_called_once_with( +# 'clean', +# 'test', +# f'-P{uat_maven_profile}', +# f'-Dselenium.hub.url={selenium_hub_url}', +# f'-Dtarget.base.url={target_base_url}', +# f'-Dcucumber.plugin=' \ +# f'html:{cucumber_html_report_path},' \ +# f'json:{cucumber_json_report_path}', +# '-f', pom_file_path, +# '-s', settings_file_path, +# '-Dmaven.wagon.http.ssl.insecure=true', +# '-Dmaven.wagon.http.ssl.allowall=true', +# '-Dmaven.wagon.http.ssl.ignore.validity.dates=true', +# _out=Any(IOBase), +# _err=Any(IOBase) +# ) + +# expected_step_result = StepResult( +# step_name='uat', +# sub_step_name='MavenSeleniumCucumber', +# sub_step_implementer_name='MavenSeleniumCucumber' +# ) +# expected_step_result.success = expected_result_success +# expected_step_result.message = expected_result_message + +# if assert_report_artifact: +# mvn_test_output_file_path = os.path.join( +# step_implementer.work_dir_path, +# 'mvn_test_output.txt' +# ) +# expected_step_result.add_artifact( +# description=f"Standard out and standard error by 'mvn -P{uat_maven_profile} test'.", +# name='maven-output', +# value=mvn_test_output_file_path +# ) +# expected_step_result.add_artifact( +# description=f"Surefire reports generated by 'mvn -P{uat_maven_profile} test'.", +# name='surefire-reports', +# value=surefire_reports_dir +# ) +# expected_step_result.add_artifact( +# description=f"Cucumber (HTML) report generated by 'mvn -P{uat_maven_profile} test'.", +# name='cucumber-report-html', +# value=cucumber_html_report_path +# ) +# expected_step_result.add_artifact( +# description=f"Cucumber (JSON) report generated by 'mvn -P{uat_maven_profile} test'.", +# name='cucumber-report-json', +# value=cucumber_json_report_path +# ) + +# if assert_evidence and not aggregate_xml_element_attribute_values_mock_fail: +# expected_step_result.add_evidence( +# name='uat-evidence-time', +# description='Surefire report value for time', +# value='42' +# ) +# expected_step_result.add_evidence( +# name='uat-evidence-tests', +# description='Surefire report value for tests', +# value='42' +# ) +# expected_step_result.add_evidence( +# name='uat-evidence-errors', +# description='Surefire report value for errors', +# value='0' +# ) +# expected_step_result.add_evidence( +# name='uat-evidence-skipped', +# description='Surefire report value for skipped', +# value='0' +# ) +# expected_step_result.add_evidence( +# name='uat-evidence-failures', +# description='Surefire report value for failures', +# value='0' +# ) +# elif assert_evidence and aggregate_xml_element_attribute_values_mock_fail: +# expected_step_result.add_evidence( +# name='uat-evidence-time', +# description='Surefire report value for time', +# value='42' +# ) +# print(result) +# self.assertEqual(expected_step_result, result) + + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_success_defaults( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_tls_verify_false( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# set_tls_verify_false=True +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_success__deployed_host_urls_str( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# deployed_host_urls = 'https://foo.ploigos.xyz' +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# deployed_host_urls=deployed_host_urls +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_success__deployed_host_urls_array_1( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# deployed_host_urls = ['https://foo.ploigos.xyz'] +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# deployed_host_urls=deployed_host_urls +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_success__deployed_host_urls_array_2( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock, +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# deployed_host_urls = ['https://foo.ploigos.xyz', 'https://foo.ploigos.xyz'] +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# deployed_host_urls=deployed_host_urls, +# expected_result_message=\ +# f"Given more then one deployed host URL ({deployed_host_urls})," \ +# f" targeting first one (https://foo.ploigos.xyz) for user acceptance test (UAT)." +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_success_provided_profile_override( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# uat_maven_profile='custom-uat-profile' +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_success_provided_pom_file_override( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# pom_file_name='custom-pom.xml' +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_success_provided_fail_on_no_tests_false_with_tests( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# fail_on_no_tests=False, +# write_mock_test_results=True, +# expected_result_success=True +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_success_provided_fail_on_no_tests_false_with_no_tests( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# assert_evidence=False, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# fail_on_no_tests=False, +# write_mock_test_results=False, +# expected_result_success=True, +# expected_result_message="No user acceptance tests defined" \ +# " using maven profile (integration-test)," \ +# " but 'fail-on-no-tests' is False." +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_fail_provided_fail_on_no_tests_true_with_no_tests( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# assert_evidence=False, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# fail_on_no_tests=True, +# write_mock_test_results=False, +# expected_result_success=False, +# expected_result_message="No user acceptance tests defined" \ +# " using maven profile (integration-test)." +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_fail_no_surefire_plugin( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# effective_pom_path = os.path.join( +# test_dir.path, +# 'working', +# 'uat', +# 'effective-pom.xml' +# ) +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# assert_evidence=False, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# expected_result_success=False, +# expected_result_message='Unit test dependency "maven-surefire-plugin" ' \ +# f'missing from effective pom ({effective_pom_path}).', +# assert_mvn_called=False, +# assert_report_artifact=False +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_success_pom_specified_reports_dir( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# {surefire_reports_dir} +# +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version, +# surefire_reports_dir=surefire_reports_dir +# ), 'utf-8' +# ) + +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# assert_evidence=True, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_fail_mvn_test_failure( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=None, +# assert_evidence=False, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# raise_error_on_tests=True, +# expected_result_success=False, +# expected_result_message="User acceptance test failures. See 'maven-output'" \ +# ", 'surefire-reports', 'cucumber-report-html', and 'cucumber-report-json'" \ +# " report artifacts for details." +# ) + +# @patch('ploigos_step_runner.step_implementers.uat.maven_selenium_cucumber.aggregate_xml_element_attribute_values') +# @patch.object(MavenSeleniumCucumber, '_generate_maven_settings') +# @patch('sh.mvn', create=True) +# @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') +# def test__run_step_failure_missing_evidence_attribute( +# self, +# write_effective_pom_mock, +# mvn_mock, +# generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock +# ): +# with TempDirectory() as test_dir: +# group_id = 'com.mycompany.app' +# artifact_id = 'my-app' +# version = '1.0' +# surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') +# pom_content = bytes( +# ''' +# 4.0.0 +# {group_id} +# {artifact_id} +# {version} +# +# 1.8 +# 1.8 +# +# +# +# +# maven-surefire-plugin +# ${{surefire-plugin.version}} +# +# +# +# '''.format( +# group_id=group_id, +# artifact_id=artifact_id, +# version=version +# ), 'utf-8' +# ) + +# self.__run__run_step_test( +# test_dir=test_dir, +# mvn_mock=mvn_mock, +# selenium_hub_url='https://test.xyz:4444', +# write_effective_pom_mock=write_effective_pom_mock, +# generate_maven_settings_mock=generate_maven_settings_mock, +# aggregate_xml_element_attribute_values_mock=aggregate_xml_element_attribute_values_mock, +# aggregate_xml_element_attribute_values_mock_fail=True, +# assert_evidence=True, +# pom_content=pom_content, +# group_id=group_id, +# artifact_id=artifact_id, +# surefire_reports_dir=surefire_reports_dir, +# expected_result_success=False, +# expected_result_message="Error gathering evidence from "\ +# "surefire report, expected attribute tests "\ +# "not found in report " + surefire_reports_dir) diff --git a/tests/step_implementers/unit_test/test_maven_unit_test.py b/tests/step_implementers/unit_test/test_maven_unit_test.py index ed2dafb0..a95c1325 100644 --- a/tests/step_implementers/unit_test/test_maven_unit_test.py +++ b/tests/step_implementers/unit_test/test_maven_unit_test.py @@ -1,23 +1,92 @@ import os -import re -from io import IOBase, StringIO -from shutil import copyfile -from unittest.mock import patch +from pathlib import Path +from unittest.mock import Mock, patch -from ploigos_step_runner import StepResult, WorkflowResult -from ploigos_step_runner.config.config import Config +from ploigos_step_runner import StepResult, StepRunnerException, WorkflowResult from ploigos_step_runner.step_implementers.unit_test import Maven -from ploigos_step_runner.utils.file import create_parent_dir from testfixtures import TempDirectory -from tests.helpers.maven_step_implementer_test_case import \ - MaveStepImplementerTestCase -from tests.helpers.test_utils import Any +from tests.helpers.base_step_implementer_test_case import \ + BaseStepImplementerTestCase -class TestStepImplementerMavenUnitTest(MaveStepImplementerTestCase): +@patch("ploigos_step_runner.step_implementers.shared.MavenGeneric.__init__") +class TestStepImplementerMavenTest___init__(BaseStepImplementerTestCase): + def test_defaults(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} + + Maven( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config + ) + + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment=None, + maven_phases_and_goals=['test'] + ) + + def test_given_environment(self, mock_super_init): + workflow_result = WorkflowResult() + parent_work_dir_path = '/fake/path' + config = {} + + Maven( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment='mock-env' + ) + + mock_super_init.assert_called_once_with( + workflow_result=workflow_result, + parent_work_dir_path=parent_work_dir_path, + config=config, + environment='mock-env', + maven_phases_and_goals=['test'] + ) + +class TestStepImplementerMavenTest_step_implementer_config_defaults( + BaseStepImplementerTestCase +): + def test_result(self): + self.assertEqual( + Maven.step_implementer_config_defaults(), + { + 'pom-file': 'pom.xml', + 'tls-verify': True, + 'maven-profiles': [], + 'maven-additional-arguments': [], + 'maven-no-transfer-progress': True, + 'fail-on-no-tests': True + } + ) + +class TestStepImplementerMavenTest__required_config_or_result_keys( + BaseStepImplementerTestCase +): + def test_result(self): + self.assertEqual( + Maven._required_config_or_result_keys(), + [ + 'pom-file', + 'fail-on-no-tests' + ] + ) + +@patch.object(Maven, '_run_maven_step') +@patch.object(Maven, 'write_working_file', return_value='/mock/mvn_output.txt') +class TestStepImplementerMavenTest__run_step( + BaseStepImplementerTestCase +): def create_step_implementer( self, step_config={}, + workflow_result=None, parent_work_dir_path='' ): return self.create_given_step_implementer( @@ -25,535 +94,448 @@ def create_step_implementer( step_config=step_config, step_name='unit-test', implementer='Maven', + workflow_result=workflow_result, parent_work_dir_path=parent_work_dir_path ) - def test_step_implementer_config_defaults(self): - defaults = Maven.step_implementer_config_defaults() - expected_defaults = { - 'fail-on-no-tests': True, - 'pom-file': 'pom.xml', - 'tls-verify': True - } - self.assertEqual(defaults, expected_defaults) - - def test__required_config_or_result_keys(self): - required_keys = Maven._required_config_or_result_keys() - expected_required_keys = [ - 'fail-on-no-tests', - 'pom-file' - ] - self.assertEqual(required_keys, expected_required_keys) - - def __run__run_step_test( + @patch.object(Maven, '_get_effective_pom_element', side_effect=['mock surefire element', None]) + def test_success_default_reports_dir( self, - test_dir, - mvn_mock, - write_effective_pom_mock, - generate_maven_settings_mock, - pom_content, - group_id, - artifact_id, - surefire_reports_dir, - write_mock_test_results=True, - assert_mvn_called=True, - assert_report_artifact=True, - expected_result_success=True, - expected_result_message='', - expected_result_message_regex=None, - fail_on_no_tests=None, - raise_error_on_tests=False, - set_tls_verify_false=False, + mock_effective_pom_element, + mock_write_working_file, + mock_run_maven_step ): - parent_work_dir_path = os.path.join(test_dir.path, 'working') + with TempDirectory() as test_dir: + parent_work_dir_path = os.path.join(test_dir.path, 'working') - test_dir.write('pom.xml', pom_content) + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + step_config = { + 'pom-file': pom_file + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) - pom_file_path = os.path.join(test_dir.path, 'pom.xml') - step_config = { - 'pom-file': pom_file_path, - 'tls-verify': True - } + # setup sideeffects + surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') + group_id = 'com.ploigos.app' + artifact_id = 'my-app' + surefire_artifact_names = [ + f'{group_id}.{artifact_id}.ClassNameTest.txt', + f'TEST-{group_id}.{artifact_id}.ClassNameTest.xml' + ] + def run_maven_side_effect(mvn_output_file_path): + os.makedirs(surefire_reports_dir, exist_ok=True) - if set_tls_verify_false: - step_config['tls-verify'] = False + for artifact_name in surefire_artifact_names: + artifact_path = os.path.join( + surefire_reports_dir, + artifact_name + ) + Path(artifact_path).touch() - if fail_on_no_tests is not None: - step_config['fail-on-no-tests'] = fail_on_no_tests - step_implementer = self.create_step_implementer( - step_config=step_config, - parent_work_dir_path=parent_work_dir_path, - ) + mock_run_maven_step.side_effect = run_maven_side_effect - # mock generating settings - settings_file_path = "/does/not/matter/settings.xml" - def generate_maven_settings_side_effect(): - return settings_file_path - generate_maven_settings_mock.side_effect = generate_maven_settings_side_effect - - # mock effective pom - def write_effective_pom_mock_side_effect(pom_file_path, output_path): - create_parent_dir(pom_file_path) - copyfile(pom_file_path, output_path) - write_effective_pom_mock.side_effect = write_effective_pom_mock_side_effect - - # mock test results - if write_mock_test_results: - mvn_mock.side_effect = MaveStepImplementerTestCase.create_mvn_side_effect( - pom_file=pom_file_path, - artifact_parent_dir=surefire_reports_dir, - artifact_names=[ - f'{group_id}.{artifact_id}.ClassNameTest.txt', - f'TEST-{group_id}.{artifact_id}.ClassNameTest.xml' - ], - raise_error_on_tests=raise_error_on_tests - ) - - result = step_implementer._run_step() - if assert_mvn_called: - if not set_tls_verify_false: - mvn_mock.assert_called_once_with( - 'clean', - 'test', - '-f', pom_file_path, - '-s', settings_file_path, - _out=Any(IOBase), - _err=Any(IOBase) - ) - else: - mvn_mock.assert_called_once_with( - 'clean', - 'test', - '-f', pom_file_path, - '-s', settings_file_path, - '-Dmaven.wagon.http.ssl.insecure=true', - '-Dmaven.wagon.http.ssl.allowall=true', - '-Dmaven.wagon.http.ssl.ignore.validity.dates=true', - _out=Any(IOBase), - _err=Any(IOBase) - ) - - expected_step_result = StepResult( - step_name='unit-test', - sub_step_name='Maven', - sub_step_implementer_name='Maven' - ) - expected_step_result.success = expected_result_success - expected_step_result.message = expected_result_message + # run step + actual_step_result = step_implementer._run_step() - if assert_report_artifact: - mvn_test_output_file_path = os.path.join( - step_implementer.work_dir_path, - 'mvn_test_output.txt' + # create expected step result + expected_step_result = StepResult( + step_name='unit-test', + sub_step_name='Maven', + sub_step_implementer_name='Maven' ) expected_step_result.add_artifact( - description="Standard out and standard error from 'mvn test'.", + description="Standard out and standard error from maven.", name='maven-output', - value=mvn_test_output_file_path + value='/mock/mvn_output.txt' ) expected_step_result.add_artifact( + description="Surefire reports generated by maven.", name='surefire-reports', - description="Surefire reports generated from 'mvn test'.", - value=surefire_reports_dir, + value=surefire_reports_dir ) - if expected_result_message_regex: - self.assertEqual(result.success, expected_step_result.success) - self.assertRegex(result.message, expected_result_message_regex) - self.assertEqual(result.artifacts, expected_step_result.artifacts) - else: - self.assertEqual(result, expected_step_result) + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) - @patch.object(Maven, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success_default_reports_dir( - self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock - ): - with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' - ) - - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - ) - - @patch.object(Maven, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_tls_verify_false( + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' + ) + + @patch.object( + Maven, + '_get_effective_pom_element', + side_effect=['mock surefire element', Mock(text='mock/fake/reports')] + ) + def test_success_pom_specified_relative_reports_dir( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock + mock_effective_pom_element, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + step_config = { + 'pom-file': pom_file + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # setup sideeffects + surefire_reports_dir = os.path.join(test_dir.path, 'mock/fake/reports') + group_id = 'com.ploigos.app' artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' - ) - - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - set_tls_verify_false=True - ) - - @patch.object(Maven, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success_pom_specified_reports_dir( + surefire_artifact_names = [ + f'{group_id}.{artifact_id}.ClassNameTest.txt', + f'TEST-{group_id}.{artifact_id}.ClassNameTest.xml' + ] + def run_maven_side_effect(mvn_output_file_path): + os.makedirs(surefire_reports_dir, exist_ok=True) + + for artifact_name in surefire_artifact_names: + artifact_path = os.path.join( + surefire_reports_dir, + artifact_name + ) + Path(artifact_path).touch() + + mock_run_maven_step.side_effect = run_maven_side_effect + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + expected_step_result = StepResult( + step_name='unit-test', + sub_step_name='Maven', + sub_step_implementer_name='Maven' + ) + expected_step_result.add_artifact( + description="Standard out and standard error from maven.", + name='maven-output', + value='/mock/mvn_output.txt' + ) + expected_step_result.add_artifact( + description="Surefire reports generated by maven.", + name='surefire-reports', + value=surefire_reports_dir + ) + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' + ) + + @patch.object(Maven, '_get_effective_pom_element') + def test_success_pom_specified_absolute_reports_dir( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock + mock_effective_pom_element, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + step_config = { + 'pom-file': pom_file + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # setup sideeffects + surefire_reports_dir = os.path.join(test_dir.path, 'mock-abs/fake/reports') + mock_effective_pom_element.side_effect = [ + 'mock surefire element', + Mock(text=surefire_reports_dir) + ] + group_id = 'com.ploigos.app' artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/custom-surefire-reports-dir') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - {surefire_reports_dir} - - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version, - surefire_reports_dir=surefire_reports_dir - ), 'utf-8' - ) - - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir - ) - - @patch.object(Maven, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_fail_missing_surefire_plugin( + surefire_artifact_names = [ + f'{group_id}.{artifact_id}.ClassNameTest.txt', + f'TEST-{group_id}.{artifact_id}.ClassNameTest.xml' + ] + def run_maven_side_effect(mvn_output_file_path): + os.makedirs(surefire_reports_dir, exist_ok=True) + + for artifact_name in surefire_artifact_names: + artifact_path = os.path.join( + surefire_reports_dir, + artifact_name + ) + Path(artifact_path).touch() + + mock_run_maven_step.side_effect = run_maven_side_effect + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + expected_step_result = StepResult( + step_name='unit-test', + sub_step_name='Maven', + sub_step_implementer_name='Maven' + ) + expected_step_result.add_artifact( + description="Standard out and standard error from maven.", + name='maven-output', + value='/mock/mvn_output.txt' + ) + expected_step_result.add_artifact( + description="Surefire reports generated by maven.", + name='surefire-reports', + value=surefire_reports_dir + ) + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' + ) + + @patch.object(Maven, '_get_effective_pom_element', side_effect=[None, None]) + @patch.object(Maven, '_get_effective_pom', return_value='mock-effective-pom.xml') + def test_fail_no_surefire_plugin( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock + mock_effective_pom, + mock_effective_pom_element, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + step_config = { + 'pom-file': pom_file + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # setup sideeffects + surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') + group_id = 'com.ploigos.app' artifact_id = 'my-app' - version = '1.0' - surefire_reports_dir = os.path.join(test_dir.path, 'target/custom-surefire-reports-dir') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' - ) - - effective_pom_path = os.path.join( - test_dir.path, - 'working', - 'unit-test', - 'effective-pom.xml' - ) - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - expected_result_success=False, - expected_result_message='Unit test dependency "maven-surefire-plugin" ' \ - f'missing from effective pom ({effective_pom_path}).', - assert_mvn_called=False, - assert_report_artifact=False - ) - - @patch.object(Maven, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_fail_no_unit_tests_defined( + surefire_artifact_names = [ + f'{group_id}.{artifact_id}.ClassNameTest.txt', + f'TEST-{group_id}.{artifact_id}.ClassNameTest.xml' + ] + def run_maven_side_effect(mvn_output_file_path): + os.makedirs(surefire_reports_dir, exist_ok=True) + + for artifact_name in surefire_artifact_names: + artifact_path = os.path.join( + surefire_reports_dir, + artifact_name + ) + Path(artifact_path).touch() + + mock_run_maven_step.side_effect = run_maven_side_effect + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result + expected_step_result = StepResult( + step_name='unit-test', + sub_step_name='Maven', + sub_step_implementer_name='Maven' + ) + expected_step_result.success = False + expected_step_result.message = 'Unit test dependency "maven-surefire-plugin" ' \ + f'missing from effective pom (mock-effective-pom.xml).' + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_run_maven_step.assert_not_called() + + @patch.object(Maven, '_get_effective_pom_element', side_effect=['mock surefire element', None]) + def test_fail_no_tests( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock + mock_effective_pom_element, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + step_config = { + 'pom-file': pom_file + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' - ) - - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - write_mock_test_results=False, - expected_result_success=False, - expected_result_message='No unit tests defined.' - ) - - @patch.object(Maven, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_success_fail_on_no_tests_false_and_no_tests( + expected_step_result = StepResult( + step_name='unit-test', + sub_step_name='Maven', + sub_step_implementer_name='Maven' + ) + expected_step_result.success = False + expected_step_result.message = 'No unit tests defined.' + expected_step_result.add_artifact( + description="Standard out and standard error from maven.", + name='maven-output', + value='/mock/mvn_output.txt' + ) + expected_step_result.add_artifact( + description="Surefire reports generated by maven.", + name='surefire-reports', + value=surefire_reports_dir + ) + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' + ) + + @patch.object(Maven, '_get_effective_pom_element', side_effect=['mock surefire element', None]) + def test_success_but_no_tests( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock + mock_effective_pom_element, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + step_config = { + 'pom-file': pom_file, + 'fail-on-no-tests': False + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # run step + actual_step_result = step_implementer._run_step() + + # create expected step result surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' - ) - - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - write_mock_test_results=False, - fail_on_no_tests=False, - expected_result_message="No unit tests defined, but 'fail-on-no-tests' is False." - ) - - @patch.object(Maven, '_generate_maven_settings') - @patch('sh.mvn', create=True) - @patch('ploigos_step_runner.step_implementers.shared.maven_generic.write_effective_pom') - def test__run_step_fail_mvn_test_failure( + expected_step_result = StepResult( + step_name='unit-test', + sub_step_name='Maven', + sub_step_implementer_name='Maven' + ) + expected_step_result.message = "No unit tests defined, but 'fail-on-no-tests' is False." + expected_step_result.add_artifact( + description="Standard out and standard error from maven.", + name='maven-output', + value='/mock/mvn_output.txt' + ) + expected_step_result.add_artifact( + description="Surefire reports generated by maven.", + name='surefire-reports', + value=surefire_reports_dir + ) + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' + ) + + @patch.object(Maven, '_get_effective_pom_element', side_effect=['mock surefire element', None]) + def test_fail_maven_run( self, - write_effective_pom_mock, - mvn_mock, - generate_maven_settings_mock + mock_effective_pom_element, + mock_write_working_file, + mock_run_maven_step ): with TempDirectory() as test_dir: - group_id = 'com.mycompany.app' - artifact_id = 'my-app' - version = '1.0' + parent_work_dir_path = os.path.join(test_dir.path, 'working') + + pom_file = os.path.join(test_dir.path, 'mock-pom.xml') + step_config = { + 'pom-file': pom_file + } + step_implementer = self.create_step_implementer( + step_config=step_config, + parent_work_dir_path=parent_work_dir_path, + ) + + # run step with mock failure + mock_run_maven_step.side_effect = StepRunnerException('Mock error running maven') + actual_step_result = step_implementer._run_step() + + # create expected step result surefire_reports_dir = os.path.join(test_dir.path, 'target/surefire-reports') - pom_content = bytes( -''' - 4.0.0 - {group_id} - {artifact_id} - {version} - - 1.8 - 1.8 - - - - - maven-surefire-plugin - ${{surefire-plugin.version}} - - - -'''.format( - group_id=group_id, - artifact_id=artifact_id, - version=version - ), 'utf-8' - ) - - self.__run__run_step_test( - test_dir=test_dir, - mvn_mock=mvn_mock, - write_effective_pom_mock=write_effective_pom_mock, - generate_maven_settings_mock=generate_maven_settings_mock, - pom_content=pom_content, - group_id=group_id, - artifact_id=artifact_id, - surefire_reports_dir=surefire_reports_dir, - raise_error_on_tests=True, - expected_result_success=False, - expected_result_message_regex=re.compile( - r"Unit test failures. See 'maven-output'" \ - r" and 'surefire-reports' report artifacts for details:" - r".*RAN: mvn" - r".*STDOUT:" - r".*mock out" - r".*STDERR:" - r".*mock error", - re.DOTALL - ) + expected_step_result = StepResult( + step_name='unit-test', + sub_step_name='Maven', + sub_step_implementer_name='Maven' + ) + expected_step_result.success = False + expected_step_result.message = "Error running 'maven test' to run unit tests. " \ + "More details maybe found in 'maven-output' and `surefire-reports` " \ + f"report artifact: Mock error running maven" + expected_step_result.add_artifact( + description="Standard out and standard error from maven.", + name='maven-output', + value='/mock/mvn_output.txt' + ) + expected_step_result.add_artifact( + description="Surefire reports generated by maven.", + name='surefire-reports', + value=surefire_reports_dir + ) + + # verify step result + self.assertEqual( + actual_step_result, + expected_step_result + ) + + mock_write_working_file.assert_called_once() + mock_run_maven_step.assert_called_with( + mvn_output_file_path='/mock/mvn_output.txt' ) diff --git a/tests/utils/test_maven.py b/tests/utils/test_maven.py index 4f031610..01935aae 100644 --- a/tests/utils/test_maven.py +++ b/tests/utils/test_maven.py @@ -4,14 +4,15 @@ """ import re import xml.etree.ElementTree as ET -from io import BytesIO -from unittest.mock import patch +from io import BytesIO, StringIO, TextIOWrapper +from unittest.mock import patch, call, mock_open import sh -from testfixtures import TempDirectory -from tests.helpers.base_test_case import BaseTestCase from ploigos_step_runner.exceptions import StepRunnerException from ploigos_step_runner.utils.maven import * +from testfixtures import TempDirectory +from tests.helpers.base_test_case import BaseTestCase +from tests.helpers.test_utils import Any class TestMavenUtils(BaseTestCase): @@ -1040,4 +1041,256 @@ def test_write_effective_pom_fail_not_absolute_path(self, mvn_mock): 'help:effective-pom', f'-f={pom_file_path}', f'-Doutput={effective_pom_path}' - ) \ No newline at end of file + ) + +class TestMavenUtils_run_maven(BaseTestCase): + @patch('sh.mvn', create=True) + @patch('ploigos_step_runner.utils.maven.create_sh_redirect_to_multiple_streams_fn_callback') + @patch("builtins.open", new_callable=mock_open) + def test_success_defaults(self, mock_open, redirect_mock, mvn_mock): + with TempDirectory() as temp_dir: + mvn_output_file_path = os.path.join(temp_dir.path, 'maven_output.txt') + settings_file = '/fake/settings.xml' + pom_file = '/fake/pom.xml' + phases_and_goals = 'fake' + + run_maven( + mvn_output_file_path=mvn_output_file_path, + settings_file=settings_file, + pom_file=pom_file, + phases_and_goals=phases_and_goals, + ) + + mock_open.assert_called_with(mvn_output_file_path, 'w') + redirect_mock.assert_has_calls([ + call([ + sys.stdout, + mock_open.return_value + ]), + call([ + sys.stderr, + mock_open.return_value + ]) + ]) + + mvn_mock.assert_called_once_with( + 'fake', + '-f', '/fake/pom.xml', + '-s', '/fake/settings.xml', + '--no-transfer-progress', + _out=Any(StringIO), + _err=Any(StringIO) + ) + + @patch('sh.mvn', create=True) + @patch('ploigos_step_runner.utils.maven.create_sh_redirect_to_multiple_streams_fn_callback') + @patch("builtins.open", new_callable=mock_open) + def test_success_with_single_profile(self, mock_open, redirect_mock, mvn_mock): + with TempDirectory() as temp_dir: + mvn_output_file_path = os.path.join(temp_dir.path, 'maven_output.txt') + settings_file = '/fake/settings.xml' + pom_file = '/fake/pom.xml' + phases_and_goals = 'fake' + + run_maven( + mvn_output_file_path=mvn_output_file_path, + settings_file=settings_file, + pom_file=pom_file, + phases_and_goals=phases_and_goals, + profiles=['fake-profile'] + ) + + mock_open.assert_called_with(mvn_output_file_path, 'w') + redirect_mock.assert_has_calls([ + call([ + sys.stdout, + mock_open.return_value + ]), + call([ + sys.stderr, + mock_open.return_value + ]) + ]) + + mvn_mock.assert_called_once_with( + 'fake', + '-f', '/fake/pom.xml', + '-s', '/fake/settings.xml', + '-P', 'fake-profile', + '--no-transfer-progress', + _out=Any(StringIO), + _err=Any(StringIO) + ) + + @patch('sh.mvn', create=True) + @patch('ploigos_step_runner.utils.maven.create_sh_redirect_to_multiple_streams_fn_callback') + @patch("builtins.open", new_callable=mock_open) + def test_success_with_multiple_profile(self, mock_open, redirect_mock, mvn_mock): + with TempDirectory() as temp_dir: + mvn_output_file_path = os.path.join(temp_dir.path, 'maven_output.txt') + settings_file = '/fake/settings.xml' + pom_file = '/fake/pom.xml' + phases_and_goals = 'fake' + + run_maven( + mvn_output_file_path=mvn_output_file_path, + settings_file=settings_file, + pom_file=pom_file, + phases_and_goals=phases_and_goals, + profiles=['fake-profile1', 'fake-profile2'] + ) + + mock_open.assert_called_with(mvn_output_file_path, 'w') + redirect_mock.assert_has_calls([ + call([ + sys.stdout, + mock_open.return_value + ]), + call([ + sys.stderr, + mock_open.return_value + ]) + ]) + + mvn_mock.assert_called_once_with( + 'fake', + '-f', '/fake/pom.xml', + '-s', '/fake/settings.xml', + '-P', 'fake-profile1,fake-profile2', + '--no-transfer-progress', + _out=Any(StringIO), + _err=Any(StringIO) + ) + + @patch('sh.mvn', create=True) + @patch('ploigos_step_runner.utils.maven.create_sh_redirect_to_multiple_streams_fn_callback') + @patch("builtins.open", new_callable=mock_open) + def test_success_with_no_tls(self, mock_open, redirect_mock, mvn_mock): + with TempDirectory() as temp_dir: + mvn_output_file_path = os.path.join(temp_dir.path, 'maven_output.txt') + settings_file = '/fake/settings.xml' + pom_file = '/fake/pom.xml' + phases_and_goals = 'fake' + + run_maven( + mvn_output_file_path=mvn_output_file_path, + settings_file=settings_file, + pom_file=pom_file, + phases_and_goals=phases_and_goals, + tls_verify=False + ) + + mock_open.assert_called_with(mvn_output_file_path, 'w') + redirect_mock.assert_has_calls([ + call([ + sys.stdout, + mock_open.return_value + ]), + call([ + sys.stderr, + mock_open.return_value + ]) + ]) + + mvn_mock.assert_called_once_with( + 'fake', + '-f', '/fake/pom.xml', + '-s', '/fake/settings.xml', + '--no-transfer-progress', + '-Dmaven.wagon.http.ssl.insecure=true', + '-Dmaven.wagon.http.ssl.allowall=true', + '-Dmaven.wagon.http.ssl.ignore.validity.dates=true', + _out=Any(StringIO), + _err=Any(StringIO) + ) + + @patch('sh.mvn', create=True) + @patch('ploigos_step_runner.utils.maven.create_sh_redirect_to_multiple_streams_fn_callback') + @patch("builtins.open", new_callable=mock_open) + def test_success_transfer_progress(self, mock_open, redirect_mock, mvn_mock): + with TempDirectory() as temp_dir: + mvn_output_file_path = os.path.join(temp_dir.path, 'maven_output.txt') + settings_file = '/fake/settings.xml' + pom_file = '/fake/pom.xml' + phases_and_goals = 'fake' + + run_maven( + mvn_output_file_path=mvn_output_file_path, + settings_file=settings_file, + pom_file=pom_file, + phases_and_goals=phases_and_goals, + no_transfer_progress=False + ) + + mock_open.assert_called_with(mvn_output_file_path, 'w') + redirect_mock.assert_has_calls([ + call([ + sys.stdout, + mock_open.return_value + ]), + call([ + sys.stderr, + mock_open.return_value + ]) + ]) + + mvn_mock.assert_called_once_with( + 'fake', + '-f', '/fake/pom.xml', + '-s', '/fake/settings.xml', + None, + _out=Any(StringIO), + _err=Any(StringIO) + ) + + @patch('sh.mvn', create=True) + @patch('ploigos_step_runner.utils.maven.create_sh_redirect_to_multiple_streams_fn_callback') + @patch("builtins.open", new_callable=mock_open) + def test_success_failure(self, mock_open, redirect_mock, mvn_mock): + with TempDirectory() as temp_dir: + mvn_output_file_path = os.path.join(temp_dir.path, 'maven_output.txt') + settings_file = '/fake/settings.xml' + pom_file = '/fake/pom.xml' + phases_and_goals = 'fake' + + mvn_mock.side_effect = sh.ErrorReturnCode('mvn', b'mock stdout', b'mock error') + + with self.assertRaisesRegex( + StepRunnerException, + re.compile( + r"Error running maven." + r".*RAN: mvn" + r".*STDOUT:" + r".*mock stdout" + r".*STDERR:" + r".*mock error", + re.DOTALL + ) + ): + run_maven( + mvn_output_file_path=mvn_output_file_path, + settings_file=settings_file, + pom_file=pom_file, + phases_and_goals=phases_and_goals, + ) + + mock_open.assert_called_with(mvn_output_file_path, 'w') + redirect_mock.assert_has_calls([ + call([ + sys.stdout, + mock_open.return_value + ]), + call([ + sys.stderr, + mock_open.return_value + ]) + ]) + + mvn_mock.assert_called_once_with( + 'fake', + '-f', '/fake/pom.xml', + '-s', '/fake/settings.xml', + '--no-transfer-progress', + _out=Any(StringIO), + _err=Any(StringIO) + )