holado 0.9.0__py3-none-any.whl → 0.9.1__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 (40) hide show
  1. holado/common/context/session_context.py +6 -5
  2. {holado-0.9.0.dist-info → holado-0.9.1.dist-info}/METADATA +1 -1
  3. {holado-0.9.0.dist-info → holado-0.9.1.dist-info}/RECORD +39 -39
  4. holado_core/common/block/base.py +3 -3
  5. holado_core/common/tools/path_manager.py +1 -1
  6. holado_django/server/django_projects/rest_api/rest_api/urls.py +1 -1
  7. holado_docker/tests/behave/steps/tools/docker_controller/client_steps.py +2 -2
  8. holado_docker/tools/docker_controller/client/rest/docker_controller_client.py +38 -1
  9. holado_docker/tools/docker_controller/server/run_docker_controller_in_docker.sh +3 -3
  10. holado_examples/tests/behave/testing_solution/environment.py +3 -3
  11. holado_examples/tests/behave/testing_solution/src/context/session_context.py +2 -2
  12. holado_examples/tests/behave/testing_solution/steps/config_steps.py +1 -1
  13. holado_multitask/multithreading/loopthread.py +4 -4
  14. holado_python/common/tools/datetime.py +35 -17
  15. holado_python/standard_library/ssl/resources/certificates/tcpbin.crt +16 -16
  16. holado_python/standard_library/ssl/resources/certificates/tcpbin.key +26 -26
  17. holado_python/tests/behave/steps/standard_library/datetime_steps.py +2 -2
  18. holado_rabbitmq/tools/rabbitmq/rabbitmq_manager.py +3 -3
  19. holado_report/campaign/campaign_manager.py +8 -3
  20. holado_report/report/builders/detailed_scenario_failed_report_builder.py +11 -7
  21. holado_report/report/builders/failure_report_builder.py +4 -3
  22. holado_report/report/builders/short_scenario_failed_report_builder.py +6 -5
  23. holado_report/report/builders/summary_report_builder.py +1 -1
  24. holado_report/report/builders/summary_scenario_failed_report_builder.py +6 -5
  25. holado_report/report/builders/summary_scenario_report_builder.py +12 -11
  26. holado_report/report/execution_historic.py +4 -2
  27. holado_report/report/report_manager.py +63 -13
  28. holado_rest/api/rest/rest_client.py +5 -1
  29. holado_test/__init__.py +3 -0
  30. holado_test/common/context/feature_context.py +3 -3
  31. holado_test/common/context/scenario_context.py +3 -3
  32. holado_test/common/context/step_context.py +3 -3
  33. holado_test/test_server/client/rest/test_server_client.py +117 -0
  34. holado_test/test_server/server/run_test_server_in_docker.sh +7 -7
  35. holado_value/common/tools/unique_value_manager.py +2 -1
  36. test_holado/environment.py +1 -1
  37. test_holado/logging.conf +1 -0
  38. holado_docker/tools/docker_controller/docker_controller_manager.py +0 -46
  39. {holado-0.9.0.dist-info → holado-0.9.1.dist-info}/WHEEL +0 -0
  40. {holado-0.9.0.dist-info → holado-0.9.1.dist-info}/licenses/LICENSE +0 -0
@@ -12,7 +12,6 @@
12
12
  #################################################
13
13
 
14
14
  from holado.common.context.session_context import SessionContext
15
- from behave.model_core import Status
16
15
  from holado_core.common.tools.tools import Tools
17
16
  import logging
18
17
  # from holado_report.report.builders.json_execution_historic_report_builder import JsonExecutionHistoricReportBuilder
@@ -37,6 +36,8 @@ class ReportManager(BaseReport):
37
36
  TFeatureReport = None
38
37
  TStepTools = None
39
38
 
39
+ _scenario_status_information_by_uid = {}
40
+
40
41
  def __init__(self):
41
42
  super().__init__()
42
43
 
@@ -185,6 +186,10 @@ class ReportManager(BaseReport):
185
186
  # scenario_duration_tags = sdm.compute_scenario_duration_tags(duration_limit_tags, "long", missing_tag=True, new_tag=True, unchanged_tag=True, with_failed=True)
186
187
  # sdm.create_file_scenario_duration_tags(fn, scenario_duration_tags)
187
188
 
189
+ # Update campaigns stored in test server
190
+ if self._get_test_server_client().is_available:
191
+ self._get_test_server_client().update_stored_campaigns()
192
+
188
193
  def __enter_current_scenario_log_file(self):
