holado 0.4.0__py3-none-any.whl → 0.4.2__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 (46) hide show
  1. holado/common/handlers/object.py +6 -0
  2. {holado-0.4.0.dist-info → holado-0.4.2.dist-info}/METADATA +2 -1
  3. {holado-0.4.0.dist-info → holado-0.4.2.dist-info}/RECORD +46 -25
  4. holado_core/tools/abstracts/blocking_command_service.py +9 -1
  5. holado_django/__init__.py +31 -0
  6. holado_django/server/HOWTO.txt +27 -0
  7. holado_django/server/django_projects/rest_api/db.sqlite3 +0 -0
  8. holado_django/server/django_projects/rest_api/manage.py +22 -0
  9. holado_django/server/django_projects/rest_api/rest_api/__init__.py +0 -0
  10. holado_django/server/django_projects/rest_api/rest_api/application/__init__.py +0 -0
  11. holado_django/server/django_projects/rest_api/rest_api/application/admin.py +3 -0
  12. holado_django/server/django_projects/rest_api/rest_api/application/apps.py +9 -0
  13. holado_django/server/django_projects/rest_api/rest_api/application/migrations/__init__.py +0 -0
  14. holado_django/server/django_projects/rest_api/rest_api/application/models.py +3 -0
  15. holado_django/server/django_projects/rest_api/rest_api/application/tests.py +3 -0
  16. holado_django/server/django_projects/rest_api/rest_api/application/views.py +6 -0
  17. holado_django/server/django_projects/rest_api/rest_api/asgi.py +16 -0
  18. holado_django/server/django_projects/rest_api/rest_api/settings.py +130 -0
  19. holado_django/server/django_projects/rest_api/rest_api/urls.py +35 -0
  20. holado_django/server/django_projects/rest_api/rest_api/wsgi.py +16 -0
  21. holado_django/server/django_server.py +110 -0
  22. holado_django/server/grpc_django_server.py +57 -0
  23. holado_django/tests/behave/steps/__init__.py +16 -0
  24. holado_django/tests/behave/steps/django_server_steps.py +83 -0
  25. holado_grpc/tests/behave/steps/private/api/grpc_steps.py +9 -9
  26. holado_logging/common/logging/log_config.py +4 -3
  27. holado_multitask/multitasking/multitask_manager.py +36 -10
  28. holado_python/standard_library/ssl/resources/certificates/tcpbin.crt +16 -16
  29. holado_python/standard_library/ssl/resources/certificates/tcpbin.key +26 -26
  30. holado_python/standard_library/ssl/ssl.py +5 -1
  31. holado_rest/api/rest/TODO.txt +1 -1
  32. holado_rest/api/rest/rest_client.py +9 -7
  33. holado_rest/tests/behave/steps/private/api/rest_steps.py +11 -13
  34. holado_swagger/swagger_hub/mockserver/mockserver_client.py +1 -1
  35. holado_system/system/command/command.py +31 -9
  36. holado_system/system/global_system.py +3 -3
  37. test_holado/environment.py +6 -4
  38. test_holado/features/NonReg/api/REST.feature +7 -2
  39. test_holado/features/NonReg/api/gRPC.feature +0 -6
  40. test_holado/initialize_holado.py +62 -0
  41. test_holado/logging.conf +4 -0
  42. test_holado/tools/django/api_rest/db.sqlite3 +0 -0
  43. {holado-0.4.0.dist-info → holado-0.4.2.dist-info}/WHEEL +0 -0
  44. {holado-0.4.0.dist-info → holado-0.4.2.dist-info}/licenses/LICENSE +0 -0
  45. /holado_helper/holado_module_template/{test → tests}/behave/steps/__init__.py +0 -0
  46. /holado_helper/holado_module_template/{test → tests}/behave/steps/private/__init__.py +0 -0
