holado 0.11.3__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.

Files changed (33) hide show
  1. holado/common/context/session_context.py +9 -12
  2. {holado-0.11.3.dist-info → holado-0.11.5.dist-info}/METADATA +1 -1
  3. {holado-0.11.3.dist-info → holado-0.11.5.dist-info}/RECORD +33 -32
  4. holado_ais/ais/ais_messages.py +2 -2
  5. holado_ais/tests/behave/steps/ais/ais_messages_steps.py +1 -1
  6. holado_core/common/resource/persisted_method_to_call_manager.py +1 -1
  7. holado_python/common/tools/datetime.py +7 -4
  8. holado_python/standard_library/ssl/resources/certificates/tcpbin.crt +16 -16
  9. holado_python/standard_library/ssl/resources/certificates/tcpbin.key +26 -26
  10. holado_report/__init__.py +1 -0
  11. holado_report/campaign/campaign_manager.py +14 -5
  12. holado_report/report/builders/detailed_scenario_failed_report_builder.py +12 -7
  13. holado_report/report/builders/failure_report_builder.py +5 -3
  14. holado_report/report/builders/json_execution_historic_report_builder.py +7 -6
  15. holado_report/report/builders/short_scenario_failed_report_builder.py +5 -7
  16. holado_report/report/builders/summary_by_category_report_builder.py +86 -0
  17. holado_report/report/builders/summary_report_builder.py +1 -1
  18. holado_report/report/builders/summary_scenario_by_category_report_builder.py +2 -5
  19. holado_report/report/builders/summary_scenario_failed_report_builder.py +5 -8
  20. holado_report/report/builders/summary_scenario_report_builder.py +13 -19
  21. holado_report/report/execution_historic.py +3 -2
  22. holado_report/report/report_manager.py +82 -9
  23. holado_test/tools/test_server/client/rest/test_server_client.py +20 -0
  24. holado_test/tools/test_server/server/rest/api/__init__.py +6 -5
  25. holado_test/tools/test_server/server/rest/openapi.yaml +11 -0
  26. holado_tools/tools/host_controller/client/rest/host_controller_client.py +22 -0
  27. holado_tools/tools/host_controller/server/rest/api/__init__.py +8 -8
  28. holado_tools/tools/host_controller/server/rest/openapi.yaml +11 -0
  29. holado_tools/tools/host_viewer/server/rest/api/__init__.py +9 -7
  30. holado_tools/tools/host_viewer/server/rest/openapi.yaml +11 -0
  31. test_holado/environment.py +7 -0
  32. {holado-0.11.3.dist-info → holado-0.11.5.dist-info}/WHEEL +0 -0
  33. {holado-0.11.3.dist-info → holado-0.11.5.dist-info}/licenses/LICENSE +0 -0
@@ -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.3
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
@@ -14,14 +14,14 @@ holado/common/tools/gc_manager.py,sha256=TjQg7MisGRhxuiQ22hB3IuqNhnWCVEWpU253-rO
14
14
  holado_ais/__init__.py,sha256=Mudcgu_7p1hBDBs6LpSz757H4haB0yLHgT70sznG82c,1807
15
15
  holado_ais/ais/MaritimeIdentificationDigits.csv,sha256=r-uHt4wOvxlbA26af9e-N3BKbuiMf6ia3PN0ZGfYk2A,8547
16
16
  holado_ais/ais/ais_manager.py,sha256=QvN94JoUBbSXT08HABl2FNsAVOM-YCmQO5tN9COg6Rc,6496
17
- holado_ais/ais/ais_messages.py,sha256=J-GZJAY2RZpSS3OwzQJc6B_HsmdtRXLAcbfaP9APbUA,17414
17
+ holado_ais/ais/ais_messages.py,sha256=0jrhIFH6htUZkUinqKcPuUp2JMtnp0qKwYFAmUk-6w0,17414
18
18
  holado_ais/ais/ais_payload.py,sha256=mdOa_4JIbkFLK4_KUmQF5jUt1nLxvZhmIcqK8i-YY6w,1791
19
19
  holado_ais/ais/enums.py,sha256=bsqfJVg65fWiJwL_VlSKwKgTY0pLoDcI4T06aEOcQnw,1108
20
20
  holado_ais/ais/patch_pyais.py,sha256=M4Fa8GZubXx4auRsk5I1yQPC40IR1p-1iVZIc4PXFfk,49850
21
21
  holado_ais/tests/behave/steps/__init__.py,sha256=cM4YsjHIq0Tb9mTTJjvDojzhLwov6mc2RyjZz8XLVA8,1321
22
22
  holado_ais/tests/behave/steps/ais/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  holado_ais/tests/behave/steps/ais/ais_manager_steps.py,sha256=nRtJUEyAzAqgm0UWwRUFAyOzhDxzRZKTGsEYU1DwE-Q,2170
24
- holado_ais/tests/behave/steps/ais/ais_messages_steps.py,sha256=XMBpCqtyRBQJ2ODRxRN-tVcWr7O72c2o0Yy-0Sd5phE,11741
24
+ holado_ais/tests/behave/steps/ais/ais_messages_steps.py,sha256=SJZlUyAvGOiEPjTa5qxrj_9y8ERcDJkmHcofzonvJDA,11741
25
25
  holado_binary/__init__.py,sha256=Gl285tg-QaPE-3etWwZql9sH26G7EnVoQn97B0NMvOI,1248
