Skip to content

Add test suite (100% cov), CI, gRPC latency/keepalive tuning, and docs#2

Merged
teddius merged 9 commits into
masterfrom
OND211-2418-add-keycloak-for-2-fa
Jul 6, 2026
Merged

Add test suite (100% cov), CI, gRPC latency/keepalive tuning, and docs#2
teddius merged 9 commits into
masterfrom
OND211-2418-add-keycloak-for-2-fa

Conversation

@teddius

@teddius teddius commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a test suite with 100% coverage, a CI workflow, gRPC latency/keepalive tuning, and project documentation to ondewo-client-utils-python. Bumps the package to 3.2.0.

Note: this work landed on the OND211-2418-add-keycloak-for-2-fa branch but is unrelated to Keycloak 2FA — it is testing/CI/performance/docs. Retitle or rebase onto a dedicated branch if preferred before merge.

Changes

Performance

  • Hoist the constant gRPC service_config_json and default channel options to module level in base_services_interface.py / async_base_services_interface.py, so they are serialized once at import instead of on every service construction (a client with N services previously ran json.dumps and rebuilt the options dict N times per connection).
  • Enable gRPC keepalive (keepalive_time_ms=30000, max_pings_without_data=0) to keep long-lived streaming RPCs warm and detect half-open connections, while keepalive_permit_without_calls=False avoids a server too_many_pings GOAWAY on idle channels.

Testing

  • Add tests/ covering every ondewo.utils module to 100% statement and branch coverage (49 tests): sync/async clients and service interfaces, config, container, helpers, and text utilities — happy paths, guard clauses, and secure/insecure/missing-cert branches.
  • Configure pytest + coverage in setup.cfg (asyncio_mode = auto, branch coverage, --cov-fail-under=100 gate).
  • Add pytest/pytest-cov/pytest-asyncio/mock to requirements-dev.txt and to the pytest Docker image.

CI

  • Add .github/workflows/tests.yml running the suite on every push and pull request across Python 3.9–3.12.
  • Pin CI actions to their Node 24 releases (checkout@v5, setup-python@v6, upload-artifact@v5) to clear the Node 20 deprecation warnings.

Docs & housekeeping

  • Add CLAUDE.md (repo overview, dev/test commands, ONDEWO conventions).
  • Document every Makefile target with a ## help comment, fix a misleading description, and make make help list digit-containing target names (e.g. flake8).
  • Bump version to 3.2.0 with a matching RELEASE.md entry.

Test plan

  • python -m pytest → 49 passed, 100% coverage (gate enforced).
  • pre-commit run --all-files → flake8, mypy, and all hooks pass.

teddius and others added 5 commits July 6, 2026 12:16
…grpc config

Performance:
- Hoist the constant gRPC service_config_json and default channel options
  to module level in base_services_interface and async_base_services_interface
  so they are serialized once at import instead of on every service
  construction (a client with N services previously ran json.dumps N times
  per connection).

Testing:
- Add tests/ covering all ondewo.utils modules to 100% statement and branch
  coverage (47 tests).
- Configure pytest + coverage in setup.cfg with a --cov-fail-under=100 gate.
- Add pytest, pytest-cov, pytest-asyncio and mock to requirements-dev.txt and
  to the pytest Docker image.

CI:
- Add .github/workflows/tests.yml to run the suite on every push and PR across
  Python 3.9-3.12.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
….2.0

- Update CI actions to their Node 24 releases (checkout v4->v5,
  setup-python v5->v6, upload-artifact v4->v5) to clear the Node 20
  deprecation warnings on the runners.
- Bump package version to 3.2.0 and add a RELEASE.md entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add a CLAUDE.md with repo overview, dev/test commands, and ONDEWO
  conventions adapted for this library.
- Document every Makefile target with a `## ` help comment, fix the
  misleading show_pypi_via_docker_image description, and include
  digit-containing target names (e.g. flake8) in `make help`.
Copilot AI review requested due to automatic review settings July 6, 2026 12:47
…tandard

Split the 3.2.0 entry into New Features and Improvements sections to
match the repository's RELEASE.md convention.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a full pytest suite (targeting 100% coverage) and a GitHub Actions workflow to continuously validate ondewo.utils, while also tuning gRPC channel defaults (keepalive + hoisted service config/options) and adding developer-facing documentation and release/version updates.

Changes:

  • Add comprehensive tests/ coverage and enforce a 100% coverage gate via pytest/coverage configuration.
  • Add CI workflow running tests on Python 3.9–3.12 and update dev/test tooling dependencies.
  • Optimize/tune gRPC channel setup by hoisting constant service config/options and enabling keepalive defaults.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