@@ -0,0 +1,110 @@
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
+ from holado_core.common.exceptions.technical_exception import TechnicalException
15
+ import logging
16
+ from holado_core.common.tools.tools import Tools
17
+ import os
18
+ from holado_core.tools.abstracts.blocking_command_service import BlockingCommandService
19
+ from holado_system.system.command.command import CommandStates
20
+ from holado_core.common.handlers.wait import WaitFuncResultVerifying
21
+ from holado.common.handlers.object import DeleteableObject
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ try:
26
+ import django # @UnusedImport
27
+ with_django = True
28
+ except Exception as exc:
29
+ if Tools.do_log(logger, logging.DEBUG):
30
+ logger.debug(f"DjangoServer is not available. Initialization failed on error: {exc}")
31
+ with_django = False
32
+
33
+
34
+ class DjangoServer(DeleteableObject):
35
+ """
36
+ Django server
37
+ """
38
+
39
+ @classmethod
40
+ def is_available(cls):
41
+ return with_django
42
+
43
+ def __init__(self, name, django_project_path, port=8000, runserver_args=None):
44
+ super().__init__(name)
45
+
46
+ self.__django_project_path = django_project_path
47
+ self.__runserver_port = port
48
+ self.__runserver_args = runserver_args
49
+ self.__project_command = None
50
+
51
+ if not os.path.exists(django_project_path):
52
+ raise TechnicalException(f"Django project doesn't exist (project path: '{django_project_path}')")
53
+
54
+ def _delete_object(self):
55
+ if self.__project_command is not None and self.__project_command.status == CommandStates.Running:
56
+ self.stop()
57
+
58
+ @property
59
+ def django_project_path(self):
60
+ return self.__django_project_path
61
+
62
+ @property
63
+ def runserver_port(self):
64
+ return self.__runserver_port
65
+
66
+ @property
67
+ def runserver_args(self):
68
+ return self.__runserver_args
69
+
70
+ def start(self):
71
+ self.__start_server_by_command()
72
+
73
+ def __start_server_by_command(self):
74
+ self.__project_command = self._new_project_command()
75
+ self.__project_command.start()
76
+ self._wait_until_server_is_reachable()
77
+
78
+ def _new_project_command(self):
79
+ manage_path = os.path.join(self.django_project_path, "manage.py")
80
+ cmd = f"python {manage_path} runserver {self.runserver_port}"
81
+ if self.runserver_args:
82
+ cmd += f" {self.runserver_args}"
83
+
84
+ res = BlockingCommandService(f"Command running Django server '{self.name}'", cmd)
85
+ res.auto_stop = True
86
+
87
+ return res
88
+
89
+ def _wait_until_server_is_reachable(self):
90
+ import requests
91
+ url = f"http://127.0.0.1:{self.runserver_port}"
92
+ redo = WaitFuncResultVerifying("server is reachable",
93
+ lambda: requests.get(url),
94
+ lambda result: result and result.status_code == 200 )
95
+ redo.ignoring(Exception)
96
+ redo.polling_every(0.01)
97
+ redo.execute()
98
+
99
+ def stop(self):
100
+ if self.__project_command is None or self.__project_command.status != CommandStates.Running:
101
+ raise TechnicalException(f"Django server of project '{self.name}' is not running (status: {self.__project_command.status if self.__project_command else 'Unkown'})")
102
+ self.__project_command.stop()
103
+
104
+ def join(self, timeout=None):
105
+ self.__project_command.join(timeout)
106
+
107
+
108
+
109
+
110
+
@@ -0,0 +1,57 @@
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
+ import os
16
+ from holado_core.tools.abstracts.blocking_command_service import BlockingCommandService
17
+ from holado_django.server.django_server import DjangoServer
18
+ from holado_core.common.handlers.wait import WaitFuncResultVerifying
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class GrpcDjangoServer(DjangoServer):
24
+ """
25
+ gRPC Django server
26
+ """
27
+
28
+ def __init__(self, name, django_project_path, runserver_args=None):
29
+ super().__init__(name, django_project_path, port=50051, runserver_args=runserver_args)
30
+
31
+ def _new_project_command(self):
32
+ manage_path = os.path.join(self.django_project_path, "manage.py")
33
+ cmd = f"python {manage_path} grpcrunserver"
34
+ if self.runserver_args:
35
+ cmd += f" {self.runserver_args}"
36
+
37
+ res = BlockingCommandService(f"Command running gRPC Django server '{self.name}'", cmd)
38
+ res.auto_stop = True
39
+
40
+ return res
41
+
42
+ def _wait_until_server_is_reachable(self):
43
+ import grpc_requests
44
+
45
+ endpoint = f"localhost:{self.runserver_port}"
46
+ def request_is_unimplemented():
47
+ try:
48
+ grpc_requests.Client.get_by_endpoint(endpoint)
49
+ except Exception as exc:
50
+ if "status = StatusCode.UNIMPLEMENTED" in str(exc):
51
+ return True
52
+ return False
53
+ redo = WaitFuncResultVerifying("server is reachable", request_is_unimplemented, lambda result: result )
54
+ redo.polling_every(0.01)
55
+ redo.execute()
56
+
57
+
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ #################################################
4
+ # HolAdo (Holistic Automation do)
5
+ #
6
+ # (C) Copyright 2021-2025 by Eric Klumpp
7
+ #
8
+ # 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:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
+
12
+ # 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.
13
+ #################################################
14
+
15
+
16
+ from .django_server_steps import *
@@ -0,0 +1,83 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ #################################################
4
+ # HolAdo (Holistic Automation do)
5
+ #
6
+ # (C) Copyright 2021-2025 by Eric Klumpp
7
+ #
8
+ # 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:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
+
12
+ # 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.
13
+ #################################################
14
+
15
+ from holado.common.context.session_context import SessionContext
16
+ from holado_test.behave.behave import * # @UnusedWildImport
17
+ import logging
18
+ from holado_test.scenario.step_tools import StepTools
19
+ from holado_django.server.django_server import DjangoServer
20
+ from holado_test.behave.scenario.behave_step_tools import BehaveStepTools
21
+ from holado_value.common.tables.converters.value_table_converter import ValueTableConverter
22
+ from holado_core.common.exceptions.technical_exception import TechnicalException
23
+ from holado_django.server.grpc_django_server import GrpcDjangoServer
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ def __get_session_context():
29
+ return SessionContext.instance()
30
+
31
+ def __get_scenario_context():
32
+ return __get_session_context().get_scenario_context()
33
+
34
+ def __get_text_interpreter():
35
+ return __get_scenario_context().get_text_interpreter()
36
+
37
+ def __get_variable_manager():
38
+ return __get_scenario_context().get_variable_manager()
39
+
40
+
41
+
42
+ @Given(r"(?P<var_name>{Variable}) = new Django server")
43
+ def step_impl(context, var_name):
44
+ var_name = StepTools.evaluate_variable_name(var_name)
45
+ table = BehaveStepTools.get_step_table(context)
46
+
47
+ kwargs = ValueTableConverter.convert_name_value_table_2_json_object(table)
48
+ if 'django_project_path' not in kwargs:
49
+ raise TechnicalException("Parameter 'django_project_path' is required")
50
+ if 'name' not in kwargs:
51
+ kwargs['name'] = f"Django server ({kwargs['django_project_path']})"
52
+
53
+ server = DjangoServer(**kwargs)
54
+
55
+ __get_variable_manager().register_variable(var_name, server)
56
+
57
+ @Given(r"(?P<var_name>{Variable}) = new gRPC Django server")
58
+ def step_impl(context, var_name):
59
+ var_name = StepTools.evaluate_variable_name(var_name)
60
+ table = BehaveStepTools.get_step_table(context)
61
+
62
+ kwargs = ValueTableConverter.convert_name_value_table_2_json_object(table)
63
+ if 'django_project_path' not in kwargs:
64
+ raise TechnicalException("Parameter 'django_project_path' is required")
65
+ if 'name' not in kwargs:
66
+ kwargs['name'] = f"Django server ({kwargs['django_project_path']})"
67
+
68
+ server = GrpcDjangoServer(**kwargs)
69
+
70
+ __get_variable_manager().register_variable(var_name, server)
71
+
72
+
73
+ @Step(r"start \(Django server: (?P<var_server>{Variable})\)")
74
+ def step_impl(context, var_server):
75
+ server = StepTools.evaluate_variable_value(var_server)
76
+ server.start()
77
+
78
+ @Step(r"stop \(Django server: (?P<var_server>{Variable})\)")
79
+ def step_impl(context, var_server):
80
+ server = StepTools.evaluate_variable_value(var_server)
81
+ server.stop()
82
+
83
+
@@ -49,18 +49,18 @@ def step_impl(context, var_name):
49
49
  var_name = StepTools.evaluate_variable_name(var_name)