26
26
  holado_binary/ipc/binary.py,sha256=QYwK7jK4dzXRKprHMxnTxFljMy1LZDSXjMJ406yEOHk,5520
27
27
  holado_binary/ipc/bit_series.py,sha256=PNuW_OXGV8yeRrMHxMPImR75np52KpcDOfXXdDKObWw,15508
@@ -98,7 +98,7 @@ holado_core/common/inspectors/tools/inspect_builder.py,sha256=v7azgwciXHtO-o7gcg
98
98
  holado_core/common/inspectors/tools/inspect_context.py,sha256=lzhhO5HxG00c6uMPyIXEUz0FHA61VCNUZr_39ykZ8lQ,2700
99
99
  holado_core/common/inspectors/tools/inspect_parameters.py,sha256=2vXUpnZlP2cCYTvI9ddI6NGhONideoM1hBJ0vGdvPKo,7346
100
100
  holado_core/common/resource/persisted_data_manager.py,sha256=Thie2st70tFb2IDWb_3LeLx656WeiW5tpAkI4xc8wQA,6641
101
- holado_core/common/resource/persisted_method_to_call_manager.py,sha256=LJOCrl2gTa_hyXkt4mLhpsBfDAB3QEIxmcc7gJQop-k,14192
101
+ holado_core/common/resource/persisted_method_to_call_manager.py,sha256=xlP1xBPN0TdYrh1CBNyOU6EnzXp5KyXSJVTQC9ynlLQ,14188
102
102
  holado_core/common/resource/resource_manager.py,sha256=VP86iQ7_NZzQQ0uUpeev1PjgiejUuwKbV5RfGCNC5tI,7179
103
103
  holado_core/common/resource/table_data_manager.py,sha256=bigQGMwh1m3P6ZEO3wi2ftmvyEwpZhGbNCVtI794ops,6289
104
104
  holado_core/common/tables/__init__.py,sha256=i2-gExPOUa_AnmEPgZJQ2lAXeK02PLpPnjEqbsgj1Co,8
@@ -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=irlQEaUfHPFbeDFcvZwtyneZxoM6s6KFLgXa6N_io6E,1237
340
- holado_python/standard_library/ssl/resources/certificates/tcpbin.key,sha256=fq0j9a8lrCUS8Jo6vS0a_FoZOwO5OfFb2Fa19u3xd9Y,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,21 +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=KiKMiZbjYa7-0yH8zs8KQdqz5VyZwwSAHizDYRwGGp8,16624
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_report_builder.py,sha256=v4LG3W5x_y4FH0kh_5MRaG8pyPOV2GfhlBImsW4BJrs,3954
379
- holado_report/report/builders/summary_scenario_by_category_report_builder.py,sha256=1rzuF4KFPzO5jFuvC_OKvsnNMRrzW3zG5nU5GUSux1U,4274
380
- holado_report/report/builders/summary_scenario_failed_report_builder.py,sha256=uqf86SUAiIQLRQOV0A434oR8Bj4e_DtxqRsy-pe84p4,3063
381
- 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
382
383
  holado_report/report/reports/base_report.py,sha256=NGnWe66uyvT4bCjhd3upwVpc6yQ2gyVNFhcy-3LeQsE,6850
383
384
  holado_report/report/reports/feature_report.py,sha256=i0wpk3LQLArVjWDsP9UcNSJzAUWwLhe73HNyfye2gYQ,4810
384
385
  holado_report/report/reports/scenario_report.py,sha256=eMyqw9EzaKMmX3pGFJN1rqAOQ5eqO2ISZdxAfK3XQR4,2945
@@ -480,7 +481,7 @@ holado_test/tests/behave/steps/__init__.py,sha256=rdqrp-UN7vRplIqORx4sXyKwMUkptR
480
481
  holado_test/tests/behave/steps/scenario/exception_steps.py,sha256=ZIE92Dz7a6O_c0jAP_0dj6Hc0tnW6YRgNKd4_aBpeR0,4054
481
482
  holado_test/tests/behave/steps/scenario/scenario_steps.py,sha256=RfM5Lh4sduKeYSD1NzUxtQ8705O7nausoz_gnpAJQB0,4616
482
483
  holado_test/tests/behave/steps/scenario/tester_steps.py,sha256=zEm36-su8jrqe0uv8ai4xN97j3_p2jmcPv_-jRRu688,2997
483
- holado_test/tools/test_server/client/rest/test_server_client.py,sha256=WJG-_FLSg1YuRXUBX-5RXd-97XEnUv1UfTvyvQnXLo4,5317
484
+ holado_test/tools/test_server/client/rest/test_server_client.py,sha256=Zoq5zWqWHHnysxMIki8zaQHaR8TFMM6U1xSbjeO7luY,6085
484
485
  holado_test/tools/test_server/server/Dockerfile,sha256=CDhwKszWuA_aSHrwruvN5oAU6g67MXbSO-coHmDNL9c,1485
485
486
  holado_test/tools/test_server/server/requirements.txt,sha256=c2iNG9IZZogAEC9oSWRTWEF9-OHW0vRtijPNK4P6_xY,45
486
487
  holado_test/tools/test_server/server/run_test_server_in_docker.sh,sha256=ISNvFT1dBM6aiw5Iv6yBhInn7L8ZYyz_7EDK_X1eCvk,3121
