robotframework-qconnect-base 1.2.2__tar.gz → 1.3.0__tar.gz

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.
Files changed (29) hide show
  1. {robotframework_qconnect_base-1.2.2/robotframework_qconnect_base.egg-info → robotframework_qconnect_base-1.3.0}/PKG-INFO +1 -1
  2. robotframework_qconnect_base-1.3.0/QConnectBase/QConnectBase.pdf +0 -0
  3. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/connection_base.py +18 -3
  4. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/connection_manager.py +41 -3
  5. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/qlogger.py +3 -1
  6. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/serialclient/serial_base.py +1 -0
  7. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/tcp/raw/raw_tcp.py +2 -0
  8. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/tcp/ssh/ssh_client.py +12 -1
  9. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/version.py +2 -2
  10. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0/robotframework_qconnect_base.egg-info}/PKG-INFO +1 -1
  11. robotframework_qconnect_base-1.2.2/QConnectBase/QConnectBase.pdf +0 -0
  12. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/LICENSE +0 -0
  13. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/__init__.py +0 -0
  14. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/constants.py +0 -0
  15. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/message/__init__.py +0 -0
  16. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/message/rabbitmq_client.py +0 -0
  17. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/serialclient/__init__.py +0 -0
  18. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/tcp/__init__.py +0 -0
  19. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/tcp/raw/__init__.py +0 -0
  20. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/tcp/ssh/__init__.py +0 -0
  21. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/tcp/tcp_base.py +0 -0
  22. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/QConnectBase/utils.py +0 -0
  23. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/README.rst +0 -0
  24. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/robotframework_qconnect_base.egg-info/SOURCES.txt +0 -0
  25. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/robotframework_qconnect_base.egg-info/dependency_links.txt +0 -0
  26. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/robotframework_qconnect_base.egg-info/requires.txt +0 -0
  27. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/robotframework_qconnect_base.egg-info/top_level.txt +0 -0
  28. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/setup.cfg +0 -0
  29. {robotframework_qconnect_base-1.2.2 → robotframework_qconnect_base-1.3.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: robotframework-qconnect-base
3
- Version: 1.2.2
3
+ Version: 1.3.0
4
4
  Summary: Robot Framework test library for TCP, SSH, serial connection
5
5
  Home-page: https://github.com/test-fullautomation/robotframework-qconnect-base
6
6
  Author: Nguyen Huynh Tri Cuong
@@ -46,6 +46,11 @@ _platform = platform.system().lower()
46
46
  class BrokenConnError(Exception):
47
47
  pass
48
48
 
49
+ class EndOfBlockNotFound(Exception):
50
+ pass
51
+
52
+ class NoFilteredMsgFound(Exception):
53
+ pass
49
54
 
50
55
  class ConnectionBase(object):
51
56
  """
@@ -61,6 +66,8 @@ Base class for all connection classes.
61
66
 
62
67
  RECV_MSGS_POLLING_INTERVAL = 0.005
63
68
 
69
+ ACCEPT_VERIFY_PARAMS = None
70
+
64
71
  _call_thrd_obj = None
65
72
  _call_thrd_init = threading.Event()
66
73
  _call_thrd_term = threading.Event()
@@ -398,14 +405,14 @@ Thread to receive data from connection continuously.
398
405
  else:
399
406
  if matchObj is not None:
400
407
  back_trace_queue.append(msg)
401
- (is_hit, result_obj) = self._filter_msg(regex_filter, "\n".join(back_trace_queue))
408
+ if len(back_trace_queue):
409
+ (is_hit, result_obj) = self._filter_msg(regex_filter, "\r\n".join(back_trace_queue))
402
410
  else:
403
411
  (is_hit, result_obj) = self._filter_msg(regex_filter, msg)
404
412
  if is_hit:
405
413
  now = time.time()
406
- if (use_fetch_block is True) and regex_end_block_pattern and (regex_end_block_pattern.pattern != ".*"):
414
+ if (use_fetch_block is True) and regex_end_block_pattern and (regex_end_block_pattern.pattern != ".*") and len(back_trace_queue):
407
415
  result_obj = regex_filter.search("\r\n".join(back_trace_queue))
408
- back_trace_queue.clear()
409
416
  msg_queue.put((now, result_obj), False)
410
417
  self.post_msg_check(msg)
411
418
  except BrokenConnError as reason:
@@ -562,12 +569,20 @@ Suspend the control flow until a Trace message is received which matches to a sp
562
569
  except queue.Empty:
563
570
  success = False
564
571
  finally:
572
+ back_trace_queue = self._traceq_obj[trq_handle][2]
573
+ filtered_line_counter = len(back_trace_queue)
574
+ back_trace_queue.clear()
565
575
  self.deactivate_and_delete_trace_queue(trq_handle, trace_queue)
566
576
 
567
577
  BuiltIn().log('Completed %s' % _mident, constants.LOG_LEVEL_DEBUG)
578
+
579
+ if match is None and filtered_line_counter == 0 and filter_pattern != ".*":
580
+ raise NoFilteredMsgFound()
568
581
  if success:
569
582
  return match
570
583
  else:
584
+ if end_of_block_pattern is not None:
585
+ raise EndOfBlockNotFound()
571
586
  return None
572
587
 
573
588
  def wait_4_trace_continuously(self, trace_queue, timeout=0, *fct_args):
@@ -27,7 +27,7 @@
27
27
  #
28
28
  # *******************************************************************************
29
29
  from QConnectBase.utils import *
30
- from QConnectBase.connection_base import ConnectionBase
30
+ from QConnectBase.connection_base import ConnectionBase, EndOfBlockNotFound, NoFilteredMsgFound
31
31
  from robot.libraries.BuiltIn import BuiltIn
32
32
  from os.path import dirname
33
33
  from QConnectBase.utils import DictToClass
@@ -145,6 +145,31 @@ Constructor for ConnectionManager class.
145
145
  self.ROBOT_LIBRARY_LISTENER = self
146
146
  self.ROBOT_LISTENER_API_VERSION = 3
147
147
 
148
+ def __validate_optional_verify_parameters(self, optional_params, conn_name):
149
+ """
150
+ Validate optional parameters for verify keyword.
151
+
152
+ **Arguments:**
153
+
154
+ * ``optional_params``
155
+
156
+ / *Condition*: required / *Type*: dict /
157
+
158
+ Dictionary of optional parameters
159
+ """
160
+ connection_obj = self.get_connection_by_name(conn_name, raise_exception=True)
161
+ accept_verify_params = getattr(connection_obj, 'ACCEPT_VERIFY_PARAMS', None)
162
+ if accept_verify_params is None:
163
+ return
164
+
165
+ msg_supported_params = ''
166
+ if len(accept_verify_params) > 0:
167
+ msg_supported_params = f" Valid params: {', '.join(accept_verify_params)}"
168
+
169
+ invalid_params = [k for k in optional_params.keys() if k not in accept_verify_params]
170
+ if len(invalid_params) > 0:
171
+ raise Exception(f"Unexpected 'verify' parameter(s) found for '{connection_obj._CONNECTION_TYPE}' connection type: {', '.join(invalid_params)}.{msg_supported_params}")
172
+
148
173
  @staticmethod
149
174
  def import_modules_from_paths(paths):
150
175
  """
@@ -757,6 +782,7 @@ Verify a pattern from connection response after sending a command.
757
782
  - ``${res}[1]`` will be **command**, i.e. the second *captured string* defined in the pattern ``(command)``.
758
783
 
759
784
  """
785
+ self.__validate_optional_verify_parameters(kwargs, conn_name)
760
786
  validate_regex_pattern(search_pattern, 'search_pattern')
761
787
  if timeout is not None and timeout < self.MIN_VERIFY_TIMEOUT:
762
788
  raise Exception(
@@ -794,9 +820,16 @@ Verify a pattern from connection response after sending a command.
794
820
 
795
821
  BuiltIn().log(f"sending command '{send_cmd}' to '{conn_name}' ...", constants.LOG_LEVEL_INFO)
796
822
  res = None
823
+ eob_found = True
824
+ has_filtered_msg = True
797
825
  for i in range(1, match_try+1):
798
826
  kwargs['send_cmd'] = send_cmd
799
- res = connection_obj.wait_4_trace(search_pattern, timeout, fetch_block, eob_pattern, filter_pattern, **kwargs)
827
+ try:
828
+ res = connection_obj.wait_4_trace(search_pattern, timeout, fetch_block, eob_pattern, filter_pattern, **kwargs)
829
+ except EndOfBlockNotFound:
830
+ eob_found = False
831
+ except NoFilteredMsgFound:
832
+ has_filtered_msg = False
800
833
  if res is None:
801
834
  log_level = constants.LOG_LEVEL_WARNING if (i == match_try) else constants.LOG_LEVEL_INFO
802
835
  BuiltIn().log(f"[{conn_name}] Match try {i}/{match_try} timed out ('{search_pattern}')", log_level)
@@ -804,7 +837,12 @@ Verify a pattern from connection response after sending a command.
804
837
  break
805
838
 
806
839
  if not res:
807
- raise AssertionError(f"Failed to match the pattern '{search_pattern}' within '{match_try}' {'try' if match_try == 1 else 'tries'} ({conn_name}).")
840
+ if not eob_found:
841
+ raise AssertionError(f"Failed to match the end of block pattern '{eob_pattern}' within '{match_try}' {'try' if match_try == 1 else 'tries'} ({conn_name}).")
842
+ elif not has_filtered_msg:
843
+ raise AssertionError(f"Failed to receive any message that matches the filter pattern '{filter_pattern}' within '{match_try}' {'try' if match_try == 1 else 'tries'} ({conn_name}).")
844
+ else:
845
+ raise AssertionError(f"Failed to match the pattern '{search_pattern}' within '{match_try}' {'try' if match_try == 1 else 'tries'} ({conn_name}).")
808
846
 
809
847
  # Determine if the pattern has capturing groups
810
848
  has_groups = has_capturing_groups(search_pattern) if search_pattern else False
@@ -163,6 +163,7 @@ Check if the connection config is supported by this handler.
163
163
  return isinstance(config.logfile, str) and \
164
164
  config.logfile != 'nonlog' and \
165
165
  config.logfile != 'console' and \
166
+ config.logfile != '' and \
166
167
  config.logfile != constants.DEFAULT_LOGGER
167
168
 
168
169
 
@@ -250,7 +251,8 @@ Check if the connection config is supported by this handler.
250
251
  False if the config is not supported.
251
252
  """
252
253
  return (isinstance(config.logfile, bool) and config.logfile) or \
253
- config.logfile == constants.DEFAULT_LOGGER
254
+ config.logfile == constants.DEFAULT_LOGGER or \
255
+ config.logfile == ''
254
256
 
255
257
 
256
258
  class QConsoleHandler(logging.StreamHandler):
@@ -58,6 +58,7 @@ Class for handling serial connection.
58
58
  """
59
59
  _CONNECTION_TYPE = "SerialBase"
60
60
  _socket_instance = 0
61
+ ACCEPT_VERIFY_PARAMS = []
61
62
 
62
63
  def __init__(self, _mode, config):
63
64
  """
@@ -92,6 +92,7 @@ class RawTCPServer(TCPBaseServer, RawTCPBase):
92
92
  Class for a raw tcp connection server.
93
93
  """
94
94
  _CONNECTION_TYPE = "TCPIPServer"
95
+ ACCEPT_VERIFY_PARAMS = []
95
96
 
96
97
  def __init__(self, mode=None, config=None):
97
98
  """
@@ -120,6 +121,7 @@ class RawTCPClient(TCPBaseClient, RawTCPBase):
120
121
  Class for a raw tcp connection client.
121
122
  """
122
123
  _CONNECTION_TYPE = "TCPIPClient"
124
+ ACCEPT_VERIFY_PARAMS = []
123
125
 
124
126
  def __init__(self, mode=None, config=None):
125
127
  """
@@ -55,6 +55,8 @@ Class to store the configuration for SSH connection.
55
55
  password = ''
56
56
  authentication = 'password'
57
57
  key_filename = None
58
+ prompt_regex = r'[#$>] ?$'
59
+ timeout = 10
58
60
 
59
61
 
60
62
  class SSHClient(TCPBase, TCPBaseClient):
@@ -62,6 +64,7 @@ class SSHClient(TCPBase, TCPBaseClient):
62
64
  SSH client connection class.
63
65
  """
64
66
  _CONNECTION_TYPE = "SSHClient"
67
+ ACCEPT_VERIFY_PARAMS = []
65
68
 
66
69
  def __init__(self, _mode, config):
67
70
  """
@@ -86,6 +89,7 @@ Constructor for SSHClient class.
86
89
  self._llrecv_thrd_obj = None
87
90
  self.chan = None
88
91
  self.client = None
92
+ self.shell_ready = threading.Event()
89
93
 
90
94
  self.config = SSHConfig(**config)
91
95
  config_tcp = {
@@ -98,6 +102,8 @@ Constructor for SSHClient class.
98
102
  self._password = self.config.password
99
103
  self._key_filename = self.config.key_filename
100
104
  self._authentication = self.config.authentication
105
+ self._conn_timeout = getattr(self.config, 'timeout', 10)
106
+ self._prompt_regex = re.compile(getattr(self.config, 'prompt_regex', r'[#$>] ?$'))
101
107
 
102
108
  # create the queue for this connection
103
109
  self.SSHq = queue.Queue()
@@ -132,6 +138,10 @@ Implementation the thread for getting data from ssh connection.
132
138
  for character in data:
133
139
  self.SSHq.put(character)
134
140
 
141
+ if not self.shell_ready.is_set():
142
+ if self._prompt_regex.search(data):
143
+ self.shell_ready.set()
144
+
135
145
  if self.chan.closed is True:
136
146
  break
137
147
 
@@ -219,7 +229,8 @@ Implementation for creating a SSH connection.
219
229
  # Therefore we need to open a shell.
220
230
  self.chan = self.client.invoke_shell()
221
231
  BuiltIn().log("%s: successfully invoked SSH shell for secure communication." % _mident, constants.LOG_LEVEL_DEBUG)
222
-
232
+ if not self.shell_ready.wait(timeout=self._conn_timeout):
233
+ raise TimeoutError(f"Shell prompt is not ready within {self._conn_timeout} seconds after invoking shell.")
223
234
  # switch echo off for this terminal
224
235
  # echo disturbs when the command contains part of the exepcted reponse, then regexp filtering will
225
236
  # fetch the command instead of the response.
@@ -12,5 +12,5 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- VERSION = '1.2.2'
16
- VERSION_DATE = '25.11.2025'
15
+ VERSION = '1.3.0'
16
+ VERSION_DATE = '13.01.2026'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: robotframework-qconnect-base
3
- Version: 1.2.2
3
+ Version: 1.3.0
4
4
  Summary: Robot Framework test library for TCP, SSH, serial connection
5
5
  Home-page: https://github.com/test-fullautomation/robotframework-qconnect-base
6
6
  Author: Nguyen Huynh Tri Cuong