50
50
 
51
51
  here = os.path.abspath(os.path.dirname(__file__))
52
- api_grpc_path = os.path.normpath(os.path.join(here, "..", "..", "..", "..", "..", "..", "..", "tests", "behave", "test_holado", "tools", "django", "api_grpc"))
53
- manage_path = os.path.join(api_grpc_path, "manage.py")
54
- cmd = f"python {manage_path} grpcrunserver"
52
+ django_project_path = os.path.normpath(os.path.join(here, "..", "..", "..", "..", "..", "..", "..", "tests", "behave", "test_holado", "tools", "django", "api_grpc"))
55
53
 
56
- obj = BlockingCommandService("internal gRPC server", cmd)
57
- obj.auto_stop = True
58
- obj.start()
59
-
60
- __get_variable_manager().register_variable(var_name, obj)
54
+ execute_steps(u"""
55
+ Given {var_name} = new gRPC Django server
56
+ | Name | Value |
57
+ | 'name' | 'gRPC server for holado tests' |
58
+ | 'django_project_path' | '{django_project_path}' |
59
+ When start (Django server: {var_name})
60
+ """.format(var_name=var_name, django_project_path=django_project_path))
61
61
 
62
62
  # Update imported grpc messages and services
63
- proto_path = os.path.join(api_grpc_path, "api_grpc", "api1", "proto")
63
+ proto_path = os.path.join(django_project_path, "api_grpc", "api1", "proto")
64
64
  __get_session_context().protobuf_messages.import_all_compiled_proto(proto_path)