@@ -489,9 +490,9 @@ holado_test/tools/test_server/server/core/server_manager.py,sha256=PW5ShUdnbdq6E
489
490
  holado_test/tools/test_server/server/rest/README,sha256=J_LIXWFxtxc8okQGZ8Kk0dMSRra9oUzbMP_ylCe4pTo,161
490
491
  holado_test/tools/test_server/server/rest/initialize_holado.py,sha256=UxNphXyjs-xraorzMWjDe6-QYw_Q3mtykyY-ENYZB1o,3464
491
492
  holado_test/tools/test_server/server/rest/logging.conf,sha256=yeNIHFQCYlDmkdLlQ3NCoMuxpUNn6i8ZDAzOUna_2aA,1282
492
- holado_test/tools/test_server/server/rest/openapi.yaml,sha256=4Juf_QggWo7z9te3_sS96TxxARWU1MtFkJZAilEsxr8,1027
493
+ holado_test/tools/test_server/server/rest/openapi.yaml,sha256=ULzbZMhj-Iw6MGwZ7_7zxkOGiRjpFnqaT6OotgL9sjY,1248
493
494
  holado_test/tools/test_server/server/rest/run.py,sha256=OpDBkjBX_ZoNfwTWc2VV7dINALjp7ZrGUUiDaSEHQVU,2395
494
- holado_test/tools/test_server/server/rest/api/__init__.py,sha256=4QcsiWhFX0sGhJYuoqUUfwEYb6ceIDlFFlU1q3ls7Xc,1442
495
+ holado_test/tools/test_server/server/rest/api/__init__.py,sha256=Y_kSr0l44kBpmWYsRRH93MXSyKM1veegaytzYFXkBA0,1407
495
496
  holado_test/tools/test_server/server/rest/api/campaign/__init__.py,sha256=btZb20N5k7_WbowNAC1C7yYDUkwPnUU5QUmh-jO0bhg,1586
496
497
  holado_test/tools/test_server/server/rest/api/campaign/scenario.py,sha256=4eTIScEGL0GKD7g6aIPHJVvaVbwz487zlEg9mRQv84Y,1737
497
498
  holado_tools/__init__.py,sha256=JzUm55NIkeBynu1RieZ3QfZGw8v4NfFDzz6HS-bN7r8,1798
@@ -500,7 +501,7 @@ holado_tools/scripts/execute_persisted_post_processes/execute_persisted_post_pro
500
501
  holado_tools/scripts/execute_persisted_post_processes/initialize_holado.py,sha256=IPYH-GYNiHV5-7ZCCH6CFmPpmACsPrTV74TYz3MRjpA,3102
501
502
  holado_tools/tests/behave/steps/__init__.py,sha256=SPh47LYMokcxbFhDa_JnlkIlyQav2D-hddf3J1ZlEbQ,1296
502
503
  holado_tools/tests/behave/steps/tools/host_controller/client_steps.py,sha256=FOaeQ5xX4KGv7OVvMh2M8U0a-AfHuUNQU5p4av_K8z0,4786
503
- holado_tools/tools/host_controller/client/rest/host_controller_client.py,sha256=U7btvQf-kodCIrBvG-DHOgY5Hk9A0-H6jYZZ13zdbr0,6432
504
+ holado_tools/tools/host_controller/client/rest/host_controller_client.py,sha256=OCMXvFcJ1Bz9W3AeG2Rdho3pTrWT48J2sJNQdICE4d0,7218
504
505
  holado_tools/tools/host_controller/server/Dockerfile,sha256=wTy-ii7MuJULRiw5_2sUWj8ssw6WUJIhAcLY2KCL0lw,1508
505
506
  holado_tools/tools/host_controller/server/requirements.txt,sha256=0RvLV3t2DyBR2FsbAd1WVEcbsVc6FVUN2horQJU4POo,57
506
507
  holado_tools/tools/host_controller/server/run_host_controller_in_docker.sh,sha256=KEBTxcxFeViVpixLii1YXBbyZhvJKfmH604jGqBFxHc,3729
@@ -510,9 +511,9 @@ holado_tools/tools/host_controller/server/grpc/proto/compile_proto.py,sha256=Njc
510
511
  holado_tools/tools/host_controller/server/grpc/proto/definitions/docker_controler.proto,sha256=n9bsXaQfnZX-R5HvfquCVt3QjpFtDJSH6p8gnTjm06k,1650
511
512
  holado_tools/tools/host_controller/server/rest/README,sha256=10hiIdQw69iXubii8ZYZUrYrs2Q2k5QiTKpBBrBK1bc,165
512
513
  holado_tools/tools/host_controller/server/rest/initialize_holado.py,sha256=UxNphXyjs-xraorzMWjDe6-QYw_Q3mtykyY-ENYZB1o,3464
513
- holado_tools/tools/host_controller/server/rest/openapi.yaml,sha256=u9D5Yt5pwVZujeOF5xhUF4W2tjXi2TODWHMFBEmLJjY,6900
514
+ holado_tools/tools/host_controller/server/rest/openapi.yaml,sha256=6MCJFmJ-fPeNOhhgELdVHCnsVej2YoyZ3ECwEMeUIsY,7121
514
515
  holado_tools/tools/host_controller/server/rest/run.py,sha256=RQFxhVCH3K3uAHFdCVVKw2MAcVcufSvenVn6f6ABCGA,2009
