Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid using the scenario name as part of the hash to generate output … #164

Merged
merged 11 commits into from
Oct 15, 2024
Merged
11 changes: 11 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
Version History
===============================================================================

Version: 4.0.8
-------------------------------------------------------------------------------
ENHANCEMENTS:

* Enhanced parallel scenario execution management by utilizing scenario lines over scenario names. This allows running scenarios that might change their name without causing issues in parallel executions.

FIXES:

* Avoid using the scenario name as part of the hash to generate output paths, as if the scenario name is changed, the path does not match. Instead, the feature filename and the line where the scenario is located is used to generate the hash.


Version: 4.0.7
-------------------------------------------------------------------------------
ENHANCEMENTS:
Expand Down
7 changes: 4 additions & 3 deletions behavex/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from behavex.conf_mgr import get_env, get_param
from behavex.global_vars import global_vars
from behavex.outputs import report_json, report_xml
from behavex.outputs.report_utils import create_log_path
from behavex.outputs.report_utils import create_log_path, strip_ansi_codes
from behavex.utils import (LOGGING_CFG, create_custom_log_when_called,
get_autoretry_attempts, get_logging_level,
get_scenario_tags, get_scenarios_instances)
Expand Down Expand Up @@ -122,8 +122,8 @@ def before_scenario(context, scenario):
context.bhx_execution_attempts[scenario.name] = 0
execution_attempt = context.bhx_execution_attempts[scenario.name]
retrying_execution = True if execution_attempt > 0 else False
concat_feature_and_scenario_name = "{}-{}".format(str(context.feature.name), str(scenario.name))
context.log_path = create_log_path(concat_feature_and_scenario_name, retrying_execution)
concat_feature_and_scenario_line = "{}-{}".format(str(context.feature.filename), str(scenario.line))
context.log_path = create_log_path(concat_feature_and_scenario_line, retrying_execution)
context.bhx_log_handler = _add_log_handler(context.log_path)
if retrying_execution:
logging.info('Retrying scenario execution...\n'.format())
Expand Down Expand Up @@ -197,6 +197,7 @@ def _add_log_handler(log_path):
)
log_level = get_logging_level()
logging.getLogger().setLevel(log_level)
file_handler.addFilter(lambda record: setattr(record, 'msg', strip_ansi_codes(str(record.msg))) or True)
file_handler.setFormatter(_get_log_formatter())
logging.getLogger().addHandler(file_handler)
return file_handler
Expand Down
4 changes: 2 additions & 2 deletions behavex/outputs/jinja/main.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,8 @@
<th style="width: 180px;height: 24px" class="text-center">Evidence</th>
</tr>
{%- for scenario in feature.scenarios -%}
{%- set concat_feature_and_scenario_name = feature.name + "-" + scenario.name -%}
{%- set scenario_hash = concat_feature_and_scenario_name|get_string_hash -%}
{%- set concat_feature_and_scenario_line = feature.filename + "-" + scenario.line|string -%}
{%- set scenario_hash = concat_feature_and_scenario_line|get_string_hash -%}
<!-- scenario_hash has been forced to be a string -->
{%- set scenario_hash = scenario_hash|string -%}
{%- set scenario_tags = scenario|get_scenario_tags -%}
Expand Down
4 changes: 2 additions & 2 deletions behavex/outputs/jinja_mgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def _exist_extra_logs(scenario):
def get_path_extra_logs(scenario):
extra_logs_folder = os.path.join(
get_env('logs'),
str(get_string_hash("{}-{}".format(str(scenario["feature"]), str(scenario["name"])))),
str(get_string_hash("{}-{}".format(str(scenario["filename"]), str(scenario["line"])))),
'evidence',
)
return extra_logs_folder
Expand All @@ -132,7 +132,7 @@ def get_relative_extra_logs_path(scenario):
[
'outputs',
'logs',
get_string_hash("{}-{}".format(str(scenario["feature"]), str(scenario["name"]))),
get_string_hash("{}-{}".format(str(scenario["filename"]), str(scenario["line"]))),
'evidence',
]
)
Expand Down
13 changes: 6 additions & 7 deletions behavex/outputs/report_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
from behavex.outputs.report_utils import (get_environment_details,
get_error_message,
match_for_execution, text)
from behavex.utils import get_scenario_tags, try_operate_descriptor
from behavex.utils import (generate_hash, get_scenario_tags,
try_operate_descriptor)


def add_step_info(step, parent_node):
Expand Down Expand Up @@ -159,6 +160,7 @@ def _processing_scenarios(scenarios, scenario_list, id_feature):
if match_for_execution(scenario_tags):
# Scenario was selectable
scenario_info = {}
scenario_info['line'] = getattr(scenario, 'line')
scenario_info['name'] = getattr(scenario, 'name')
scenario_info['duration'] = getattr(scenario, 'duration')
scenario_info['status'] = getattr(scenario, 'status').name
Expand All @@ -179,7 +181,8 @@ def _processing_scenarios(scenarios, scenario_list, id_feature):
scenario_info['error_lines'] = error_lines
scenario_info['error_step'] = error_step
scenario_info['error_background'] = error_background
scenario_info['id_hash'] = _generate_hash(scenario.name)
scenario_info['id_hash'] = generate_hash("{}:{}".format(scenario.filename,
scenario.line))
if scenario.feature.name in global_vars.retried_scenarios:
if (
scenario.name
Expand Down Expand Up @@ -253,13 +256,9 @@ def _step_to_dict(index, step):
def process_step_definition(step, step_info):
definition = registry.find_step_definition(step)
if definition:
hash_step = _generate_hash(definition.pattern)
hash_step = generate_hash(definition.pattern)
if hash_step not in global_vars.steps_definitions:
global_vars.steps_definitions[hash_step] = definition.pattern
step_info['hash'] = hash_step
else:
step_info['hash'] = 0


def _generate_hash(word):
return abs(hash(word)) % (10 ** 8)
8 changes: 6 additions & 2 deletions behavex/outputs/report_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,11 @@ def gather_steps(features):


def gather_errors(scenario, retrieve_step_name=False):
error_msg = list(map(lambda line: strip_ansi_codes(line), scenario['error_msg']))
if retrieve_step_name:
return scenario['error_msg'], scenario['error_lines'], scenario['error_step']
return error_msg, scenario['error_lines'], scenario['error_step']
else:
return scenario['error_msg'], scenario['error_lines']
return error_msg, scenario['error_lines']


def pretty_print_time(seconds_float, sec_decimals=1):
Expand Down Expand Up @@ -449,3 +450,6 @@ def get_environment_details():
environment_details_raw_data = os.getenv('ENVIRONMENT_DETAILS', None)
environment_details = environment_details_raw_data.split(',') if environment_details_raw_data else []
return environment_details

def strip_ansi_codes(from_str: str):
return re.sub(r'\x1B\[[0-?9;]*[mGJK]', '', from_str)
Loading
Loading