65
65
  __get_session_context().grpc_services.import_all_compiled_proto(proto_path)
66
66
 
@@ -32,6 +32,10 @@ class LogConfig(object):
32
32
  logging.warning(f"Logging was already configured, it is not possible to configure it twice. This new configuration is skipped.")
33
33
  return
34
34
 
35
+ # Use holado loggers
36
+ if use_holado_logger:
37
+ cls.__set_holado_loggers()
38
+
35
39
  # HolAdo needs at least to add logging level TRACE and PRINT
36
40
  cls.add_logging_level_trace()
37
41
  cls.add_logging_level_print()
@@ -58,9 +62,6 @@ class LogConfig(object):
58
62
  log_in_file = True if log_in_file == "True" else False
59
63
  cls.log_in_file = log_in_file
60
64
 
61
- if use_holado_logger:
62
- cls.__set_holado_loggers()
63
-
64
65
  cls.__is_configured = True
65
66
 
66
67
  @classmethod
@@ -22,6 +22,8 @@ from holado_core.common.tools.tools import Tools
22
22
  from holado_python.standard_library.typing import Typing
23
23
  from holado.common.handlers.undefined import default_context
24
24
  from holado.common.context.session_context import SessionContext
25
+ import psutil
26
+ import signal
25
27
 
26
28
  logger = logging.getLogger(__name__)
27
29
 
@@ -60,16 +62,40 @@ class MultitaskManager(object):
60
62
  if pid is None:
61
63
  return os.getppid()
62
64
  else:
63
- if GlobalSystem.get_os_type() == OSTypes.Linux:
64
- # Read /proc/<pid>/status and look for the line `PPid:\t120517\n`
65
- with open(f"/proc/{pid}/status", encoding="ascii") as f:
66
- for line in f.readlines():
67
- if line.startswith("PPid:\t"):
68
- return int(line[6:])
69
- raise TechnicalException(f"No PPid line found in /proc/{pid}/status")
70
- else:
71
- raise TechnicalException(f"Unmanaged OS type {GlobalSystem.get_os_type().name}")
72
-
65
+ process = psutil.Process(pid)
66
+ return process.ppid()
67
+
68
+ @classmethod
69
+ def get_children_process_ids(cls, pid=None, recursive=False):
70
+ if pid is None:
71
+ pid = os.getpid()
72
+
73
+ process = psutil.Process(pid)
74
+ children = process.children(recursive=recursive)
75
+ return [c.pid for c in children]
76
+
77
+ @classmethod
78
+ def kill_process(cls, pid, sig=signal.SIGTERM, do_kill_children=True, recursively=True):
79
+ try:
80
+ process = psutil.Process(pid)
81
+ except psutil.NoSuchProcess:
82
+ return
83
+
84
+ # Kill children
85
+ if do_kill_children:
86
+ children = process.children(recursive=recursively)
87
+ for proc in children:
88
+ try:
89
+ proc.send_signal(sig)
90
+ except signal.SIGTERM:
91
+ pass
92
+
93
+ # Kill process
94
+ try:
95
+ process.send_signal(sig)
96
+ except signal.SIGTERM:
97
+ pass
98
+
73
99
  @classmethod
74
100
  def has_thread_native_id(cls):
75
101
  from holado_multitask.multithreading.threadsmanager import ThreadsManager
@@ -2,20 +2,20 @@
2
2
  MIIDZTCCAk2gAwIBAgIBKjANBgkqhkiG9w0BAQsFADCBizELMAkGA1UEBhMCVVMx
3
3
  CzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKDAZ0
4
4
  Y3BiaW4xDDAKBgNVBAsMA29wczETMBEGA1UEAwwKdGNwYmluLmNvbTEjMCEGCSqG