515
- holado_tools/tools/host_controller/server/rest/api/__init__.py,sha256=3VgcIa1WhkxMBTNrxKsh4xIqiSMeDxQpbx2cAdME9vg,1459
516
+ holado_tools/tools/host_controller/server/rest/api/__init__.py,sha256=Y_kSr0l44kBpmWYsRRH93MXSyKM1veegaytzYFXkBA0,1407
516
517
  holado_tools/tools/host_controller/server/rest/api/config.py,sha256=Ln__1bsigSzJZ-Iy3MQgmiZMnpBxC3TCQE0O72g5cAs,2459
517
518
  holado_tools/tools/host_controller/server/rest/api/os.py,sha256=EA3DCxGBCnMd2XJyn9kb6IWmtbaPIyv5UfZypCNzkhY,2123
518
519
  holado_tools/tools/host_controller/server/rest/api/docker/__init__.py,sha256=FlLRagAiw1LDxnF0CmW7Y6bVXuj8x6volT8-DuHTTVY,2427
@@ -523,9 +524,9 @@ holado_tools/tools/host_viewer/server/requirements.txt,sha256=0RvLV3t2DyBR2FsbAd
523
524
  holado_tools/tools/host_viewer/server/run_host_viewer_in_docker.sh,sha256=XeJfyjPVj34-rK_9K_6C9iD0EiAZ2WVkoD1L5rvZzw4,3606
524
525
  holado_tools/tools/host_viewer/server/rest/README,sha256=1FMg-U_D9pUMBVmZJsirOXHFLTciDL5jB-Yqzp9U6uM,163
525
526
  holado_tools/tools/host_viewer/server/rest/initialize_holado.py,sha256=UxNphXyjs-xraorzMWjDe6-QYw_Q3mtykyY-ENYZB1o,3464
526
- holado_tools/tools/host_viewer/server/rest/openapi.yaml,sha256=XP644LfEcDi7R9IV7_FIbRHpmw9Jlgtlfs-8qsc3DGQ,2788
527
+ holado_tools/tools/host_viewer/server/rest/openapi.yaml,sha256=tU9N6eGW7ESxtbODyUeYDdKYUxQSNoTjHiUrvgqr5JM,3007
527
528
  holado_tools/tools/host_viewer/server/rest/run.py,sha256=jgJgmFFdppadLBahWU8Yw8-PdA5HJzBTDCPTPHGRzbA,2007
528
- holado_tools/tools/host_viewer/server/rest/api/__init__.py,sha256=MTjW5ixe0v7jIjWkN_NovDHbHeVlb0VKkJRtC_oWlHc,1456
529
+ holado_tools/tools/host_viewer/server/rest/api/__init__.py,sha256=Y_kSr0l44kBpmWYsRRH93MXSyKM1veegaytzYFXkBA0,1407
529
530
  holado_tools/tools/host_viewer/server/rest/api/docker/__init__.py,sha256=FlLRagAiw1LDxnF0CmW7Y6bVXuj8x6volT8-DuHTTVY,2427
530
531
  holado_value/__init__.py,sha256=60VyLyWux76dFwn03uH4Fz3R6itf6fqKu0pQUdvwblU,1561
531
532
  holado_value/common/tables/value_table.py,sha256=fJgb-HWdlMwHOAx5CS38sPiVrjGelEiQBbG9HuHqe-A,1726
@@ -559,7 +560,7 @@ test_holado/Dockerfile_test_holado,sha256=zO6OUFnC1X9ZG7fPWWWfcWgZwnxif4WDE4ZDEm
559
560
  test_holado/__init__.py,sha256=TIHAHrF05rvz6-VDKuDBSBjasD6PxTxXvcXjMEC3D6E,54
560
561
  test_holado/__main__.py,sha256=PVdCX8V_RGRzbQQKVxf7eyt8a10XfUJ1pcaajGgIlus,1509
561
562
  test_holado/build_docker_image_to_test_holado_in_docker.sh,sha256=B3hbi0yKnEC-t9S18o6ZR27AU1bqiuptwOqm6H7tv8s,142
562
- test_holado/environment.py,sha256=SLGJ2v1BoyP_s_KucvuQJLnWPzPJAD6cS4C8eBNaJW8,2381
563
+ test_holado/environment.py,sha256=2K_VLB92bDfHh6e1EHVBp30Y8cgeVIjUI8C2ezPWXqA,2661
563
564
  test_holado/initialize_holado.py,sha256=IPYH-GYNiHV5-7ZCCH6CFmPpmACsPrTV74TYz3MRjpA,3102
564
565
  test_holado/logging.conf,sha256=vsCMsRnvSMHl6nBmRqG7kBYC3qshAcxiAg5iUUw1Udw,1318
565
566
  test_holado/test_holado_session_context.py,sha256=qOB_i2k8mYjkR3-q2uv0B04xFc1K3p-K20ttYwe1Z18,1364
@@ -679,7 +680,7 @@ test_holado/tools/django/api_rest/api_rest/api1/serializers.py,sha256=o_YxFr-tgC
679
680
  test_holado/tools/django/api_rest/api_rest/api1/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
680
681
  test_holado/tools/django/api_rest/api_rest/api1/views.py,sha256=kOt2xT6bxO47_z__5yYR9kcYIWWv4qYzpX0K8Tqonik,758
