holado 0.11.4__py3-none-any.whl → 0.11.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of holado might be problematic. Click here for more details.

@@ -333,15 +333,19 @@ class SessionContext(Context):
333
333
  log_prefix = f"[After scenario '{scenario.name}'] "
334
334
 
335
335
  with self.__multitask_lock:
336
+ # End scenario
337
+ if not self.has_feature_context(is_reference=True):
338
+ raise TechnicalException(f"{log_prefix}No feature context is defined")
339
+ if not self.has_scenario_context(is_reference=True):
340
+ raise TechnicalException(f"{log_prefix}No scenario context is defined")
341
+ self.get_scenario_context().end()
342
+
336
343
  # Log error on failing scenario
337
- category_validation, status_validation, step_failed, step_number = ReportManager.get_current_scenario_status_information(scenario)
344
+ category_validation, status_validation, step_failed, step_number, scenario_context, step_context = ReportManager.get_current_scenario_status_information(scenario)
338
345
  if status_validation != "Passed":
339
346
  msg_list = []
340
347
  category_str = f" => {category_validation}" if category_validation else ""
341
- if step_failed is not None:
342
- msg_list.append(f"Scenario {status_validation}{category_str}: [scenario in {scenario.filename} at l.{scenario.line} - step {step_number} (l.{step_failed.line})]")
343
- else:
344
- msg_list.append(f"Scenario {status_validation}{category_str}: [scenario in {scenario.filename} at l.{scenario.line} - step ? (missing step implementation ?)]")
348
+ msg_list.append(f"Scenario {status_validation}{category_str}: {ReportManager.format_context_period(scenario_context)} {ReportManager.format_scenario_short_description(scenario)} - {ReportManager.format_step_short_description(step_failed, step_number, step_context, dt_ref=scenario_context.start_datetime)}")
345
349
  step_error_message = ReportManager.get_step_error_message(step_failed)
346
350
  if step_error_message:
347
351
  msg_list.append(step_error_message)
@@ -359,13 +363,6 @@ class SessionContext(Context):
359
363
  # MemoryProfiler.log_tracker_diff(name="scenarios objects", prefix="[After scenario] ", level=logging.INFO, logger_=logger) # @UndefinedVariable
360
364
  GlobalSystem.log_resource_usage(prefix=log_prefix, level=logging.INFO, logger_=logger)
361
365
 
362
- if not self.has_feature_context(is_reference=True):
363
- raise TechnicalException(f"{log_prefix}No feature context is defined")
364
- if not self.has_scenario_context(is_reference=True):
365
- raise TechnicalException(f"{log_prefix}No scenario context is defined")
366
-
367
- self.get_scenario_context().end()
368
-
369
366
  # Post processes
370
367
  logger.info(f"{log_prefix}Post processing...")
371
368
  self.get_scenario_context().scope_manager.reset_scope_level()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: holado
3
- Version: 0.11.4
3
+ Version: 0.11.5
4
4
  Summary: HolAdo framework
5
5
  Project-URL: Homepage, https://gitlab.com/holado_framework/python
6
6
  Project-URL: Issues, https://gitlab.com/holado_framework/python/-/issues
@@ -4,7 +4,7 @@ holado/common/__init__.py,sha256=ZjXM-FRQgnfzRNXqcvJOGewDHVRR-U5-ugStSs8U2Xs,152
4
4
  holado/common/context/__init__.py,sha256=3jJBLm8myrYF9jbdV1EhIA6BtnlmjX33eeoDpTzwmLA,1604
5
5
  holado/common/context/context.py,sha256=MV8A6JSpUcTcfia_QzjyDLybQC50rZ-NA0ffotnHXQY,11994
6
6
  holado/common/context/service_manager.py,sha256=LaCn8ukE1aqJynmwoexAYj5hCkdb_F3hXRtUBGqorUE,14087
7
- holado/common/context/session_context.py,sha256=IWxkeYnMSVImNyamTd3PXZSFIkXY96qFyAlC1y8s0J4,23475
7
+ holado/common/context/session_context.py,sha256=PhdnA7mcNRW3N0CCOmnvHNc8eG9lSEqYRs9AwP0Fnlc,23414
8
8
  holado/common/handlers/__init__.py,sha256=d0KDUpaAAw1eBXyX08gaRh4RECnJlXjYQ0TcU-Ndicc,1372
9
9
  holado/common/handlers/enums.py,sha256=ieqKVoukEiNyfE3KrKmMOImdbFS1ocUMud8JHe2xNLs,1662
10
10
  holado/common/handlers/object.py,sha256=rDaav8zHTYfKVEaLtEdeXMxYXATGVcs2a7um1f5MvCs,7205
@@ -313,7 +313,7 @@ holado_protobuf/tests/behave/steps/ipc/protobuf_steps.py,sha256=Pbw5E-AbTTSKR_i_
313
313
  holado_python/__init__.py,sha256=DuWuDU7MxVsAOz1G6TiYRRsIhApFWMNNwA8Xwp0LhtU,1658
314
314
  holado_python/common/enums.py,sha256=iwffWOqUdiFaOn83RPmjRVVHakTjQve55sNsbY4x8Ek,1535
315
315
  holado_python/common/iterables.py,sha256=p5X6h18W-GSnZ4WHt5Y5g3Ri4TB4B5i5NhyAwb7g1Ww,2064
316
- holado_python/common/tools/datetime.py,sha256=h6dcKnBikFH5V2EK688zG6poeLPhXYdudiITsraG2aI,13453
316
+ holado_python/common/tools/datetime.py,sha256=bjalKiY_2NKeb3ouhGxcJWGeDHx04DuGwsi1w-88Oh4,13765
317
317
  holado_python/common/tools/comparators/boolean_comparator.py,sha256=66AtqQ1u7NLTKAmgZHdnbE8vMPfgwJ2ZrzMiea90jX0,2042
318
318
  holado_python/common/tools/comparators/bytes_comparator.py,sha256=VKD5Q734n1k5Q0zX14fYgvM-66ysyRWkjo2fLgleyt0,2412
319
319
  holado_python/common/tools/comparators/datetime_comparator.py,sha256=6smSvQ7ErnNuBNHkSbkf4HoSUJU54DNS2ILhxM1FHAk,3487
@@ -336,8 +336,8 @@ holado_python/standard_library/ssl/resources/certificates/NOTES.txt,sha256=GlPGG
336
336
  holado_python/standard_library/ssl/resources/certificates/localhost.crt,sha256=iLmZpDuOQVawUlbZkb72g2-uv1c4SAmRJOrm4Th5anY,1123
337
337
  holado_python/standard_library/ssl/resources/certificates/localhost.key,sha256=lP2NCvB9mr2E5sk8whA8FyQRcyU6H7sdWkJeKz80Hyc,1704
338
338
  holado_python/standard_library/ssl/resources/certificates/rootCACert.pem,sha256=ECQDZ8OHRfqpZHCu6JRLMUjiONaPIhKZQF0-kidVrWQ,1424
339
- holado_python/standard_library/ssl/resources/certificates/tcpbin.crt,sha256=wfv4sQssCQ8BGpJQGCrhSCB2jW1Te9rzWaqpnBM05Yc,1237
340
- holado_python/standard_library/ssl/resources/certificates/tcpbin.key,sha256=yrGFLYQ1i12IUjwX8tp6Su1rMYZINA6dzUa76elo5h0,1704
339
+ holado_python/standard_library/ssl/resources/certificates/tcpbin.crt,sha256=phGEtgs44UXM0-8PpQbCDI378uJ4IwA4CKmbgZmgmnE,1237
340
+ holado_python/standard_library/ssl/resources/certificates/tcpbin.key,sha256=jwmluX8OxRIKf9X6KFRAL4ZXQ2Nb07fbmGIydyRz1B8,1704
341
341
  holado_python/tests/behave/steps/__init__.py,sha256=TWEk-kBTTDHi9I4nuu48nufmNMdZ9FHAhPZv0A_cWzc,1661
342
342
  holado_python/tests/behave/steps/convert_steps.py,sha256=bZqRvJVp_u6fSPpdu4ne9NwVyZmui7R-AVdO2-H-I1A,2728