189
194
  if SessionContext.instance().log_manager.in_file and self.has_report_path:
190
195
  log_filename = self.current_scenario_report.get_path("logs", "report.log")
@@ -197,21 +202,66 @@ class ReportManager(BaseReport):
197
202
  if SessionContext.instance().log_manager.in_file and self.has_report_path:
198
203
  log_filename = self.current_scenario_report.get_path("logs", "report.log")
199
204
  SessionContext.instance().log_manager.leave_log_file(log_filename, do_remove_log_file=True)
200
-
205
+
206
+ @classmethod
207
+ def _get_test_server_client(cls):
208
+ return SessionContext.instance().test_server_client
209
+
210
+ @classmethod
211
+ def _get_scenario_uid(cls, scenario):
212
+ return f"{scenario.filename} at l.{scenario.line}"
213
+
201
214
  @classmethod
202
215
  def get_current_scenario_status_information(cls, scenario):
203
- step_failed, step_nb = cls.get_step_failed_info(scenario)
204
-
205
- if step_failed is not None and hasattr(SessionContext.instance().get_scenario_context(), "is_in_preconditions") and SessionContext.instance().get_scenario_context().is_in_preconditions:
206
- status = "Failed in Preconditions"
207
- elif step_failed is not None and step_failed.keyword == "Given":
208
- status = "Failed in Given"
209
- elif step_failed is not None or scenario.status.has_failed():
210
- status = "Failed"
211
- else:
212
- status = scenario.status.name.capitalize()
216
+ scenario_uid = cls._get_scenario_uid(scenario)
217
+ if scenario_uid not in cls._scenario_status_information_by_uid:
218
+ step_failed, step_nb = cls.get_step_failed_info(scenario)
213
219
 
214
- return [status, step_failed, step_nb]
220
+ # Define scenario status
221
+ if step_failed is not None and hasattr(SessionContext.instance().get_scenario_context(), "is_in_preconditions") and SessionContext.instance().get_scenario_context().is_in_preconditions:
222
+ status = "Failed in Preconditions"
223
+ elif step_failed is not None and step_failed.keyword == "Given":
224
+ status = "Failed in Given"
225
+ elif step_failed is not None or scenario.status.has_failed():
226
+ status = "Failed"
227
+ else:
228
+ status = scenario.status.name.capitalize()
229
+
230
+ # Define scenario category
231
+ category = None
232
+ if cls._get_test_server_client().is_available:
233
+ # Get scenario execution statuses
234
+ scenario_name = f"{scenario.filename} at l.{scenario.line}"
235
+ sce_hist = cls._get_test_server_client().get_scenario_history(scenario_name=scenario_name, size=10)
236
+ statuses = [s['status'] for s in sce_hist[0]['statuses']] if sce_hist else []
237
+ statuses.append(status)
238
+
239
+ # Get scenario status sequences
240
+ passed_sequences = []
241
+ for status in statuses:
242
+ if status == 'Passed':
243
+ passed = True
244
+ elif status.startswith("Failed"):
245
+ passed = False
246
+ else:
247
+ continue
248
+ if len(passed_sequences) == 0 or passed != passed_sequences[-1]:
249
+ passed_sequences.append(passed)
250
+
251
+ # Compute category
252
+ if passed_sequences:
253
+ if len(passed_sequences) == 1:
254
+ category = 'Success' if passed_sequences[0] else 'Failed'
255
+ elif len(passed_sequences) > 2:
256
+ category = 'Randomly Failed'
257
+ elif passed_sequences[-1]:
258
+ category = 'Newly Success'
259
+ else:
260
+ category = 'Newly Failed'
261
+
262
+ cls._scenario_status_information_by_uid[scenario_uid] = [category, status, step_failed, step_nb]
263
+
264
+ return cls._scenario_status_information_by_uid[scenario_uid]
215
265
 
216
266
  @classmethod
217
267
  def get_step_failed_info(cls, scenario):
@@ -55,7 +55,11 @@ class RestClient(Object):
55
55
  self.__kwargs = {}
56
56
 
57
57
  self.__request_log_level = Config.log_level_rest_request
58
-
58
+
59
+ @property
60
+ def url(self):
61
+ return self.__url
62
+
59
63
  @property
60
64
  def request_log_level(self):
61
65
  return self.__request_log_level
holado_test/__init__.py CHANGED
@@ -23,5 +23,8 @@ def register():
23
23
  from holado_test.behave.behave_manager import BehaveManager