681
682
  test_holado/tools/django/api_rest/api_rest/api1/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
682
- holado-0.11.3.dist-info/METADATA,sha256=WqOxGK8nQl9F-5TCd1mOpqI4VYDpMhStD355pcPKBWI,7660
683
- holado-0.11.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
684
- holado-0.11.3.dist-info/licenses/LICENSE,sha256=IgGmNlcFHnbp7UWrLJqAFvs_HIgjJDTmjCNRircJLsk,1070
685
- holado-0.11.3.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,,
@@ -93,7 +93,7 @@ class AISMessages(object):
93
93
  msg_dict = msg.asdict(enum_as_int=enum_as_int, ignore_spare=ignore_spare)
94
94
 
95
95
  # Extract tagblock of first sentence if present, and add tagblock information in result
96
- tag_block_str, _ = self.split_sentence_to_tab_block_and_message(sentences[0])
96
+ tag_block_str, _ = self.split_sentence_to_tag_block_and_message(sentences[0])
97
97
  if tag_block_str is None:
98
98
  tag_block_dict = None
99
99
  else:
@@ -283,7 +283,7 @@ class AISMessages(object):
283
283
 
284
284
  return res
285
285
 
286
- def split_sentence_to_tab_block_and_message(self, ais_sentence):
286
+ def split_sentence_to_tag_block_and_message(self, ais_sentence):
287
287
  if isinstance(ais_sentence, str):
288
288
  split_char = '\\'
289
289
  elif isinstance(ais_sentence, bytes):
@@ -208,7 +208,7 @@ if AISMessages.is_available():
208
208
  msg_var_name = StepTools.evaluate_variable_name(msg_var_name)
209
209
  ais_sentence = StepTools.evaluate_scenario_parameter(ais_sentence)
210
210
 
211
- tb, msg = __get_ais_messages().split_sentence_to_tab_block_and_message(ais_sentence)
211
+ tb, msg = __get_ais_messages().split_sentence_to_tag_block_and_message(ais_sentence)
212
212
 
213
213
  __get_variable_manager().register_variable(tb_var_name, tb)
214
214
  __get_variable_manager().register_variable(msg_var_name, msg)
@@ -99,7 +99,7 @@ class PersistedMethodToCallManager(PersistedDataManager):
99
99
  @param delete_on_fail: If True, delete method after its fail
100
100
  @param delete_on_success_after_fail: If True, delete method after its success even if it has previously failed