343
343
  holado_python/tests/behave/steps/iterable_steps.py,sha256=f4vGIWBH8Qnjq69Q-ZBluYyctQ8SKauazTc41dsktZA,4041
@@ -364,22 +364,22 @@ holado_redis/tests/behave/steps/tools/redis_client_steps.py,sha256=lOh0YlumJcszt
364
364
  holado_redis/tools/redis/TODO.txt,sha256=cmFyx6qS6_FgL1Ph0OWRsWch6MQaklfv1j0qBO2ZpZU,202
365
365
  holado_redis/tools/redis/redis_client.py,sha256=KWuOrnwTcwt5xkD3rtI_l07v164Y_bsoo1kE0IGzqaQ,8316
366
366
  holado_redis/tools/redis/redis_manager.py,sha256=tMO0XrCZTCfGdByFfgWXk9R-I_TUPLO9wXMQf8yCYcQ,1814
367
- holado_report/__init__.py,sha256=3wtu5g9d4d-AICmLZclPQrw2MS-FJL9CyiVO1n2MYWA,1868
368
- holado_report/campaign/campaign_manager.py,sha256=fZtxvtFc7_BZm3KGZNMYh0p8SJ-znEX89MlEY6Gp3aE,8748
369
- holado_report/report/execution_historic.py,sha256=M4lYoZwyrSivRa17Q39GOAgROnr0oBvIZX5BNcO5Mnc,6951
370
- holado_report/report/report_manager.py,sha256=jOCWa4OxXgYSGimy0hnueKW7PqPOnM80at5NNQgJa4I,16878
367
+ holado_report/__init__.py,sha256=dNP5UmrdXFTibffSkWUM0D0NEdhRDq7DPrND4pbY0Io,1917
368
+ holado_report/campaign/campaign_manager.py,sha256=v6_dywd_KGcx6qQuI8EWBq8qS-A_tDXzcP_pHyCur8w,9217
369
+ holado_report/report/execution_historic.py,sha256=bF8TKU0icsGXm6Up4secmJ2Z07oGzMYD5YGUZOLXIAY,6983
370
+ holado_report/report/report_manager.py,sha256=qRENdptYi0ulKsg2mS5pGBhdJ1-iTCB345ESB8DgNsU,20320
371
371
  holado_report/report/analyze/execution_historic_manager.py,sha256=FMKKPguXOvWNxjF7Q8DodHHsH-2ci9pFzrTV41B8nL4,4556
372
372
  holado_report/report/analyze/scenario_duration_manager.py,sha256=Preaxu83qFKGfbvQnzolhSXztZ4i5Zo_Bnxx8tNA80Q,12468
373
- holado_report/report/builders/detailed_scenario_failed_report_builder.py,sha256=hOXxHYniL9mpN-U7YTW5xVEaE4Z-GlPq8ltT_iNJan4,7892
374
- holado_report/report/builders/failure_report_builder.py,sha256=WLLlLgLbEyYJNENEoxSkQQSf11DDoKpSa4kdaq7eV8U,6533
375
- holado_report/report/builders/json_execution_historic_report_builder.py,sha256=M7OGUvkqNRTG5Td7fO96tv1SJEzRzjm0pl1W02v052E,5929
373
+ holado_report/report/builders/detailed_scenario_failed_report_builder.py,sha256=JJ6bpMWk7cOQ2Z1Q-fpbCEJmi2WGEYgJq_Aj1xfxot0,8613
374
+ holado_report/report/builders/failure_report_builder.py,sha256=4yBE_KU1gJFI6wAEBDFTqU5r5R7SeckUls2jHDmKCW4,6983
375
+ holado_report/report/builders/json_execution_historic_report_builder.py,sha256=9urkQcEEgZXeNABFwzBF2iMhxEXMiYGp-cvH9pqAEiE,6271
376
376
  holado_report/report/builders/report_builder.py,sha256=5qlhxbdTkSN7p9q6EADkpHQGPDVEHquIhgA3mK2Ck2k,2261
377
- holado_report/report/builders/short_scenario_failed_report_builder.py,sha256=50pXhWX8xwIDZWSFaBejzMUlS9a0GRXqA82d84V3udk,4012
378
- holado_report/report/builders/summary_by_category_report_builder.py,sha256=5i_zWxIYabiFcMs0De3JDa4YptfDIbFYkVkvaXDRX5M,4496
379
- holado_report/report/builders/summary_report_builder.py,sha256=v4LG3W5x_y4FH0kh_5MRaG8pyPOV2GfhlBImsW4BJrs,3954
380
- holado_report/report/builders/summary_scenario_by_category_report_builder.py,sha256=1rzuF4KFPzO5jFuvC_OKvsnNMRrzW3zG5nU5GUSux1U,4274
381
- holado_report/report/builders/summary_scenario_failed_report_builder.py,sha256=uqf86SUAiIQLRQOV0A434oR8Bj4e_DtxqRsy-pe84p4,3063
382
- holado_report/report/builders/summary_scenario_report_builder.py,sha256=ZtOg5SWgFUsOJyG-KLybT-8twTX3CwmuFTVIaWJXXZ8,3865
377
+ holado_report/report/builders/short_scenario_failed_report_builder.py,sha256=mlLyekgq8hKQ1bcseTUMdNKOaTZVL8qeI7fUyk6nRak,4147
378
+ holado_report/report/builders/summary_by_category_report_builder.py,sha256=aLHgOQI7NcMs0lxA8UnzNm5jAEI2bWIgA5Rh0M0hb3A,4502
379
+ holado_report/report/builders/summary_report_builder.py,sha256=Qzh9VsRINv_XVijnJxpU_5JOHpKsQQo9f94MgkCDSLE,3960
380
+ holado_report/report/builders/summary_scenario_by_category_report_builder.py,sha256=_pqce8vi6gXxPQsw8GNSau-gGlkLCDg9TswNNutt8Io,4227
381
+ holado_report/report/builders/summary_scenario_failed_report_builder.py,sha256=LJ1nNAjC8uRRildxSKps4WyIO5JPZKVlApSN_jXAXeY,3073
382
+ holado_report/report/builders/summary_scenario_report_builder.py,sha256=QKG-LabVsImX2npmSXDAjDDP9q84SAICvf6J4rI9QMQ,4082
383
383
  holado_report/report/reports/base_report.py,sha256=NGnWe66uyvT4bCjhd3upwVpc6yQ2gyVNFhcy-3LeQsE,6850
384
384
  holado_report/report/reports/feature_report.py,sha256=i0wpk3LQLArVjWDsP9UcNSJzAUWwLhe73HNyfye2gYQ,4810
385
385
  holado_report/report/reports/scenario_report.py,sha256=eMyqw9EzaKMmX3pGFJN1rqAOQ5eqO2ISZdxAfK3XQR4,2945
@@ -680,7 +680,7 @@ test_holado/tools/django/api_rest/api_rest/api1/serializers.py,sha256=o_YxFr-tgC
680
680
  test_holado/tools/django/api_rest/api_rest/api1/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
681
681
  test_holado/tools/django/api_rest/api_rest/api1/views.py,sha256=kOt2xT6bxO47_z__5yYR9kcYIWWv4qYzpX0K8Tqonik,758
682
682
  test_holado/tools/django/api_rest/api_rest/api1/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