24
24
  SessionContext.instance().services.register_service_type("behave_manager", BehaveManager)
25
25
 
26
+ from holado_test.test_server.client.rest.test_server_client import TestServerClient
27
+ SessionContext.instance().services.register_service_type("test_server_client", TestServerClient.new_client)
28
+
26
29
 
27
30
 
@@ -13,10 +13,10 @@
13
13
 
14
14
  from builtins import super
15
15
  from holado.common.context.context import Context
16
- from datetime import datetime
17
16
  from holado_core.common.exceptions.technical_exception import TechnicalException
18
17
  from holado_scripting.common.tools.variable_manager import VariableManager
19
18
  from holado.common.context.session_context import SessionContext
19
+ from holado_python.common.tools.datetime import DateTime
20
20
 
21
21
  class FeatureContext(Context):
22
22
  def __init__(self, feature):
@@ -24,7 +24,7 @@ class FeatureContext(Context):
24
24
 
25
25
  self.__feature = feature
26
26
 
27
- self.__start_date = datetime.now()
27
+ self.__start_date = DateTime.now()
28
28
  self.__end_date = None
29
29
  self.__scenarios = []
30
30
 
@@ -64,7 +64,7 @@ class FeatureContext(Context):
64
64
  self.__scenarios.append(scenario_context)
65
65
 
66
66
  def end(self):
67
- self.__end_date = datetime.now()
67
+ self.__end_date = DateTime.now()
68
68
 
69
69
  def has_variable_manager(self):
70
70
  return self.has_object("variable_manager")
@@ -21,10 +21,10 @@ from holado_scripting.common.tools.expression_evaluator import ExpressionEvaluat
21
21
  from holado.common.context.session_context import SessionContext
22
22
  from holado_core.common.block.scope_manager import ScopeManager
23
23
  from holado_core.common.block.block_manager import BlockManager
24
- from datetime import datetime
25
24
  from holado_core.common.exceptions.technical_exception import TechnicalException
26
25
  from holado_scripting.text.verifier.text_verifier import TextVerifier
27
26
  from holado_multitask.multitasking.multitask_manager import MultitaskManager
27
+ from holado_python.common.tools.datetime import DateTime
28
28
 
29
29
  logger = logging.getLogger(__name__)
30
30
 
@@ -35,7 +35,7 @@ class ScenarioContext(Context):
35
35
 
36
36
  self.__scenario = scenario
37
37
 
38
- self.__start_date = datetime.now()
38
+ self.__start_date = DateTime.now()
39
39
  self.__end_date = None
40
40
 
41
41
  self.__main_thread_uid = SessionContext.instance().multitask_manager.main_thread_uid
@@ -150,7 +150,7 @@ class ScenarioContext(Context):
150
150
  return self.get_object("expression_evaluator")
151
151
 
152
152
  def end(self):
153
- self.__end_date = datetime.now()
153
+ self.__end_date = DateTime.now()
154
154
 
155
155
 
156
156
 
@@ -14,7 +14,7 @@
14
14
  from builtins import super
15
15
  from holado.common.context.context import Context
16
16
  import logging
17
- from datetime import datetime
17
+ from holado_python.common.tools.datetime import DateTime
18
18
 
19
19
  logger = logging.getLogger(__name__)
20
20
 
@@ -26,7 +26,7 @@ class StepContext(Context):
26
26
  self.__step = step
27
27
  self.__status = None
28
28
 
29
- self.__start_date = datetime.now()
29
+ self.__start_date = DateTime.now()
30
30
  self.__end_date = None
31
31
 
32
32
  def __str__(self):
@@ -60,7 +60,7 @@ class StepContext(Context):
60
60
  return None
61
61
 
62
62
  def end(self):
63
- self.__end_date = datetime.now()
63
+ self.__end_date = DateTime.now()
64
64
 
65
65
 
66
66
 
