Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .coverage
Binary file not shown.
13 changes: 13 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[run]
branch = True
source = jsocket
omit =
*/__init__.py

[report]
show_missing = True
skip_covered = True
exclude_lines =
pragma: no cover
if __name__ == .__main__.

24 changes: 23 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
.PHONY: test-behave
.PHONY: test-behave test-pytest-cov test-behave-cov coverage lint

test-behave:
PYTHONPATH=. behave -f progress2

# Pytest coverage (terminal report)
test-pytest-cov:
pytest -q --cov=jsocket --cov-branch --cov-report=term-missing

# Behave coverage (appends to same .coverage data)
test-behave-cov:
coverage run -a -m behave -f progress2

# Combined coverage: erase, run pytest+behave, show and export XML/HTML
coverage:
coverage erase
pytest -q --cov=jsocket --cov-branch --cov-report=term
coverage run -a -m behave -f progress2
coverage report -m
coverage xml -o coverage.xml
coverage html -d .coverage_html

# Static analysis with pylint; fail if score below threshold
lint:
mkdir -p .pylint.d
PYLINTHOME=.pylint.d pylint jsocket tests features/steps --fail-under=9.0 --persistent=n
310 changes: 310 additions & 0 deletions coverage.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
<?xml version="1.0" ?>
<coverage version="7.10.5" timestamp="1756175364137" lines-valid="286" lines-covered="254" line-rate="0.8881" branches-valid="44" branches-covered="36" branch-rate="0.8182" complexity="0">
<!-- Generated by coverage.py: https://coverage.readthedocs.io/en/7.10.5 -->
<!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
<sources>
<source>/home/chris/python-json-socket/jsocket</source>
</sources>
<packages>
<package name="." line-rate="0.8881" branch-rate="0.8182" complexity="0">
<classes>
<class name="jsocket_base.py" filename="jsocket_base.py" complexity="0" line-rate="0.8955" branch-rate="0.9286">
<methods/>
<lines>
<line number="4" hits="1"/>
<line number="5" hits="1"/>
<line number="6" hits="1"/>
<line number="22" hits="1"/>
<line number="24" hits="1"/>
<line number="25" hits="1"/>
<line number="26" hits="1"/>
<line number="27" hits="1"/>
<line number="28" hits="1"/>
<line number="30" hits="1"/>
<line number="33" hits="1"/>
<line number="36" hits="1"/>
<line number="37" hits="1"/>
<line number="38" hits="1"/>
<line number="39" hits="1"/>
<line number="40" hits="1"/>
<line number="41" hits="1"/>
<line number="43" hits="1"/>
<line number="45" hits="1"/>
<line number="47" hits="1"/>
<line number="48" hits="1" branch="true" condition-coverage="50% (1/2)" missing-branches="exit"/>
<line number="49" hits="1"/>
<line number="50" hits="1"/>
<line number="51" hits="1"/>
<line number="52" hits="1"/>
<line number="53" hits="1"/>
<line number="54" hits="1"/>
<line number="56" hits="1"/>
<line number="58" hits="1"/>
<line number="59" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="60" hits="1"/>
<line number="62" hits="1"/>
<line number="64" hits="1"/>
<line number="65" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="66" hits="1"/>
<line number="67" hits="1"/>
<line number="68" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="69" hits="1"/>
<line number="70" hits="1"/>
<line number="72" hits="1"/>
<line number="74" hits="1"/>
<line number="75" hits="1"/>
<line number="76" hits="1"/>
<line number="78" hits="1"/>
<line number="80" hits="1"/>
<line number="81" hits="1"/>
<line number="82" hits="1"/>
<line number="83" hits="1"/>
<line number="84" hits="1"/>
<line number="86" hits="1"/>
<line number="88" hits="1"/>
<line number="89" hits="1"/>
<line number="90" hits="1"/>
<line number="92" hits="1"/>
<line number="94" hits="1"/>
<line number="95" hits="1"/>
<line number="96" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="97" hits="1"/>
<line number="98" hits="1"/>
<line number="99" hits="1"/>
<line number="100" hits="1"/>
<line number="101" hits="1"/>
<line number="102" hits="1"/>
<line number="103" hits="0"/>
<line number="104" hits="0"/>
<line number="105" hits="0"/>
<line number="106" hits="0"/>
<line number="108" hits="1"/>
<line number="110" hits="1"/>
<line number="111" hits="1"/>
<line number="112" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="113" hits="1"/>
<line number="114" hits="1"/>
<line number="115" hits="0"/>
<line number="116" hits="0"/>
<line number="117" hits="1"/>
<line number="118" hits="1"/>
<line number="119" hits="0"/>
<line number="120" hits="0"/>
<line number="121" hits="0"/>
<line number="122" hits="0"/>
<line number="124" hits="1"/>
<line number="126" hits="1"/>
<line number="128" hits="1"/>
<line number="130" hits="1"/>
<line number="131" hits="1"/>
<line number="133" hits="1"/>
<line number="135" hits="1"/>
<line number="137" hits="1"/>
<line number="139" hits="0"/>
<line number="141" hits="1"/>
<line number="143" hits="1"/>
<line number="145" hits="1"/>
<line number="147" hits="0"/>
<line number="149" hits="1"/>
<line number="150" hits="1"/>
<line number="151" hits="1"/>
<line number="154" hits="1"/>
<line number="157" hits="1"/>
<line number="158" hits="1"/>
<line number="159" hits="1"/>
<line number="161" hits="1"/>
<line number="162" hits="1"/>
<line number="164" hits="1"/>
<line number="165" hits="1"/>
<line number="167" hits="1"/>
<line number="168" hits="1"/>
<line number="170" hits="1"/>
<line number="172" hits="1"/>
<line number="173" hits="1"/>
<line number="174" hits="1"/>
<line number="175" hits="1"/>
<line number="179" hits="1"/>
<line number="181" hits="1"/>
<line number="183" hits="1"/>
<line number="184" hits="1"/>
<line number="185" hits="1"/>
<line number="186" hits="0"/>
<line number="187" hits="0"/>
<line number="189" hits="1"/>
<line number="192" hits="1"/>
<line number="195" hits="1"/>
<line number="196" hits="1"/>
<line number="198" hits="1"/>
<line number="200" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="201" hits="1"/>
<line number="202" hits="1"/>
<line number="203" hits="1"/>
<line number="204" hits="1"/>
<line number="205" hits="1"/>
<line number="206" hits="1"/>
<line number="207" hits="1"/>
<line number="208" hits="1"/>
<line number="209" hits="1"/>
</lines>
</class>
<class name="tserver.py" filename="tserver.py" complexity="0" line-rate="0.8816" branch-rate="0.7667">
<methods/>
<lines>
<line number="5" hits="1"/>
<line number="6" hits="1"/>
<line number="7" hits="1"/>
<line number="23" hits="1"/>
<line number="25" hits="1"/>
<line number="26" hits="1"/>
<line number="27" hits="1"/>
<line number="28" hits="1"/>
<line number="29" hits="1"/>
<line number="30" hits="1"/>
<line number="31" hits="1"/>
<line number="33" hits="1"/>
<line number="36" hits="1"/>
<line number="39" hits="1"/>
<line number="40" hits="1"/>
<line number="41" hits="1"/>
<line number="42" hits="1"/>
<line number="44" hits="1"/>
<line number="45" hits="1"/>
<line number="54" hits="0"/>
<line number="56" hits="1"/>
<line number="59" hits="1" branch="true" condition-coverage="50% (1/2)" missing-branches="60"/>
<line number="60" hits="0"/>
<line number="61" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="62" hits="1"/>
<line number="63" hits="1"/>
<line number="64" hits="1"/>
<line number="65" hits="1"/>
<line number="66" hits="1"/>
<line number="67" hits="0"/>
<line number="69" hits="0" branch="true" condition-coverage="0% (0/2)" missing-branches="70,72"/>
<line number="70" hits="0"/>
<line number="72" hits="0"/>
<line number="73" hits="0"/>
<line number="74" hits="0"/>
<line number="76" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="77" hits="1"/>
<line number="78" hits="1"/>
<line number="79" hits="1"/>
<line number="80" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="81" hits="1"/>
<line number="82" hits="1"/>
<line number="83" hits="1"/>
<line number="84" hits="1"/>
<line number="85" hits="1"/>
<line number="86" hits="1"/>
<line number="88" hits="1"/>
<line number="89" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="90" hits="1"/>
<line number="92" hits="1"/>
<line number="93" hits="1"/>
<line number="94" hits="1"/>
<line number="96" hits="1"/>
<line number="97" hits="1"/>
<line number="98" hits="0"/>
<line number="99" hits="0"/>
<line number="101" hits="1"/>
<line number="107" hits="1"/>
<line number="108" hits="1"/>
<line number="109" hits="1"/>
<line number="111" hits="1"/>
<line number="117" hits="1"/>
<line number="118" hits="1"/>
<line number="121" hits="1"/>
<line number="124" hits="1"/>
<line number="125" hits="1"/>
<line number="126" hits="1"/>
<line number="127" hits="1"/>
<line number="129" hits="1"/>
<line number="135" hits="1"/>
<line number="136" hits="1"/>
<line number="138" hits="1"/>
<line number="142" hits="1" branch="true" condition-coverage="50% (1/2)" missing-branches="156"/>
<line number="143" hits="1"/>
<line number="144" hits="1"/>
<line number="145" hits="1"/>
<line number="146" hits="1" branch="true" condition-coverage="50% (1/2)" missing-branches="142"/>
<line number="147" hits="1"/>
<line number="148" hits="1"/>
<line number="149" hits="1"/>
<line number="150" hits="0"/>
<line number="151" hits="0"/>
<line number="152" hits="1"/>
<line number="153" hits="1"/>
<line number="154" hits="1"/>
<line number="155" hits="1"/>
<line number="156" hits="1"/>
<line number="158" hits="1"/>
<line number="159" hits="1"/>
<line number="166" hits="0"/>
<line number="168" hits="1"/>
<line number="174" hits="1"/>
<line number="175" hits="1"/>
<line number="176" hits="1"/>
<line number="178" hits="1"/>
<line number="185" hits="1"/>
<line number="186" hits="1"/>
<line number="189" hits="1"/>
<line number="191" hits="1"/>
<line number="192" hits="1"/>
<line number="193" hits="1" branch="true" condition-coverage="50% (1/2)" missing-branches="194"/>
<line number="194" hits="0"/>
<line number="195" hits="1"/>
<line number="196" hits="1"/>
<line number="197" hits="1"/>
<line number="198" hits="1"/>
<line number="199" hits="1"/>
<line number="201" hits="1"/>
<line number="203" hits="0"/>
<line number="205" hits="1"/>
<line number="208" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="209" hits="1"/>
<line number="210" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="211" hits="1"/>
<line number="212" hits="1"/>
<line number="213" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="214" hits="1"/>
<line number="215" hits="1"/>
<line number="216" hits="1"/>
<line number="217" hits="1"/>
<line number="218" hits="1"/>
<line number="219" hits="1"/>
<line number="220" hits="1"/>
<line number="221" hits="1"/>
<line number="224" hits="1"/>
<line number="226" hits="1"/>
<line number="227" hits="1"/>
<line number="228" hits="1"/>
<line number="229" hits="1"/>
<line number="230" hits="1"/>
<line number="232" hits="1"/>
<line number="233" hits="1"/>
<line number="235" hits="1"/>
<line number="236" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="237" hits="1" branch="true" condition-coverage="100% (2/2)"/>
<line number="238" hits="1"/>
<line number="239" hits="1"/>
<line number="241" hits="1"/>
<line number="243" hits="1"/>
<line number="245" hits="1"/>
<line number="247" hits="1"/>
<line number="248" hits="1"/>
<line number="249" hits="1"/>
<line number="250" hits="0"/>
<line number="251" hits="0"/>
<line number="252" hits="1"/>
<line number="254" hits="1"/>
<line number="255" hits="1" branch="true" condition-coverage="50% (1/2)" missing-branches="256"/>
<line number="256" hits="0"/>
<line number="258" hits="1"/>
<line number="259" hits="1"/>
<line number="261" hits="1"/>
</lines>
</class>
</classes>
</package>
</packages>
</coverage>
19 changes: 15 additions & 4 deletions features/steps/steps.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
"""Behave step implementations for json socket scenarios.

Note: Pylint is unaware of Behave's decorator callables, so we disable the
"not-callable" check for this file.
"""
# pylint: disable=not-callable, missing-function-docstring