5
- SIb3DQEJARYUaGFycnliYWdkaUBnbWFpbC5jb20wHhcNMjUwNTI4MTMxODIwWhcN
6
- MjUwNTI5MTMxODIwWjAcMRowGAYDVQQDDBF0Y3BiaW4uY29tLWNsaWVudDCCASIw
7
- DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANvo9G/86es6qoCHTum0RAoqAAiY
8
- qnOCLgXmamgfQgbfYoBIkNTBBVzsZyoZIY4QuuO8E07VmbrnH23czCSAO5akPb7D
9
- teotATqDf4My0Ybht62nLoxhHBb9jrzSgv4+04gy/W6wu5diyfeY8BNopHkUkmEN
10
- WhmGkP9s9npUGaEfEeasuiB1JMkAEOWnw+kHqE3Us+4Av4Mht6srswst3B90WCIV
11
- Rry48gRJS4qZoAk1dwZHIcYSOfMJ8Pu69wS1qjRwRPLc3dfnUs2E3dAx1FDxDBkK
12
- eQ73VUm64A5AXLYRk3PvgPwbcgerkLAnYAb5o8YJmyufGXKQNhmZxcCt+t0CAwEA
13
- AaNCMEAwHQYDVR0OBBYEFDgjXXI6juiInalFSZEZM6BcEW9UMB8GA1UdIwQYMBaA
14
- FOLuMowBSAZfV5v82LmlaIIOvU/DMA0GCSqGSIb3DQEBCwUAA4IBAQAu6SJ3OT6D
15
- fhjfg4wRMHZVsaYSF6Kwe0RNt6izRkv5MUGi6Ew0SK1Mm+qxE51G3aaVCE4G+P1e
16
- ACOiBL55saWDJtdng2VTKhUsFxIk2c/t+tuh7ttV7i0yGbaLGDP0N2FveBhKj/5d
17
- SaPpAQvZ1rFhXpUU1jQr+xi5pP/iOPH02O8A8VgHyGebDVXs8iWMHjozOrRhgQVJ
18
- YAl5lyYs+aj199p9ixwY3RPPWbUcggvAipv9bu6uEEIWMOMMERM2P7yFYaWJBcw5
19
- A/Uqu2bBLmOu9/qmlEj2uQfTeVhnoT/bZBfmPcrL64tHjw7G5u0WuooPNTI23z28
20
- 3ttcr+fDbDR4
5
+ SIb3DQEJARYUaGFycnliYWdkaUBnbWFpbC5jb20wHhcNMjUwNzAxMTQyMDI3WhcN
6
+ MjUwNzAyMTQyMDI3WjAcMRowGAYDVQQDDBF0Y3BiaW4uY29tLWNsaWVudDCCASIw
7
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALmLkz54fCoSSM/uG945GvhavQF8
8
+ unsEDd0RuHWZPIBcrlEzhLLiiiegET4UFlywF4wSfbiNGgwr3Uw+6ph3xLrNs91B
9
+ EYqOGesT9wRPMlon88qsaVIFfbqfg4e1m0si+/NwZMk+5bBeYC0blXk7HiTZ5KJt
10
+ QNLeduIYaPSuyq+qxl/xDqWOifbKcgycitgCPKPxohtwa5h6IjU3WYb7+xNPt3cx
11
+ +hoCwfab1NgVBse6ZsUf81nkCEVKKLaNvlDkmXp9ItqZZay+0/yzLCgNyf8gDprU
12
+ 8u+nDM+pcz83OtIQWVeN5MtFjkA4nik55yqdlqnB1OWzEzaMSMh6Vsy13xMCAwEA
13
+ AaNCMEAwHQYDVR0OBBYEFG5H5JaQhWehs8VRJu88HbHgK9CvMB8GA1UdIwQYMBaA
14
+ FOLuMowBSAZfV5v82LmlaIIOvU/DMA0GCSqGSIb3DQEBCwUAA4IBAQCs93UG22r0
15
+ ZIF10IAoXVbPWOeXpKJgWpsQYURsGw7sB+Cgr/vK3P1lkZVMl72LUzNazmOQldev
16
+ zUQ0TtOq24go1iAYWc7zYlxo9OHNkbAUDoViKP63K/CkXNCIkXg00vmEUco1PQWU
17
+ +OEaTNrQCeiW2eqYie9WNc4T5a7aUHT3Xno7G8KXTM7gtW35FNI/b0CwVWHRFzev
18
+ n9VhRI9xrNYxpDqqxYu7diIV4TQVmscmNicuEtDB98kJ7yOAhlpzQhIFi1vQEefD
19
+ 4gZZ3ihlLd2XJWxiXZgeiz7dzva4oGcr9mU5Uohza3u/sjF34kx02+gNuv8x4Wil
20
+ CU9Rl0WFGJ00
21
21
  -----END CERTIFICATE-----