101
101
  """
102
- if self.__scope_name is not any_value:
102
+ if self.__scope_name is any_value:
103
103
  raise TechnicalException("To add a method to call, the scope name must be specified")
104
104
 
105
105
  # Define persisted data that can define if method is already persisted
@@ -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
- SIb3DQEJARYUaGFycnliYWdkaUBnbWFpbC5jb20wHhcNMjUxMDIyMDkwOTA0WhcN
6
- MjUxMDIzMDkwOTA0WjAcMRowGAYDVQQDDBF0Y3BiaW4uY29tLWNsaWVudDCCASIw
7
- DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxBxWBybXhqGWMhtI3vpad9SP9k
8
- 0IsZSIHRRPI27FU/kfoTfMrQayKVggdlyenD3OojsEfNd8mvjz9ApIpogouYgZD4
9
- 0zqHT8G4B15RASWP2K20WWNuKr7HgvraPwTbjDbtg8XU4kwgGOs1XftPhSi9N2DU
10
- /O6sEkgprqpkNAAZvn8bHRTpDB4FMqbTmH3ojawtz6PeW4I9YJLvbYFYwmmYrNpD
11
- L5pLnfyt6MS5/x5MGlpvcCaiQU3hWS8JOKpgP6XrIIsu65fQC+UU4MJIYg/StGPj
12
- rJ7eRBUoi11tGMCfF38AtYUgdNXdVjDM93F+Oks8tVGSZ9d7cwQknKMUgwECAwEA
13
- AaNCMEAwHQYDVR0OBBYEFBOraPFlFALkITNnlh3s4B564QvFMB8GA1UdIwQYMBaA
14
- FOLuMowBSAZfV5v82LmlaIIOvU/DMA0GCSqGSIb3DQEBCwUAA4IBAQA/LgtD4+3x
15
- myJUWPz8TAJ41zIK2AxUgLmlinQnKzvXdHFjJZtYQPxadOdZon7q3Jw7J2FpaQLh
16
- cc1h9pKIVaPXiR6I4CStKzw6peBtKJ2oN6uaZpSCQza+TC7Bg50uMbJmW+ph8tkY
17
- t2wmNFh6Q3+yC8kxQM5u0Cg2NDYGepwNhdUfVy1HpgLaM8Gr5gPSD01p1fyb7pcJ
18
- MWBK0kK6f0JcxZsIvSVuDX4Fc51LppEqv1THL5G4q3sWacksy0VG/izxLgB3hXs1
19
- VJBUWAMgbvAjAV15XCmvC3k5mMlyIrfXRO8uPpD5iIDdgQQJ5/Bo4UPFGJPOkLV3
20
- OEqtvNchmuBf
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
- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCsQcVgcm14ahlj
3
- IbSN76WnfUj/ZNCLGUiB0UTyNuxVP5H6E3zK0GsilYIHZcnpw9zqI7BHzXfJr48/
4
- QKSKaIKLmIGQ+NM6h0/BuAdeUQElj9ittFljbiq+x4L62j8E24w27YPF1OJMIBjr
5
- NV37T4UovTdg1PzurBJIKa6qZDQAGb5/Gx0U6QweBTKm05h96I2sLc+j3luCPWCS
6
- 722BWMJpmKzaQy+aS538rejEuf8eTBpab3AmokFN4VkvCTiqYD+l6yCLLuuX0Avl
7
- FODCSGIP0rRj46ye3kQVKItdbRjAnxd/ALWFIHTV3VYwzPdxfjpLPLVRkmfXe3ME
8
- JJyjFIMBAgMBAAECggEBAIfNwqJrFEseuq0g4YwVJ3CIoYhYHuHLKRLPvZ+IFYKP
9
- /7I8suHittQpMr5KTYly1TPytwOkxY/ITRL9D7ve8SzFK0D0KvO1wfdj8ss06caH
10
- RbiMuvxc2m5WNLk4Xv6haEXVs1HAqDiEBaFKDbIX209m/cXlpRM1raQe2ImVPjnk
11
- xtdzpLYgRIf4MHtjAI22knlsSgypay6cpUF+PArmgepmsIaw+ioy5ItSWTmvq8QU
12
- 9KhnEtdn8UOciLiP2rnLgql+qF8RCL9R/NTTZo+kC00AMEliQBFaLHsLHuFuAQwT
13
- 6X9ueOtEOAewWhhelScbfub5ZlVwvvWhawLqoyGiRZECgYEA1TAlMXhZCrtAIyk/
14
- Q0dCbrMl24Mr6Yv+PC8Z9N/EC5UrddPwk2W4/L+e8kU6XyyJ4Gw3ZQgJd8gTb1/0
15
- zpnaFXdK2VhyHxWz3UNzQ4lRuMVB1qK/5/yByqRhysKczzhufhf2XuIcDqiYsWHg
16
- C4VwpQAQSp9Vbcpd1biXEv1O8AMCgYEAztliCAXlExU3DmcRWbV0RpIjREAm9f6w
17
- uX8RRuFYZsHVY1pEkv5iACjofeZz9s/EC8QGo4ixcELEou5pFX1HYFyjjw2CwBmS
18
- a63l5KJyQcChF2tkDaEFsspM0Tri001h8LpChep6cZK4CkHkJ3MTXD4mqa+vpYgr
19
- RDUwZhdYu6sCgYBO0nE9/Dg3zonlNi/sySEX2ubpZXNL83W5fNTFBCLxAWNDOmxd
20
- oyOlV5gGDXCKleYYcwp8MV+GyRPefwT9ikbm3uduutPfCGArM/AfDVuIzG4OVLhN
21
- pr+6U9LQa+ocd8nqlyOBa2piRRXHp991gw3mA8MCRC0K3eKZzZkV7VBNTwKBgCTu
22
- UP9ntgebMRJEOqfOquzyqJNF9O7Uw07LLhV+pF7sWqH7euTXwD2REDlyTOATJkiH
23
- fjvyauPFOABzGpX4oSbGQ3mGCwMrTaYmDTat/kJZFynsRZfdWPwb/G0a22aomUT2
24
- rGvmemgOrwc9znNwq1M70YFYWb7vOfJaoMKJhpEzAoGBAKQCWrZWZRBEeid9QsQ3
25
- SVedImc8PN5IOC0vyydrkF5qV8LYsPmqMzfkOx0XAx6xrEUyjtSzZRgz/na1EzE6
26
- juGFIBW30Dx3Ej2A/pKQ7/Yuhdrhl5Nd/Dv5sBgtziBeC+5PYI0XqCV7nIGGOu2/
27
- 8SjHFk7En45EM/cT8l/VahAv
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:
@@ -0,0 +1,86 @@
1
+
2
+ #################################################
3
+ # HolAdo (Holistic Automation do)
4
+ #
5
+ # (C) Copyright 2021-2025 by Eric Klumpp
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
+ #
9
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
+
11
+ # The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.
12
+ #################################################
13
+
14
+ import logging
15
+ from holado_report.report.builders.report_builder import ReportBuilder
16
+ from holado_system.system.filesystem.file import File
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+
22
+ class SummaryByCategoryReportBuilder(ReportBuilder):
23
+ def __init__(self, filepath):
24
+ self.__filepath = filepath
25
+ self.__counter_by_category = {}
26
+ self.__categories_order = [
27
+ 'Regression',
28
+ 'Always Failed',
29
+ 'Random',
30
+ 'Regression but Not Relevant',
31
+ 'Always Not Relevant',
32
+ 'Random but Not Relevant',
33
+ 'Always Success',
34
+ 'Fixed',
35
+ 'Unknown'
36
+ ]
37
+
38
+ def build(self):
39
+ '''
40
+ The file is built after each scenario
41
+ '''
42
+ pass
43
+
44
+ def after_scenario(self, scenario, scenario_report=None):
45
+ from holado_report.report.report_manager import ReportManager
46
+ category_validation, _, _, _, _, _ = ReportManager.get_current_scenario_status_information(scenario)
47
+
48
+ if category_validation is not None:
49
+ ind = category_validation.find(' (')
50
+ category = category_validation[:ind] if ind > 0 else category_validation
51
+
52
+ if category not in self.__counter_by_category:
53
+ self.__counter_by_category[category] = 0
54
+ self.__counter_by_category[category] += 1
55
+
56
+ # Update categories order with unexpected category
57
+ if category not in self.__categories_order:
58
+ self.__categories_order.append(category)
59
+
60
+ self.__update_file()
61
+
62
+ def __update_file(self):
63
+ list_by_group = {
64
+ 'Success': [(k,self.__counter_by_category[k]) for k in self.__categories_order
65
+ if k in self.__counter_by_category and k in ['Always Success', 'Fixed']],
66
+ 'Failed': [(k,self.__counter_by_category[k]) for k in self.__categories_order
67
+ if k in self.__counter_by_category and k in ['Regression', 'Always Failed', 'Random']],
68
+ 'Not Relevant': [(k,self.__counter_by_category[k]) for k in self.__categories_order
69
+ if k in self.__counter_by_category and k in ['Regression but Not Relevant', 'Always Not Relevant', 'Random but Not Relevant']]
70
+ }
71
+ others_list = [(k,v) for k,v in self.__counter_by_category.items()
72
+ if k not in ['Always Success', 'Fixed', 'Regression', 'Always Failed', 'Random', 'Regression but Not Relevant', 'Always Not Relevant', 'Random but Not Relevant']]
73
+
74
+ lines = []
75
+ for group_name, group_list in list_by_group.items():
76
+ if group_list:
77
+ lines.append(f"{group_name:>12s}: {sum([x[1] for x in group_list]):5d} ({' ; '.join([f'{x[0]}: {x[1]}' for x in group_list])})")
78
+ else:
79
+ lines.append(f"{group_name:>12s}: {0:5d}")
80
+ if others_list:
81
+ lines.append(f"{'Others':>12s}: {sum([x[1] for x in others_list]):5d} ({' ; '.join([f'{x[0]}: {x[1]}' for x in others_list])})")
82
+
83
+ with File(self.__filepath, mode='wt', auto_flush=False) as fout:
84
+ fout.writelines(lines)
85
+
86
+
@@ -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,16 +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
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
27
26
  # from holado_core.scenario.scenario_duration_manager import ScenarioDurationManager
28
27
 
29
28
  logger = logging.getLogger(__name__)
@@ -58,6 +57,15 @@ class ReportManager(BaseReport):
58
57
  self.__multitask_manager = multitask_manager
59
58
 
60
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
+
61
69
  # self.set_execution_historic()
62
70
 
63
71
  if self.has_report_path:
@@ -86,6 +94,9 @@ class ReportManager(BaseReport):
86
94
  fn = self.get_path("report_summary.txt")
87
95
  self.add_report_builder(SummaryReportBuilder(fn))
88
96
 
97
+ fn = self.get_path("report_summary_by_category.txt")
98
+ self.add_report_builder(SummaryByCategoryReportBuilder(fn))
99
+
89
100
  @property
90
101
  def __feature_reports(self):
91
102
  return self.children_reports("feature")
@@ -289,7 +300,9 @@ class ReportManager(BaseReport):
289
300
 
290
301
  logger.debug(f"Category of scenario '{scenario}': {category} (computed from last statuses: {statuses})")
291
302
 
292
- 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]
293
306
 
294
307
  return cls._scenario_status_information_by_uid[scenario_uid]
295
308
 
@@ -339,4 +352,64 @@ class ReportManager(BaseReport):
339
352
  return cls.get_step_error_message(step)
340
353
  return None
341
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
+
342
415
 
@@ -21,6 +21,7 @@ from holado.common.handlers.undefined import undefined_argument, undefined_value
21
21
  import os
22
22
  from holado_core.common.tools.converters.converter import Converter
23
23
  from holado_core.common.exceptions.technical_exception import TechnicalException
24
+ from holado_core.common.handlers.wait import WaitFuncResult
24
25
 
25
26
  logger = logging.getLogger(__name__)
26
27
 
@@ -72,6 +73,8 @@ class TestServerClient(RestClient):
72
73
  logger.info(f"Test server is {'not ' if not self.__is_available else ''}available")
73
74
  return self.__is_available
74
75
 
76
+ # Monitoring
77
+
75
78
  def ping(self):
76
79
  url_parsed = urllib.parse.urlparse(self.url)
77
80
  netloc_pattern = r"(?P<host>.*?)(?::(?P<port>\d+))?$"
@@ -98,6 +101,23 @@ class TestServerClient(RestClient):
98
101
  logger.debug(f"Ping of test server succeeded for ({host}, {port})")
99
102
  return True
100
103
 
104
+ def is_healthy(self):
105
+ try:
106
+ response = self.get(f"health")
107
+ return response.status_code == 200
108
+ except:
109
+ return False
110
+
111
+ def wait_is_healthy(self, timeout_sec=300, do_raise_on_timeout=True):
112
+ logger.info("Waiting for test-server to be healthy...")
113
+ wait_context = WaitFuncResult(f"wait test-server is healthy", self.is_healthy)
114
+ wait_context.with_timeout(timeout_sec) \
115
+ .with_raise_on_timeout(do_raise_on_timeout) \
116
+ .with_process_in_thread(False)
117
+ wait_context.redo_until(True)
118
+ wait_context.execute()
119
+ logger.info("test-server is healthy")
120
+
101
121
 
102
122
  # Manage campaigns actions
103
123
 
@@ -11,13 +11,14 @@
11
11
  #################################################
12
12
 
13
13
  from flask.views import MethodView
14
- from holado.common.context.session_context import SessionContext
15
- import logging
14
+ # import logging
16
15
 
17
- logger = logging.getLogger(__name__)
16
+ # logger = logging.getLogger(__name__)
18
17
 
19
18
 
19
+ class HealthView(MethodView):
20
+
21
+ def get(self):
22
+ return {'status': 'healthy'}
20
23
 
21
- def _get_session_context():
22
- return SessionContext.instance()
23
24
 
@@ -5,6 +5,17 @@ info:
5
5
  description: |
6
6
  API exposed by Test Server.
7
7
  paths:
8
+ /health:
9
+ get:
10
+ description: "Healthcheck"
11
+ responses:
12
+ 200:
13
+ description: "Healthy"
14
+ content:
15
+ application/json:
16
+ schema:
17
+ type: "string"
18
+
8
19
  /campaign/update:
9
20
  put:
10
21
  description: "Update stored campaigns"
@@ -18,6 +18,7 @@ from holado.common.handlers.undefined import default_value, undefined_argument,\
18
18
  import os
19
19
  from holado_core.common.tools.converters.converter import Converter
20
20
  from holado_rest.api.rest.rest_manager import RestManager
21
+ from holado_core.common.handlers.wait import WaitFuncResult
21
22
 
22
23
  logger = logging.getLogger(__name__)
23
24
 
@@ -63,6 +64,27 @@ class HostControllerClient(RestClient):
63
64
  def __init__(self, name, url, headers=None):
64
65
  super().__init__(name, url, headers)
65
66
 
67
+
68
+ # Monitoring
69
+
70
+ def is_healthy(self):
71
+ try:
72
+ response = self.get(f"health")
73
+ return response.status_code == 200
74
+ except:
75
+ return False
76
+
77
+ def wait_is_healthy(self, timeout_sec=300, do_raise_on_timeout=True):
78
+ logger.info("Waiting for host-controller to be healthy...")
79
+ wait_context = WaitFuncResult(f"wait test-server is healthy", self.is_healthy)
80
+ wait_context.with_timeout(timeout_sec) \
81
+ .with_raise_on_timeout(do_raise_on_timeout) \
82
+ .with_process_in_thread(False)
83
+ wait_context.redo_until(True)
84
+ wait_context.execute()
85
+ logger.info("host-controller is healthy")
86
+
87
+
66
88
  # Common features
67
89
 
68
90
  def get_environment_variable_value(self, var_name):
@@ -10,15 +10,15 @@
10
10
  # The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.
11
11
  #################################################
12
12
 
13
- # from flask.views import MethodView
14
- # from holado.common.context.session_context import SessionContext
13
+ from flask.views import MethodView
15
14
  # import logging
16
- #
15
+
17
16
  # logger = logging.getLogger(__name__)
18
- #
19
- #
20
- #
21
- # def _get_session_context():
22
- # return SessionContext.instance()
17
+
18
+
19
+ class HealthView(MethodView):
20
+
21
+ def get(self):
22
+ return {'status': 'healthy'}
23
23
 
24
24
 
@@ -9,6 +9,17 @@ info:
9
9
  For example, it is usefull for a testing solution needing to restart a microservice of the SUT (System Under Test),
10
10
  but the testing solution docker image has not the privileges to do it.
11
11
  paths:
12
+ /health:
13
+ get:
14
+ description: "Healthcheck"
15
+ responses:
16
+ 200:
17
+ description: "Healthy"
18
+ content:
19
+ application/json:
20
+ schema:
21
+ type: "string"
22
+
12
23
  /os/env:
13
24
  get:
14
25
  description: "Get environment variable values"
@@ -10,13 +10,15 @@
10
10
  # The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.
11
11
  #################################################
12
12
 
13
- # from flask.views import MethodView
14
- # from holado.common.context.session_context import SessionContext
13
+ from flask.views import MethodView
15
14
  # import logging
16
- #
15
+
17
16
  # logger = logging.getLogger(__name__)
18
- #
19
- #
20
- # def _get_session_context():
21
- # return SessionContext.instance()
17
+
18
+
19
+ class HealthView(MethodView):
20
+
21
+ def get(self):
22
+ return {'status': 'healthy'}
23
+
22
24
 
@@ -8,6 +8,17 @@ info:
8
8
  whereas all other microservices have user privileges.
9
9
  For example, it is usefull to monitor containers statuses from any terminal on the network.
10
10
  paths:
11
+ /health:
12
+ get:
13
+ description: "Healthcheck"
14
+ responses:
15
+ 200:
16
+ description: "Healthy"
17
+ content:
18
+ application/json:
19
+ schema:
20
+ type: "string"
21
+
11
22
  /os/env:
12
23
  get:
13
24
  description: "Get environment variable values"
@@ -44,3 +44,10 @@ from holado_test.behave.behave_environment import * # @UnusedWildImport
44
44
 
45
45
  # Define project specific environment methods
46
46
 
47
+ # Wait test daemons are healthy
48
+ from holado_core.common.tools.converters.converter import Converter
49
+ do_wait_test_server = Converter.to_boolean(os.getenv("HOLADO_WAIT_TEST_SERVER", True))
50
+ if do_wait_test_server:
51
+ SessionContext.instance().test_server_client.wait_is_healthy()
52
+
53
+