import json
import logging
import time
Expand All @@ -12,8 +19,10 @@


class MyServer(jsocket.ThreadedServer):
"""Simple echo server used by Behave scenarios."""

def __init__(self, **kwargs):
super(MyServer, self).__init__(**kwargs)
super().__init__(**kwargs)
self.timeout = 2.0

def _process_message(self, obj):
Expand Down Expand Up @@ -60,7 +69,7 @@ def server_sends_object(context, obj):
def client_sees_message(context, obj):
expected = json.loads(obj)
msg = context.jsonclient.read_obj()
assert msg == expected, "%s" % expected
assert msg == expected, f"{expected}"


@then(r"within (\d+(?:\.\d+)?) seconds the server is connected")
Expand Down Expand Up @@ -138,6 +147,8 @@ def client_attempts_read_with_timeout(context, seconds):
def client_read_fails(context):
e = getattr(context, 'client_read_exception', None)
# Either a socket.timeout or a RuntimeError("socket connection broken") is acceptable
assert e is not None, "client read unexpectedly succeeded: %r" % getattr(context, 'client_read_value', None)
acceptable = isinstance(e, socket.timeout) or (isinstance(e, RuntimeError) and 'socket connection broken' in str(e))
assert e is not None, f"client read unexpectedly succeeded: {getattr(context, 'client_read_value', None)!r}"
acceptable = isinstance(e, socket.timeout) or (
isinstance(e, RuntimeError) and 'socket connection broken' in str(e)
)
assert acceptable, f"unexpected exception type: {type(e)} {e}"
Loading