@@ -1,28 +1,28 @@
1
1
  -----BEGIN PRIVATE KEY-----
2
- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDb6PRv/OnrOqqA
3
- h07ptEQKKgAImKpzgi4F5mpoH0IG32KASJDUwQVc7GcqGSGOELrjvBNO1Zm65x9t
4
- 3MwkgDuWpD2+w7XqLQE6g3+DMtGG4betpy6MYRwW/Y680oL+PtOIMv1usLuXYsn3
5
- mPATaKR5FJJhDVoZhpD/bPZ6VBmhHxHmrLogdSTJABDlp8PpB6hN1LPuAL+DIber
6
- K7MLLdwfdFgiFUa8uPIESUuKmaAJNXcGRyHGEjnzCfD7uvcEtao0cETy3N3X51LN
7
- hN3QMdRQ8QwZCnkO91VJuuAOQFy2EZNz74D8G3IHq5CwJ2AG+aPGCZsrnxlykDYZ
8
- mcXArfrdAgMBAAECggEAe76UfcfloTY752M8ZonHl6iWqD+v+puQZkWILtsX/mIJ
9
- PYKX7QBIkkd8rdXCafzEDY4xlzTe8qtHpjyOqyN1ZIk7LXNXlFSK0nBYem1INgwh
10
- nZfru5aRheZcQah7ibG0unlm3riYdtFiMO9geKtzkaafz/kBcEemo/SepatZWK3m
11
- DQX6okkpHh04GZNIO52K2QCaYpmj14fXIi2p5M4+KD+gmYbXhkmzNdcjz2l/wkqo
12
- SziZf31nzuoHd6FuQ6vAsmXU/m6jW7Nll0wsxTm5Ynw5SoIrAbreJJmSSD8o2Shj
13
- mvzWlurk1SgOhtoHP+AaVAn454x/Fn7+8u0f5ptNyQKBgQDvKc/3etCi22ntlgQM
14
- dIwxbUPnmSvwejpMPOq3kMGTQWUJcKFinbPC28s/lJGzVjMsH5VisjiprCt3TXGN
15
- XwmLNaUycWN3po9HyLSndAjHWM4aQ3yTOFKfLFEDUhKi8Dxy995KmHhgSSHd65qM
16
- PvnPhITZWfKLkItCOmNEULxE8wKBgQDrZCji91ztgNyN3MHDGN2o854lAvWc1l6s
17
- 4L8ZwU/RCNYyvMkdhadASzLwVC44q/6txGjTHGjnJPdkzV2u+WsPVWG2uCaD9PV1
18
- 3L8wyG9sJ2YoJE5QcAQ+1J+rRN3fluzSKFiQNDpf7C5YqCPvk7C7lXFllGHM6FmF
19
- hoYbyIb07wKBgQDKaF+qulViz0FqIwFQLT8NAcVrd7W5MyitpwyayLcbUkgZYioj
20
- lQYzDuOH7swUtApg+GXsfpr39k9fC7rjg6BHIeKqu04MUHmIrjM+WTSoyd68WYtP
21
- 6WX7cn0py0ccgScXwfFuvnV6P8qaz7Afq5iuaSAp9zcPqQhCx7mFcrKzwwKBgQCo
22
- VH3woNgxd59BS4a8j8GjmmOTMCSYPayCkE3Yiyca4ujaa6qek/9guOX6exh6qnR7
23
- qyMTJRPXh9XqnfnKsM5grrwrwFC6uKf32x5WMl+LxjkFp8DhQNmoXMC554uK4xED
24
- 0JpUtSSxh+I0wDjCkKkn29y1uYCe2eF63RJ2N9ZavQKBgQCbHI/bMIZw/fsaijg3
25
- 676mpQqFPiQdXTogw8UWzZBAvP6eQOnqQ9aw4tJt6OZWnwCDMwXrEYk3H8qisZl7
26
- ou63o5t8bTrU4C6e1VIQ1XuQM4FEpx6/TFwBG2FXkgzGHUpHlR9+woxqvmQgfsiW
27
- tEJ/TZv7bU6s9FRLTzMspp+tIA==
2
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC5i5M+eHwqEkjP
3
+ 7hveORr4Wr0BfLp7BA3dEbh1mTyAXK5RM4Sy4oonoBE+FBZcsBeMEn24jRoMK91M
4
+ PuqYd8S6zbPdQRGKjhnrE/cETzJaJ/PKrGlSBX26n4OHtZtLIvvzcGTJPuWwXmAt
5
+ G5V5Ox4k2eSibUDS3nbiGGj0rsqvqsZf8Q6ljon2ynIMnIrYAjyj8aIbcGuYeiI1
6
+ N1mG+/sTT7d3MfoaAsH2m9TYFQbHumbFH/NZ5AhFSii2jb5Q5Jl6fSLamWWsvtP8
7
+ sywoDcn/IA6a1PLvpwzPqXM/NzrSEFlXjeTLRY5AOJ4pOecqnZapwdTlsxM2jEjI
8
+ elbMtd8TAgMBAAECggEAfLWcfSOcSObLO76NyppVT1IlsWc1K9O4wbrUYW5iZOBm
9
+ Zbub2GQ9eY6zqCb2NMxCt2oCSFXGiSG+dy3eniX5+5ig6PiAIsGKGB/uKl5UuJYb
10
+ 3UBu9astK49lZ4Sf4Sudbq0/gKge16FHQWpF2BrtEtXFP4rxRAo0m5jOio8lOlYG
11
+ VSBFrkww7aS0pbymELj+Yg0twrUQjeG/hhoA4juiAq8T6oilrNfxhgc8pi2e23Ix
12
+ iokPjVWWAylKr6+oKhgBj/MKoIcEPeyYem1rBCesO2Th5CHy4YwIsZq+456Wo9/z
13
+ efxjnr+1vrsH+WK83nff3wUMruchKbdP1p9sMSkwqQKBgQD0y8b7sK4omV/JRdS3
14
+ sADYETu2wshP22EuUbkDPICe5/ct1LWlTJAI84MkMcg4rOHuLubD32ttRA3SWnK/
15
+ eqXB3gkcstVhipjj5qH5sg3gCIOa5rmePY1Zn5v75BImYzHYBfqQ0Z99czBNQ4un
16
+ MPMxe1IRT+b6aU7EOWjSWG2X/wKBgQDCCZGpv+pFQqxb5YjPQqDn/7M9wE89b22T
17
+ G2weESzoBrnLCUA4M0QEhhgBkcb9grZQ0aCOzjqKTDF/2AnFOhP6IIzEVxkrsC/0
18
+ c150lU8kiIlkymVF7N5vwayPFUeNqaO5NdHOYu0HkEQ8h9FCFurc0OjA/8xRPXkp
19
+ AGar8P/Y7QKBgE+5jjSqdg4C5Y9Hjt/EEoJMGoaLKXHYoO3U78x+B+W45memvwH2
20
+ zXIc3LkM/Yh3xZ0s6TshqHsNjvLTQkvaReG9znnqRFRgLysKEfagZqRwIWxxeEJx
21
+ CXgG42ZGASM/axxP1isUGj1hJnoDZZgt+QZEg5Xfz/n+EgkWKW1YH1lBAoGAMw7L
22
+ ioxae+Egc4oBpvAUYRfStXQOJc9VWPlFSOAiHefvKbMEeAVdZ4dVd8xBPWIQ0VFn
23
+ 20v+8Xc9KzPQ1loC+bVo9R0qHWneJIfbGfhT+/wFk0UCwxSiL2waGQhzbJ5v24OC
24
+ 8rjrQCtBGWBvuuFG6dX6+RYWUGZJpHVbjvD6kb0CgYAnU00V1AZu39ku1iozaHoY
25
+ STedxCDtGZotOISDFzaqIxaJ1JUeWZ/90ZMIVHdE+pP8n2P8MN7rppBbTN6Mxcbq
26
+ uE9BfZJGN5A8PuugoJWBJwkfnhrEMXXSpz5SPQntCkrET7pkAW2Nx1CWRQKaj1pu
27
+ +CKEVUIhv/elJOdMV9mGbA==
28
28
  -----END PRIVATE KEY-----
@@ -90,7 +90,11 @@ class SslManager(object):
90
90
  f"Note: step 'Given CACERTS_PATH = CA certs file path (from certifi package)' can be used to get the path to CA file coming with 'certifi' package that is supposed to be installed when using ssl module",
91
91
  ]
92
92
  raise TechnicalException("\n".join(msg_list))
93
- logger.debug(f"Loaded CA certificates: {res.get_ca_certs()})")
93
+ try:
94
+ logger.debug(f"Loaded CA certificates: {res.get_ca_certs()})")
95
+ except NotImplementedError:
96
+ # Depending on environment, get_ca_certs can be not implemented (ex: python 3.10 and pip v25.1.1)
97
+ pass
94
98
  logger.debug(f"Loaded ciphers: {res.get_ciphers()})")
95
99
 
96
100
  except Exception as exc:
@@ -1,2 +1,2 @@
1
- Client with library "requests"
2
1
  Client with library "httpx"
2
+
@@ -66,15 +66,17 @@ class RestClient(object):
66
66
  self.__kwargs.update(ssl_kwargs)
67
67
 
68
68
  def response_result(self, response, status_ok=200):
69
- if response.status_code != status_ok:
70
- raise FunctionalException(f"[{self.name}] Request failed with status {response.status_code} (expected success status: {status_ok}")
71
-
72
69
  if "application/json" in response.headers['Content-Type']:
73
- return response.json()
70
+ res = response.json()
74
71
  elif response.headers['Content-Type'].startswith('text'):
75
- return response.text
72
+ res = response.text
76
73
  else:
77
- return response.content
74
+ res = response.content
75
+
76
+ if response.status_code != status_ok:
77
+ raise FunctionalException(f"[{self.name}] Request failed with status {response.status_code} (expected success status: {status_ok}) on error: {res}")
78
+
79
+ return res
78
80
 
79
81
  def request(self, method, path, **kwargs):
80
82
  url = self.__build_url(path=path)
@@ -117,7 +119,7 @@ class RestClient(object):
117
119
  # Ensure data is in json string format
118
120
  if 'data' in request_kwargs:
119
121
  data = request_kwargs.pop('data')
120
- if not isinstance(data, str):
122
+ if data is not None and not isinstance(data, str):
121
123
  data = json.dumps(data)
122
124
  res['data'] = data
123
125
 
@@ -17,6 +17,7 @@ from holado_test.behave.behave import * # @UnusedWildImport
17
17
  import os.path
18
18
  import logging
19
19
  from holado_test.scenario.step_tools import StepTools
20
+ from holado_django.server.django_server import DjangoServer
20
21
 
21
22
  logger = logging.getLogger(__name__)
22
23
 
@@ -40,22 +41,19 @@ def step_impl(context, var_name):
40
41
  var_name = StepTools.evaluate_variable_name(var_name)
41
42
 
42
43
  here = os.path.abspath(os.path.dirname(__file__))
43
- manage_path = os.path.normpath(os.path.join(here, "..", "..", "tools", "django", "api_rest", "manage.py"))
44
- cmd = f"python {manage_path} runserver"
44
+ django_project_path = os.path.normpath(os.path.join(here, "..", "..", "..", "..", "..", "..", "..", "tests", "behave", "test_holado", "tools", "django", "api_rest"))
45
45
 
46
46
  execute_steps(u"""
47
- Given {var_name} = new command '{cmd}' with
48
- | Name | Value |
49
- | 'auto_stop' | True |
50
- | 'blocking' | True |
51
- | 'name' | 'internal REST server' |
52
- Given run command {var_name}
53
- Then command {var_name} has status Ready
54
- When wait 5 seconds
55
- Then command {var_name} has status Running
56
- """.format(cmd=cmd, var_name=var_name))
57
-
47
+ Given {var_name} = new Django server
48
+ | Name | Value |
49
+ | 'name' | 'REST server for holado tests' |
50
+ | 'django_project_path' | '{django_project_path}' |
51
+ | 'port' | 8000 |
52
+ When start (Django server: {var_name})
53
+ """.format(var_name=var_name, django_project_path=django_project_path))
58
54
 
55
+
56
+
59
57
  @Given(r"(?P<var_name>{Variable}) = new internal REST client")
60
58
  def step_impl(context, var_name):
61
59
  var_name = StepTools.evaluate_variable_name(var_name)
@@ -45,7 +45,7 @@ class MockServerClient(RestClient):
45
45
  params['format'] = format_
46
46
 
47
47
  result = self.put('/mockserver/retrieve', params=params)
48
- res = result.json()
48
+ res = self.response_result(result)
49
49
 
50
50
  if since_datetime is not None:
51
51
  if not isinstance(since_datetime, datetime.datetime):