@@ -0,0 +1,117 @@
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_rest.api.rest.rest_client import RestClient
16
+ import socket
17
+ import urllib.parse
18
+ import re
19
+ from holado_rest.api.rest.rest_manager import RestManager
20
+ from holado.common.handlers.undefined import undefined_argument, undefined_value
21
+ import os
22
+ from holado_core.common.tools.converters.converter import Converter
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class TestServerClient(RestClient):
28
+
29
+ @classmethod
30
+ def new_client(cls, use_localhost=undefined_argument, **kwargs):
31
+ if 'name' not in kwargs:
32
+ kwargs['name'] = None
33
+ if 'url' not in kwargs:
34
+ if use_localhost is undefined_argument:
35
+ env_use = os.getenv("HOLADO_USE_LOCALHOST", False)
36
+ use_localhost = Converter.is_boolean(env_use) and Converter.to_boolean(env_use)
37
+
38
+ url = os.getenv("HOLADO_TEST_SERVER_URL", undefined_value)
39
+ if url is undefined_value:
40
+ scheme = kwargs.get('scheme', undefined_value)
41
+ if scheme is undefined_value:
42
+ scheme = os.getenv("HOLADO_TEST_SERVER_SCHEME", "http")
43
+ host = kwargs.get('host', undefined_value)
44
+ if host is undefined_value:
45
+ host = "localhost" if use_localhost else os.getenv("HOLADO_TEST_SERVER_HOST", "holado_test_server")
46
+ port = kwargs.get('port', undefined_value)
47
+ if port is undefined_value:
48
+ port = os.getenv("HOLADO_TEST_SERVER_PORT", 51232)
49
+
50
+ if port is None:
51
+ url = f"{scheme}://{host}"
52
+ else:
53
+ url = f"{scheme}://{host}:{port}"
54
+ kwargs['url'] = url
55
+
56
+ manager = RestManager(default_client_class=cls)
57
+ res = manager.new_client(**kwargs)
58
+
59
+ return res
60
+
61
+
62
+ def __init__(self, name, url, headers=None):
63
+ super().__init__(name, url, headers)
64
+
65
+ self.__is_available = None
66
+
67
+ @property
68
+ def is_available(self):
69
+ if self.__is_available is None:
70
+ self.__is_available = self.ping()
71
+ logger.info(f"Test server is {'not ' if not self.__is_available else ''}available")
72
+ return self.__is_available
73
+
74
+ def ping(self):
75
+ url_parsed = urllib.parse.urlparse(self.url)
76
+ netloc_pattern = r"(?P<host>.*?)(?::(?P<port>\d+))?$"
77
+ m = re.match(netloc_pattern, url_parsed.netloc)
78
+ host = m.group('host')
79
+ port = Converter.to_integer(m.group('port'))
80
+
81
+ sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
82
+ sock.settimeout(1)
83
+ try:
84
+ sock.connect((host,port))
85
+ except Exception as exc:
86
+ logger.debug(f"Ping of test server failed for ({host}, {port}): {str(exc)}")
87
+ return False
88
+ else:
89
+ sock.close()
90
+ logger.debug(f"Ping of test server succeeded")
91
+ return True
92
+
93
+
94
+ # Manage campaigns actions
95
+
96
+ def update_stored_campaigns(self):
97
+ response = self.put(f"campaign/update")
98
+ return self.response_result(response, status_ok=[200, 204])
99
+
100
+ def get_scenario_history(self, scenario_name=None, size=None):
101
+ data = {}
102
+ if scenario_name is not None:
103
+ data['scenario_name'] = scenario_name
104
+ if size is not None:
105
+ data['size'] = size
106
+
107
+ if data:
108
+ response = self.get(f"campaign/scenario/history", json=data)
109
+ else:
110
+ response = self.get(f"campaign/scenario/history", json=data)
111
+
112
+ return self.response_result(response, status_ok=[200, 204])
113
+
114
+
115
+
116
+
117
+
@@ -12,8 +12,8 @@
12
12
  # Have access to any HolAdo registry.
13
13
  #
14
14
  # Optionally, define in .profile the following variables
15
- # - HOLADO_TEST_SERVER_NAME: name of the container
16
- # - HOLADO_TEST_SERVER_PORT: REST API port to use (default: 8001)
15
+ # - HOLADO_TEST_SERVER_HOST: host of test-server, or name of its container
16
+ # - HOLADO_TEST_SERVER_PORT: REST API port to use (default: 51232)
17
17
  # - HOLADO_IMAGE_REGISTRY: docker image registry to use (default: holado/test_server)
18
18
  # - HOLADO_IMAGE_TAG: docker image tag to use (default: latest)
19
19
  # - HOLADO_OUTPUT_BASEDIR: absolute path to base output directory (default: [HOME]/.holado/output)
@@ -75,21 +75,21 @@ fi
75
75
 
76
76
  # Define port to use
77
77
  if [[ -z "$HOLADO_TEST_SERVER_PORT" ]]; then
78
- HOLADO_TEST_SERVER_PORT=8001
78
+ HOLADO_TEST_SERVER_PORT=51232
79
79
  fi
80
80
 
81
81
 
82
82
  # Docker run
83
- if [[ -z "$HOLADO_TEST_SERVER_NAME" ]]; then
84
- HOLADO_TEST_SERVER_NAME=holado_test_server
83
+ if [[ -z "$HOLADO_TEST_SERVER_HOST" ]]; then
84
+ HOLADO_TEST_SERVER_HOST=holado_test_server
85
85
  fi
86
86
 
87
87
  echo
88
- echo "Running Test Server (docker name: ${HOLADO_TEST_SERVER_NAME})..."
88
+ echo "Running Test Server (docker name: ${HOLADO_TEST_SERVER_HOST})..."
89
89
  echo " port: ${HOLADO_TEST_SERVER_PORT}"
90
90
  #echo " NETWORK_DEF_COMMAND=${NETWORK_DEF_COMMAND}"
91
91
  echo
92
- docker run --rm --user root --name ${HOLADO_TEST_SERVER_NAME} \
92
+ docker run --rm --user root --name ${HOLADO_TEST_SERVER_HOST} \
93
93
  -v "${OUTPUT_DIR}":/output \
94
94
  -v "${RESOURCES_DIR}":/resources \
95
95
  -e HOLADO_OUTPUT_BASEDIR=/output \
@@ -17,6 +17,7 @@ from datetime import datetime
17
17
  import string
18
18
  from holado_core.common.exceptions.technical_exception import TechnicalException
19
19
  from holado_core.common.tools.tools import Tools
20
+ from holado_python.common.tools.datetime import DateTime
20
21
 
21
22
  logger = logging.getLogger(__name__)
22
23
 
@@ -41,7 +42,7 @@ class UniqueValueManager(object):
41
42
  def new_integer(self, do_log=True):
42
43
  if self.__last_unique_int is None:
43
44
  # Compute timestamp as number of seconds since 01/01/2016
44
- self.__last_unique_int = int((datetime.now() - datetime(2020, 1, 1)).total_seconds()) - 1
45
+ self.__last_unique_int = int((DateTime.now(tz=None) - datetime(2020, 1, 1)).total_seconds()) - 1
45
46
 
46
47
  self.__last_unique_int += 1
47
48
  res = self.__last_unique_int
@@ -22,7 +22,7 @@ here = os.path.abspath(os.path.dirname(__file__))
22
22
  sys.path.insert(0, here)
23
23
 
24
24
  # Add HolAdo source paths (needed when using a clone of HolAdo project)
25
- from initialize_holado import insert_holado_source_paths
25
+ from initialize_holado import insert_holado_source_paths # @UnresolvedImport
26
26
  insert_holado_source_paths()
27
27
 
28
28
 
test_holado/logging.conf CHANGED
@@ -36,6 +36,7 @@ holado_s3.tools.s3.minio_client.trace=INFO
36
36
 
37
37
  #holado_system=DEBUG
38
38
  #holado_test.behave.behave=DEBUG
39
+ holado_test.test_server=DEBUG
39
40
  #holado_yaml=DEBUG
40
41
 
41
42
  # External libraries
@@ -1,46 +0,0 @@
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_core.common.tools.converters.converter import Converter
16
- import os
17
- from holado_docker.tools.docker_controller.client.rest.docker_controller_client import DockerControllerClient
18
- from holado_rest.api.rest.rest_manager import RestManager
19
- from holado.common.handlers.undefined import undefined_argument
20
-
21
- logger = logging.getLogger(__name__)
22
-
23
-
24
- class DockerControllerManager(object):
25
-
26
- @classmethod
27
- def new_client(cls, use_localhost=undefined_argument, **kwargs):
28
- if 'name' not in kwargs:
29
- kwargs['name'] = None
30
- if 'url' not in kwargs:
31
- if use_localhost is undefined_argument:
32
- env_use = os.getenv("HOLADO_USE_LOCALHOST", False)
33
- use_localhost = Converter.is_boolean(env_use) and Converter.to_boolean(env_use)
34
-
35
- host = "localhost" if use_localhost else os.getenv("HOLADO_DOCKER_CONTROLLER_NAME", "holado_docker_controller")
36
- port = os.getenv("HOLADO_DOCKER_CONTROLLER_PORT", 8000)
37
- kwargs['url'] = f"http://{host}:{port}"
38
-
39
- manager = RestManager(default_client_class=DockerControllerClient)
40
- res = manager.new_client(**kwargs)
41
-
42
- return res
43
-
44
-
45
-
46
-
File without changes