683
- holado-0.11.4.dist-info/METADATA,sha256=w4vz367qdwA3K6pb1rwff-SLW8-4ivNAkAr_kuff5mc,7660
684
- holado-0.11.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
685
- holado-0.11.4.dist-info/licenses/LICENSE,sha256=IgGmNlcFHnbp7UWrLJqAFvs_HIgjJDTmjCNRircJLsk,1070
686
- holado-0.11.4.dist-info/RECORD,,
683
+ holado-0.11.5.dist-info/METADATA,sha256=3OtsrMJ9qwxe0NGZLLS2F7eVdjCalvrbe39uaU6nxkc,7660
684
+ holado-0.11.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
685
+ holado-0.11.5.dist-info/licenses/LICENSE,sha256=IgGmNlcFHnbp7UWrLJqAFvs_HIgjJDTmjCNRircJLsk,1070
686
+ holado-0.11.5.dist-info/RECORD,,
@@ -38,6 +38,8 @@ EPOCH_JULIAN_NASA = datetime.datetime(year=1968, month=5, day=24, tzinfo=datetim
38
38
  FORMAT_DATETIME_ISO = '%Y-%m-%dT%H:%M:%S.%fZ'
39
39
  FORMAT_DATETIME_ISO_SECONDS = '%Y-%m-%dT%H:%M:%SZ'
40
40
  FORMAT_DATETIME_HUMAN_SECOND = '%Y-%m-%d %H:%M:%S'
41
+ FORMAT_TIME_ISO = '%H:%M:%S.%f'
42
+ FORMAT_TIME_ISO_SECONDS = '%H:%M:%S'
41
43
 
42
44
  TIMEZONE_LOCAL = datetime.datetime.now().astimezone().tzinfo
43
45
  TIMEZONE_UTC = datetime.timezone.utc
@@ -331,8 +333,9 @@ class DateTime(object):
331
333
 
332
334
  return dt_src - DateTime.utc_to_tai_timedelta()
333
335
 
334
-
335
-
336
-
337
-
336
+ @classmethod
337
+ def truncate_datetime(cls, dt, precision_nanoseconds=1):
338
+ total_us = cls.datetime_to_timestamp(dt) * 1e9
339
+ trunc_total_us = total_us // precision_nanoseconds * precision_nanoseconds
340
+ return cls.timestamp_to_datetime(trunc_total_us / 1e9)
338
341
 
@@ -2,20 +2,20 @@
2
2
  MIIDZTCCAk2gAwIBAgIBKjANBgkqhkiG9w0BAQsFADCBizELMAkGA1UEBhMCVVMx
3
3
  CzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKDAZ0
4
4
  Y3BiaW4xDDAKBgNVBAsMA29wczETMBEGA1UEAwwKdGNwYmluLmNvbTEjMCEGCSqG
5
- SIb3DQEJARYUaGFycnliYWdkaUBnbWFpbC5jb20wHhcNMjUxMDI3MDkyNzQ4WhcN
6
- MjUxMDI4MDkyNzQ4WjAcMRowGAYDVQQDDBF0Y3BiaW4uY29tLWNsaWVudDCCASIw
7
- DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMDSXOJuPmc0k1e7OMyWKhIxcC44
8
- wmG71lF8E/F11DW+yw3iiJ95ZvkiLuVEGnkMFS+iJJ0LLvCsNq71yVggbeEhRCVe
9
- vY0RmfZMY3BA27ru3d4QK5Xuffb8eg8x3KRSaeD47ZFATzL5j4EVhsTLe5L2hOIE
10
- ZAuc1C+mHbGdr23o2r9CqGLq3gl7JNRSjfOzzS1pvgoj/C6vsMViJutx0MYCd2Z6
11
- 4CfPfRO0L1JXzU9GPq1HIDFUDEnopdMALA6KSRSOt0qLChKgKFqRS954e2PZYxwO
12
- XqvHwD1vGwMl6t1gprSpsAPuaEv/1l8iuA7zHL1jiIergwsLDad1flFSulkCAwEA
13
- AaNCMEAwHQYDVR0OBBYEFFaEMYPq4DeN+4OAfat4KVqgrWVLMB8GA1UdIwQYMBaA
14
- FOLuMowBSAZfV5v82LmlaIIOvU/DMA0GCSqGSIb3DQEBCwUAA4IBAQAi3cHZCPtV
15
- LgOXO4+5Z26Jx4wnqKmsWfEqdXKwcpTm5NKa+pyFcswNRAzk6HL6x2Bd1VO2tT71
16
- PnDz6/YJWdJqzkCCCInPs5dvptE3ByFAG8nXGi+TE7FzQW8Pa5/d6Vcglxj6269B
17
- rWdwfDZoFnSJAkRkTbeY6It1kqJB54+DIqVZNtVCQ7axh0Trpzk4B7QjHMvKJlwz
18
- FPycVbH51IXYts9uHEtT5gdpSXA4hKuEc/p5kRkzomS/8vAolyh6lqkAMGly1tza
19
- wTpCnzC6pZOJXinN75KplX5f+Wk4aMlchpocVqTPlTjHAzy/DceCGPieGgpx1EhG
20
- TQm3tdNDnLkY
5
+ SIb3DQEJARYUaGFycnliYWdkaUBnbWFpbC5jb20wHhcNMjUxMDI5MTIwMzM4WhcN
6
+ MjUxMDMwMTIwMzM4WjAcMRowGAYDVQQDDBF0Y3BiaW4uY29tLWNsaWVudDCCASIw
7
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN7qgObpLDNcyQwO1SAw580Zs9qE
8
+ QbyBNvKeYsI02n9TcLbqo/4PUtFgUeI4uiWp2AgXrQOSsYpOfUibqPZX2ERIlTsP
9
+ ZLintHRQ35oWLzocteGv8rAEy3X1mG9LULOEFXmn8Ae410z1ULh0tOE65XW1jMAH
10
+ xgJCMxDwdH8ZhPVD+4KePgluv7cz6nWNsroN+injaJCIDNZUBD0MMkR41gvv86AR
11
+ Vm60sVSlnmoExD9xJaPMfA6Wh3Q0fQSazrAtznGgLl/C7Yb6xqBT1V5wTofctzs4
12
+ bdKJmr8Mq5dOy8J3kBt6KbQNpw+/OP+uDgPVO4HannXpdoCXrCgmeCElmKMCAwEA
13
+ AaNCMEAwHQYDVR0OBBYEFEioQrAa0ViJpdokrFKGzn1HHlNvMB8GA1UdIwQYMBaA
14
+ FOLuMowBSAZfV5v82LmlaIIOvU/DMA0GCSqGSIb3DQEBCwUAA4IBAQCQS60nEPW0
15
+ cJsl1jGTR+F3oUiWpdnZtJO6jAuQAZ1s7/dwgK3vUMesWwSwZIIdyZcHSfAn/Su6
16
+ HcJMUkL7okUmS5hM/cQ8VNTiyImqmxP84NIzP+ZZpBN7/gkrwVRrQbcsfLGYE6NO
17
+ VfozTdT7KMYZVjdyKuKV0gS2OFEhGH1fWrX04lXGmfOGLLCkNqjg0SSO4LThJCFV
18
+ vOHEGYADuKdXpRV3ffN0NiBmhcHKapHynqVbkAhK1dC6s7ml/xIBuYn5o5X5I9er
19
+ g3Jmhz/XZvWbsi5OwzMMP2Z9w2FaEvilhJriIy9S+BW5eb3C9kpRZk4tvZVFrFVW
20
+ hL8GIS9XOL4C
21
21
  -----END CERTIFICATE-----
@@ -1,28 +1,28 @@
1
1
  -----BEGIN PRIVATE KEY-----
2
- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDA0lzibj5nNJNX
3
- uzjMlioSMXAuOMJhu9ZRfBPxddQ1vssN4oifeWb5Ii7lRBp5DBUvoiSdCy7wrDau
4
- 9clYIG3hIUQlXr2NEZn2TGNwQNu67t3eECuV7n32/HoPMdykUmng+O2RQE8y+Y+B
5
- FYbEy3uS9oTiBGQLnNQvph2xna9t6Nq/Qqhi6t4JeyTUUo3zs80tab4KI/wur7DF
6
- YibrcdDGAndmeuAnz30TtC9SV81PRj6tRyAxVAxJ6KXTACwOikkUjrdKiwoSoCha
7
- kUveeHtj2WMcDl6rx8A9bxsDJerdYKa0qbAD7mhL/9ZfIrgO8xy9Y4iHq4MLCw2n
8
- dX5RUrpZAgMBAAECggEBAKPrse8EzaQrO/9fOEAkgIuK39VLh2RSrTYEh2fERa2T
9
- D0g0hvUb3gB5oOhi5yZ0sSYXb4zaTwNnQ+2lIY/7sa2r/CTQz8+3YO3Trs1lNedK
10
- 3e7ETGlfoFJx/MoiF3LSZRROSpgq1al+IxMX28Q9QEaFsB38oZiFsJT5YVD3voVt
11
- 7jYr/yE6A7Nuq4A8EmpXTqNqdIGlBQ5Iq865KfUmqEM7vAJDzo/NPCf3CeCe5yzU
12
- 31sL/odZpj0MJWsFe6P9k932cd47VdXZ84XCcXQHEkKZ6AVwv+EBQfSMfBJUp4pw
13
- 4Cd112jzJR0Gdew6BTwytPHM55Pm7sx3Kx2/+1lr7CECgYEA8fqe1b6HXCC7RUDD
14
- J2XDkPZbLdyjqWW0mGVps7xX3371BVndXjWTmrKgtLS64XclW9coLGhJMlNel7pO
15
- dadC24naHF3qNXsTITgz9VJWG5MSNrzDHg4ZzYxllFxm1j7DiorDa4umzHu0w0d1
16
- 7WUZFPP9fm3jlB5dv80HBSWIpWUCgYEAy/6SSGBJfv+hYJjPOtrneQxUGkpnw9mr
17
- tqA4l2+vMlLJs6xvjgqytV8MgTAc750ASf3/lug497m/PlGxvwj6GwwT8zUhUmBb
18
- pRJBS2EwHvJBcyeu2GVJJAqnbmoEVdywV21VjUSJ5PH5zg48wJAaJspttOOmmUTt
19
- Ou+6eh7Ou+UCgYBbm8EENKR0KWQcfL8lLC6Us9+jBjPjjsCHLWWOCRDPaPYD95iJ
20
- 8QiXeWbD4uQZNY0sLtFjtnt3lP5rvLm1awQxrwem05s2cgi0+90X0/sLZ2tu05me
21
- yEHWgn92YmEAXTSUP6JqFa2pHnA5udUYcbzEJPbkJWASFEjzswAkX6hSzQKBgFpV
22
- 67W9Xg6taWt7gBmSIvtJ6FyUIotqc042eZkmTjE81DGK5QPD3QvQgZscEVRS9HPP
23
- 1UWgpMmfKf+Q8eOlOAyONq93EcCHB058XQniigrKQQ2bvyP5BoC9bxPIQw864aR1
24
- uHMMrPwD5BnJ2EF2Dv6qmhaG0ZoCGgQFcVDvH6G5AoGAfrF8W04Is7Q0eSF6D296
25
- BZgICLCNJUykBGp2jXecOHelpKBsSH95mPrwcUHxyxZJhp1iMdua5IAyyS0LkvDX
26
- ElsFK7kaMbHJPvBhjhWXvB331qJAVjhnYuyiDENEuDJy40+dj+MXN0RFg7fGkz4a
27
- m0HQFSt8G76mGDV6eQ+xdrc=
2
+ MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDe6oDm6SwzXMkM
3
+ DtUgMOfNGbPahEG8gTbynmLCNNp/U3C26qP+D1LRYFHiOLolqdgIF60DkrGKTn1I
4
+ m6j2V9hESJU7D2S4p7R0UN+aFi86HLXhr/KwBMt19ZhvS1CzhBV5p/AHuNdM9VC4
5
+ dLThOuV1tYzAB8YCQjMQ8HR/GYT1Q/uCnj4Jbr+3M+p1jbK6Dfop42iQiAzWVAQ9
6
+ DDJEeNYL7/OgEVZutLFUpZ5qBMQ/cSWjzHwOlod0NH0Ems6wLc5xoC5fwu2G+sag
7
+ U9VecE6H3Lc7OG3SiZq/DKuXTsvCd5Abeim0DacPvzj/rg4D1TuB2p516XaAl6wo
8
+ JnghJZijAgMBAAECggEAWv1/tkGRYDnMetaHGke8JpUKO/TmXEqmIiyShVFLqtNl
9
+ W9S1MdwRYxOc+OlM2ljUrKD1Z1L2k0zsiLm5IyzCQ0UZXO0woMsbtqrYSq4pgt/7
10
+ Qe8u8bhTUIf6O9uTSmNs3Ka3LH+/qlMsKs7AknsW9JAxrqS9p2hcLdrowoSpJ+9f
11
+ 7InJg8+vPoO6hCdumRcCOsy1jREP2Bb2sWZDLOmdlXBsdPdgQBsbbvJ4tVmhDwjo
12
+ KuTKyVtQvkwxc8qqCf0ocXSoKPmh3WTztqfs3VyGYyDZHw0kI0sH2wULHQbyrhrd
13
+ cFmq65VzrjkLeBXn6gzspQ1tjEIn4rN4QZeT5J+HoQKBgQDyf5Z+rnzb1PglFN5H
14
+ HuY8hY9hYX0obnynGgg/Lo8J78RsF0YwDK+1I9641ZnbZfef2Au+UD/EFWLT2kXI
15
+ MgkUrH103R3BXCRBGDrqfNEJE+QoM3Vo6LHP+pOcDI3EuLifLpu11iNxeza+stIP
16
+ GG7MJxMxJ8Kk/y+0ydJP7iOasQKBgQDrU801enTD7bBPmqPaV5FlrcFISe/s8Lz4
17
+ +fikZsx2GMNdJXExPWvfroijryveq6e2vMlFWGHJWuy59dwzEmfOLSrTBtpkMDVW
18
+ Z4j0eh8p5T7iYjjUlQZWfDGS0afVS0ik990SbOb9yD2z6KasV7sopOB0pfTwhbpt
19
+ 2cyPDYdVkwKBgEMO60QO5nI4G4LNmYYbUlnMKVEpj1295/Shq0QlkOKTjkLB0OP6
20
+ riAuUinUz54vPWHTcbPoJyoHK/QfuQpaY852wJ6vgsn0vAXQOIKdj4SuHnrLeB1R
21
+ s9IqneUaR53t4wgJ8H9BPz3jb8keVB5eiE0mRRVjxFyyQLQC14jI9smRAoGBAKKX
22
+ zyRRDJZHBtepb+avND19lRr+QvCB0P9xrzLf+Arsxyb3dMLhvkPZUn1NzdDW51Ui
23
+ ESqBi2bVFNTTo6YB5IkWugz+IiyxBllBxeWs7xVCWHWQCdYPdUaSHqpjg0Oi9XlN
24
+ 7IgLiHn2PXOtnmNbZmwJpy/RbnA05X96yZRZc5VTAoGBAOlOjnENg8STyhKSCj+9
25
+ wwYOAx/ks6LBRVbeP+mz13jxbyWQeTZyxzghcTWkVHubAR8DVacgtRMqaZz/WqIY
26
+ LROx47E/N7C3vTW4RLdPOT0hHVpEEoxzsUW2fKalvCyX8xDN9bO1n6OKBpqAocfk
27
+ CPXz80n1EOuohfZnmD8rTQf0
28
28
  -----END PRIVATE KEY-----
holado_report/__init__.py CHANGED
@@ -18,6 +18,7 @@ def configure_module():
18
18
  from holado_python.common.tools.datetime import TIMEZONE_UTC
19
19
 
20
20
  Config.report_timezone = TIMEZONE_UTC
21
+ Config.report_compact_datetime_period = True
21
22
 
22
23
  def dependencies():
23
24
  return ["holado_multitask"]
@@ -18,6 +18,7 @@ from holado_python.common.tools.datetime import DateTime, TIMEZONE_LOCAL
18
18
  import os
19
19
  from holado_system.system.filesystem.file import File
20
20
  import re
21
+ from holado_core.common.exceptions.technical_exception import TechnicalException
21
22
 
22
23
 
23
24
  logger = logging.getLogger(__name__)
@@ -179,13 +180,21 @@ class CampaignManager(object):
179
180
  file_path = os.path.join(report_path, 'report_summary_scenario_all.txt')
180
181
  lines = File(file_path, mode='rt').readlines(strip_newline=True)
181
182
 
183
+ regex_line_period = re.compile(r"^\[.+ - ([^\]]+)\] (.+) - (.*)$")
184
+ regex_line_time = re.compile(r"^(.+) - (.+) - (.+)$")
185
+ regex_status = re.compile(r"^(.*?)(?: \(.*\)| => .*)?$")
186
+
182
187
  for line in lines:
183
- parts = line.split(' - ')
184
- status_dt_str = parts[0]
185
- scenario_name = parts[1]
186
- status_info = parts[-1]
188
+ m = regex_line_period.match(line)
189
+ if not m:
190
+ m = regex_line_time.match(line)
191
+ if not m:
192
+ raise TechnicalException(f"Unexpected line format in {file_path}: [{line}]")
193
+ status_dt_str = m.group(1)
194
+ scenario_name = m.group(2)
195
+ status_info = m.group(3)
187
196
 
188
- m = re.match(r"^(.*?)(?: \(.*\)| => .*)?$", status_info)
197
+ m = regex_status.match(status_info)
189
198
  status = m.group(1)
190
199
 
191
200
  self.update_or_add_campaign_scenario(camp_id, scenario_name, status=status, status_at_str=status_dt_str)
@@ -33,10 +33,10 @@ class DetailedScenarioFailedReportBuilder(ReportBuilder):
33
33
 
34
34
  def after_scenario(self, scenario, scenario_report=None):
35
35
  from holado_report.report.report_manager import ReportManager
36
- category_validation, status_validation, step_failed, step_number = ReportManager.get_current_scenario_status_information(scenario)
36
+ category_validation, status_validation, step_failed, step_number, scenario_context, step_context = ReportManager.get_current_scenario_status_information(scenario)
37
37
 
38
38
  if status_validation != "Passed":
39
- self.__file_fail_add_scenario(scenario, scenario_report, category_validation, status_validation, step_failed, step_number)
39
+ self.__file_fail_add_scenario(scenario, scenario_report, category_validation, status_validation, step_failed, step_number, scenario_context, step_context)
40
40
 
41
41
  def after_all(self):
42
42
  # Manage file fail
@@ -44,13 +44,13 @@ class DetailedScenarioFailedReportBuilder(ReportBuilder):
44
44
  self.__file_fail.close()
45
45
  self.__file_fail = None
46
46
 
47
- def __file_fail_add_scenario(self, scenario, scenario_report, category_validation, status_validation, step_failed, step_number):
47
+ def __file_fail_add_scenario(self, scenario, scenario_report, category_validation, status_validation, step_failed, step_number, scenario_context, step_context):
48
48
  if self.__is_format_xml:
49
- self.__file_fail_add_scenario_xml(scenario, scenario_report, category_validation, status_validation, step_failed, step_number)
49
+ self.__file_fail_add_scenario_xml(scenario, scenario_report, category_validation, status_validation, step_failed, step_number, scenario_context, step_context)
50
50
  else:
51
- self.__file_fail_add_scenario_txt(scenario, scenario_report, category_validation, status_validation, step_failed, step_number)
51
+ self.__file_fail_add_scenario_txt(scenario, scenario_report, category_validation, status_validation, step_failed, step_number, scenario_context, step_context)
52
52
 
53
- def __file_fail_add_scenario_xml(self, scenario, scenario_report, category_validation, status_validation, step_failed, step_number):
53
+ def __file_fail_add_scenario_xml(self, scenario, scenario_report, category_validation, status_validation, step_failed, step_number, scenario_context, step_context):
54
54
  from holado_report.report.report_manager import ReportManager
55
55
 
56
56
  self.__open_file_if_needed()
@@ -59,6 +59,7 @@ class DetailedScenarioFailedReportBuilder(ReportBuilder):
59
59
  msg_list.append(f" <file>{scenario.filename} - l.{scenario.line}</file>")
60
60
  msg_list.append(f" <feature>{scenario.feature.name}</feature>")
61
61
  msg_list.append(f" <scenario>{scenario.name}</scenario>")
62
+ msg_list.append(f" <scenario_period>{ReportManager.format_context_period(scenario_context)}</scenario_period>")
62
63
  msg_list.append(f" <report>{scenario_report.report_path}</report>")
63
64
  msg_list.append(f" <tags>-t " + " -t ".join(scenario.feature.tags + scenario.tags) + "</tags>")
64
65
  if category_validation:
@@ -68,6 +69,8 @@ class DetailedScenarioFailedReportBuilder(ReportBuilder):
68
69
  msg_list.append(f" <failure>")
69
70
  msg_list.append(f" <step_number>{step_number}</step_number>")
70
71
  msg_list.append(f" <step_line>{step_failed.line}</step_line>")
72
+ if step_context is not None:
73
+ msg_list.append(f" <step_period>{ReportManager.format_context_period(step_context)}</step_period>")
71
74
  step_descr = ReportManager.get_step_description(step_failed)
72
75
  if "\n" in step_descr:
73
76
  msg_list.append(f" <step>")
@@ -104,7 +107,7 @@ class DetailedScenarioFailedReportBuilder(ReportBuilder):
104
107
  self.__file_fail.write(msg)
105
108
  self.__file_fail.flush()
106
109
 
107
- def __file_fail_add_scenario_txt(self, scenario, scenario_report, category_validation, status_validation, step_failed, step_number):
110
+ def __file_fail_add_scenario_txt(self, scenario, scenario_report, category_validation, status_validation, step_failed, step_number, scenario_context, step_context):
108
111
  from holado_report.report.report_manager import ReportManager
109
112
 
110
113
  self.__open_file_if_needed()
@@ -113,6 +116,7 @@ class DetailedScenarioFailedReportBuilder(ReportBuilder):
113
116
  msg_list.append(f" Feature: {scenario.feature.name}")
114
117
  msg_list.append(f" Scenario: {scenario.name}")
115
118
  msg_list.append(f" Report: {scenario_report.report_path}")
119
+ msg_list.append(f" Scenario period: {ReportManager.format_context_period(scenario_context)}")
116
120
  msg_list.append(f" Tags: -t " + " -t ".join(scenario.feature.tags + scenario.tags))
117
121
  if category_validation:
118
122
  msg_list.append(f" Validation category: {category_validation}")
@@ -120,6 +124,7 @@ class DetailedScenarioFailedReportBuilder(ReportBuilder):
120
124
  if step_failed is not None:
121
125
  msg_list.append(f" Failure:")
122
126
  msg_list.append(f" Step number-line: {step_number} - l.{step_failed.line}")
127
+ msg_list.append(f" Step period: {ReportManager.format_context_period(step_context)}")
123
128
  step_descr = ReportManager.get_step_description(step_failed)
124
129
  if "\n" in step_descr:
125
130
  msg_list.append(f" Step:")
@@ -41,7 +41,7 @@ class FailureReportBuilder(ReportBuilder):
41
41
 
42
42
  def after_scenario(self, scenario, scenario_report=None):
43
43
  from holado_report.report.report_manager import ReportManager
44
- category_validation, status_validation, step_failed, step_number = ReportManager.get_current_scenario_status_information(scenario)
44
+ category_validation, status_validation, step_failed, step_number, scenario_context, step_context = ReportManager.get_current_scenario_status_information(scenario)
45
45
 
46
46
  if status_validation != "Passed":
47
47
  step_error_message = ReportManager.get_step_error_message(step_failed).strip()
@@ -51,19 +51,21 @@ class FailureReportBuilder(ReportBuilder):
51
51
  category_str = f" => {category_validation}" if category_validation else ""
52
52
  if self.__file_format == 'txt':
53
53
  msg_list = []
54
- msg_list.append(f"scenario in {scenario.filename} at l.{scenario.line} - step {step_number} (l.{step_failed.line}) - {status_validation}{category_str}")
54
+ msg_list.append(f"scenario in {ReportManager.format_scenario_short_description(scenario)} - {ReportManager.format_step_short_description(step_failed, step_number)} - {status_validation}{category_str}")
55
55
  msg_list.append(f" Feature/Scenario: {scenario.feature.name} => {scenario.name}")
56
56
  msg_list.append(f" Report: {scenario_report.report_path}")
57
57
  msg_list.append(f" Tags: -t " + " -t ".join(scenario.feature.tags + scenario.tags))
58
+ msg_list.append(f" Scenario/Step periods: {ReportManager.format_context_period(scenario_context)} -> {ReportManager.format_context_period(step_context)}")
58
59
  msg_scenario = "\n".join(msg_list)
59
60
 
60
61
  self.__failures[step_error_message].append(msg_scenario)
61
62
  elif self.__file_format in ['json', 'xml']:
62
63
  scenario_info = {
63
- 'title': f"{scenario.filename} - l.{scenario.line} - step {step_number} (l.{step_failed.line}) - {status_validation}{category_str}",
64
+ 'title': f"{ReportManager.format_scenario_short_description(scenario)} - {ReportManager.format_step_short_description(step_failed, step_number)} - {status_validation}{category_str}",
64
65
  'scenario': f"{scenario.feature.name} => {scenario.name}",
65
66
  'report': scenario_report.report_path,
66
67
  'tags': "-t " + " -t ".join(scenario.feature.tags + scenario.tags),
68
+ 'periods': f"{ReportManager.format_context_period(scenario_context)} -> {ReportManager.format_context_period(step_context)}"
67
69
  }
68
70
  self.__failures[step_error_message].append(scenario_info)
69
71
  else:
@@ -15,6 +15,7 @@ import json
15
15
  import logging
16
16
  from holado_report.report.builders.report_builder import ReportBuilder
17
17
  import weakref
18
+ from holado_python.common.tools.datetime import FORMAT_DATETIME_ISO, DateTime
18
19
 
19
20
  logger = logging.getLogger(__name__)
20
21
 
@@ -51,10 +52,10 @@ class JsonExecutionHistoricReportBuilder(ReportBuilder):
51
52
  'tags': [str(tag) for tag in feature.tags],
52
53
  'status': feature.status.name,
53
54
  'duration': feature.duration,
54
- 'start_date': feature_context.start_datetime.isoformat()
55
+ 'start_date': DateTime.datetime_2_str(feature_context.start_datetime, dt_format=FORMAT_DATETIME_ISO)
55
56
  }