tests/__init__.py Adds test package marker (license header only).
tests/test_text.py Adds unit tests for TextHelper.from_camel_to_snake_case.
tests/test_helpers.py Adds tests for helpers (get_struct_from_dict, recursive attr helpers).
tests/test_base_services_interface.py Adds sync channel/options tests for BaseServicesInterface.
tests/test_async_base_services_interface.py Adds async channel/options tests for AsyncBaseServicesInterface.
tests/test_base_service_container.py Adds a basic dataclass/instantiation test for the service container.
tests/test_base_client.py Adds sync BaseClient connect/disconnect/guard-clause tests.
tests/test_async_base_client.py Adds async AsyncBaseClient connect/disconnect/guard-clause tests.
setup.cfg Adds pytest + coverage configuration (including 100% gate).
requirements-dev.txt Adds testing dependencies used by the new suite.
dockerfiles/pytest.Dockerfile Updates pytest image to install test dependencies.
.github/workflows/tests.yml Adds CI workflow running pytest/coverage across a Python matrix.
ondewo/utils/base_services_interface.py Hoists service config/options and applies keepalive defaults; adjusts secure channel handling.
ondewo/utils/async_base_services_interface.py Async equivalent of hoisted config/options and keepalive defaults; adjusts secure channel handling.
ondewo/utils/async_base_client.py Updates async channel close call to include grace=None.
mypy.ini Changes mypy target Python version setting.
Makefile Improves make help discoverability and adds/adjusts target documentation comments.
CLAUDE.md Adds repository/development guidance and conventions.
RELEASE.md Adds 3.2.0 release entry for tests/CI/performance changes.
ondewo/version.py Bumps package version to 3.2.0.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 98 to 105
def get_secure_channel(
host: str,
cert: str,
options: Optional[List[Tuple[str, Any]]] = None,
) -> grpc.Channel:
credentials = grpc.ssl_channel_credentials(root_certificates=cert)
# cert is bytes at runtime (BaseClientConfig.__post_init__ encodes it).
credentials = grpc.ssl_channel_credentials(root_certificates=cast(bytes, cert))
return grpc.secure_channel(
Comment on lines 21 to 29
from typing import (
Any,
Dict,
List,
Optional,
Set,
Tuple,
cast,
)
Comment on lines 91 to 98
def get_secure_channel(
host: str,
cert: str,
options: Optional[List[Tuple[str, Any]]] = None,
) -> grpc.aio.Channel:
credentials = grpc.ssl_channel_credentials(root_certificates=cert)
# cert is bytes at runtime (BaseClientConfig.__post_init__ encodes it).
credentials = grpc.ssl_channel_credentials(root_certificates=cast(bytes, cert))
return grpc.aio.secure_channel(
Comment on lines 22 to 30
from typing import (
Any,
Dict,
List,
Optional,
Set,
Tuple,
cast,
)
Comment on lines +74 to +81
def test_get_secure_channel_builds_credentials() -> None:
with mock.patch.object(bsi.grpc, "ssl_channel_credentials") as creds, mock.patch.object(
bsi.grpc, "secure_channel"
) as secure_channel:
channel = get_secure_channel(host="localhost:50051", cert="cert-bytes", options=[])
creds.assert_called_once_with(root_certificates="cert-bytes")
secure_channel.assert_called_once()
assert channel is secure_channel.return_value
Comment on lines +70 to +77
def test_get_secure_channel_builds_credentials() -> None:
with mock.patch.object(absi.grpc, "ssl_channel_credentials") as creds, mock.patch.object(
absi.grpc.aio, "secure_channel"
) as secure_channel:
channel = get_secure_channel(host="localhost:50051", cert="cert-bytes", options=[])
creds.assert_called_once_with(root_certificates="cert-bytes")
secure_channel.assert_called_once()
assert channel is secure_channel.return_value
Comment thread mypy.ini

[mypy]
python_version = 3.9
python_version = 3.10
Comment thread setup.cfg
Comment on lines 1 to 3
# Generated by synthtool. DO NOT EDIT!
[bdist_wheel]
universal = 1
Comment thread requirements-dev.txt
Comment thread dockerfiles/pytest.Dockerfile Outdated
teddius added 2 commits July 6, 2026 15:07
…d cythonization support

- Add complete PEP 484 type annotations (constants, params, returns, class
  and local vars) and Google-style docstrings with type info to every source
  and test module.
- Add cython_compile.py to compile the pure-Python ondewo modules into native
  extensions, skipping @DataClass files (unsupported by Cython) and package
  markers; build with annotation_typing=False so the new hints do not change
  compiled behaviour. Add a `make cythonize` target and Cython dev dependency.
- Make the Makefile version extraction robust to the annotated __version__.
- Ignore missing Cython stubs in mypy config.

Verified: mypy clean (21 files), flake8 clean, pytest 49 passed at 100%
coverage, and the cythonized .so build imports and passes the full suite.
…and config

- get_secure_channel now accepts Union[str, bytes] and normalizes a str cert
  to bytes instead of using a runtime-noop cast(bytes, cert); drop the unused
  cast import (sync + async). Tests now assert the bytes value handed to gRPC.
- Move pytest/coverage config out of the synthtool-managed setup.cfg into
  dedicated pytest.ini and .coveragerc so a regeneration cannot clobber it.
- Remove the unused `mock` backport dependency (tests use unittest.mock) from
  requirements-dev.txt and the pytest Docker image.
- Document why mypy targets python_version 3.10 (current mypy rejects 3.9).

Verified: mypy clean (21 files), flake8 clean, pytest 49 passed at 100%
coverage, and both changed modules still cythonize.
@teddius

teddius commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the Copilot review in d777714:

  • cert typing (4 comments)get_secure_channel (sync + async) now takes Union[str, bytes] and normalizes a str to bytes before calling gRPC, replacing the runtime-noop cast(bytes, cert); removed the now-unused cast import.
  • cert tests (2 comments) — both tests now assert root_certificates=b"cert-bytes", exercising the bytes value gRPC actually receives.
  • setup.cfg synthtool — moved the pytest/coverage config out of the DO NOT EDIT setup.cfg into dedicated pytest.ini and .coveragerc.
  • unused mock — removed from requirements-dev.txt and the pytest Docker image (tests use unittest.mock).
  • mypy python_version (not changed) — current mypy rejects python_version = 3.9 ("must be 3.10 or higher"), so it stays 3.10; added a comment explaining this. The library uses no 3.10-only syntax, so checks aren't weakened.

Verified: mypy clean (21 files), flake8 clean, pytest 49 passed at 100% coverage, and the modules still cythonize.

…aders

Bump the copyright end year to 2026 across all source and test file headers
(2017-2024 -> 2017-2026, 2020-2024 -> 2020-2026, and the single-year 2021 -> 2021-2026).
@teddius
teddius merged commit 8cccc10 into master Jul 6, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants