diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..85161c2 --- /dev/null +++ b/.flake8 @@ -0,0 +1,20 @@ +[flake8] +max-line-length = 119 +ignore = + # D10*: Missing docstring + D10 + # E203: whitespace before ':' + # This error is not PEP8 complaint and should be ignored + E203 + # W503: line break before binary operator + # seems to conflict with black code formatting + W503 + # W605: invalid escape sequence '\d' + W605 +exclude = + .git, + .tox, + .eggs, + __pycache__, + build, + dist diff --git a/Dockerfile b/Dockerfile index 15b0e05..debc411 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,42 +1,23 @@ -FROM debian:buster as builder +ARG BASE_IMAGE=alpine:3.17 +FROM ${BASE_IMAGE} ARG LIBDLT_VERSION=v2.18.8 RUN set -ex \ - && apt-get update \ - && apt-get upgrade -y \ - && apt-get install -y build-essential git cmake libdbus-1-dev cmake-data \ - libdbus-1-dev systemd libsystemd-dev wget curl zlib1g-dev - -# Install libdlt -RUN set -ex \ + && apk add --no-cache build-base musl-dev linux-headers git cmake ninja \ + wget curl dbus zlib \ + python3 python3-dev py3-pip py3-tox \ && git clone https://github.com/GENIVI/dlt-daemon \ && cd /dlt-daemon \ && git checkout ${LIBDLT_VERSION} \ && cd /dlt-daemon \ && cmake CMakeLists.txt \ - && make \ - && make install - -FROM debian:buster + && make -j \ + && make install \ + && ldconfig /usr/local/lib -# Install libdlt.so -COPY --from=builder /usr/local/lib /usr/local/lib +RUN mkdir -p /workspace -RUN set -ex \ - && ldconfig - -RUN set -ex \ - && apt-get update \ - && apt-get upgrade -y \ - && apt-get install -y python3 python3-pip python2 python2-dev git \ - && pip3 install --no-cache-dir setuptools tox \ - && apt-get clean all \ - && rm -rf \ - /var/cache/debconf/* \ - /var/lib/apt/lists/* \ - /var/log/* \ - /tmp/* \ - /var/tmp/* +WORKDIR /workspace # vim: set ft=dockerfile : diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..b5af3ef --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include LICENCE.txt diff --git a/Makefile b/Makefile index d1f72e9..50c5364 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ LIBDLT_VERSION=v2.18.8 IMAGE=python-dlt/python-dlt-unittest TAG?=latest DK_CMD=docker run --rm -v $(shell pwd):/pydlt -w /pydlt -TEST_ARGS?="-e py3,py27" +TEST_ARGS?="-e py3,lint" .PHONY: all all: diff --git a/README.rst b/README.md similarity index 92% rename from README.rst rename to README.md index a47d0f2..00447c8 100644 --- a/README.rst +++ b/README.md @@ -1,5 +1,4 @@ -python-dlt -========== +# python-dlt python-dlt is a thin Python ctypes wrapper around libdlt functions. It was primarily created for use with BMW's test execution framework. However, @@ -11,16 +10,14 @@ later versions might require adaptations. The package will not support previous versions from python-dlt v2.0. Also only GENIVI DLT daemon produced traces have been tested. - -Design ------- +## Design The code is split up into 3 primary components: * The `core`: This subpackage provides the major chunk of ctypes wrappers for the structures defined in libdlt. It abstracts out the libdlt structures for use - by the rest of mgu_dlt. Classes defined here ideally should *not* be used - outside of mgu_dlt. The module `core_base.py` provides the default + by the rest of python-dlt. Classes defined here ideally should *not* be used + outside of python-dlt. The module `core_base.py` provides the default implementation of the classes and the other `core_*.py` modules provide the overrides for the version specific implementations of libdlt. The correct version specific implementation will be loaded automatically at runtime. (the logic for @@ -29,11 +26,11 @@ The code is split up into 3 primary components: * The python interface classes: These are defined in `dlt.py`. Most of the classes here derive from their corresponding ctypes class definitions from `core` and provide a more python friendly api/access to the underlying C/ctypes - implementations. Ideally, python code using `mgu_dlt` would use these classes + implementations. Ideally, python code using `python-dlt` would use these classes rather than the base classes in `core`. * API for tools: This is the component that provides common interfaces required - by the tools that use `mgu_dlt`, like the `DLTBroker`, 'DLTLifecycle' etc. These + by the tools that use `python-dlt`, like the `DLTBroker`, 'DLTLifecycle' etc. These classes do not have equivalents in libdlt and were created based on usage requirements (and as such make assumptions about the manner in which they would be used). @@ -46,7 +43,7 @@ in C and is a pretty well laid out, straight forward (ie: not many layers of abstractions), small code base. Makes for good bedtime reading. The rest of this document will describe and demonstrate some of the design of -the external API of mgu_dlt. +the external API of python-dlt. The classes most relevant for users of python-dlt possibly are `DLTClient`, `DLTFile`, `DLTMessage`, `DLTBroker`. The names hopefully make their purpose @@ -56,6 +53,7 @@ Here are examples of some interesting ways to use these classes: * DLTFile and DLTMessage:: +```python >>> from dlt import dlt >>> # DLTFile object can be obtained by lading a trace file >>> d = dlt.load("high_full_trace.dlt") @@ -76,10 +74,12 @@ Here are examples of some interesting ways to use these classes: ... # the pickle protocol (this is to enable sharing ... # of the DLTMessage in a multiprocessing ... # environment) +``` * DLTClient and DLTBroker:: +```python >>> from dlt import dlt >>> c = dlt.DLTClient(servIP="127.0.0.1") # Only initializes the client >>> c.connect() # ...this connects @@ -102,10 +102,9 @@ Here are examples of some interesting ways to use these classes: >>> broker.start() >>> print(ctx.wait_for(count=10)) >>> +``` - -Design of DLTBroker -~~~~~~~~~~~~~~~~~~~ +## Design of DLTBroker The DLTBroker abstracts out the management of 2 (multiprocessing) queues: diff --git a/dlt/__init__.py b/dlt/__init__.py index c26635c..4e2690d 100644 --- a/dlt/__init__.py +++ b/dlt/__init__.py @@ -4,6 +4,7 @@ import collections import logging import subprocess + if not hasattr(subprocess, "TimeoutExpired"): import subprocess32 as subprocess # pylint: disable=import-error @@ -22,17 +23,14 @@ def run_command(command, timeout=60, shell=True): :rtype: subprocess compatible ProcessResult :raises RuntimeError: If timeout expires. """ - process = subprocess.Popen(command, - shell=shell, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + process = subprocess.Popen( + command, shell=shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) try: stdout, stderr = process.communicate(timeout=timeout) except subprocess.TimeoutExpired: process.terminate() - raise RuntimeError("Timeout %d seconds reached for command '%s'" - % (timeout, command)) + raise RuntimeError("Timeout %d seconds reached for command '%s'" % (timeout, command)) if isinstance(stdout, bytes): stdout = stdout.decode("utf-8") if isinstance(stderr, bytes): diff --git a/dlt/core/__init__.py b/dlt/core/__init__.py index 9703c8d..b44c318 100644 --- a/dlt/core/__init__.py +++ b/dlt/core/__init__.py @@ -1,14 +1,9 @@ # Copyright (C) 2017. BMW Car IT GmbH. All rights reserved. """Basic ctypes binding to the DLT library""" - -# pylint: disable=invalid-name,wildcard-import - import ctypes import os -import six - -from dlt.core.core_base import * +from dlt.core.core_base import * # noqa: F403 API_VER = None @@ -23,10 +18,7 @@ def get_version(loaded_lib): # buf would be something like: # DLT Package Version: X.XX.X STABLE, Package Revision: vX.XX.XX build on Jul XX XXXX XX:XX:XX # -SYSTEMD -SYSTEMD_WATCHDOG -TEST -SHM - if six.PY3: - buf_split = buf.value.decode().split() - else: - buf_split = buf.value.split() + buf_split = buf.value.decode().split() API_VER = buf_split[3] @@ -35,15 +27,15 @@ def get_version(loaded_lib): def get_api_specific_file(version): """Return specific version api filename, if not found fallback to first major version release""" - version_tuple = [int(num) for num in version.split('.')] - name = 'core_{}.py'.format("".join((str(num) for num in version_tuple))) + version_tuple = [int(num) for num in version.split(".")] + name = "core_{}.py".format("".join((str(num) for num in version_tuple))) if os.path.exists(os.path.join(os.path.dirname(os.path.abspath(__file__)), name)): return name # The minor version does not exist, try to truncate if version_tuple[-1] != 0: version_tuple = version_tuple[:-1] + [0] - name = 'core_{}.py'.format("".join((str(num) for num in version_tuple))) + name = "core_{}.py".format("".join((str(num) for num in version_tuple))) if not os.path.exists(os.path.join(os.path.dirname(os.path.abspath(__file__)), name)): raise ImportError("No module file: {}".format(name)) @@ -55,13 +47,15 @@ def check_libdlt_version(api_ver): python-dlt now only supports to run libdlt 2.18.5 or above. """ - ver_info = tuple(int(num) for num in api_ver.split('.')) + ver_info = tuple(int(num) for num in api_ver.split(".")) if ver_info < (2, 18, 5): - raise ImportError("python-dlt only supports libdlt \ - v2.18.5 (33fbad18c814e13bd7ba2053525d8959fee437d1) or above") + raise ImportError( + "python-dlt only supports libdlt \ + v2.18.5 (33fbad18c814e13bd7ba2053525d8959fee437d1) or above" + ) -API_VER = get_version(dltlib) +API_VER = get_version(dltlib) # noqa: F405 check_libdlt_version(API_VER) # Load version specific definitions, if such a file exists, possibly @@ -79,5 +73,5 @@ def check_libdlt_version(api_ver): # (as opposed to loading multiple implementations in a specific order) # to provide new/overriding implementations. api_specific_file = get_api_specific_file(API_VER) -overrides = __import__('dlt.core.{}'.format(api_specific_file[:-3]), globals(), locals(), ['*']) +overrides = __import__("dlt.core.{}".format(api_specific_file[:-3]), globals(), locals(), ["*"]) locals().update(overrides.__dict__) diff --git a/dlt/core/core_2185.py b/dlt/core/core_2185.py index a2b5d15..5435eb0 100644 --- a/dlt/core/core_2185.py +++ b/dlt/core/core_2185.py @@ -19,10 +19,13 @@ class sockaddr_in(ctypes.Structure): # pylint: disable=invalid-name """Auxiliary definition for cDltReceiver. Defined in netinet/in.h header""" - _fields_ = [("sa_family", ctypes.c_ushort), # sin_family - ("sin_port", ctypes.c_ushort), - ("sin_addr", ctypes.c_byte * 4), - ("__pad", ctypes.c_byte * 8)] # struct sockaddr_in is 16 + + _fields_ = [ + ("sa_family", ctypes.c_ushort), # sin_family + ("sin_port", ctypes.c_ushort), + ("sin_addr", ctypes.c_byte * 4), + ("__pad", ctypes.c_byte * 8), + ] # struct sockaddr_in is 16 class cDltReceiver(ctypes.Structure): # pylint: disable=invalid-name @@ -42,15 +45,18 @@ class cDltReceiver(ctypes.Structure): # pylint: disable=invalid-name struct sockaddr_in addr; /**< socket address information */ } DltReceiver; """ - _fields_ = [("lastBytesRcvd", ctypes.c_int32), - ("bytesRcvd", ctypes.c_int32), - ("totalBytesRcvd", ctypes.c_int32), - ("buffer", ctypes.POINTER(ctypes.c_char)), - ("buf", ctypes.POINTER(ctypes.c_char)), - ("backup_buf", ctypes.POINTER(ctypes.c_char)), - ("fd", ctypes.c_int), - ("buffersize", ctypes.c_int32), - ("addr", sockaddr_in)] + + _fields_ = [ + ("lastBytesRcvd", ctypes.c_int32), + ("bytesRcvd", ctypes.c_int32), + ("totalBytesRcvd", ctypes.c_int32), + ("buffer", ctypes.POINTER(ctypes.c_char)), + ("buf", ctypes.POINTER(ctypes.c_char)), + ("backup_buf", ctypes.POINTER(ctypes.c_char)), + ("fd", ctypes.c_int), + ("buffersize", ctypes.c_int32), + ("addr", sockaddr_in), + ] class cDltClient(ctypes.Structure): # pylint: disable=invalid-name @@ -69,13 +75,16 @@ class cDltClient(ctypes.Structure): # pylint: disable=invalid-name DltClientMode mode; /**< mode DltClientMode */ } DltClient; """ - _fields_ = [("receiver", cDltReceiver), - ("sock", ctypes.c_int), - ("servIP", ctypes.c_char_p), - ("hostip", ctypes.c_char_p), - ("port", ctypes.c_int), - ("serialDevice", ctypes.c_char_p), - ("socketPath", ctypes.c_char_p), - ("ecuid", ctypes.c_char * 4), - ("baudrate", ctypes.c_uint), - ("mode", ctypes.c_int)] + + _fields_ = [ + ("receiver", cDltReceiver), + ("sock", ctypes.c_int), + ("servIP", ctypes.c_char_p), + ("hostip", ctypes.c_char_p), + ("port", ctypes.c_int), + ("serialDevice", ctypes.c_char_p), + ("socketPath", ctypes.c_char_p), + ("ecuid", ctypes.c_char * 4), + ("baudrate", ctypes.c_uint), + ("mode", ctypes.c_int), + ] diff --git a/dlt/core/core_2188.py b/dlt/core/core_2188.py index 3b53464..db72a0b 100644 --- a/dlt/core/core_2188.py +++ b/dlt/core/core_2188.py @@ -2,9 +2,8 @@ """v2.18.8 specific class definitions""" import ctypes import logging -import six -from .core_base import dltlib +from dlt.core.core_base import dltlib # DltClientMode from dlt_client.h DLT_CLIENT_MODE_UNDEFINED = -1 @@ -59,16 +58,18 @@ class cDltReceiver(ctypes.Structure): # pylint: disable=invalid-name } DltReceiver; """ - _fields_ = [("lastBytesRcvd", ctypes.c_int32), - ("bytesRcvd", ctypes.c_int32), - ("totalBytesRcvd", ctypes.c_int32), - ("buffer", ctypes.POINTER(ctypes.c_char)), - ("buf", ctypes.POINTER(ctypes.c_char)), - ("backup_buf", ctypes.POINTER(ctypes.c_char)), - ("fd", ctypes.c_int), - ("type", ctypes.c_int), - ("buffersize", ctypes.c_int32), - ("addr", sockaddr_in)] + _fields_ = [ + ("lastBytesRcvd", ctypes.c_int32), + ("bytesRcvd", ctypes.c_int32), + ("totalBytesRcvd", ctypes.c_int32), + ("buffer", ctypes.POINTER(ctypes.c_char)), + ("buf", ctypes.POINTER(ctypes.c_char)), + ("backup_buf", ctypes.POINTER(ctypes.c_char)), + ("fd", ctypes.c_int), + ("type", ctypes.c_int), + ("buffersize", ctypes.c_int32), + ("addr", sockaddr_in), + ] class cDltClient(ctypes.Structure): # pylint: disable=invalid-name @@ -131,16 +132,15 @@ class cDLTFilter(ctypes.Structure): # pylint: disable=invalid-name # pylint: disable=too-many-arguments def add(self, apid, ctid, log_level=0, payload_min=0, payload_max=ctypes.c_uint32(-1).value // 2): """Add new filter pair""" - if six.PY3: - if isinstance(apid, str): - apid = bytes(apid, "ascii") - if isinstance(ctid, str): - ctid = bytes(ctid, "ascii") + if isinstance(apid, str): + apid = bytes(apid, "ascii") + if isinstance(ctid, str): + ctid = bytes(ctid, "ascii") if ( - dltlib.dlt_filter_add( - ctypes.byref(self), apid or b"", ctid or b"", log_level, payload_min, payload_max, self.verbose - ) - == DLT_RETURN_ERROR + dltlib.dlt_filter_add( + ctypes.byref(self), apid or b"", ctid or b"", log_level, payload_min, payload_max, self.verbose + ) + == DLT_RETURN_ERROR ): if self.counter >= DLT_FILTER_MAX: logger.error("Maximum number (%d) of allowed filters reached, ignoring filter!\n", DLT_FILTER_MAX) diff --git a/dlt/core/core_base.py b/dlt/core/core_base.py index bbd674d..cc3e623 100644 --- a/dlt/core/core_base.py +++ b/dlt/core/core_base.py @@ -3,9 +3,6 @@ import ctypes import logging import sys -import six - -# pylint: disable=too-few-public-methods,invalid-name,consider-using-ternary if sys.platform.startswith("darwin"): dltlib = ctypes.cdll.LoadLibrary("libdlt.dylib") @@ -63,22 +60,22 @@ DLT_CONTROL_TIME = 0x03 DLT_MSIN_MSTP_SHIFT = 1 # shift right offset to get mstp value DLT_MSIN_MTIN_SHIFT = 4 # shift right offset to get mtin value -DLT_MSIN_MSTP = 0x0e # message type -DLT_MSIN_MTIN = 0xf0 # message type info +DLT_MSIN_MSTP = 0x0E # message type +DLT_MSIN_MTIN = 0xF0 # message type info DLT_MSIN_VERB = 0x01 # verbose mode DLT_MSIN_CONTROL_RESPONSE = (DLT_TYPE_CONTROL << DLT_MSIN_MSTP_SHIFT) | (DLT_CONTROL_RESPONSE << DLT_MSIN_MTIN_SHIFT) # dlt_protocol.h DLT_SERVICE_ID_GET_SOFTWARE_VERSION = 0x13 # Service ID: Get software version -DLT_SERVICE_ID_UNREGISTER_CONTEXT = 0xf01 # Service ID: Message unregister context -DLT_SERVICE_ID_CONNECTION_INFO = 0xf02 # Service ID: Message connection info -DLT_SERVICE_ID_TIMEZONE = 0xf03 # Service ID: Timezone -DLT_SERVICE_ID_MARKER = 0xf04 # Service ID: Marker +DLT_SERVICE_ID_UNREGISTER_CONTEXT = 0xF01 # Service ID: Message unregister context +DLT_SERVICE_ID_CONNECTION_INFO = 0xF02 # Service ID: Message connection info +DLT_SERVICE_ID_TIMEZONE = 0xF03 # Service ID: Timezone +DLT_SERVICE_ID_MARKER = 0xF04 # Service ID: Marker DLT_CONNECTION_STATUS_DISCONNECTED = 0x01 # Client is disconnected DLT_CONNECTION_STATUS_CONNECTED = 0x02 # Client is connected -DLT_TYPE_INFO_TYLE = 0x0000000f # Length of standard data: 1 = 8bit, 2 = 16bit, 3 = 32 bit, 4 = 64 bit, 5 = 128 bit +DLT_TYPE_INFO_TYLE = 0x0000000F # Length of standard data: 1 = 8bit, 2 = 16bit, 3 = 32 bit, 4 = 64 bit, 5 = 128 bit DLT_TYPE_INFO_BOOL = 0x00000010 # Boolean data DLT_TYPE_INFO_SINT = 0x00000020 # Signed integer data DLT_TYPE_INFO_UINT = 0x00000040 # Unsigned integer data @@ -108,25 +105,79 @@ # dlt-viever/qdltbase.cpp qDltMessageType = [b"log", b"app_trace", b"nw_trace", b"control", b"", b"", b"", b""] -qDltLogInfo = [b"", b"fatal", b"error", b"warn", b"info", b"debug", b"verbose", b"", b"", b"", b"", - b"", b"", b"", b"", b""] -qDltTraceType = [b"", b"variable", b"func_in", b"func_out", b"state", b"vfb", b"", b"", b"", b"", - b"", b"", b"", b"", b"", b""] -qDltNwTraceType = [b"", b"ipc", b"can", b"flexray", b"most", b"vfb", b"", b"", b"", b"", b"", b"", - b"", b"", b"", b""] -qDltControlType = [b"", b"request", b"response", b"time", b"", b"", b"", b"", b"", b"", b"", b"", - b"", b"", b"", b""] +qDltLogInfo = [ + b"", + b"fatal", + b"error", + b"warn", + b"info", + b"debug", + b"verbose", + b"", + b"", + b"", + b"", + b"", + b"", + b"", + b"", + b"", +] +qDltTraceType = [ + b"", + b"variable", + b"func_in", + b"func_out", + b"state", + b"vfb", + b"", + b"", + b"", + b"", + b"", + b"", + b"", + b"", + b"", + b"", +] +qDltNwTraceType = [b"", b"ipc", b"can", b"flexray", b"most", b"vfb", b"", b"", b"", b"", b"", b"", b"", b"", b"", b""] +qDltControlType = [b"", b"request", b"response", b"time", b"", b"", b"", b"", b"", b"", b"", b"", b"", b"", b"", b""] cqDltMode = [b"non-verbose", b"verbose"] qDltEndianness = [b"little-endian", b"big-endian"] -cqDltTypeInfo = [b"String", b"Bool", b"SignedInteger", b"UnsignedInteger", b"Float", b"RawData", b"TraceInfo", - b"Utf8String"] -qDltCtrlServiceId = [b"", b"set_log_level", b"set_trace_status", b"get_log_info", b"get_default_log_level", - b"store_config", - b"reset_to_factory_default", b"set_com_interface_status", b"set_com_interface_max_bandwidth", - b"set_verbose_mode", b"set_message_filtering", b"set_timing_packets", b"get_local_time", - b"use_ecu_id", b"use_session_id", b"use_timestamp", b"use_extended_header", - b"set_default_log_level", - b"set_default_trace_status", b"get_software_version", b"message_buffer_overflow"] +cqDltTypeInfo = [ + b"String", + b"Bool", + b"SignedInteger", + b"UnsignedInteger", + b"Float", + b"RawData", + b"TraceInfo", + b"Utf8String", +] +qDltCtrlServiceId = [ + b"", + b"set_log_level", + b"set_trace_status", + b"get_log_info", + b"get_default_log_level", + b"store_config", + b"reset_to_factory_default", + b"set_com_interface_status", + b"set_com_interface_max_bandwidth", + b"set_verbose_mode", + b"set_message_filtering", + b"set_timing_packets", + b"get_local_time", + b"use_ecu_id", + b"use_session_id", + b"use_timestamp", + b"use_extended_header", + b"set_default_log_level", + b"set_default_trace_status", + b"get_software_version", + b"message_buffer_overflow", +] qDltCtrlReturnType = [b"ok", b"not_supported", b"error", b"3", b"4", b"5", b"6", b"7", b"no_matching_context_id"] @@ -140,15 +191,19 @@ class cDltServiceConnectionInfo(ctypes.Structure): char comid[DLT_ID_SIZE]; /**< communication interface */ } PACKED DltServiceConnectionInfo; """ - _fields_ = [("service_id", ctypes.c_uint32), - ("status", ctypes.c_uint8), - ("state", ctypes.c_uint8), - ("comid", DLT_ID_SIZE * ctypes.c_byte)] + + _fields_ = [ + ("service_id", ctypes.c_uint32), + ("status", ctypes.c_uint8), + ("state", ctypes.c_uint8), + ("comid", DLT_ID_SIZE * ctypes.c_byte), + ] _pack_ = 1 class MessageMode(object): """Default properties for the DLTMessage""" + # pylint: disable=no-member @property @@ -164,7 +219,7 @@ def is_mode_verbose(self): @property def mode_string(self): """Returns 'verbose' if DLTMessage is set to verbose mode. Otherwise 'non-verbose'""" - return b'verbose' if self.is_mode_verbose else b'non-verbose' + return b"verbose" if self.is_mode_verbose else b"non-verbose" @property def is_mode_non_verbose(self): @@ -274,9 +329,9 @@ def payload_decoded(self): """ text = b"" if self.is_mode_non_verbose and not self.is_type_control and self.noar == 0: - buf = ctypes.create_string_buffer('\000' * DLT_DAEMON_TEXTSIZE) + buf = ctypes.create_string_buffer("\000" * DLT_DAEMON_TEXTSIZE) dltlib.dlt_message_payload(ctypes.byref(self), buf, DLT_DAEMON_TEXTSIZE, DLT_OUTPUT_ASCII, self.verbose) - return b"[%s] #%s#" % (self.message_id_string, buf.value[4:].rstrip(b'\000')) + return b"[%s] #%s#" % (self.message_id_string, buf.value[4:].rstrip(b"\000")) if self.type == DLT_TYPE_CONTROL and self.subtype == DLT_CONTROL_RESPONSE: if self.ctrl_service_id == DLT_SERVICE_ID_MARKER: @@ -286,37 +341,38 @@ def payload_decoded(self): service_id = self.ctrl_service_id if self.ctrl_service_id == DLT_SERVICE_ID_GET_SOFTWARE_VERSION: - text += ctypes.string_at(self.databuffer, self.datasize)[9:].rstrip(b'\000') + text += ctypes.string_at(self.databuffer, self.datasize)[9:].rstrip(b"\000") elif self.ctrl_service_id == DLT_SERVICE_ID_CONNECTION_INFO: if self.datasize == ctypes.sizeof(cDltServiceConnectionInfo): - conn_info = cDltServiceConnectionInfo.from_buffer(bytearray(self.databuffer[:self.datasize])) + conn_info = cDltServiceConnectionInfo.from_buffer(bytearray(self.databuffer[: self.datasize])) if conn_info.state == DLT_CONNECTION_STATUS_DISCONNECTED: text += b"disconnected" elif conn_info.state == DLT_CONNECTION_STATUS_CONNECTED: text += b"connected" else: text += b"unknown" - text += b" " + ctypes.string_at(conn_info.comid, DLT_ID_SIZE).rstrip(b'\000') + text += b" " + ctypes.string_at(conn_info.comid, DLT_ID_SIZE).rstrip(b"\000") else: - text += ctypes.string_at(self.databuffer, self.datasize)[5:256+5].rstrip(b'\000') + text += ctypes.string_at(self.databuffer, self.datasize)[5 : 256 + 5].rstrip(b"\000") elif service_id == DLT_SERVICE_ID_TIMEZONE: - text += ctypes.string_at(self.databuffer, self.datasize)[5:256+5].rstrip(b'\000') + text += ctypes.string_at(self.databuffer, self.datasize)[5 : 256 + 5].rstrip(b"\000") else: - buf = ctypes.create_string_buffer(b'\000' * DLT_DAEMON_TEXTSIZE) - dltlib.dlt_message_payload(ctypes.byref(self), buf, DLT_DAEMON_TEXTSIZE, DLT_OUTPUT_ASCII, - self.verbose) - text += buf.value.rstrip(b'\000') + buf = ctypes.create_string_buffer(b"\000" * DLT_DAEMON_TEXTSIZE) + dltlib.dlt_message_payload( + ctypes.byref(self), buf, DLT_DAEMON_TEXTSIZE, DLT_OUTPUT_ASCII, self.verbose + ) + text += buf.value.rstrip(b"\000") return text if self.type == DLT_TYPE_CONTROL: return b"[%s] %s" % ( self.ctrl_service_id_string, - ctypes.string_at(self.databuffer, self.datasize)[4:256+4].rstrip(b'\000'), + ctypes.string_at(self.databuffer, self.datasize)[4 : 256 + 4].rstrip(b"\000"), ) - buf = ctypes.create_string_buffer(b'\000' * DLT_DAEMON_TEXTSIZE) + buf = ctypes.create_string_buffer(b"\000" * DLT_DAEMON_TEXTSIZE) dltlib.dlt_message_payload(ctypes.byref(self), buf, DLT_DAEMON_TEXTSIZE, DLT_OUTPUT_ASCII, self.verbose) - return buf.value.rstrip(b'\000').strip() + return buf.value.rstrip(b"\000").strip() class cDltStorageHeader(ctypes.Structure): @@ -332,10 +388,13 @@ class cDltStorageHeader(ctypes.Structure): char ecu[DLT_ID_SIZE]; /**< The ECU id is added, if it is not already in the DLT message itself */ } PACKED DltStorageHeader; """ - _fields_ = [("pattern", ctypes.c_char * DLT_ID_SIZE), - ("seconds", ctypes.c_uint32), - ("microseconds", ctypes.c_int32), - ("ecu", ctypes.c_char * DLT_ID_SIZE)] + + _fields_ = [ + ("pattern", ctypes.c_char * DLT_ID_SIZE), + ("seconds", ctypes.c_uint32), + ("microseconds", ctypes.c_int32), + ("ecu", ctypes.c_char * DLT_ID_SIZE), + ] _pack_ = 1 def __reduce__(self): @@ -352,9 +411,8 @@ class cDltStandardHeader(ctypes.BigEndianStructure): uint16_t len; /**< Length of the complete message, without storage header */ } PACKED DltStandardHeader; """ - _fields_ = [("htyp", ctypes.c_uint8), - ("mcnt", ctypes.c_uint8), - ("len", ctypes.c_ushort)] + + _fields_ = [("htyp", ctypes.c_uint8), ("mcnt", ctypes.c_uint8), ("len", ctypes.c_ushort)] _pack_ = 1 def __reduce__(self): @@ -371,9 +429,8 @@ class cDltStandardHeaderExtra(ctypes.Structure): uint32_t tmsp; /**< Timestamp since system start in 0.1 milliseconds */ } PACKED DltStandardHeaderExtra; """ - _fields_ = [("ecu", ctypes.c_char * DLT_ID_SIZE), - ("seid", ctypes.c_uint32), - ("tmsp", ctypes.c_uint32)] + + _fields_ = [("ecu", ctypes.c_char * DLT_ID_SIZE), ("seid", ctypes.c_uint32), ("tmsp", ctypes.c_uint32)] _pack_ = 1 def __reduce__(self): @@ -391,10 +448,13 @@ class cDltExtendedHeader(ctypes.Structure): char ctid[DLT_ID_SIZE]; /**< context id */ } PACKED DltExtendedHeader; """ - _fields_ = [("msin", ctypes.c_uint8), - ("noar", ctypes.c_uint8), - ("apid", ctypes.c_char * DLT_ID_SIZE), - ("ctid", ctypes.c_char * DLT_ID_SIZE)] + + _fields_ = [ + ("msin", ctypes.c_uint8), + ("noar", ctypes.c_uint8), + ("apid", ctypes.c_char * DLT_ID_SIZE), + ("ctid", ctypes.c_char * DLT_ID_SIZE), + ] _pack_ = 1 def __reduce__(self): @@ -431,23 +491,28 @@ class cDLTMessage(ctypes.Structure): } DltMessage; """ - _fields_ = [("found_serialheader", ctypes.c_int8), - ("resync_offset", ctypes.c_int32), - - ("headersize", ctypes.c_int32), - ("datasize", ctypes.c_int32), - - ("headerbuffer", ctypes.c_uint8 * (ctypes.sizeof(cDltStorageHeader) + - ctypes.sizeof(cDltStandardHeader) + - ctypes.sizeof(cDltStandardHeaderExtra) + - ctypes.sizeof(cDltExtendedHeader))), - ("databuffer", ctypes.POINTER(ctypes.c_uint8)), - ("databuffersize", ctypes.c_uint32), - - ("p_storageheader", ctypes.POINTER(cDltStorageHeader)), - ("p_standardheader", ctypes.POINTER(cDltStandardHeader)), - ("headerextra", cDltStandardHeaderExtra), - ("p_extendedheader", ctypes.POINTER(cDltExtendedHeader))] + _fields_ = [ + ("found_serialheader", ctypes.c_int8), + ("resync_offset", ctypes.c_int32), + ("headersize", ctypes.c_int32), + ("datasize", ctypes.c_int32), + ( + "headerbuffer", + ctypes.c_uint8 + * ( + ctypes.sizeof(cDltStorageHeader) + + ctypes.sizeof(cDltStandardHeader) + + ctypes.sizeof(cDltStandardHeaderExtra) + + ctypes.sizeof(cDltExtendedHeader) + ), + ), + ("databuffer", ctypes.POINTER(ctypes.c_uint8)), + ("databuffersize", ctypes.c_uint32), + ("p_storageheader", ctypes.POINTER(cDltStorageHeader)), + ("p_standardheader", ctypes.POINTER(cDltStandardHeader)), + ("headerextra", cDltStandardHeaderExtra), + ("p_extendedheader", ctypes.POINTER(cDltExtendedHeader)), + ] class cDltReceiver(ctypes.Structure): @@ -465,13 +530,16 @@ class cDltReceiver(ctypes.Structure): int32_t buffersize; /**< size of receiver buffer */ } DltReceiver; """ - _fields_ = [("lastBytesRcvd", ctypes.c_int32), - ("bytesRcvd", ctypes.c_int32), - ("totalBytesRcvd", ctypes.c_int32), - ("buffer", ctypes.POINTER(ctypes.c_char)), - ("buf", ctypes.POINTER(ctypes.c_char)), - ("fd", ctypes.c_int), - ("buffersize", ctypes.c_int32)] + + _fields_ = [ + ("lastBytesRcvd", ctypes.c_int32), + ("bytesRcvd", ctypes.c_int32), + ("totalBytesRcvd", ctypes.c_int32), + ("buffer", ctypes.POINTER(ctypes.c_char)), + ("buf", ctypes.POINTER(ctypes.c_char)), + ("fd", ctypes.c_int), + ("buffersize", ctypes.c_int32), + ] class cDltClient(ctypes.Structure): @@ -487,12 +555,14 @@ class cDltClient(ctypes.Structure): } DltClient; """ - _fields_ = [("receiver", cDltReceiver), - ("sock", ctypes.c_int), - ("servIP", ctypes.c_char_p), - ("serialDevice", ctypes.c_char_p), - ("baudrate", ctypes.c_int), - ("serial_mode", ctypes.c_int)] + _fields_ = [ + ("receiver", cDltReceiver), + ("sock", ctypes.c_int), + ("servIP", ctypes.c_char_p), + ("serialDevice", ctypes.c_char_p), + ("baudrate", ctypes.c_int), + ("serial_mode", ctypes.c_int), + ] class cDLTFilter(ctypes.Structure): # pylint: disable=invalid-name @@ -514,11 +584,10 @@ class cDLTFilter(ctypes.Structure): # pylint: disable=invalid-name # pylint: disable=too-many-arguments def add(self, apid, ctid): """Add new filter pair""" - if six.PY3: - if isinstance(apid, str): - apid = bytes(apid, "ascii") - if isinstance(ctid, str): - ctid = bytes(ctid, "ascii") + if isinstance(apid, str): + apid = bytes(apid, "ascii") + if isinstance(ctid, str): + ctid = bytes(ctid, "ascii") if dltlib.dlt_filter_add(ctypes.byref(self), apid or b"", ctid or b"", self.verbose) == DLT_RETURN_ERROR: if self.counter >= DLT_FILTER_MAX: logger.error("Maximum number (%d) of allowed filters reached, ignoring filter!\n", DLT_FILTER_MAX) diff --git a/dlt/dlt.py b/dlt/dlt.py index fc85c5f..72222a2 100644 --- a/dlt/dlt.py +++ b/dlt/dlt.py @@ -1,8 +1,5 @@ # Copyright (C) 2015. BMW Car IT GmbH. All rights reserved. """Pure Python implementation of DLT library""" -# pylint: disable=too-many-lines -from __future__ import absolute_import - import ctypes import ipaddress as ip import logging @@ -13,26 +10,45 @@ import time import threading -import six - from dlt.core import ( - cDLTFilter, dltlib, DLT_CLIENT_MODE_UDP_MULTICAST, DLT_ID_SIZE, DLT_HTYP_WEID, DLT_HTYP_WSID, DLT_HTYP_WTMS, - DLT_HTYP_UEH, DLT_RETURN_OK, DLT_RETURN_ERROR, DLT_RETURN_TRUE, DLT_MESSAGE_ERROR_OK, - cDltExtendedHeader, cDltClient, MessageMode, cDLTMessage, cDltStorageHeader, cDltStandardHeader, - DLT_TYPE_INFO_UINT, DLT_TYPE_INFO_SINT, DLT_TYPE_INFO_STRG, DLT_TYPE_INFO_SCOD, - DLT_TYPE_INFO_TYLE, DLT_TYPE_INFO_VARI, DLT_TYPE_INFO_RAWD, - DLT_SCOD_ASCII, DLT_SCOD_UTF8, DLT_TYLE_8BIT, DLT_TYLE_16BIT, DLT_TYLE_32BIT, DLT_TYLE_64BIT, - DLT_TYLE_128BIT, DLT_DAEMON_TCP_PORT, DLT_CLIENT_RCVBUFSIZE, + cDLTFilter, + dltlib, + DLT_CLIENT_MODE_UDP_MULTICAST, + DLT_ID_SIZE, + DLT_HTYP_WEID, + DLT_HTYP_WSID, + DLT_HTYP_WTMS, + DLT_HTYP_UEH, + DLT_RETURN_OK, + DLT_RETURN_ERROR, + DLT_RETURN_TRUE, + DLT_MESSAGE_ERROR_OK, + cDltExtendedHeader, + cDltClient, + MessageMode, + cDLTMessage, + cDltStorageHeader, + cDltStandardHeader, + DLT_TYPE_INFO_UINT, + DLT_TYPE_INFO_SINT, + DLT_TYPE_INFO_STRG, + DLT_TYPE_INFO_SCOD, + DLT_TYPE_INFO_TYLE, + DLT_TYPE_INFO_VARI, + DLT_TYPE_INFO_RAWD, + DLT_SCOD_ASCII, + DLT_SCOD_UTF8, + DLT_TYLE_8BIT, + DLT_TYLE_16BIT, + DLT_TYLE_32BIT, + DLT_TYLE_64BIT, + DLT_TYLE_128BIT, + DLT_DAEMON_TCP_PORT, + DLT_CLIENT_RCVBUFSIZE, DLT_RECEIVE_SOCKET, ) from dlt.helpers import bytes_to_str -try: - # Use xrange by default on Python 2 - range = xrange # pylint: disable=redefined-builtin,undefined-variable,invalid-name -except Exception: # pylint: disable=broad-except - pass - MAX_LOG_IN_ROW = 3 logger = logging.getLogger(__name__) # pylint: disable=invalid-name @@ -50,7 +66,7 @@ class cached_property(object): # pylint: disable=invalid-name """ # noqa def __init__(self, func): - self.__doc__ = getattr(func, '__doc__') + self.__doc__ = getattr(func, "__doc__") self.func = func def __get__(self, obj, cls): @@ -82,7 +98,7 @@ def __repr__(self): apids = [ctypes.string_at(entry[:DLT_ID_SIZE]) for entry in self.apid] ctids = [ctypes.string_at(entry[:DLT_ID_SIZE]) for entry in self.ctid] - return str(list(zip(apids[:self.counter], ctids[:self.counter]))) + return str(list(zip(apids[: self.counter], ctids[: self.counter]))) def __nonzero__(self): """Truth value testing""" @@ -130,7 +146,7 @@ def get_scod(type_info): if (get_scod(type_info) == DLT_SCOD_ASCII) or (get_scod(type_info) == DLT_SCOD_UTF8): length = struct.unpack_from("H", self._buf, offset)[0] offset += struct.calcsize("H") - value = self._buf[offset:offset + length - 1] # strip the string terminating char \x00 + value = self._buf[offset : offset + length - 1] # strip the string terminating char \x00 offset += length elif type_info & DLT_TYPE_INFO_UINT: @@ -183,7 +199,7 @@ def get_scod(type_info): length = struct.unpack_from("H", self._buf, offset)[0] offset += struct.calcsize("H") - value = self._buf[offset:offset + length] + value = self._buf[offset : offset + length] offset += length else: @@ -232,13 +248,15 @@ def __reduce__(self): ctypes.memmove(databuffer, self.databuffer, self.datasize) init_args = (self.found_serialheader, self.resync_offset, self.headersize, self.datasize) - state_dict = {'headerbuffer': bytearray(self.headerbuffer), - 'databuffer': bytearray(databuffer), - 'databuffersize': self.databuffersize, - 'storageheader': self.storageheader, - 'standardheader': self.standardheader, - 'headerextra': self.headerextra, - 'extendedheader': self.extendedheader, } + state_dict = { + "headerbuffer": bytearray(self.headerbuffer), + "databuffer": bytearray(databuffer), + "databuffersize": self.databuffersize, + "storageheader": self.storageheader, + "standardheader": self.standardheader, + "headerextra": self.headerextra, + "extendedheader": self.extendedheader, + } return (DLTMessage, init_args, state_dict) # pylint: disable=attribute-defined-outside-init @@ -248,19 +266,19 @@ def __setstate__(self, state): This method is called by the pickle module to populate a deserialized object's state after it has been created. """ - self.databuffersize = state['databuffersize'] - self.p_storageheader.contents = state['storageheader'] - self.p_standardheader.contents = state['standardheader'] - self.headerextra = state['headerextra'] - self.p_extendedheader.contents = state['extendedheader'] + self.databuffersize = state["databuffersize"] + self.p_storageheader.contents = state["storageheader"] + self.p_standardheader.contents = state["standardheader"] + self.headerextra = state["headerextra"] + self.p_extendedheader.contents = state["extendedheader"] # - populate databuffer databuffer = ctypes.ARRAY(ctypes.c_uint8, self.datasize)() - for index, byte in enumerate(state['databuffer']): + for index, byte in enumerate(state["databuffer"]): databuffer[index] = byte self.databuffer = databuffer # - populate headerbuffer - for index, byte in enumerate(state['headerbuffer']): + for index, byte in enumerate(state["headerbuffer"]): self.headerbuffer[index] = byte # - This is required because we are not calling @@ -277,11 +295,13 @@ def from_bytes(data): buf = ctypes.create_string_buffer(remainder) - dltlib.dlt_message_read(ctypes.byref(msg), - ctypes.cast(buf, ctypes.POINTER(ctypes.c_uint8)), - ctypes.c_uint(len(remainder)), - 0, # resync - 0) # verbose + dltlib.dlt_message_read( + ctypes.byref(msg), + ctypes.cast(buf, ctypes.POINTER(ctypes.c_uint8)), + ctypes.c_uint(len(remainder)), + 0, # resync + 0, + ) # verbose msg.p_storageheader.contents = storageheader msg.initialized_as_object = False @@ -298,14 +318,14 @@ def __copy__(self): @staticmethod def extract_storageheader(data): """Split binary message data into storage header and remainder""" - header = data[0:ctypes.sizeof(cDltStorageHeader)] + header = data[0 : ctypes.sizeof(cDltStorageHeader)] # pylint: disable=no-member - return (cDltStorageHeader.from_buffer_copy(header), data[ctypes.sizeof(cDltStorageHeader):]) + return (cDltStorageHeader.from_buffer_copy(header), data[ctypes.sizeof(cDltStorageHeader) :]) @staticmethod def extract_sort_data(data): """Extract timestamp, message length, apid, ctid from a bytestring in DLT storage format (speed optimized)""" - htyp_data = ord(chr(data[16])) if six.PY3 else ord(data[16]) + htyp_data = ord(chr(data[16])) len_data = data[19:17:-1] len_value = ctypes.cast(len_data, ctypes.POINTER(ctypes.c_ushort)).contents.value + 16 apid = b"" @@ -320,13 +340,13 @@ def extract_sort_data(data): if htyp_data & DLT_HTYP_WTMS: tmsp_base = 31 + bytes_offset # Typical timestamp end offset - tmsp_data = data[tmsp_base:tmsp_base - 4:-1] + tmsp_data = data[tmsp_base : tmsp_base - 4 : -1] tmsp_value = ctypes.cast(tmsp_data, ctypes.POINTER(ctypes.c_uint32)).contents.value / 10000.0 if htyp_data & DLT_HTYP_UEH: apid_base = 38 + bytes_offset # Typical APID end offset - apid = data[apid_base - 4:apid_base].rstrip(b"\x00") - ctid = data[apid_base:apid_base + 4].rstrip(b"\x00") + apid = data[apid_base - 4 : apid_base].rstrip(b"\x00") + ctid = data[apid_base : apid_base + 4].rstrip(b"\x00") apid = bytes_to_str(apid) ctid = bytes_to_str(ctid) @@ -361,8 +381,8 @@ def extendedheader(self): def __eq__(self, other): """Equal test - not comparing storage header (contains timestamps)""" - header1 = ctypes.string_at(self.headerbuffer, self.headersize)[ctypes.sizeof(cDltStorageHeader):] - header2 = ctypes.string_at(other.headerbuffer, other.headersize)[ctypes.sizeof(cDltStorageHeader):] + header1 = ctypes.string_at(self.headerbuffer, self.headersize)[ctypes.sizeof(cDltStorageHeader) :] + header2 = ctypes.string_at(other.headerbuffer, other.headersize)[ctypes.sizeof(cDltStorageHeader) :] data1 = ctypes.string_at(self.databuffer, self.datasize) data2 = ctypes.string_at(other.databuffer, other.datasize) @@ -392,12 +412,12 @@ def compare(self, other=None): # pylint: disable=too-many-return-statements,too # pylint: disable=protected-access if hasattr(other, "_fields_") and [x[0] for x in other._fields_] == [ - "apid", - "ctid", - "log_level", - "payload_max", - "payload_min", - "counter", + "apid", + "ctid", + "log_level", + "payload_max", + "payload_min", + "counter", ]: # other id DLTFilter return dltlib.dlt_message_filter_check(ctypes.byref(self), ctypes.byref(other), 0) @@ -568,22 +588,24 @@ class cDLTFile(ctypes.Structure): # pylint: disable=invalid-name } DltFile; """ - _fields_ = [("handle", ctypes.POINTER(ctypes.c_int)), - ("index", ctypes.POINTER(ctypes.c_long)), - ("counter", ctypes.c_int32), - ("counter_total", ctypes.c_int32), - ("position", ctypes.c_int32), - ("file_length", ctypes.c_uint64), - ("file_position", ctypes.c_uint64), - ("error_messages", ctypes.c_int32), - ("filter", ctypes.POINTER(DLTFilter)), - ("filter_counter", ctypes.c_int32), - ("msg", DLTMessage)] + _fields_ = [ + ("handle", ctypes.POINTER(ctypes.c_int)), + ("index", ctypes.POINTER(ctypes.c_long)), + ("counter", ctypes.c_int32), + ("counter_total", ctypes.c_int32), + ("position", ctypes.c_int32), + ("file_length", ctypes.c_uint64), + ("file_position", ctypes.c_uint64), + ("error_messages", ctypes.c_int32), + ("filter", ctypes.POINTER(DLTFilter)), + ("filter_counter", ctypes.c_int32), + ("msg", DLTMessage), + ] def __init__(self, **kwords): self.verbose = kwords.pop("verbose", 0) self.filename = kwords.pop("filename", None) - if six.PY3 and isinstance(self.filename, str): + if isinstance(self.filename, str): self.filename = bytes(self.filename, "utf-8") super(cDLTFile, self).__init__(**kwords) if dltlib.dlt_file_init(ctypes.byref(self), self.verbose) == DLT_RETURN_ERROR: @@ -598,9 +620,9 @@ def __init__(self, **kwords): def __repr__(self): # pylint: disable=bad-continuation - return ''.format( - "filename={}".format(self.filename) if self.filename else "", - self.counter_total) + return "".format( + "filename={}".format(self.filename) if self.filename else "", self.counter_total + ) def __del__(self): if dltlib.dlt_file_free(ctypes.byref(self), self.verbose) == DLT_RETURN_ERROR: @@ -679,7 +701,7 @@ def read(self, filename, filters=None): # load the filters self.set_filters(filters) - if six.PY3 and isinstance(filename, str): + if isinstance(filename, str): filename = bytes(filename, "utf-8") # read and index file self.filename = filename @@ -691,11 +713,10 @@ def set_filters(self, filters): if filters is not None: dlt_filter = DLTFilter(verbose=self.verbose) for apid, ctid in filters: - if six.PY3: - if isinstance(apid, str): - apid = bytes(apid, "ascii") - if isinstance(ctid, str): - ctid = bytes(ctid, "ascii") + if isinstance(apid, str): + apid = bytes(apid, "ascii") + if isinstance(ctid, str): + ctid = bytes(ctid, "ascii") dlt_filter.add(apid, ctid) self.filters = dlt_filter dltlib.dlt_file_set_filter(ctypes.byref(self), ctypes.byref(dlt_filter), self.verbose) @@ -746,7 +767,7 @@ def __getitem__(self, index): def _open_file(self): """Open the configured file for processing""" file_opened = False - while not self.stop_reading.isSet(): + while not self.stop_reading.is_set(): if dltlib.dlt_file_open(ctypes.byref(self), self.filename, self.verbose) >= DLT_RETURN_OK: file_opened = True break @@ -773,8 +794,9 @@ def _log_message_progress(self): def __iter__(self): # pylint: disable=too-many-branches """Iterate over messages in the file""" logger.debug("Starting File Read") - logger.debug("File Position: %d File Counter: %d File Name: %s", - self.file_position, self.counter, self.filename) + logger.debug( + "File Position: %d File Counter: %d File Name: %s", self.file_position, self.counter, self.filename + ) cached_mtime = 0 cached_file_pos = 0 corruption_check_try = True @@ -782,7 +804,7 @@ def __iter__(self): # pylint: disable=too-many-branches self._open_file() found_data = False - while not self.stop_reading.isSet() or corruption_check_try: # pylint: disable=too-many-nested-blocks + while not self.stop_reading.is_set() or corruption_check_try: # pylint: disable=too-many-nested-blocks os_stat = os.stat(self.filename) mtime = os_stat.st_mtime @@ -792,8 +814,10 @@ def __iter__(self): # pylint: disable=too-many-branches while dltlib.dlt_file_read(ctypes.byref(self), self.verbose) >= DLT_RETURN_OK: found_data = True - if self.filter and dltlib.dlt_message_filter_check( - ctypes.byref(self.msg), self.filter, 0) != DLT_RETURN_TRUE: + if ( + self.filter + and dltlib.dlt_message_filter_check(ctypes.byref(self.msg), self.filter, 0) != DLT_RETURN_TRUE + ): continue index = self.position @@ -849,7 +873,7 @@ def __init__(self, **kwords): if "servIP" in kwords: serv_ip = kwords.pop("servIP") if isinstance(serv_ip, str): - serv_ip = serv_ip.encode('utf8') + serv_ip = serv_ip.encode("utf8") ip_init_state = dltlib.dlt_client_set_server_ip(ctypes.byref(self), ctypes.create_string_buffer(serv_ip)) if ip_init_state == DLT_RETURN_ERROR: raise RuntimeError("Could not initialize servIP for DLTClient") @@ -860,16 +884,14 @@ def __init__(self, **kwords): if "hostIP" in kwords: host_ip = kwords.pop("hostIP") if isinstance(host_ip, str): - host_ip = host_ip.encode('utf8') + host_ip = host_ip.encode("utf8") ip_init_state = dltlib.dlt_client_set_host_if_address( - ctypes.byref(self), - ctypes.create_string_buffer(host_ip) + ctypes.byref(self), ctypes.create_string_buffer(host_ip) ) if ip_init_state == DLT_RETURN_ERROR: raise RuntimeError("Could not initialize multicast address for DLTClient") - set_mode_state = dltlib.dlt_client_set_mode(ctypes.byref(self), - DLT_CLIENT_MODE_UDP_MULTICAST) + set_mode_state = dltlib.dlt_client_set_mode(ctypes.byref(self), DLT_CLIENT_MODE_UDP_MULTICAST) logger.info("DLTClient using UDP set mode state: %s", set_mode_state) if set_mode_state == DLT_RETURN_ERROR: raise RuntimeError("Could not initialize socket mode for DLTClient") @@ -906,12 +928,14 @@ def connect(self, timeout=None): while time.time() < end_time: timeout_remaining = max(end_time - time.time(), 1) if timeout else None try: - self._connected_socket = socket.create_connection((ctypes.string_at(self.servIP), self.port), - timeout=timeout_remaining) + self._connected_socket = socket.create_connection( + (ctypes.string_at(self.servIP), self.port), timeout=timeout_remaining + ) except IOError as exc: if error_count < MAX_LOG_IN_ROW: - logger.debug("DLT client connect failed to connect to %s:%s : %s", - self.servIP, self.port, exc) + logger.debug( + "DLT client connect failed to connect to %s:%s : %s", self.servIP, self.port, exc + ) error_count += 1 time.sleep(1) @@ -921,14 +945,13 @@ def connect(self, timeout=None): # - also init the receiver to replicate # dlt_client_connect() behavior if hasattr(self.receiver, "type"): - connected = dltlib.dlt_receiver_init(ctypes.byref(self.receiver), - self.sock, - DLT_RECEIVE_SOCKET, - DLT_CLIENT_RCVBUFSIZE) + connected = dltlib.dlt_receiver_init( + ctypes.byref(self.receiver), self.sock, DLT_RECEIVE_SOCKET, DLT_CLIENT_RCVBUFSIZE + ) else: - connected = dltlib.dlt_receiver_init(ctypes.byref(self.receiver), - self.sock, - DLT_CLIENT_RCVBUFSIZE) + connected = dltlib.dlt_receiver_init( + ctypes.byref(self.receiver), self.sock, DLT_CLIENT_RCVBUFSIZE + ) break else: connected = dltlib.dlt_client_connect(ctypes.byref(self), self.verbose) @@ -972,11 +995,13 @@ def read_message(self, verbose=False): :rtype: DLTMessage|None """ msg = DLTMessage(verbose=verbose) - res = dltlib.dlt_message_read(ctypes.byref(msg), - ctypes.cast(self.receiver.buf, ctypes.POINTER(ctypes.c_uint8)), - ctypes.c_uint(self.receiver.bytesRcvd), # length - ctypes.c_int(0), # resync - ctypes.c_int(verbose)) # verbose + res = dltlib.dlt_message_read( + ctypes.byref(msg), + ctypes.cast(self.receiver.buf, ctypes.POINTER(ctypes.c_uint8)), + ctypes.c_uint(self.receiver.bytesRcvd), # length + ctypes.c_int(0), # resync + ctypes.c_int(verbose), + ) # verbose if res != DLT_MESSAGE_ERROR_OK: # - failed to read a complete message, possibly read an incomplete diff --git a/dlt/dlt_broker.py b/dlt/dlt_broker.py index 660d0aa..13b2300 100644 --- a/dlt/dlt_broker.py +++ b/dlt/dlt_broker.py @@ -1,17 +1,11 @@ # Copyright (C) 2015. BMW Car IT GmbH. All rights reserved. """DLT Broker is running in a loop in a separate thread until stop_flag is set and adding received messages to all registered queues""" -from __future__ import absolute_import, print_function - from contextlib import contextmanager import ipaddress as ip import logging from multiprocessing import Event, Queue - -try: - import Queue as tqueue -except ImportError: - import queue as tqueue # pylint: disable=import-error +import queue as tqueue from dlt.dlt_broker_handlers import ( DLT_DAEMON_TCP_PORT, @@ -43,10 +37,17 @@ def create_filter_ack_queue(filter_ack_msg_handler): class DLTBroker(object): """DLT Broker class manages receiving and filtering of DLT Messages""" - def __init__(self, ip_address, port=DLT_DAEMON_TCP_PORT, use_proxy=False, - enable_dlt_time=False, - enable_filter_set_ack=False, filter_set_ack_timeout=2.0, ignore_filter_set_ack_timeout=False, - **kwargs): + def __init__( + self, + ip_address, + port=DLT_DAEMON_TCP_PORT, + use_proxy=False, + enable_dlt_time=False, + enable_filter_set_ack=False, + filter_set_ack_timeout=2.0, + ignore_filter_set_ack_timeout=False, + **kwargs, + ): """Initialize the DLT Broker :param str ip_address: IP address of the DLT Daemon. Defaults to TCP connection, unless a multicast address is @@ -85,7 +86,10 @@ def __init__(self, ip_address, port=DLT_DAEMON_TCP_PORT, use_proxy=False, kwargs["port"] = port kwargs["timeout"] = kwargs.get("timeout", DLT_CLIENT_TIMEOUT) self.msg_handler = DLTMessageHandler( - self.filter_queue, self.message_queue, self.mp_stop_flag, kwargs, + self.filter_queue, + self.message_queue, + self.mp_stop_flag, + kwargs, dlt_time_value=self._dlt_time_value, filter_ack_queue=self.filter_ack_queue, ) @@ -99,7 +103,12 @@ def start(self): """DLTBroker main worker method""" logger.debug( "Starting DLTBroker with parameters: use_proxy=%s, ip_address=%s, port=%s, filename=%s, multicast=%s", - False, self._ip_address, self._port, self._filename, ip.ip_address(self._ip_address).is_multicast) + False, + self._ip_address, + self._port, + self._filename, + ip.ip_address(self._ip_address).is_multicast, + ) if self._dlt_time_value: logger.debug("Enable dlt time for DLTBroker.") @@ -127,9 +136,7 @@ def _recv_filter_set_ack(self, context_filter_ack_queue, required_response): except tqueue.Empty as err: if self.ignore_filter_set_ack_timeout: logger.info( - "Timeout for getting filter-setting ack: %s, %s", - id(context_filter_ack_queue), - required_response + "Timeout for getting filter-setting ack: %s, %s", id(context_filter_ack_queue), required_response ) return None @@ -160,9 +167,14 @@ def add_context(self, context_queue, filters=None): if not self._recv_filter_set_ack(context_filter_ack_queue, True): logger.warning( - ("Could not receive filter-setting messge ack. It's possible that DLTClient client does " - "not start. If it's a test case. It might be an error. For now, Run it anyway. " - "filters: %s, queue_id: %s"), filters, id(context_queue)) + ( + "Could not receive filter-setting messge ack. It's possible that DLTClient client does " + "not start. If it's a test case. It might be an error. For now, Run it anyway. " + "filters: %s, queue_id: %s" + ), + filters, + id(context_queue), + ) else: self.context_handler.register(context_queue, filters) diff --git a/dlt/dlt_broker_handlers.py b/dlt/dlt_broker_handlers.py index d55d166..43e6a6e 100644 --- a/dlt/dlt_broker_handlers.py +++ b/dlt/dlt_broker_handlers.py @@ -2,18 +2,18 @@ """Handlers are classes that assist dlt_broker in receiving and filtering DLT messages """ -from __future__ import absolute_import from collections import defaultdict import ctypes import logging from multiprocessing import Lock, Process, Value -from multiprocessing.queues import Empty +from queue import Empty import socket import time from threading import Thread, Event from dlt.dlt import DLTClient, DLT_DAEMON_TCP_PORT, py_dlt_client_main_loop + DLT_CLIENT_TIMEOUT = 5 logger = logging.getLogger(__name__) # pylint: disable=invalid-name @@ -62,6 +62,7 @@ def timestamp(self, new_timestamp): class DLTFilterAckMessageHandler(Thread): """Receive filter-set ack message and pass it to the corresponding ack queue""" + def __init__(self, filter_ack_queue): # (multiprocessing.Queue[Tuple[ContextQueueID, bool]]) -> None super(DLTFilterAckMessageHandler, self).__init__() @@ -173,8 +174,7 @@ def unregister(self, queue, context_filter_ack_queue=None): ) def run(self): - """The thread's main loop - """ + """The thread's main loop""" while not self.stop_flag.is_set(): queue_id, message = None, None try: @@ -207,8 +207,9 @@ class DLTMessageHandler(Process): them on the messages queue. """ - def __init__(self, filter_queue, message_queue, mp_stop_event, client_cfg, - dlt_time_value=None, filter_ack_queue=None): + def __init__( + self, filter_queue, message_queue, mp_stop_event, client_cfg, dlt_time_value=None, filter_ack_queue=None + ): self.filter_queue = filter_queue self.filter_ack_queue = filter_ack_queue self.message_queue = message_queue @@ -235,8 +236,12 @@ def _client_connect(self): :returns: True if connected, False otherwise :rtype: bool """ - logger.debug("Creating DLTClient (ip_address='%s', Port='%s', logfile='%s')", - self._ip_address, self._port, self._filename) + logger.debug( + "Creating DLTClient (ip_address='%s', Port='%s', logfile='%s')", + self._ip_address, + self._port, + self._filename, + ) self._client = DLTClient(servIP=self._ip_address, port=self._port, verbose=self.verbose) connected = self._client.connect(self.timeout) if connected: diff --git a/dlt/helpers.py b/dlt/helpers.py index a3cb579..425db6a 100644 --- a/dlt/helpers.py +++ b/dlt/helpers.py @@ -1,6 +1,5 @@ # Copyright (C) 2015. BMW Car IT GmbH. All rights reserved. """DLT client helpers""" -import six class LimitCondition(object): @@ -57,8 +56,7 @@ def __call__(self, message): def bytes_to_str(byte_or_str): """Return string from bytes""" - if six.PY3: - if isinstance(byte_or_str, bytes): - return byte_or_str.decode('utf8', errors="replace") + if isinstance(byte_or_str, bytes): + return byte_or_str.decode("utf8", errors="replace") return str(byte_or_str) diff --git a/dlt/py_dlt_receive.py b/dlt/py_dlt_receive.py index 30378b2..9cad7ca 100644 --- a/dlt/py_dlt_receive.py +++ b/dlt/py_dlt_receive.py @@ -1,14 +1,13 @@ # Copyright (C) 2017. BMW Car IT GmbH. All rights reserved. """DLT Receive using py_dlt""" -from __future__ import absolute_import import argparse import logging import time from dlt.dlt_broker import DLTBroker -logging.basicConfig(format='%(asctime)s %(name)s %(levelname)-8s %(message)s') +logging.basicConfig(format="%(asctime)s %(name)s %(levelname)-8s %(message)s") root_logger = logging.getLogger() # pylint: disable=invalid-name logger = logging.getLogger("py-dlt-receive") # pylint: disable=invalid-name @@ -32,7 +31,7 @@ def dlt_receive(options): try: logger.info("Receiving messages...") while True: - time.sleep(.1) + time.sleep(0.1) except KeyboardInterrupt: logger.info("Interrupted...") finally: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..0eafc2c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,63 @@ +[project] +name = "dlt" +dynamic = ["version"] +description = "Python implementation for DLT" +authors = [ + {name = "BMW CarIT", email="carit.info@bmw.de"}, +] +readme = "README.md" +license = {file = "LICENCE.txt"} +classifiers = [ + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", + "Intended Audience :: Developers", + "Topic :: Software Development", + "Topic :: System :: Logging", + "Programming Language :: Python :: 3", +] + +dependencies = [ +] + +[project.optional-dependencies] +dev = [ + "black>=22.10", + "flake8>=5", + "pytest>=7.2.0", + "pytest-cov>=4.0.0" +] + +[project.urls] +"Homepage" = "https://github.com/bmwcarit/python-dlt" + +[tool.setuptools.packages.find] +include = ["dlt*"] +exclude = ["playbook*", "zuul.d*", "extracted_files*", "tests"] + +[build-system] +requires = ["setuptools>=45", "setuptools_scm[toml]>=6.2"] +build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 119 +target_version = ['py37'] +include = '\.pyi?$' +exclude = ''' +( + /( + \.eggs # exclude a few common directories in the + | \.git # root of the project + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + )/ + | foo.py # also separately exclude a file named foo.py in + # the root of the project + | _version.py +) +''' diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index c685fd3..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -coverage==4.5.4 -nose==1.3.7 -pycodestyle==2.5.0 diff --git a/requirements2.7.txt b/requirements2.7.txt deleted file mode 100644 index c962160..0000000 --- a/requirements2.7.txt +++ /dev/null @@ -1,4 +0,0 @@ -mock -subprocess32 -pylint==1.9.5 -backport_ipaddress \ No newline at end of file diff --git a/requirements3.txt b/requirements3.txt deleted file mode 100644 index f1c1eea..0000000 --- a/requirements3.txt +++ /dev/null @@ -1 +0,0 @@ -pylint==2.4.2 diff --git a/setup.py b/setup.py deleted file mode 100644 index f1b0658..0000000 --- a/setup.py +++ /dev/null @@ -1,30 +0,0 @@ -import setuptools - - -setuptools.setup( - name="dlt", - description="Python DLT implementation for DLT", - use_scm_version=True, - url="https://github.com/bmwcarit/python-dlt", - author="BMW Car IT", - license="MPL 2.0", - classifiers=[ # See:https://pypi.org/classifiers/ - "Development Status :: 5 - Production/Stable", - "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", - "Intended Audience :: Developers", - "Topic :: Software Development", - "Topic :: System :: Logging", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - ], - keywords="dlt log trace testing", - packages=setuptools.find_packages(exclude=["tests", "tests.*"]), - install_requires=[], - zip_safe=False, - test_suite="tests", - entry_points={ - 'console_scripts': [ - 'py_dlt_receive = dlt.py_dlt_receive:main', - ], - }, -) diff --git a/tests/condition_tests.py b/tests/condition_test.py similarity index 58% rename from tests/condition_tests.py rename to tests/condition_test.py index 1a98292..006b8c9 100644 --- a/tests/condition_tests.py +++ b/tests/condition_test.py @@ -1,7 +1,5 @@ # Copyright (C) 2016. BMW Car IT GmbH. All rights reserved. -from nose.tools import assert_equals, assert_false, assert_true, raises - from dlt.helpers import LimitCondition @@ -11,11 +9,11 @@ class TestsLimitCondition(object): def test_none(self): cond = LimitCondition(None) - assert_true(cond()) + assert cond() def test_limit_decreasing(self): cond = LimitCondition(2) cond() - assert_equals(cond.limit, 1) - assert_true(cond()) # limit=0 - assert_false(cond()) # limit=-1 + assert cond.limit == 1 + assert cond() # limit=0 + assert not cond() # limit=-1 diff --git a/tests/continuousness_helper_test.py b/tests/continuousness_helper_test.py index f1611fa..072e747 100644 --- a/tests/continuousness_helper_test.py +++ b/tests/continuousness_helper_test.py @@ -1,6 +1,5 @@ -from nose.tools import raises - from dlt.helpers import ContinuousnessChecker +import pytest class Msg(object): @@ -18,67 +17,47 @@ def run_check(messages): class TestsContinuousness(object): - def test_simple(self): messages = [ - Msg("X", "Y", "99", 4), - Msg("X", "Y", "99", 5), - Msg("X", "Y", "99", 6), - Msg("X", "Y", "99", 7), - Msg("X", "Y", "99", 8) - ] + Msg("X", "Y", "99", 4), + Msg("X", "Y", "99", 5), + Msg("X", "Y", "99", 6), + Msg("X", "Y", "99", 7), + Msg("X", "Y", "99", 8), + ] run_check(messages) - @raises(RuntimeError) def test_simple_missing(self): - messages = [ - Msg("X", "Y", "99", 4), - Msg("X", "Y", "99", 5), - Msg("X", "Y", "99", 6), - # 7 is missing - Msg("X", "Y", "99", 8), - Msg("X", "Y", "99", 9) - ] - run_check(messages) + with pytest.raises(RuntimeError): + messages = [ + Msg("X", "Y", "99", 4), + Msg("X", "Y", "99", 5), + Msg("X", "Y", "99", 6), + # 7 is missing + Msg("X", "Y", "99", 8), + Msg("X", "Y", "99", 9), + ] + run_check(messages) def test_simple_over(self): # message counter is a unsigned char so counts till 255 and then restarted back to 0 - messages = [ - Msg("X", "Y", "99", 254), - Msg("X", "Y", "99", 255), - Msg("X", "Y", "99", 0), - Msg("X", "Y", "99", 1) - ] + messages = [Msg("X", "Y", "99", 254), Msg("X", "Y", "99", 255), Msg("X", "Y", "99", 0), Msg("X", "Y", "99", 1)] run_check(messages) - @raises(RuntimeError) def test_simple_reset(self): - messages = [ - Msg("X", "Y", "99", 230), - Msg("X", "Y", "99", 231), - Msg("X", "Y", "99", 0) - ] - run_check(messages) + with pytest.raises(RuntimeError): + messages = [Msg("X", "Y", "99", 230), Msg("X", "Y", "99", 231), Msg("X", "Y", "99", 0)] + run_check(messages) def test_ignore_control(self): - messages = [ - Msg("DA1", "DC1", "0", 0), - Msg("X", "Y", "99", 231), - Msg("DA1", "DC1", "0", 0) - ] + messages = [Msg("DA1", "DC1", "0", 0), Msg("X", "Y", "99", 231), Msg("DA1", "DC1", "0", 0)] run_check(messages) def test_zeros_da1_dc1(self): - messages = [ - Msg("DA1", "DC1", "0", 0), - Msg("DA1", "DC1", "0", 0) - ] + messages = [Msg("DA1", "DC1", "0", 0), Msg("DA1", "DC1", "0", 0)] run_check(messages) - @raises(RuntimeError) def test_zeros_non_da1_dc1(self): - messages = [ - Msg("X", "Y", "0", 0), - Msg("X", "Y", "0", 0) - ] - run_check(messages) + with pytest.raises(RuntimeError): + messages = [Msg("X", "Y", "0", 0), Msg("X", "Y", "0", 0)] + run_check(messages) diff --git a/tests/dlt_broker_time_tests.py b/tests/dlt_broker_time_test.py similarity index 84% rename from tests/dlt_broker_time_tests.py rename to tests/dlt_broker_time_test.py index f66ad2e..892ff09 100644 --- a/tests/dlt_broker_time_tests.py +++ b/tests/dlt_broker_time_test.py @@ -1,28 +1,17 @@ # Copyright (C) 2021. BMW Car IT GmbH. All rights reserved. """Test DLTBroker with enabling dlt_time""" from contextlib import contextmanager -import itertools from multiprocessing import Queue +import queue as tqueue import time +from unittest.mock import ANY, patch, MagicMock -from nose.tools import assert_false, assert_is_none, assert_is_not_none, assert_raises, assert_true, eq_ -from parameterized import parameterized -import six +import pytest from dlt.dlt_broker import create_filter_ack_queue, DLTBroker, logger from dlt.dlt_broker_handlers import DLTContextHandler, DLTFilterAckMessageHandler, DLTMessageHandler from tests.utils import MockDLTMessage -if six.PY2: - from mock import ANY, patch, MagicMock -else: - from unittest.mock import ANY, patch, MagicMock - -try: - import Queue as tqueue -except ImportError: - import queue as tqueue # pylint: disable=import-error - def fake_py_dlt_client_main_loop(client, callback, *args, **kwargs): return True @@ -79,20 +68,21 @@ def fake_dlt_msg_handler(msg, with_filter_ack_queue): def test_start_stop_dlt_broker(): """Test to stop DLTBroker with dlt-time normally""" with dlt_broker(fake_py_dlt_client_main_loop, enable_dlt_time=True) as broker: - assert_is_not_none(broker._dlt_time_value) + assert broker._dlt_time_value def test_start_stop_dlt_broker_without_dlt_time(): """Test to stop DLTBroker without dlt-time normally""" with dlt_broker(fake_py_dlt_client_main_loop, enable_dlt_time=False) as broker: - assert_is_none(broker._dlt_time_value) + assert not broker._dlt_time_value -@parameterized( +@pytest.mark.parametrize( + "input_sec,input_msec,expected_value", [ (42, 42, 42.42), # normal test case (1618993559, 7377682, 1618993559.7377682), # big value. The value will be truncated when type is not double - ] + ], ) def test_dlt_broker_get_dlt_time(input_sec, input_msec, expected_value): """Test to get time from DLTBroker""" @@ -103,7 +93,7 @@ def handle(client, callback=None, *args, **kwargs): with dlt_broker(handle) as broker: time.sleep(0.01) - eq_(broker.dlt_time(), expected_value) + assert broker.dlt_time() == expected_value def test_dlt_broker_get_latest_dlt_time(): @@ -124,19 +114,19 @@ def handle(client, callback=None, *args, **kwargs): time_vals.add(broker.dlt_time()) time.sleep(0.01) - eq_(sorted(time_vals), [0.0, 43.42, 44.42, 45.42]) + assert sorted(time_vals) == [0.0, 43.42, 44.42, 45.42] def test_start_stop_dlt_broker_with_dlt_ack_msg_handler(): """Test to stop DLTBroker with ack msg handler normally""" with dlt_broker(fake_py_dlt_client_main_loop, enable_dlt_time=True, enable_filter_set_ack=True) as broker: - assert_is_not_none(broker.filter_ack_msg_handler) + assert broker.filter_ack_msg_handler def test_start_stop_dlt_broker_without_dlt_ack_msg_handler(): """Test to stop DLTBroker without ack msg handler normally""" with dlt_broker(fake_py_dlt_client_main_loop, enable_dlt_time=True, enable_filter_set_ack=False) as broker: - assert_is_none(broker.filter_ack_msg_handler) + assert not broker.filter_ack_msg_handler def test_create_filter_ack_queue(): @@ -145,20 +135,28 @@ def test_create_filter_ack_queue(): with create_filter_ack_queue(handler_mock) as queue: queue.put(True) - assert_true(queue.get()) + assert queue.get() handler_mock.register.assert_called_with(queue) handler_mock.unregister.assert_called_with(queue) -@parameterized([(True, True, True), (False, False, True), (True, False, False), (False, True, False)]) +@pytest.mark.parametrize( + "ack,required_ack,return_val", + [ + (True, True, True), + (False, False, True), + (True, False, False), + (False, True, False), + ], +) def test_recv_filter_set_ack(ack, required_ack, return_val): """Test to receive an ack value""" queue = tqueue.Queue() queue.put(ack) with dlt_broker(enable_filter_set_ack=True) as broker: - eq_(return_val, broker._recv_filter_set_ack(queue, required_ack)) + assert return_val == broker._recv_filter_set_ack(queue, required_ack) def test_recv_filter_set_ack_timeout_ignore(): @@ -169,7 +167,7 @@ def test_recv_filter_set_ack_timeout_ignore(): broker.filter_set_ack_timeout = 0.01 broker.ignore_filter_set_ack_timeout = True - assert_is_none(broker._recv_filter_set_ack(queue, True)) + assert not broker._recv_filter_set_ack(queue, True) def test_recv_filter_set_ack_timeout_exception(): @@ -180,10 +178,10 @@ def test_recv_filter_set_ack_timeout_exception(): broker.filter_set_ack_timeout = 0.01 broker.ignore_filter_set_ack_timeout = False - with assert_raises(tqueue.Empty) as err: + with pytest.raises(tqueue.Empty) as err: broker._recv_filter_set_ack(queue, True) - eq_(str(err.exception), "") + assert not str(err.value) def test_add_context_with_ack(): @@ -230,7 +228,7 @@ def test_start_stop_dlt_filter_ack_msg_handler(): with dlt_filter_ack_msg_handler() as (handler, _): pass - assert_false(handler.is_alive()) + assert not handler.is_alive() def test_dlt_filter_ack_msg_handler_register(): @@ -241,7 +239,7 @@ def test_dlt_filter_ack_msg_handler_register(): handler.register(queue_ack) queue.put((id(queue_ack), True)) - assert_true(queue_ack.get()) + assert queue_ack.get() def test_dlt_filter_ack_msg_handler_unregister(): @@ -252,7 +250,7 @@ def test_dlt_filter_ack_msg_handler_unregister(): handler.register(queue_ack) handler.unregister(queue_ack) - with assert_raises(tqueue.Empty): + with pytest.raises(tqueue.Empty): queue.put((id(queue_ack), False)) queue_ack.get_nowait() @@ -265,10 +263,7 @@ def test_make_send_filter_msg(): filters = [("APID", "CTID")] queue = MagicMock() - eq_( - handler._make_send_filter_msg(queue, filters, is_register), - (id(queue), filters, is_register), - ) + assert handler._make_send_filter_msg(queue, filters, is_register) == (id(queue), filters, is_register) def test_make_send_filter_msg_with_ack_queue(): @@ -280,9 +275,11 @@ def test_make_send_filter_msg_with_ack_queue(): queue = MagicMock() queue_ack = MagicMock() - eq_( - handler._make_send_filter_msg(queue, filters, is_register, context_filter_ack_queue=queue_ack), - (id(queue), id(queue_ack), filters, is_register), + assert handler._make_send_filter_msg(queue, filters, is_register, context_filter_ack_queue=queue_ack) == ( + id(queue), + id(queue_ack), + filters, + is_register, ) @@ -291,7 +288,7 @@ def test_dlt_message_handler_process_filter_queue_add(): handler = fake_dlt_msg_handler(msg=(42, [("APID", "CTID")], True), with_filter_ack_queue=True) handler._process_filter_queue() - eq_(handler.context_map[("APID", "CTID")], [42]) + assert handler.context_map[("APID", "CTID")] == [42] handler.filter_ack_queue.put.assert_not_called() @@ -300,7 +297,7 @@ def test_dlt_message_handler_process_filter_queue_add_ack(): handler = fake_dlt_msg_handler(msg=(42, 43, [("APID", "CTID")], True), with_filter_ack_queue=True) handler._process_filter_queue() - eq_(handler.context_map[("APID", "CTID")], [42]) + assert handler.context_map[("APID", "CTID")] == [42] handler.filter_ack_queue.put.assert_called_with((43, True)) @@ -311,7 +308,7 @@ def test_dlt_message_handler_process_filter_queue_remove(): handler._process_filter_queue() - assert_true(("APID", "CTID") not in handler.context_map) + assert ("APID", "CTID") not in handler.context_map handler.filter_ack_queue.put.assert_not_called() @@ -322,7 +319,7 @@ def test_dlt_message_handler_process_filter_queue_remove_ack(): handler._process_filter_queue() - assert_true(("APID", "CTID") not in handler.context_map) + assert ("APID", "CTID") not in handler.context_map handler.filter_ack_queue.put.assert_called_with((43, False)) @@ -332,5 +329,5 @@ def test_dlt_message_handler_process_filter_queue_remove_exception(): handler._process_filter_queue() - eq_(handler.context_map[("APID", "CTID")], []) + assert not handler.context_map[("APID", "CTID")] handler.filter_ack_queue.put.assert_not_called() diff --git a/tests/dlt_client_unit_tests.py b/tests/dlt_client_unit_test.py similarity index 54% rename from tests/dlt_client_unit_tests.py rename to tests/dlt_client_unit_test.py index b692964..e35f7bc 100644 --- a/tests/dlt_client_unit_tests.py +++ b/tests/dlt_client_unit_test.py @@ -2,31 +2,28 @@ """Basic unittests for DLTClient class""" import unittest - -try: - from mock import patch, Mock -except ImportError: - from unittest.mock import patch, Mock +from unittest.mock import patch, Mock from dlt.dlt import DLTClient, DLT_RETURN_OK, DLT_RETURN_ERROR class TestDLTClient(unittest.TestCase): - def setUp(self): # - patch port so that connect fails even if dlt-daemon is running - self.client = DLTClient(servIP='127.0.0.1', port=424242) + self.client = DLTClient(servIP="127.0.0.1", port=424242) def test_connect_with_timeout_failed(self): # - timeout error self.assertFalse(self.client.connect(timeout=2)) # - dlt_receiver_init error - with patch('socket.create_connection', return_value=Mock(fileno=Mock(return_value=2000000))), \ - patch('dlt.dlt.dltlib.dlt_receiver_init', return_value=DLT_RETURN_ERROR): + with patch("socket.create_connection", return_value=Mock(fileno=Mock(return_value=2000000))), patch( + "dlt.dlt.dltlib.dlt_receiver_init", return_value=DLT_RETURN_ERROR + ): self.assertFalse(self.client.connect(timeout=2)) def test_connect_with_timeout_success(self): - with patch('socket.create_connection', return_value=Mock(fileno=Mock(return_value=2000000))), \ - patch('dlt.dlt.dltlib.dlt_receiver_init', return_value=DLT_RETURN_OK): + with patch("socket.create_connection", return_value=Mock(fileno=Mock(return_value=2000000))), patch( + "dlt.dlt.dltlib.dlt_receiver_init", return_value=DLT_RETURN_OK + ): self.assertTrue(self.client.connect(timeout=2)) diff --git a/tests/dlt_context_handler_unit_tests.py b/tests/dlt_context_handler_unit_test.py similarity index 90% rename from tests/dlt_context_handler_unit_tests.py rename to tests/dlt_context_handler_unit_test.py index 02cb373..8b9e619 100644 --- a/tests/dlt_context_handler_unit_tests.py +++ b/tests/dlt_context_handler_unit_test.py @@ -1,25 +1,14 @@ # Copyright (C) 2016. BMW Car IT GmbH. All rights reserved. +from multiprocessing import Queue as mp_queue +from queue import Empty, Queue import time import unittest -try: - from Queue import Queue -except ImportError: - from queue import Queue - -import six - -from multiprocessing.queues import Empty -if six.PY2: - from multiprocessing.queues import Queue as mp_queue -else: - from multiprocessing import Queue as mp_queue from dlt.dlt_broker_handlers import DLTContextHandler -from .utils import create_messages, stream_one, stream_multiple +from tests.utils import create_messages, stream_one, stream_multiple class TestDLTContextHandler(unittest.TestCase): - def setUp(self): self.filter_queue = mp_queue() self.message_queue = mp_queue() @@ -96,7 +85,7 @@ def test_run_no_messages(self): self.handler.stop() self.assertTrue(self.handler.stop_flag.is_set()) self.assertFalse(self.handler.is_alive()) - except: + except: # noqa: E722 self.fail() def test_run_single_context_queue(self): @@ -141,7 +130,7 @@ def test_run_multiple_context_queue(self): # - simulate feeding of messages into the message_queue for _ in range(10): for message in create_messages(stream_multiple, from_file=True): - queue_id = queue_id0 if message.apid == 'DA1' else queue_id1 + queue_id = queue_id0 if message.apid == "DA1" else queue_id1 self.handler.message_queue.put((queue_id, message)) # - simulate feeding of all messages for the queue with # no filter. @@ -157,11 +146,12 @@ def test_run_multiple_context_queue(self): all_messages.append(queue2.get(timeout=0.01)) # these queues should not get any messages from other queues - self.assertTrue(all(msg.apid == 'DA1' for msg in da1_messages)) - self.assertTrue(all(msg.apid == 'SYS' for msg in sys_messages)) + self.assertTrue(all(msg.apid == "DA1" for msg in da1_messages)) + self.assertTrue(all(msg.apid == "SYS" for msg in sys_messages)) # this queues should get all messages - self.assertFalse(all(msg.apid == 'DA1' for msg in all_messages) or - all(msg.apid == 'SYS' for msg in all_messages)) + self.assertFalse( + all(msg.apid == "DA1" for msg in all_messages) or all(msg.apid == "SYS" for msg in all_messages) + ) except Empty: # - we should not get an Empty for at least 10 messages self.fail() diff --git a/tests/dlt_core_unit_tests.py b/tests/dlt_core_unit_test.py similarity index 68% rename from tests/dlt_core_unit_tests.py rename to tests/dlt_core_unit_test.py index 3844cbb..4439e20 100644 --- a/tests/dlt_core_unit_tests.py +++ b/tests/dlt_core_unit_test.py @@ -1,45 +1,50 @@ # Copyright (C) 2017. BMW Car IT GmbH. All rights reserved. """Basic size tests for ctype wrapper definitions, to protect against regressions""" +import ctypes +import importlib import os import unittest -import ctypes - -try: - from mock import patch, MagicMock -except ImportError: - from unittest.mock import patch, MagicMock +from unittest.mock import patch, MagicMock import dlt class TestCoreStructures(unittest.TestCase): - def setUp(self): - self.size_map = {'cDltServiceConnectionInfo': 10, - 'cDltStorageHeader': 16, - 'cDltStandardHeader': 4, - 'cDltStandardHeaderExtra': 12, - 'cDltExtendedHeader': 10, - 'cDLTMessage': 120, - 'cDltReceiver': 72, - 'cDltClient': 144, - 'cDLTFilter': 604} + self.size_map = { + "cDltServiceConnectionInfo": 10, + "cDltStorageHeader": 16, + "cDltStandardHeader": 4, + "cDltStandardHeaderExtra": 12, + "cDltExtendedHeader": 10, + "cDLTMessage": 120, + "cDltReceiver": 72, + "cDltClient": 144, + "cDLTFilter": 604, + } def test_sizeof(self): + importlib.import_module("dlt.core") + for clsname, expected in self.size_map.items(): actual = ctypes.sizeof(getattr(dlt.core, clsname)) - self.assertEqual(actual, expected, - msg="v{0}, sizeof {1}: {2} != {3}".format( - dlt.core.get_version(dlt.core.dltlib), clsname, actual, expected)) + self.assertEqual( + actual, + expected, + msg="v{0}, sizeof {1}: {2} != {3}".format( + dlt.core.get_version(dlt.core.dltlib), clsname, actual, expected + ), + ) class TestImportSpecificVersion(unittest.TestCase): - def setUp(self): self.original_api_version = dlt.core.API_VER self.version_answer = b"2.18.5" - self.version_str = (b"DLT Package Version: 2.18.5 STABLE, Package Revision: v2.18.5_5_g33fbad1, " - b"build on Sep 2 2020 11:55:50\n-SYSTEMD -SYSTEMD_WATCHDOG -TEST -SHM\n") + self.version_str = ( + b"DLT Package Version: 2.18.5 STABLE, Package Revision: v2.18.5_5_g33fbad1, " + b"build on Sep 2 2020 11:55:50\n-SYSTEMD -SYSTEMD_WATCHDOG -TEST -SHM\n" + ) self.version_filename = "core_2185.py" self.version_truncate_str = "2.18.5" self.version_truncate_filename = "core_2180.py" @@ -71,7 +76,7 @@ def test_get_api_specific_file(self): def test_get_api_specific_file_not_found(self): with patch.object(os.path, "exists", side_effect=[False, False]): with self.assertRaises(ImportError) as err_cm: - filename = dlt.core.get_api_specific_file(self.version_answer.decode()) + dlt.core.get_api_specific_file(self.version_answer.decode()) self.assertEqual(str(err_cm.exception), "No module file: {}".format(self.version_truncate_filename)) diff --git a/tests/dlt_filter_unit_test.py b/tests/dlt_filter_unit_test.py new file mode 100644 index 0000000..bf1b720 --- /dev/null +++ b/tests/dlt_filter_unit_test.py @@ -0,0 +1,63 @@ +# Copyright (C) 2015. BMW Car IT GmbH. All rights reserved. +"""Basic unittests for DLTFilter definition""" +import unittest + +import ctypes + +from dlt.dlt import DLTFilter +from dlt.core.core_base import DLT_FILTER_MAX, DLT_ID_SIZE + + +class TestDLTFilter(unittest.TestCase): + def setUp(self): + self.dlt_filter = DLTFilter() + + def tearDown(self): + del self.dlt_filter + + def test_init(self): + assert len(self.dlt_filter.apid) == DLT_FILTER_MAX + assert len(self.dlt_filter.ctid) == DLT_FILTER_MAX + assert self.dlt_filter.counter == 0 + + for entry in self.dlt_filter.apid: + assert ctypes.string_at(entry, DLT_ID_SIZE) == b"\0\0\0\0" + + for entry in self.dlt_filter.ctid: + assert ctypes.string_at(entry, DLT_ID_SIZE) == b"\0\0\0\0" + + def test_add0(self): + assert self.dlt_filter.add("AAA", "BBB") == 0 + assert self.dlt_filter.counter == 1 + assert len(self.dlt_filter.apid[0]) == 4 + assert len(self.dlt_filter.ctid[0]) == 4 + assert ctypes.string_at(self.dlt_filter.apid[0], DLT_ID_SIZE) == b"AAA\0" + assert ctypes.string_at(self.dlt_filter.ctid[0], DLT_ID_SIZE) == b"BBB\0" + + def test_add1(self): + assert self.dlt_filter.add("AAA", "BBB") == 0 + assert self.dlt_filter.add("XXX", "YYY") == 0 + assert self.dlt_filter.counter == 2 + assert ctypes.string_at(self.dlt_filter.apid[0], DLT_ID_SIZE) == b"AAA\0" + assert ctypes.string_at(self.dlt_filter.ctid[0], DLT_ID_SIZE) == b"BBB\0" + assert ctypes.string_at(self.dlt_filter.apid[1], DLT_ID_SIZE) == b"XXX\0" + assert ctypes.string_at(self.dlt_filter.ctid[1], DLT_ID_SIZE) == b"YYY\0" + + def test_add2(self): + assert self.dlt_filter.add("AAAA", "BBBB") == 0 + assert self.dlt_filter.add("XXX", "YYY") == 0 + assert self.dlt_filter.add("CCCC", "DDDD") == 0 + assert self.dlt_filter.counter == 3 + assert ctypes.string_at(self.dlt_filter.apid[0], DLT_ID_SIZE) == b"AAAA" + assert ctypes.string_at(self.dlt_filter.ctid[0], DLT_ID_SIZE) == b"BBBB" + assert ctypes.string_at(self.dlt_filter.apid[1], DLT_ID_SIZE) == b"XXX\0" + assert ctypes.string_at(self.dlt_filter.ctid[1], DLT_ID_SIZE) == b"YYY\0" + assert ctypes.string_at(self.dlt_filter.apid[2], DLT_ID_SIZE) == b"CCCC" + assert ctypes.string_at(self.dlt_filter.ctid[2], DLT_ID_SIZE) == b"DDDD" + + def test_repr(self): + assert self.dlt_filter.add("AAAA", "BBBB") == 0 + assert self.dlt_filter.add("XXX", "YYY") == 0 + assert self.dlt_filter.add("CCCC", "DDDD") == 0 + print(self.dlt_filter) + assert str(self.dlt_filter) == str([(b"AAAA", b"BBBB"), (b"XXX", b"YYY"), (b"CCCC", b"DDDD")]) diff --git a/tests/dlt_filter_unit_tests.py b/tests/dlt_filter_unit_tests.py deleted file mode 100644 index ea1f329..0000000 --- a/tests/dlt_filter_unit_tests.py +++ /dev/null @@ -1,66 +0,0 @@ - -# Copyright (C) 2015. BMW Car IT GmbH. All rights reserved. -"""Basic unittests for DLTFilter definition""" -from __future__ import print_function - -import ctypes - -from nose.tools import * - -from dlt.dlt import DLTFilter -from dlt.core.core_base import DLT_FILTER_MAX, DLT_ID_SIZE - -class TestDLTFilter(object): - - def setUp(self): - self.dlt_filter = DLTFilter() - - def tearDown(self): - del(self.dlt_filter) - - def test_init(self): - assert_equal(len(self.dlt_filter.apid), DLT_FILTER_MAX) - assert_equal(len(self.dlt_filter.ctid), DLT_FILTER_MAX) - assert_equal(self.dlt_filter.counter, 0) - - for entry in self.dlt_filter.apid: - assert_true(ctypes.string_at(entry, DLT_ID_SIZE) == b"\0\0\0\0") - - for entry in self.dlt_filter.ctid: - assert_true(ctypes.string_at(entry, DLT_ID_SIZE) == b"\0\0\0\0") - - def test_add0(self): - assert_equal(self.dlt_filter.add("AAA", "BBB"), 0) - assert_equal(self.dlt_filter.counter, 1) - assert_equal(len(self.dlt_filter.apid[0]), 4) - assert_equal(len(self.dlt_filter.ctid[0]), 4) - assert_true(ctypes.string_at(self.dlt_filter.apid[0], DLT_ID_SIZE) == b"AAA\0") - assert_true(ctypes.string_at(self.dlt_filter.ctid[0], DLT_ID_SIZE) == b"BBB\0") - - def test_add1(self): - assert_equal(self.dlt_filter.add("AAA", "BBB"), 0) - assert_equal(self.dlt_filter.add("XXX", "YYY"), 0) - assert_equal(self.dlt_filter.counter, 2) - assert_true(ctypes.string_at(self.dlt_filter.apid[0], DLT_ID_SIZE) == b"AAA\0") - assert_true(ctypes.string_at(self.dlt_filter.ctid[0], DLT_ID_SIZE) == b"BBB\0") - assert_true(ctypes.string_at(self.dlt_filter.apid[1], DLT_ID_SIZE) == b"XXX\0") - assert_true(ctypes.string_at(self.dlt_filter.ctid[1], DLT_ID_SIZE) == b"YYY\0") - - def test_add2(self): - assert_equal(self.dlt_filter.add("AAAA", "BBBB"), 0) - assert_equal(self.dlt_filter.add("XXX", "YYY"), 0) - assert_equal(self.dlt_filter.add("CCCC", "DDDD"), 0) - assert_equal(self.dlt_filter.counter, 3) - assert_true(ctypes.string_at(self.dlt_filter.apid[0], DLT_ID_SIZE) == b"AAAA") - assert_true(ctypes.string_at(self.dlt_filter.ctid[0], DLT_ID_SIZE) == b"BBBB") - assert_true(ctypes.string_at(self.dlt_filter.apid[1], DLT_ID_SIZE) == b"XXX\0") - assert_true(ctypes.string_at(self.dlt_filter.ctid[1], DLT_ID_SIZE) == b"YYY\0") - assert_true(ctypes.string_at(self.dlt_filter.apid[2], DLT_ID_SIZE) == b"CCCC") - assert_true(ctypes.string_at(self.dlt_filter.ctid[2], DLT_ID_SIZE) == b"DDDD") - - def test_repr(self): - assert_equal(self.dlt_filter.add("AAAA", "BBBB"), 0) - assert_equal(self.dlt_filter.add("XXX", "YYY"), 0) - assert_equal(self.dlt_filter.add("CCCC", "DDDD"), 0) - print(self.dlt_filter) - assert_true(str(self.dlt_filter) == str([(b"AAAA", b"BBBB"), (b"XXX", b"YYY"), (b"CCCC", b"DDDD")])) diff --git a/tests/dlt_main_loop_unit_tests.py b/tests/dlt_main_loop_unit_test.py similarity index 61% rename from tests/dlt_main_loop_unit_tests.py rename to tests/dlt_main_loop_unit_test.py index 2d3c840..857a721 100644 --- a/tests/dlt_main_loop_unit_tests.py +++ b/tests/dlt_main_loop_unit_test.py @@ -2,23 +2,14 @@ """Basic unittests for the py_dlt_client_main_loop function""" import ctypes import functools +from io import BytesIO as StringIO import socket import unittest -try: - from cStringIO import StringIO -except ImportError: - from io import BytesIO as StringIO - -import six - -try: - from mock import patch, Mock -except ImportError: - from unittest.mock import patch, Mock +from unittest.mock import patch, Mock from dlt.dlt import py_dlt_client_main_loop, DLTClient, logger from dlt.core import cDltStorageHeader -from .utils import stream_one +from tests.utils import stream_one def mock_dlt_receiver_receive_socket(client_receiver, partial=False, Fail=False): @@ -35,41 +26,37 @@ def mock_dlt_receiver_receive_socket(client_receiver, partial=False, Fail=False) class TestMainLoop(unittest.TestCase): - def setUp(self): self.client = DLTClient() self.client._connected_socket = Mock() def test_target_down(self): - with patch.object(self.client._connected_socket, 'recv', side_effect=socket.timeout): + with patch.object(self.client._connected_socket, "recv", side_effect=socket.timeout): callback = Mock(return_value="should not be called") - if six.PY3: - with self.assertLogs(logger=logger) as dlt_logger: - return_value = py_dlt_client_main_loop(self.client, callback=callback) - self.assertFalse(return_value) + with self.assertLogs(logger=logger) as dlt_logger: + return_value = py_dlt_client_main_loop(self.client, callback=callback) + self.assertFalse(return_value) - log_output = dlt_logger.output - self.assertEqual(len(log_output), 1) - self.assertEqual(log_output[0], 'ERROR:dlt.dlt:[]: DLTLib closed connected socket') - else: - self.assertRaises(socket.timeout, py_dlt_client_main_loop, self.client, callback=callback) + log_output = dlt_logger.output + self.assertEqual(len(log_output), 1) + self.assertEqual(log_output[0], "ERROR:dlt.dlt:[]: DLTLib closed connected socket") self.assertFalse(callback.called) def test_target_up_nothing_to_read(self): - with patch.object(self.client._connected_socket, 'recv', return_value=b"") as mock_recv: + with patch.object(self.client._connected_socket, "recv", return_value=b"") as mock_recv: callback = Mock(return_value="should not be called") self.assertFalse(py_dlt_client_main_loop(self.client, callback=callback)) self.assertEqual(mock_recv.call_count, 1) self.assertFalse(callback.called) - @patch('dlt.dlt.dltlib.dlt_receiver_move_to_begin', return_value=0) + @patch("dlt.dlt.dltlib.dlt_receiver_move_to_begin", return_value=0) def test_exit_if_callback_returns_false(self, *ignored): - with patch.object(self.client._connected_socket, 'recv', return_value=b'X'): + with patch.object(self.client._connected_socket, "recv", return_value=b"X"): # setup dlt_receiver_receive to return a partial message replacement = functools.partial(mock_dlt_receiver_receive_socket, partial=True) - with patch('dlt.dlt.dltlib.dlt_receiver_receive', new=replacement): + with patch("dlt.dlt.dltlib.dlt_receiver_receive", new=replacement): self.assertFalse(py_dlt_client_main_loop(self.client, callback=lambda msg: False)) def test_read_message(self, *ignored): @@ -78,10 +65,10 @@ def test_read_message(self, *ignored): stream_one.seek(0) expected = stream_one.read() - with patch.object(self.client._connected_socket, 'recv', return_value=b'X'): + with patch.object(self.client._connected_socket, "recv", return_value=b"X"): # setup dlt_receiver_receive to return a complete message replacement = functools.partial(mock_dlt_receiver_receive_socket) callback = Mock(side_effect=[True, False, False]) - with patch('dlt.dlt.dltlib.dlt_receiver_receive', new=replacement): + with patch("dlt.dlt.dltlib.dlt_receiver_receive", new=replacement): self.assertTrue(py_dlt_client_main_loop(self.client, dumpfile=dumpfile, callback=callback)) - self.assertEqual(dumpfile.getvalue()[ctypes.sizeof(cDltStorageHeader):], expected) + self.assertEqual(dumpfile.getvalue()[ctypes.sizeof(cDltStorageHeader) :], expected) diff --git a/tests/dlt_message_handler_unit_tests.py b/tests/dlt_message_handler_unit_test.py similarity index 89% rename from tests/dlt_message_handler_unit_tests.py rename to tests/dlt_message_handler_unit_test.py index 572665b..ad3eaf9 100644 --- a/tests/dlt_message_handler_unit_tests.py +++ b/tests/dlt_message_handler_unit_test.py @@ -2,30 +2,23 @@ import os import time import unittest -from multiprocessing.queues import Empty -from multiprocessing import Event - -import six - -if six.PY2: - from multiprocessing.queues import Queue -else: - from multiprocessing import Queue +from queue import Empty +from multiprocessing import Event, Queue from dlt.dlt_broker_handlers import DLTMessageHandler -from .utils import create_messages, stream_multiple +from tests.utils import create_messages, stream_multiple class TestDLTMessageHandler(unittest.TestCase): - def setUp(self): self.filter_queue = Queue() self.message_queue = Queue() - self.client_cfg = {"ip_address": b"127.0.0.1", - "filename": b"/dev/null", - "verbose": 0, - "port": "1234", - } + self.client_cfg = { + "ip_address": b"127.0.0.1", + "filename": b"/dev/null", + "verbose": 0, + "port": "1234", + } self.stop_event = Event() self.handler = DLTMessageHandler(self.filter_queue, self.message_queue, self.stop_event, self.client_cfg) @@ -119,12 +112,12 @@ def test_handle_message_tag_and_distribute(self): messages = [self.message_queue.get(timeout=0.01) for _ in range(60)] # these queues should not get any messages from other queues - self.assertEqual(len([msg for qid, msg in messages if qid == 'queue_id0']), 10) - self.assertEqual(len([msg for qid, msg in messages if qid == 'queue_id1']), 10) - self.assertEqual(len([msg for qid, msg in messages if qid == 'queue_id2']), 10) - self.assertEqual(len([msg for qid, msg in messages if qid == 'queue_id3']), 10) + self.assertEqual(len([msg for qid, msg in messages if qid == "queue_id0"]), 10) + self.assertEqual(len([msg for qid, msg in messages if qid == "queue_id1"]), 10) + self.assertEqual(len([msg for qid, msg in messages if qid == "queue_id2"]), 10) + self.assertEqual(len([msg for qid, msg in messages if qid == "queue_id3"]), 10) # this queue should get all messages - self.assertEqual(len([msg for qid, msg in messages if qid == 'queue_id4']), 20) + self.assertEqual(len([msg for qid, msg in messages if qid == "queue_id4"]), 20) except Empty: # - we should not get an Empty for at least 40 messages self.fail() diff --git a/tests/dlt_message_performance_tests.py b/tests/dlt_message_performance_test.py similarity index 74% rename from tests/dlt_message_performance_tests.py rename to tests/dlt_message_performance_test.py index eacf186..60581ac 100644 --- a/tests/dlt_message_performance_tests.py +++ b/tests/dlt_message_performance_test.py @@ -2,22 +2,19 @@ """Basic unittests for DLT messages""" import io -import time - -from nose.tools import assert_less +import unittest from dlt.dlt import DLTFilter from .utils import create_messages -stream_one = io.BytesIO(b'5\x00\x00 MGHS\xdd\xf6e\xca&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00') -stream_two = io.BytesIO(b'5\x00\x00 MGHS\xdd\xf6e\xca&\x01DA1\x00DC2\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00') +stream_one = io.BytesIO(b"5\x00\x00 MGHS\xdd\xf6e\xca&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00") +stream_two = io.BytesIO(b"5\x00\x00 MGHS\xdd\xf6e\xca&\x01DA1\x00DC2\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00") LOOPS = 100000 -class TestsDLTMessagePerf(object): - +class TestsDLTMessagePerf(unittest.TestCase): def setUp(self): self.msgs = [create_messages(stream_one) for i in range(int(LOOPS * 0.1))] self.msgs += [create_messages(stream_two) for i in range(int(LOOPS * 0.9))] diff --git a/tests/dlt_message_unit_test.py b/tests/dlt_message_unit_test.py new file mode 100644 index 0000000..b9c12b2 --- /dev/null +++ b/tests/dlt_message_unit_test.py @@ -0,0 +1,243 @@ +# Copyright (C) 2015. BMW Car IT GmbH. All rights reserved. +"""Basic unittests for DLT messages""" +import io +import pickle +import re +from unittest.mock import patch, PropertyMock + +import pytest + +from dlt.dlt import DLTMessage +from tests.utils import create_messages, stream_one, stream_with_params, stream_multiple, msg_benoit, control_one + + +class TestsDLTMessageUnit(object): + def test_compare_default_attrs(self): + attrs = {"extendedheader.apid": "DA1", "extendedheader.ctid": "DC1"} + msg = create_messages(stream_one) + + assert msg.compare(other=attrs) + assert msg.compare(other={"extendedheader.ctid": "DC1"}) + + def test_equal(self): + msg1 = create_messages(stream_one) + msg2 = create_messages(stream_one) + + assert msg1 == msg2 + + def test_easy_attributes(self): + msg = create_messages(stream_one) + + assert msg.ecuid == "MGHS" + assert msg.seid == 0 + assert msg.tmsp == 372391.26500000001 + assert msg.apid == "DA1" + assert msg.ctid == "DC1" + + def test_compare(self): + msg1 = create_messages(stream_one) + msg2 = create_messages(stream_one) + + assert msg1.compare(msg2) + assert msg1.compare(other=msg2) + assert msg1.compare(dict(apid="DA1", ctid="DC1")) + assert not msg1.compare(dict(apid="DA1", ctid="XX")) + + def test_compare_regexp(self): + msg1 = create_messages(stream_one) + + assert msg1.compare(dict(apid="DA1", ctid=re.compile(r"D.*"))) + assert msg1.compare( + dict(apid="DA1", ctid=re.compile(r"D.*"), payload_decoded=re.compile(r".connection_info ok.")) + ) + assert msg1.compare( + dict(apid="DA1", ctid=re.compile(r"D.*"), payload_decoded=re.compile(r".connection_info ok.")) + ) + assert msg1.compare(dict(apid="DA1", ctid=re.compile(r"D.*"), payload_decoded=re.compile(r".*info ok."))) + assert msg1.compare(dict(apid="DA1", ctid="DC1", payload_decoded=re.compile(r".*info ok."))) + assert msg1.compare(dict(apid=re.compile(r"D."))) + assert msg1.compare(dict(apid=re.compile(r"D.+"))) + assert msg1.compare(dict(apid=re.compile(r"D."))) + assert not msg1.compare(dict(apid=re.compile(r"X."))) + + def test_compare_regexp_nsm(self): + nsm = create_messages( + io.BytesIO(b"5\x00\x00 MGHS\xdd\xf6e\xca&\x01NSM\x00DC1\x00\x02\x0f\x00\x00" b"\x00\x02\x00\x00\x00\x00") + ) + nsma = create_messages( + io.BytesIO(b"5\x00\x00 MGHS\xdd\xf6e\xca&\x01NSMADC1\x00\x02\x0f\x00\x00" b"\x00\x02\x00\x00\x00\x00") + ) + + assert nsm.compare(dict(apid=re.compile("^NSM$"))) + assert not nsma.compare(dict(apid=re.compile("^NSM$"))) + + assert nsm.compare(dict(apid="NSM")) + assert not nsma.compare(dict(apid="NSM")) + + assert nsm.compare(dict(apid=re.compile("NSM"))) + assert nsma.compare(dict(apid=re.compile("NSM"))) + + def test_compare_regexp_throw(self): + nsm = create_messages( + io.BytesIO(b"5\x00\x00 MGHS\xdd\xf6e\xca&\x01NSM\x00DC1\x00\x02\x0f\x00\x00" b"\x00\x02\x00\x00\x00\x00") + ) + with pytest.raises(Exception): + assert nsm.compare(dict(apid=b"NSM"), regexp=True) + + def test_compare_regexp_benoit(self): + msg1 = create_messages(msg_benoit, from_file=True)[0] + assert msg1.compare( + { + "apid": "DEMO", + "ctid": "DATA", + "payload_decoded": re.compile("Logging from the constructor of a global instance"), + } + ) + + def test_compare_two_msgs(self): + msgs = create_messages(stream_multiple, from_file=True) + assert msgs[0] != msgs[-1] + + def test_compare_other_not_modified(self): + msg = create_messages(stream_one) + other = dict(apid="XX", ctid="DC1") + assert not msg.compare(other) + assert other == dict(apid="XX", ctid="DC1") + + def test_compare_quick_return(self): + msg = create_messages(stream_one) + other = dict(apid=b"DA1", ctid=b"XX", ecuid=b"FOO") + + with patch("dlt.dlt.DLTMessage.ecuid", new_callable=PropertyMock) as ecuid: + ecuid.return_value = b"FOO" + assert not msg.compare(other) + ecuid.assert_not_called() + + def test_compare_matching_apid_ctid(self): + msg = create_messages(stream_one) + other = dict(apid="DA1", ctid="DC1", ecuid="FOO") + + with patch("dlt.dlt.DLTMessage.ecuid", new_callable=PropertyMock) as ecuid: + ecuid.return_value = "BAR" + assert not msg.compare(other) + ecuid.assert_called_once() + + ecuid.return_value = "FOO" + assert msg.compare(other) + assert ecuid.call_count == 2 + + def test_pickle_api(self): + messages = create_messages(stream_multiple, from_file=True) + for msg in messages: + assert msg == pickle.loads(pickle.dumps(msg)) + + def test_from_bytes_control(self): + msg = DLTMessage.from_bytes( + b"DLT\x011\xd9PY(<\x08\x00MGHS5\x00\x00 MGHS\x00\x00\x96\x85&\x01DA1\x00DC1" + b"\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" + ) + + assert msg.apid == "DA1" + assert msg.ctid == "DC1" + assert msg.ecuid == "MGHS" + assert msg.tmsp == 3.8533 + assert msg.storage_timestamp == 1498470705.539688 + assert msg.payload_decoded == "[connection_info ok] connected " + + def test_from_bytes_log_multipayload(self): + msg = DLTMessage.from_bytes( + b"DLT\x011\xd9PYfI\x08\x00MGHS=\x00\x000MGHS\x00\x00\x03\x1e\x00\x00\x94\xc8A" + b"\x01MON\x00CPUS\x00\x02\x00\x00\x10\x004 online cores\n\x00" + ) + + assert msg.apid == "MON" + assert msg.ctid == "CPUS" + assert msg.ecuid == "MGHS" + assert msg.tmsp == 3.8088 + assert msg.payload_decoded == "4 online cores" + + def test_sort_data_control(self): + data = ( + b"DLT\x011\xd9PY(<\x08\x00MGHS5\x00\x00 MGHS\x00\x00\x96\x85&\x01DA1\x00DC1" + b"\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" + ) + tmsp, length, apid, ctid = DLTMessage.extract_sort_data(data) + + assert tmsp == 3.8533 + assert length == len(data) + assert apid == "DA1" + assert ctid == "DC1" + + def test_sort_data_log_multipayload(self): + data = ( + b"DLT\x011\xd9PYfI\x08\x00MGHS=\x00\x000MGHS\x00\x00\x03\x1e\x00\x00\x94\xc8A" + b"\x01MON\x00CPUS\x00\x02\x00\x00\x10\x004 online cores\n\x00" + ) + tmsp, length, apid, ctid = DLTMessage.extract_sort_data(data) + + assert tmsp == 3.8088 + assert length == len(data) + assert apid == "MON" + assert ctid == "CPUS" + + def test_largelog(self): + data = ( + b"DLT\x012\xd9PY)\x00\x01\x00MGHS=o\x02\x04MGHS\x00\x00\x03\x1e\x00\x00\x9e\xb7" + b"A\x01MON\x00THRD\x00\x02\x00\x00\xe4\x01Process avb_streamhandl with pid: 307 " + b'"/usr/bin/avb_streamhandler_app_someip -s pluginias-media_transport-avb_config' + b"uration_bmw_mgu.so --bg setup --target Harman_MGU_B1 -p MGU_ICAM -k local.alsa" + b".baseperiod=256 -k ptp.loopcount=0 -k ptp.pdelaycount=0 -k ptp.synccount=0 -k " + b"sched.priority=20 -k tspec.vlanprio.low=3 -k tspec.presentation.time.offset.lo" + b"w=2200000 -k tspec.interval.low=1333000 -k debug.loglevel._RXE=4 -k alsa.group" + b'name=mgu_avbsh -n socnet0 -b 2 " started 2401 msec ago\x00' + ) + + msg = DLTMessage.from_bytes(data) + assert msg.apid == "MON" + assert msg.ctid == "THRD" + assert msg.ecuid == "MGHS" + assert msg.tmsp == 4.0631 + assert ( + msg.payload_decoded == 'Process avb_streamhandl with pid: 307 "/usr/bin/avb_streamhandler_app_someip -s ' + "pluginias-media_transport-avb_configuration_bmw_mgu.so --bg setup --target Harman_MGU_B1 -p MGU_ICAM " + "-k local.alsa.baseperiod=256 -k ptp.loopcount=0 -k ptp.pdelaycount=0 -k ptp.synccount=0 " + "-k sched.priority=20 -k tspec.vlanprio.low=3 -k tspec.presentation.time.offset.low=2200000 " + "-k tspec.interval.low=1333000 -k debug.loglevel._RXE=4 -k alsa.groupname=mgu_avbsh -n socnet0 " + '-b 2 " started 2401 msec ago' + ) + + tmsp, length, apid, ctid = DLTMessage.extract_sort_data(data) + assert msg.tmsp == tmsp + assert len(msg.to_bytes()) == length + assert msg.apid == apid + assert msg.ctid == ctid + + +class TestsPayload(object): + def test_split(self): + msg = create_messages(stream_with_params, from_file=True)[0] + payload = msg.payload + assert len(payload) == msg.noar + assert payload[0] == b"CLevelMonitor::notification() => commandType" + assert payload[1] == 3 + assert payload[2] == b"deviceId" + assert payload[3] == 5 + assert payload[4] == b"value" + assert payload[5] == 4074 + assert payload[6] == b"simulation status" + assert payload[7] == 0 + + with pytest.raises(IndexError): + payload.__getitem__(8) + + +class TestsControl(object): + def test_load(self): + msg = create_messages(control_one, from_file=True)[0] + assert msg.apid == "DA1" + assert msg.ctid == "DC1" + assert msg.is_mode_verbose == 0 + assert ( + msg.payload_decoded == "[get_log_info 7] get_log_info, 07, 01 00 48 44 44 4d 01 00 43 41 50 49 ff" + " ff 04 00 43 41 50 49 06 00 68 64 64 6d 67 72 72 65 6d 6f" + ) diff --git a/tests/dlt_message_unit_tests.py b/tests/dlt_message_unit_tests.py deleted file mode 100644 index e352500..0000000 --- a/tests/dlt_message_unit_tests.py +++ /dev/null @@ -1,234 +0,0 @@ -# Copyright (C) 2015. BMW Car IT GmbH. All rights reserved. -"""Basic unittests for DLT messages""" -import io -import pickle -import re - -try: - from mock import patch, PropertyMock -except ImportError: - from unittest.mock import patch, PropertyMock - -from nose.tools import * - -from dlt.dlt import DLTMessage - -from .utils import create_messages, stream_one, stream_with_params, stream_multiple, msg_benoit, control_one - - -class TestsDLTMessageUnit(object): - - def test_compare_default_attrs(self): - attrs = {"extendedheader.apid": "DA1", "extendedheader.ctid": "DC1"} - msg = create_messages(stream_one) - - assert_true(msg.compare(other=attrs)) - assert_true(msg.compare(other={"extendedheader.ctid": "DC1"})) - - def test_equal(self): - msg1 = create_messages(stream_one) - msg2 = create_messages(stream_one) - - assert_equal(msg1, msg2) - - def test_easy_attributes(self): - msg = create_messages(stream_one) - - assert_equal(msg.ecuid, "MGHS") - assert_equal(msg.seid, 0) - assert_equal(msg.tmsp, 372391.26500000001) - assert_equal(msg.apid, "DA1") - assert_equal(msg.ctid, "DC1") - - def test_compare(self): - msg1 = create_messages(stream_one) - msg2 = create_messages(stream_one) - - assert_true(msg1.compare(msg2)) - assert_true(msg1.compare(other=msg2)) - assert_true(msg1.compare(dict(apid="DA1", ctid="DC1"))) - assert_false(msg1.compare(dict(apid="DA1", ctid="XX"))) - - def test_compare_regexp(self): - msg1 = create_messages(stream_one) - - assert_true(msg1.compare(dict(apid="DA1", ctid=re.compile(r"D.*")))) - assert_true(msg1.compare(dict(apid="DA1", ctid=re.compile(r"D.*"), - payload_decoded=re.compile(r".connection_info ok.")))) - assert_true(msg1.compare(dict(apid="DA1", ctid=re.compile(r"D.*"), - payload_decoded=re.compile(r".connection_info ok.")))) - assert_true(msg1.compare(dict(apid="DA1", ctid=re.compile(r"D.*"), - payload_decoded=re.compile(r".*info ok.")))) - assert_true(msg1.compare(dict(apid="DA1", ctid="DC1", payload_decoded=re.compile(r".*info ok.")))) - assert_true(msg1.compare(dict(apid=re.compile(r"D.")))) - assert_true(msg1.compare(dict(apid=re.compile(r"D.+")))) - assert_true(msg1.compare(dict(apid=re.compile(r"D.")))) - assert_false(msg1.compare(dict(apid=re.compile(r"X.")))) - - def test_compare_regexp_nsm(self): - nsm = create_messages(io.BytesIO(b'5\x00\x00 MGHS\xdd\xf6e\xca&\x01NSM\x00DC1\x00\x02\x0f\x00\x00' - b'\x00\x02\x00\x00\x00\x00')) - nsma = create_messages(io.BytesIO(b'5\x00\x00 MGHS\xdd\xf6e\xca&\x01NSMADC1\x00\x02\x0f\x00\x00' - b'\x00\x02\x00\x00\x00\x00')) - - assert_true(nsm.compare(dict(apid=re.compile("^NSM$")))) - assert_false(nsma.compare(dict(apid=re.compile("^NSM$")))) - - assert_true(nsm.compare(dict(apid="NSM"))) - assert_false(nsma.compare(dict(apid="NSM"))) - - assert_true(nsm.compare(dict(apid=re.compile("NSM")))) - assert_true(nsma.compare(dict(apid=re.compile("NSM")))) - - @raises(Exception) - def test_compare_regexp_throw(self): - assert_true(nsm.compare(dict(apid=b"NSM"), regexp=True)) - - def test_compare_regexp_benoit(self): - msg1 = create_messages(msg_benoit, from_file=True)[0] - assert_true(msg1.compare({"apid": "DEMO", - "ctid": "DATA", - "payload_decoded": re.compile("Logging from the constructor of a global instance")})) - - def test_compare_two_msgs(self): - msgs = create_messages(stream_multiple, from_file=True) - assert_not_equal(msgs[0], msgs[-1]) - - def test_compare_other_not_modified(self): - msg = create_messages(stream_one) - other = dict(apid='XX', ctid='DC1') - assert_false(msg.compare(other)) - assert_equal(other, dict(apid='XX', ctid='DC1')) - - def test_compare_quick_return(self): - msg = create_messages(stream_one) - other = dict(apid=b'DA1', ctid=b'XX', ecuid=b'FOO') - - with patch('dlt.dlt.DLTMessage.ecuid', new_callable=PropertyMock) as ecuid: - ecuid.return_value = b'FOO' - assert_false(msg.compare(other)) - ecuid.assert_not_called() - - def test_compare_matching_apid_ctid(self): - msg = create_messages(stream_one) - other = dict(apid='DA1', ctid='DC1', ecuid='FOO') - - with patch('dlt.dlt.DLTMessage.ecuid', new_callable=PropertyMock) as ecuid: - ecuid.return_value = 'BAR' - assert_false(msg.compare(other)) - ecuid.assert_called_once() - - ecuid.return_value = 'FOO' - assert_true(msg.compare(other)) - assert_equal(ecuid.call_count, 2) - - def test_pickle_api(self): - messages = create_messages(stream_multiple, from_file=True) - for msg in messages: - assert_equal(msg, pickle.loads(pickle.dumps(msg))) - - def test_from_bytes_control(self): - msg = DLTMessage.from_bytes(b"DLT\x011\xd9PY(<\x08\x00MGHS5\x00\x00 MGHS\x00\x00\x96\x85&\x01DA1\x00DC1" - b"\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00") - - assert_equal(msg.apid, "DA1") - assert_equal(msg.ctid, "DC1") - assert_equal(msg.ecuid, "MGHS") - assert_equal(msg.tmsp, 3.8533) - assert_equal(msg.storage_timestamp, 1498470705.539688) - assert_equal(msg.payload_decoded, "[connection_info ok] connected ") - - def test_from_bytes_log_multipayload(self): - msg = DLTMessage.from_bytes(b"DLT\x011\xd9PYfI\x08\x00MGHS=\x00\x000MGHS\x00\x00\x03\x1e\x00\x00\x94\xc8A" - b"\x01MON\x00CPUS\x00\x02\x00\x00\x10\x004 online cores\n\x00") - - assert_equal(msg.apid, "MON") - assert_equal(msg.ctid, "CPUS") - assert_equal(msg.ecuid, "MGHS") - assert_equal(msg.tmsp, 3.8088) - assert_equal(msg.payload_decoded, "4 online cores") - - def test_sort_data_control(self): - data = ( - b"DLT\x011\xd9PY(<\x08\x00MGHS5\x00\x00 MGHS\x00\x00\x96\x85&\x01DA1\x00DC1" - b"\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" - ) - tmsp, length, apid, ctid = DLTMessage.extract_sort_data(data) - - assert_equal(tmsp, 3.8533) - assert_equal(length, len(data)) - assert_equal(apid, "DA1") - assert_equal(ctid, "DC1") - - def test_sort_data_log_multipayload(self): - data = ( - b"DLT\x011\xd9PYfI\x08\x00MGHS=\x00\x000MGHS\x00\x00\x03\x1e\x00\x00\x94\xc8A" - b"\x01MON\x00CPUS\x00\x02\x00\x00\x10\x004 online cores\n\x00" - ) - tmsp, length, apid, ctid = DLTMessage.extract_sort_data(data) - - assert_equal(tmsp, 3.8088) - assert_equal(length, len(data)) - assert_equal(apid, "MON") - assert_equal(ctid, "CPUS") - - def test_largelog(self): - data = ( - b'DLT\x012\xd9PY)\x00\x01\x00MGHS=o\x02\x04MGHS\x00\x00\x03\x1e\x00\x00\x9e\xb7' - b'A\x01MON\x00THRD\x00\x02\x00\x00\xe4\x01Process avb_streamhandl with pid: 307 ' - b'"/usr/bin/avb_streamhandler_app_someip -s pluginias-media_transport-avb_config' - b'uration_bmw_mgu.so --bg setup --target Harman_MGU_B1 -p MGU_ICAM -k local.alsa' - b'.baseperiod=256 -k ptp.loopcount=0 -k ptp.pdelaycount=0 -k ptp.synccount=0 -k ' - b'sched.priority=20 -k tspec.vlanprio.low=3 -k tspec.presentation.time.offset.lo' - b'w=2200000 -k tspec.interval.low=1333000 -k debug.loglevel._RXE=4 -k alsa.group' - b'name=mgu_avbsh -n socnet0 -b 2 " started 2401 msec ago\x00' - ) - - msg = DLTMessage.from_bytes(data) - assert_equal(msg.apid, "MON") - assert_equal(msg.ctid, "THRD") - assert_equal(msg.ecuid, "MGHS") - assert_equal(msg.tmsp, 4.0631) - assert_equal( - msg.payload_decoded, - 'Process avb_streamhandl with pid: 307 "/usr/bin/avb_streamhandler_app_someip -s ' - 'pluginias-media_transport-avb_configuration_bmw_mgu.so --bg setup --target Harman_MGU_B1 -p MGU_ICAM ' - '-k local.alsa.baseperiod=256 -k ptp.loopcount=0 -k ptp.pdelaycount=0 -k ptp.synccount=0 ' - '-k sched.priority=20 -k tspec.vlanprio.low=3 -k tspec.presentation.time.offset.low=2200000 ' - '-k tspec.interval.low=1333000 -k debug.loglevel._RXE=4 -k alsa.groupname=mgu_avbsh -n socnet0 ' - '-b 2 " started 2401 msec ago' - ) - - tmsp, length, apid, ctid = DLTMessage.extract_sort_data(data) - assert_equal(msg.tmsp, tmsp) - assert_equal(len(msg.to_bytes()), length) - assert_equal(msg.apid, apid) - assert_equal(msg.ctid, ctid) - - -class TestsPayload(object): - - def test_split(self): - msg = create_messages(stream_with_params, from_file=True)[0] - payload = msg.payload - assert_equal(len(payload), msg.noar) - assert_equal(payload[0], b"CLevelMonitor::notification() => commandType") - assert_equal(payload[1], 3) - assert_equal(payload[2], b"deviceId") - assert_equal(payload[3], 5) - assert_equal(payload[4], b"value") - assert_equal(payload[5], 4074) - assert_equal(payload[6], b"simulation status") - assert_equal(payload[7], 0) - assert_raises(IndexError, payload.__getitem__, 8) - - -class TestsControl(object): - - def test_load(self): - msg = create_messages(control_one, from_file=True)[0] - assert_equal(msg.apid, "DA1") - assert_equal(msg.ctid, "DC1") - assert_equal(msg.is_mode_verbose, 0) - assert_equal(msg.payload_decoded, "[get_log_info 7] get_log_info, 07, 01 00 48 44 44 4d 01 00 43 41 50 49 ff" - " ff 04 00 43 41 50 49 06 00 68 64 64 6d 67 72 72 65 6d 6f") diff --git a/tests/static_check_tests.py b/tests/static_check_tests.py deleted file mode 100644 index efb8499..0000000 --- a/tests/static_check_tests.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (C) 2015. BMW Car IT GmbH. All rights reserved. -"""Static checks for python-dlt""" - -import os -import unittest - -from nose.tools import assert_equal - -from dlt import run_command - - -def search_bin_path(search_bin, search_path): - for path in search_path: - if all(os.path.exists(os.path.join(path, bin_name)) for bin_name in search_bin): - return path - - raise ValueError("Could not find path for {}".format(search_bin)) - - -class TestCodingStyleCheck(unittest.TestCase): - def setUp(self): - search_bin = ['pycodestyle', 'pylint'] - search_path = ['/opt/nativesysroot/usr/bin', '/usr/local/bin'] - - tox_bin_path = os.getenv('PATH').split(':')[0] - if tox_bin_path.startswith(os.path.join(os.getcwd(), '.tox')): - search_path.append(tox_bin_path) - - self.prefix_path = search_bin_path(search_bin, search_path) - - def test_check_pycodestyle(self): - command = [os.path.join(self.prefix_path, "pycodestyle"), "dlt"] - stdout, stderr, return_code = run_command(command, shell=False) - assert_equal(return_code, 0, "Stdout: {}\nStderr: {}".format(stdout, stderr)) - - def test_check_pylint(self): - command = [os.path.join(self.prefix_path, "pylint"), "--rcfile", "setup.cfg", "dlt"] - stdout, stderr, return_code = run_command(command, shell=False) - assert_equal(return_code, 0, "Stdout: {}\nStderr: {}".format(stdout, stderr)) diff --git a/tests/utils.py b/tests/utils.py index 9c2dc7b..cf73c62 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -10,99 +10,113 @@ from dlt.dlt import DLTClient, load -stream_one = io.BytesIO(b'5\x00\x00 MGHS\xdd\xf6e\xca&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00') -stream_with_params = (b"DLT\x01\xc2<\x85W\xc7\xc5\x02\x00MGHS=r\x00\xa0MGHS\x00\x00\x02B\x00X\xd4\xf1A\x08" - b"ENV\x00LVLM\x00\x02\x00\x00-\x00CLevelMonitor::notification() => commandType\x00#" - b"\x00\x00\x00\x03\x00\x00\x00\x00\x02\x00\x00\t\x00deviceId\x00#\x00\x00\x00\x05\x00" - b"\x00\x00\x00\x02\x00\x00\x06\x00value\x00#\x00\x00\x00\xea\x0f\x00\x00\x00\x02\x00" - b"\x00\x12\x00simulation status\x00#\x00\x00\x00\x00\x00\x00\x00") - -stream_multiple = (b"DLT\x01#o\xd1WD>\x0c\x00MGHS5\x00\x00YMGHS\x00\x01\x80\xd1&\x01DA1\x00DC1\x00\x03\x00\x00\x00" - b"\x07\x01\x00SYS\x00\x01\x00FILE\xff\xff\x16\x00File transfer manager.\x12\x00" - b"DLT System ManagerremoDLT\x01#o\xd1Wo>\x0c\x00MGHS=\x00\x01PMGHS\x00\x00\x03\xf4\x00" - b"\x01i\xa6A\x05SYS\x00JOUR\x00\x02\x00\x00\x1b\x002011/11/11 11:11:18.005274\x00\x00\x02\x00\x00" - b"\t\x006.005274\x00\x00\x02\x00\x00\x16\x00systemd-journal[748]:\x00\x00\x02\x00\x00\x0f\x00" - b"Informational:\x00\x00\x02\x00\x00\xcf\x00Runtime journal (/run/log/journal/) is currently" - b" using 8.0M.\nMaximum allowed usage is set to 385.9M.\nLeaving at least 578.8M free (of" - b" currently available 3.7G of space).\nEnforced usage limit is thus 385.9M.\x00") - -msg_benoit = (b"DLT\x01\xa5\xd1\xceW\x90\xb9\r\x00MGHS=\x00\x00RMGHS\x00\x00\n[\x00\x0f\x9b#A\x01DEMODATA\x00" - b"\x82\x00\x002\x00Logging from the constructor of a global instance\x00") - - -control_one = (b'DLT\x01#o\xd1W\x99!\x0c\x00MGHS5\x00\x00;MGHS\x00\x01\x7f\xdb&\x01DA1\x00DC1\x00\x03' - b'\x00\x00\x00\x07\x01\x00HDDM\x01\x00CAPI\xff\xff\x04\x00CAPI\x06\x00hddmgrremo') +stream_one = io.BytesIO(b"5\x00\x00 MGHS\xdd\xf6e\xca&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00") +stream_with_params = ( + b"DLT\x01\xc2<\x85W\xc7\xc5\x02\x00MGHS=r\x00\xa0MGHS\x00\x00\x02B\x00X\xd4\xf1A\x08" + b"ENV\x00LVLM\x00\x02\x00\x00-\x00CLevelMonitor::notification() => commandType\x00#" + b"\x00\x00\x00\x03\x00\x00\x00\x00\x02\x00\x00\t\x00deviceId\x00#\x00\x00\x00\x05\x00" + b"\x00\x00\x00\x02\x00\x00\x06\x00value\x00#\x00\x00\x00\xea\x0f\x00\x00\x00\x02\x00" + b"\x00\x12\x00simulation status\x00#\x00\x00\x00\x00\x00\x00\x00" +) + +stream_multiple = ( + b"DLT\x01#o\xd1WD>\x0c\x00MGHS5\x00\x00YMGHS\x00\x01\x80\xd1&\x01DA1\x00DC1\x00\x03\x00\x00\x00" + b"\x07\x01\x00SYS\x00\x01\x00FILE\xff\xff\x16\x00File transfer manager.\x12\x00" + b"DLT System ManagerremoDLT\x01#o\xd1Wo>\x0c\x00MGHS=\x00\x01PMGHS\x00\x00\x03\xf4\x00" + b"\x01i\xa6A\x05SYS\x00JOUR\x00\x02\x00\x00\x1b\x002011/11/11 11:11:18.005274\x00\x00\x02\x00\x00" + b"\t\x006.005274\x00\x00\x02\x00\x00\x16\x00systemd-journal[748]:\x00\x00\x02\x00\x00\x0f\x00" + b"Informational:\x00\x00\x02\x00\x00\xcf\x00Runtime journal (/run/log/journal/) is currently" + b" using 8.0M.\nMaximum allowed usage is set to 385.9M.\nLeaving at least 578.8M free (of" + b" currently available 3.7G of space).\nEnforced usage limit is thus 385.9M.\x00" +) + +msg_benoit = ( + b"DLT\x01\xa5\xd1\xceW\x90\xb9\r\x00MGHS=\x00\x00RMGHS\x00\x00\n[\x00\x0f\x9b#A\x01DEMODATA\x00" + b"\x82\x00\x002\x00Logging from the constructor of a global instance\x00" +) + + +control_one = ( + b"DLT\x01#o\xd1W\x99!\x0c\x00MGHS5\x00\x00;MGHS\x00\x01\x7f\xdb&\x01DA1\x00DC1\x00\x03" + b"\x00\x00\x00\x07\x01\x00HDDM\x01\x00CAPI\xff\xff\x04\x00CAPI\x06\x00hddmgrremo" +) # DLT file with invalid storage header and frames -file_storage_clean = (b"DLT\x01\x9a\xc6\xbfW\x020\t\x00MGHS5\x00\x00 MGHS\x00\x02\x8aC&\x01DA1\x00DC1" - b"\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00DLT\x01\x9a\xc6\xbfWoA\t\x00MGHS=" - b"\x00\x00NMGHS\x00\x00\x049\x00\x01p\n\x00MGHS5\x00\x00 MGHS" # not to buffer - b"\x00\x00mj&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" - ) - -file_with_lifecycles_without_start = (b"DLT\x01\xc5\x82\xdaX\x19\x93\r\x00XORA'\x01\x00\x1bXORA" # trace to buffer - b"\x16\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x04\x00\x00\x00\x00" - b"DLT\x01\xc5\x82\xdaXQi\x0e\x00MGHS5\x00\x00 MGHS" # trace to buffer - b"\x00\x03U\xe0&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" - b"DLT\x01m\xc2\x91Y\xad\xe4\x07\x00MGHS=\x01\x00zMGHS" # random trace - b"\x00\x00\x02\xab\x00\x00@VA\x01DLTDINTM\x00\x02\x00\x00Z\x00" - b"ApplicationID 'DBSY' registered for PID 689, Description=DBus" - b" Logging|SysInfra|Log&Trace\n\x00" - b"DLT\x01\xed\xc2\x91Y\x0f\xf0\x08\x00MGHS5\x00\x00 MGHS" # trace to buffer - b"\x00\x00\x9dC&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" - b"DLT\x01\xed\xc2\x91Y\x17.\n\x00MGHS=\x00\x00NMGHS" # new lifecycle - b"\x00\x00\x02\xae\x00\x00@/A\x01DLTDINTM\x00\x02\x00\x00.\x00" - b"Daemon launched. Starting to output traces...\x00" - ) +file_storage_invalid_storage_hdr = ( + b"DLT\x01V\x03EX8\x06\x0b\x00\x00\x00\x00\x00=\x9d\x00\xaaMGHS\x00" + b"\x00\x04$\x00\n\x11\xed1\x01NAVCSPCODLT\x01V\x03EXuD\x0c\x00\x00" + b"\x00\x00\x00'\x01\x00\x1bXORA\x16\x02\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x11\x04\x00\x00\x00\x00DLT\x01V\x03EX\xfd[\x0c\x00" + b"\x00\x00\x00\x005\x00\x00 MGHS\x00\n\x14\xda&\x01DA1\x00DC1\x00\x02" + b"\x0f\x00\x00\x00\x02\x00\x00\x00\x00DLT\x01V\x03EXel\x0c\x00\x00\x00" + b"\x00\x005\x00\x00 MGHS\x00\n\x11\xfb&\x01DA1\x00DC1\x00\x02\x0f\x00" + b"\x00\x00\x01\x00\x00\x00\x00DLT\x01V\x03EXvl\x0c\x00\x00\x00\x00\x00" + b"=\x86\x00cMGHS\x00\x00\x07\xa7\x00\n\x12\x1cA\x01NAVIASIA\x00\x02\x00" + b"\x00C\x00[MSG_NV_MD] [NVS_MV][WIN1]iparam_update gui_mode(0) shmem " + b"val(0) \n\x00DLT\x01V\x03EX}l\x0c\x00\x00\x00\x00\x00=\x87\x00WMGHS" + b"\x00\x00\x07\xa7\x00\n\x12!A\x01NAVIASIA\x00\x02\x00\x007\x00[MSG_NV" + b"_MD] [NVS_MV][WIN1] full menu stratframe(1479)\n\x00DLT\x01V\x03EX\x86" + b"l\x0c\x00\x00\x00\x00\x00=n\x00\x89MGHS\x00\x00\x04$\x00\n\x12*A\x01NAV" + b"CBLPS\x00\x02\x00\x00i\x00[Thread A] [PositioningCanAdapter.cpp::operat" + b"or():92] Send: GPSRo" +) + +file_with_four_lifecycles = ( + b"DLT\x01\xc5\x82\xdaX\x19\x93\r\x00XORA'\x01\x00\x1bXORA" # trace to buffer + b"\x16\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x04\x00\x00\x00\x00" + b"DLT\x01\xc5\x82\xdaXQi\x0e\x00MGHS5\x00\x00 MGHS" # trace to buffer + b"\x00\x03U\xe0&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" + b"DLT\x01\xc5\x82\xdaX\x82o\x0e\x00MGHS=\x00\x00NMGHS" # first lifecycle + b"\x00\x00\x02r\x00\x00\x8frA\x01DLTDINTM\x00\x02\x00\x00.\x00" + b"Daemon launched. Starting to output traces...\x00" + b"DLT\x01\xc9\xc1\x91Y\xbf\x1b\x00\x00MGHS5\x00\x00 MGHS" # trace to buffer + b"\x00\x00v\n&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" + b"DLT\x01\xc9\xc1\x91Y\x9f/\x00\x00MGHS=\x00\x00NMGHS" # new lifecycle + b"\x00\x00\x032\x00\x00IWA\x01DLTDINTM\x00\x02\x00\x00.\x00" + b"Daemon launched. Starting to output traces...\x00" + b"DLT\x01m\xc2\x91Y\x9f\xda\x07\x00MGHS5\x00\x00 MGHS" # no new lifecycle + b"\x00\x00_\xde&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" + b"DLT\x01m\xc2\x91Y\xad\xe4\x07\x00MGHS=\x01\x00zMGHS" # random trace + b"\x00\x00\x02\xab\x00\x00@VA\x01DLTDINTM\x00\x02\x00\x00Z\x00" + b"ApplicationID 'DBSY' registered for PID 689, Description=DBus" + b" Logging|SysInfra|Log&Trace\n\x00" + b"DLT\x01\xed\xc2\x91Y\x0f\xf0\x08\x00MGHS5\x00\x00 MGHS" # trace to buffer + b"\x00\x00\x9dC&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" + b"DLT\x01\xed\xc2\x91Y\x17.\n\x00MGHS=\x00\x00NMGHS" # new lifecycle + b"\x00\x00\x02\xae\x00\x00@/A\x01DLTDINTM\x00\x02\x00\x00.\x00" + b"Daemon launched. Starting to output traces...\x00" + b"DLT\x01]\xc3\x91Y,\x91\r\x00MGHS=\x00\x00NMGHS" # new lifecycle + b"\x00\x00\x02\xbd\x00\x00G\xefA\x01DLTDINTM\x00\x02\x00\x00.\x00" + b"Daemon launched. Starting to output traces...\x00" + b"DLT\x01U\xc4\x91Y\x8c>\n\x00MGHS5\x00\x00 MGHS" # not to buffer + b"\x00\x00mj&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" +) + +file_with_lifecycles_without_start = ( + b"DLT\x01\xc5\x82\xdaX\x19\x93\r\x00XORA'\x01\x00\x1bXORA" # trace to buffer + b"\x16\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x04\x00\x00\x00\x00" + b"DLT\x01\xc5\x82\xdaXQi\x0e\x00MGHS5\x00\x00 MGHS" # trace to buffer + b"\x00\x03U\xe0&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" + b"DLT\x01m\xc2\x91Y\xad\xe4\x07\x00MGHS=\x01\x00zMGHS" # random trace + b"\x00\x00\x02\xab\x00\x00@VA\x01DLTDINTM\x00\x02\x00\x00Z\x00" + b"ApplicationID 'DBSY' registered for PID 689, Description=DBus" + b" Logging|SysInfra|Log&Trace\n\x00" + b"DLT\x01\xed\xc2\x91Y\x0f\xf0\x08\x00MGHS5\x00\x00 MGHS" # trace to buffer + b"\x00\x00\x9dC&\x01DA1\x00DC1\x00\x02\x0f\x00\x00\x00\x02\x00\x00\x00\x00" + b"DLT\x01\xed\xc2\x91Y\x17.\n\x00MGHS=\x00\x00NMGHS" # new lifecycle + b"\x00\x00\x02\xae\x00\x00@/A\x01DLTDINTM\x00\x02\x00\x00.\x00" + b"Daemon launched. Starting to output traces...\x00" +) def create_messages(stream, from_file=False): @@ -131,6 +145,7 @@ def create_messages(stream, from_file=False): class MockDLTMessage(object): """Mock DLT message for dltlyse plugin testing""" + def __init__(self, ecuid="MGHS", apid="SYS", ctid="JOUR", sid="958", payload="", tmsp=0.0, sec=0, msec=0, mcnt=0): self.ecuid = ecuid self.apid = apid @@ -161,6 +176,7 @@ def __repr__(self): class MockStorageHeader(object): """Mock DLT storage header for plugin testing""" + def __init__(self, msec=0, sec=0): self.microseconds = msec self.seconds = sec diff --git a/tox.ini b/tox.ini index 74d6a3d..8eb4029 100644 --- a/tox.ini +++ b/tox.ini @@ -1,29 +1,47 @@ [tox] -envlist = py3,py27,lint -skipdist = True +envlist = py3,lint +output_dir={env:SPHINX_OUTPUT_DIR:{toxworkdir}/_build} +isolated_build = True [testenv] -deps = -r{toxinidir}/requirements.txt - six - parameterized -commands = coverage erase - coverage run {envbindir}/nosetests -sv {posargs} - coverage report +deps = + pytest + pytest-cov +commands = + pytest \ + --cov=dlt \ + --cov-branch \ + --cov-report=html \ + --cov-report=term-missing \ + {posargs:tests} -[testenv:py27] -# Python 2.7 specific requirements -deps = {[testenv]deps} - -r{toxinidir}/requirements2.7.txt +[testenv:lint] +skip_install = True +skipsdist = True +deps = + flake8 + black +commands = + flake8 + black -l 119 --check . -[testenv:py3] -# Python 3 specific requirements -deps = {[testenv]deps} - -r{toxinidir}/requirements3.txt +[testenv:docs] +deps=-r{toxinidir}/docs/requirements-docs.txt +commands= + # Workaround for https://github.com/tox-dev/tox/issues/149 + pip install -q -r {toxinidir}/docs/requirements-docs.txt + sphinx-build -T -j auto --color -W -c docs docs {[tox]output_dir} {posargs} + python -c 'import pathlib; print("website available under file://\{0\}".format(pathlib.Path(r"{[tox]output_dir}") / "index.html"))' -[testenv:lint] +[testenv:release] +basepython = python3 +passenv = SOURCE_DATE_EPOCH skip_install = True skipsdist = True -deps = {[testenv]deps} - -r{toxinidir}/requirements3.txt -commands = pycodestyle dlt - pylint --rcfile=setup.cfg dlt +deps = + build + twine + wheel +commands = + python -m build + twine upload -r software-factory-pypi dist/*