56
57
  if feature_context.end_datetime:
57
- res['end_date'] = feature_context.end_datetime.isoformat()
58
+ res['end_date'] = DateTime.datetime_2_str(feature_context.end_datetime, dt_format=FORMAT_DATETIME_ISO)
58
59
  res.update({
59
60
  'filename': feature.filename,
60
61
  'report': feature_report.report_path
@@ -77,10 +78,10 @@ class JsonExecutionHistoricReportBuilder(ReportBuilder):
77
78
  'tags': [str(tag) for tag in scenario.tags],
78
79
  'status': scenario.status.name,
79
80
  'duration': scenario.duration,
80
- 'start_date': scenario_context.start_datetime.isoformat()
81
+ 'start_date': DateTime.datetime_2_str(scenario_context.start_datetime, dt_format=FORMAT_DATETIME_ISO)
81
82
  }
82
83
  if scenario_context.end_datetime:
83
- res['end_date'] = scenario_context.end_datetime.isoformat()
84
+ res['end_date'] = DateTime.datetime_2_str(scenario_context.end_datetime, dt_format=FORMAT_DATETIME_ISO)
84
85
  res.update({
85
86
  'filename': scenario.filename,
86
87
  'line': scenario.line,
@@ -96,9 +97,9 @@ class JsonExecutionHistoricReportBuilder(ReportBuilder):
96
97
  if eh_step.step_context is not None:
97
98
  if eh_step.step_context.status is not None:
98
99
  res['status'] = eh_step.step_context.status
99
- res['start_date'] = eh_step.step_context.start_datetime.isoformat()
100
+ res['start_date'] = DateTime.datetime_2_str(eh_step.step_context.start_datetime, dt_format=FORMAT_DATETIME_ISO)
100
101
  if eh_step.step_context.end_datetime:
101
- res['end_date'] = eh_step.step_context.end_datetime.isoformat()
102
+ res['end_date'] = DateTime.datetime_2_str(eh_step.step_context.end_datetime, dt_format=FORMAT_DATETIME_ISO)
102
103
 
103
104
  res['description'] = eh_step.step_description
104
105
  if eh_step.sub_steps:
@@ -32,10 +32,10 @@ class ShortScenarioFailedReportBuilder(ReportBuilder):
32
32
 
33
33
  def after_scenario(self, scenario, scenario_report=None):
34
34
  from holado_report.report.report_manager import ReportManager
35
- category_validation, status_validation, step_failed, step_number = ReportManager.get_current_scenario_status_information(scenario)
35
+ category_validation, status_validation, step_failed, step_number, scenario_context, step_context = ReportManager.get_current_scenario_status_information(scenario)
36
36
 
37
37
  if status_validation != "Passed":
38
- self.__file_fail_add_scenario(scenario, scenario_report, category_validation, status_validation, step_failed, step_number)
38
+ self.__file_fail_add_scenario(scenario, scenario_report, category_validation, status_validation, step_failed, step_number, scenario_context, step_context)
39
39
 
40
40
  def after_all(self):
41
41
  # Manage file fail
@@ -43,20 +43,18 @@ class ShortScenarioFailedReportBuilder(ReportBuilder):
43
43
  self.__file_fail.close()
44
44
  self.__file_fail = None
45
45
 
46
- def __file_fail_add_scenario(self, scenario, scenario_report, category_validation, status_validation, step_failed, step_number):
46
+ def __file_fail_add_scenario(self, scenario, scenario_report, category_validation, status_validation, step_failed, step_number, scenario_context, step_context):
47
47
  from holado_report.report.report_manager import ReportManager
48
48
 
49
49
  self.__open_file_if_needed()
50
50
 
51
51
  msg_list = []
52
52
  category_str = f" => {category_validation}" if category_validation else ""
53
- if step_failed is not None:
54
- msg_list.append(f"scenario in {scenario.filename} at l.{scenario.line} - step {step_number} (l.{step_failed.line}) - {status_validation}{category_str}")
55
- else:
56
- msg_list.append(f"scenario in {scenario.filename} at l.{scenario.line} - step ? (missing step implementation ?) - {status_validation}{category_str}")
53
+ msg_list.append(f"scenario in {ReportManager.format_scenario_short_description(scenario)} - {ReportManager.format_step_short_description(step_failed, step_number)} - {status_validation}{category_str}")
57
54
  msg_list.append(f" Feature/Scenario: {scenario.feature.name} => {scenario.name}")
58
55
  msg_list.append(f" Report: {scenario_report.report_path}")
59
56
  msg_list.append(f" Tags: -t " + " -t ".join(scenario.feature.tags + scenario.tags))
57
+ msg_list.append(f" Scenario/Step periods: {ReportManager.format_context_period(scenario_context)} -> {ReportManager.format_context_period(step_context, dt_ref=scenario_context.start_datetime)}")
60
58
  step_error_message = ReportManager.get_step_error_message(step_failed)
61
59
  if step_error_message:
62
60
  if "\n" in step_error_message:
@@ -43,7 +43,7 @@ class SummaryByCategoryReportBuilder(ReportBuilder):
43
43
 
44
44
  def after_scenario(self, scenario, scenario_report=None):
45
45
  from holado_report.report.report_manager import ReportManager
46
- category_validation, _, _, _ = ReportManager.get_current_scenario_status_information(scenario)
46
+ category_validation, _, _, _, _, _ = ReportManager.get_current_scenario_status_information(scenario)
47
47
 
48
48
  if category_validation is not None:
49
49
  ind = category_validation.find(' (')
@@ -63,7 +63,7 @@ class SummaryReportBuilder(ReportBuilder):
63
63
 
64
64
  def after_scenario(self, scenario, scenario_report=None):
65
65
  from holado_report.report.report_manager import ReportManager
66
- _, status_name, _, _ = ReportManager.get_current_scenario_status_information(scenario)
66
+ _, status_name, _, _, _, _ = ReportManager.get_current_scenario_status_information(scenario)
67
67
 
68
68
  if status_name not in self.__scenarios:
69
69
  self.__scenarios[status_name] = 0
@@ -44,7 +44,7 @@ class SummaryScenarioByCategoryReportBuilder(ReportBuilder):
44
44
 
45
45
  def after_scenario(self, scenario, scenario_report=None):
46
46
  from holado_report.report.report_manager import ReportManager
47
- category_validation, status_validation, step_failed, step_number = ReportManager.get_current_scenario_status_information(scenario)
47
+ category_validation, status_validation, step_failed, step_number, scenario_context, step_context = ReportManager.get_current_scenario_status_information(scenario)
48
48
 
49
49
  if category_validation is not None:
50
50
  ind = category_validation.find(' (')
@@ -56,10 +56,7 @@ class SummaryScenarioByCategoryReportBuilder(ReportBuilder):
56
56
 
57
57
  # Add scenario information into category
58
58
  category_str = f" => {category_validation}" if category_validation else ""
59
- if step_failed is not None:
60
- scenario_txt = f"scenario in {scenario.filename} at l.{scenario.line} - step {step_number} (l.{step_failed.line}) - {status_validation}{category_str}"
61
- else:
62
- scenario_txt = f"scenario in {scenario.filename} at l.{scenario.line} - step ? (missing step implementation ?) - {status_validation}{category_str}"
59
+ scenario_txt = f"{ReportManager.format_context_period(scenario_context)} {ReportManager.format_scenario_short_description(scenario)} - {ReportManager.format_step_short_description(step_failed, step_number, step_context, dt_ref=scenario_context.start_datetime)} - {status_validation}{category_str}"
63
60
 
64
61
  if category not in self.__scenarios_by_category:
65
62
  self.__scenarios_by_category[category] = []
@@ -13,6 +13,7 @@
13
13
 
14
14
  import logging
15
15
  from holado_report.report.builders.report_builder import ReportBuilder
16
+ from holado_report.report.report_manager import ReportManager
16
17
 
17
18
  logger = logging.getLogger(__name__)
18
19
 
@@ -30,11 +31,10 @@ class SummaryScenarioFailedReportBuilder(ReportBuilder):
30
31
  pass
31
32
 
32
33
  def after_scenario(self, scenario, scenario_report=None):
33
- from holado_report.report.report_manager import ReportManager
34
- category_validation, status_validation, step_failed, step_number = ReportManager.get_current_scenario_status_information(scenario)
34
+ category_validation, status_validation, step_failed, step_number, scenario_context, step_context = ReportManager.get_current_scenario_status_information(scenario)
35
35
 
36
36
  if status_validation != "Passed":
37
- self.__file_fail_add_scenario(scenario, category_validation, status_validation, step_failed, step_number)
37
+ self.__file_fail_add_scenario(scenario, category_validation, status_validation, step_failed, step_number, scenario_context, step_context)
38
38
 
39
39
  def after_all(self):
40
40
  # Manage file fail
@@ -42,13 +42,10 @@ class SummaryScenarioFailedReportBuilder(ReportBuilder):
42
42
  self.__file_fail.close()
43
43
  self.__file_fail = None
44
44
 
45
- def __file_fail_add_scenario(self, scenario, category_validation, status_validation, step_failed, step_number):
45
+ def __file_fail_add_scenario(self, scenario, category_validation, status_validation, step_failed, step_number, scenario_context, step_context):
46
46
  self.__open_file_if_needed()
47
47
  category_str = f" => {category_validation}" if category_validation else ""
48
- if step_failed is not None:
49
- self.__file_fail.write(f"scenario in {scenario.filename} at l.{scenario.line} - step {step_number} (l.{step_failed.line}) - {status_validation}{category_str}\n")
50
- else:
51
- self.__file_fail.write(f"scenario in {scenario.filename} at l.{scenario.line} - step ? (missing step implementation ?) - {status_validation}{category_str}\n")
48
+ self.__file_fail.write(f"{ReportManager.format_context_period(scenario_context)} {ReportManager.format_scenario_short_description(scenario)} - {ReportManager.format_step_short_description(step_failed, step_number, step_context, dt_ref=scenario_context.start_datetime)} - {status_validation}{category_str}\n")
52
49
  self.__file_fail.flush()
53
50
 
54
51
  def __open_file_if_needed(self):
@@ -13,8 +13,7 @@
13
13
 
14
14
  import logging
15
15
  from holado_report.report.builders.report_builder import ReportBuilder
16
- from holado_python.common.tools.datetime import DateTime,\
17
- FORMAT_DATETIME_HUMAN_SECOND
16
+ from holado_report.report.report_manager import ReportManager
18
17
 
19
18
  logger = logging.getLogger(__name__)
20
19
 
@@ -32,13 +31,12 @@ class SummaryScenarioReportBuilder(ReportBuilder):
32
31
  pass
33
32
 
34
33
  def after_scenario(self, scenario, scenario_report=None):
35
- from holado_report.report.report_manager import ReportManager
36
- category_validation, status_validation, step_failed, step_number = ReportManager.get_current_scenario_status_information(scenario)
34
+ category_validation, status_validation, step_failed, step_number, scenario_context, step_context = ReportManager.get_current_scenario_status_information(scenario)
37
35
 
38
36
  if status_validation == "Passed":
39
- self.__file_add_scenario_success(scenario, category_validation, status_validation)
37
+ self.__file_add_scenario_success(scenario, category_validation, status_validation, scenario_context)
40
38
  else:
41
- self.__file_add_scenario_fail(scenario, category_validation, status_validation, step_failed, step_number)
39
+ self.__file_add_scenario_fail(scenario, category_validation, status_validation, step_failed, step_number, scenario_context, step_context)
42
40
 
43
41
  def after_all(self):
44
42
  # Manage file fail
@@ -46,28 +44,24 @@ class SummaryScenarioReportBuilder(ReportBuilder):
46
44
  self.__file.close()
47
45
  self.__file = None
48
46
 
49
- def __file_add_scenario_success(self, scenario, category_validation, status_validation):
47
+ def __file_add_scenario_success(self, scenario, category_validation, status_validation, scenario_context):
50
48
  self.__open_file_if_needed()
51
- self.__file_write(scenario, None, category_validation, status_validation)
49
+ self.__file_write(scenario, None, category_validation, status_validation, scenario_context)
52
50
  self.__file.flush()
53
51
 
54
- def __file_add_scenario_fail(self, scenario, category_validation, status_validation, step_failed, step_number):
52
+ def __file_add_scenario_fail(self, scenario, category_validation, status_validation, step_failed, step_number, scenario_context, step_context):
55
53
  self.__open_file_if_needed()
56
- if step_failed is not None:
57
- self.__file_write(scenario, f"step {step_number} (l.{step_failed.line})", category_validation, status_validation)
58
- else:
59
- self.__file_write(scenario, f"step ? (missing step implementation ?)", category_validation, status_validation)
54
+ self.__file_write(scenario, ReportManager.format_step_short_description(step_failed, step_number, step_context, dt_ref=scenario_context.start_datetime), category_validation, status_validation, scenario_context)
60
55
  self.__file.flush()
61
56
 
62
- def __file_write(self, scenario, text, category_validation, status_validation):
63
- dt = DateTime.now()
64
- dt_str = DateTime.datetime_2_str(dt, FORMAT_DATETIME_HUMAN_SECOND)
65
-
57
+ def __file_write(self, scenario, text, category_validation, status_validation, scenario_context):
58
+ # Note: This report is currently used to extract scenarios statuses in CampaignManager.
59
+ # Thus scenario period cannot be in compact format
66
60
  category_str = f" => {category_validation}" if category_validation else ""
67
61
  if text:
68
- self.__file.write(f"{dt_str} - {scenario.filename} at l.{scenario.line} - {text} - {status_validation}{category_str}\n")
62
+ self.__file.write(f"{ReportManager.format_context_period(scenario_context, use_compact_format=False)} {ReportManager.format_scenario_short_description(scenario)} - {text} - {status_validation}{category_str}\n")
69
63
  else:
70
- self.__file.write(f"{dt_str} - {scenario.filename} at l.{scenario.line} - {status_validation}{category_str}\n")
64
+ self.__file.write(f"{ReportManager.format_context_period(scenario_context, use_compact_format=False)} {ReportManager.format_scenario_short_description(scenario)} - {status_validation}{category_str}\n")
71
65
 
72
66
  def __open_file_if_needed(self):
73
67
  if self.__file is None:
@@ -56,7 +56,8 @@ class ExecutionHistoric():
56
56
  self.__get_execution_historic_current_feature_scenarios().append(seh)
57
57
 
58
58
  def __new_ScenarioExecutionHistoric(self, scenario_context, scenario, scenario_report):
59
- res = NamedTuple("ScenarioExecutionHistoric", scenario_context=object, scenario=object, scenario_report=object, steps_by_scope=dict, category_validation=str, status_validation=str, step_failed=object, step_failed_number=int)
59
+ res = NamedTuple("ScenarioExecutionHistoric", scenario_context=object, scenario=object, scenario_report=object, steps_by_scope=dict,
60
+ category_validation=str, status_validation=str, step_failed=object, step_failed_number=int)
60
61
  res.scenario_context = scenario_context
61
62
  res.scenario = scenario
62
63
  res.scenario_report = scenario_report
@@ -88,7 +89,7 @@ class ExecutionHistoric():
88
89
 
89
90
  def after_scenario(self, scenario, scenario_report=None):
90
91
  from holado_report.report.report_manager import ReportManager
91
- category_validation, status_validation, step_failed, step_number = ReportManager.get_current_scenario_status_information(scenario)
92
+ category_validation, status_validation, step_failed, step_number, _, _ = ReportManager.get_current_scenario_status_information(scenario)
92
93
 
93
94
  # Update execution historic
94
95
  current_scenario = self.__get_execution_historic_current_scenario()
@@ -14,17 +14,15 @@
14
14
  from holado.common.context.session_context import SessionContext
15
15
  from holado_core.common.tools.tools import Tools
16
16
  import logging
17
- # from holado_report.report.builders.json_execution_historic_report_builder import JsonExecutionHistoricReportBuilder
18
- from holado_report.report.builders.detailed_scenario_failed_report_builder import DetailedScenarioFailedReportBuilder
19
- from holado_report.report.builders.summary_report_builder import SummaryReportBuilder
20
- from holado_report.report.builders.summary_scenario_failed_report_builder import SummaryScenarioFailedReportBuilder
21
- from holado_report.report.builders.short_scenario_failed_report_builder import ShortScenarioFailedReportBuilder
22
17
  from holado_report.report.reports.base_report import BaseReport
23
18
  from holado_scripting.common.tools.evaluate_parameters import EvaluateParameters
24
- from holado_report.report.builders.summary_scenario_report_builder import SummaryScenarioReportBuilder
25
- from holado_report.report.builders.failure_report_builder import FailureReportBuilder
26
- from holado_report.report.builders.summary_scenario_by_category_report_builder import SummaryScenarioByCategoryReportBuilder
27
- from holado_report.report.builders.summary_by_category_report_builder import SummaryByCategoryReportBuilder
19
+ from holado_python.common.tools.datetime import DateTime,\
20
+ FORMAT_DATETIME_ISO_SECONDS, FORMAT_DATETIME_ISO, DurationUnit,\
21
+ FORMAT_TIME_ISO, FORMAT_TIME_ISO_SECONDS
22
+ from holado_python.common.enums import ArithmeticOperator
23
+ from holado.common.handlers.undefined import default_value
24
+ from holado.holado_config import Config
25
+ import copy
28
26
  # from holado_core.scenario.scenario_duration_manager import ScenarioDurationManager
29
27
 
30
28
  logger = logging.getLogger(__name__)
@@ -59,6 +57,15 @@ class ReportManager(BaseReport):
59
57
  self.__multitask_manager = multitask_manager
60
58
 
61
59
  def initialize_reports(self):
60
+ from holado_report.report.builders.detailed_scenario_failed_report_builder import DetailedScenarioFailedReportBuilder
61
+ from holado_report.report.builders.summary_report_builder import SummaryReportBuilder
62
+ from holado_report.report.builders.summary_scenario_failed_report_builder import SummaryScenarioFailedReportBuilder
63
+ from holado_report.report.builders.short_scenario_failed_report_builder import ShortScenarioFailedReportBuilder
64
+ from holado_report.report.builders.summary_scenario_report_builder import SummaryScenarioReportBuilder
65
+ from holado_report.report.builders.failure_report_builder import FailureReportBuilder
66
+ from holado_report.report.builders.summary_scenario_by_category_report_builder import SummaryScenarioByCategoryReportBuilder
67
+ from holado_report.report.builders.summary_by_category_report_builder import SummaryByCategoryReportBuilder
68
+
62
69
  # self.set_execution_historic()
63
70
 
64
71
  if self.has_report_path:
@@ -293,7 +300,9 @@ class ReportManager(BaseReport):
293
300
 
294
301
  logger.debug(f"Category of scenario '{scenario}': {category} (computed from last statuses: {statuses})")
295
302
 
296
- cls._scenario_status_information_by_uid[scenario_uid] = [category, status, step_failed, step_nb]
303
+ cls._scenario_status_information_by_uid[scenario_uid] = [category, status, step_failed, step_nb,
304
+ SessionContext.instance().get_scenario_context(),
305
+ SessionContext.instance().get_scenario_context().get_step(step_nb-1) if step_nb is not None else None]
297
306
 
298
307
  return cls._scenario_status_information_by_uid[scenario_uid]
299
308
 
@@ -343,4 +352,64 @@ class ReportManager(BaseReport):
343
352
  return cls.get_step_error_message(step)
344
353
  return None
345
354
 
355
+ @classmethod
356
+ def format_context_period(cls, context, format_precision_nsec=None, dt_ref=None, use_compact_format=default_value):
357
+ # Truncate datetimes with precision
358
+ dt_start, dt_end = context.start_datetime, context.end_datetime
359
+ if format_precision_nsec is not None:
360
+ dt_start = DateTime.truncate_datetime(dt_start, precision_nanoseconds=format_precision_nsec)
361
+ dt_end = DateTime.truncate_datetime(dt_end, precision_nanoseconds=format_precision_nsec)
362
+
363
+ # Define formats
364
+ dt_format_start = cls._get_datetime_format_compared_to_reference(dt_start, dt_ref, use_compact_format=use_compact_format)
365
+ dt_format_end = cls._get_datetime_format_compared_to_reference(dt_end, dt_start, use_compact_format=use_compact_format)
366
+ if len(dt_format_end) > len(dt_format_start):
367
+ dt_format_start = dt_format_end
368
+
369
+ # Format datetimes
370
+ start_txt = DateTime.datetime_2_str(dt_start, dt_format=dt_format_start)
371
+ end_txt = DateTime.datetime_2_str(dt_end, dt_format=dt_format_end)
372
+
373
+ # Truncate formatted datetimes if needed
374
+ if format_precision_nsec is not None:
375
+ trunc_len = len(f'{int(format_precision_nsec)}') - 4
376
+ if trunc_len > 0:
377
+ start_txt = start_txt[:-trunc_len-1]+'Z' if start_txt.endswith('Z') else start_txt[:-trunc_len]
378
+ end_txt = end_txt[:-trunc_len-1]+'Z' if end_txt.endswith('Z') else end_txt[:-trunc_len]
379
+
380
+ return f"[{start_txt} - {end_txt}]"
381
+
382
+ @classmethod
383
+ def _get_datetime_format_compared_to_reference(cls, dt, dt_ref=None, use_compact_format=default_value):
384
+ if use_compact_format is default_value:
385
+ use_compact_format = Config.report_compact_datetime_period # @UndefinedVariable
386
+
387
+ if dt_ref is None:
388
+ return FORMAT_DATETIME_ISO
389
+
390
+ if not use_compact_format or dt.date() != dt_ref.date():
391
+ return FORMAT_DATETIME_ISO
392
+ elif dt.hour != dt_ref.hour:
393
+ return FORMAT_TIME_ISO
394
+ elif dt.minute != dt_ref.minute:
395
+ return '%M:%S.%f'
396
+ elif dt.second != dt_ref.second:
397
+ return '%S.%f'
398
+ else:
399
+ return '.%f'
400
+
401
+ @classmethod
402
+ def format_scenario_short_description(cls, scenario):
403
+ return f"{scenario.filename} at l.{scenario.line}"
404
+
405
+ @classmethod
406
+ def format_step_short_description(cls, step, step_number, step_context=None, dt_ref=None):
407
+ if step:
408
+ if step_context:
409
+ return f"step {step_number} (l.{step.line} on {cls.format_context_period(step_context, dt_ref=dt_ref)})"
410
+ else:
411
+ return f"step {step_number} (l.{step.line})"
412
+ else:
413
+ return "step ? (missing step implementation ?)"
414
+
346
415