Skip to content

feat(someip): add server/provider side (offer services, answer RPC, publish events) - #913

Open
kirkbrauer wants to merge 1 commit into
mainfrom
feature/someip-server
Open

feat(someip): add server/provider side (offer services, answer RPC, publish events)#913
kirkbrauer wants to merge 1 commit into
mainfrom
feature/someip-server

Conversation

@kirkbrauer

@kirkbrauer kirkbrauer commented Jul 23, 2026

Copy link
Copy Markdown
Member

The SOME/IP driver is currently client-only. opensomeip already ships a full server-side API (SomeIpServer /SdServer / RpcServer / EventPublisher), so this exposes it through the driver so a Jumpstarter exporter can act as a simulated ECU that a device-under-test's SOME/IP client talks to.

New exported verbs (driver + client)

  • start_server / stop_server — server lifecycle (lazily started on first offer)
  • offer_service / stop_offer_service / list_offered_services — SD offering
  • set_method_response / clear_method_response — canned RPC responses
  • register_event / publish_event / set_field — event-group notifications and cached field events

Design note

RPC handlers run inside the exporter process (opensomeip receive thread) and cannot call back to the Jumpstarter client per request, so responses are configured declaratively per (service_id, method_id) rather than via a per-request callback. This maps naturally onto getter-style SOME/IP methods, updating the response changes what a client reads without re-registration.

Also included

  • SomeIpOfferedService model for server-side introspection
  • README "Server / Provider" usage section + a provider exporter example
  • 13 server-side unit tests (patching opensomeip.SomeIpServer); full package suite: 83 passed, 2 skipped

The client side is unchanged; all additions are additive.

@kirkbrauer
kirkbrauer requested a review from mangelajo July 23, 2026 01:08
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cd9071e6-481e-457b-aa87-f0c6d087eec8

📥 Commits

Reviewing files that changed from the base of the PR and between 756f728 and f07ee6b.

📒 Files selected for processing (6)
  • python/packages/jumpstarter-driver-someip/README.md
  • python/packages/jumpstarter-driver-someip/examples/exporter.yaml
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/client.py
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/common.py
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver.py
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver_test.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • python/packages/jumpstarter-driver-someip/examples/exporter.yaml
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/common.py
  • python/packages/jumpstarter-driver-someip/README.md
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver_test.py
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/client.py
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver.py

📝 Walkthrough

Walkthrough

The SOME/IP driver now supports provider/server mode, including service offering, canned RPC responses, event registration and publication, field updates, introspection, lifecycle management, client wrappers, tests, documentation, and an example exporter configuration.

Changes

SOME/IP provider support

Layer / File(s) Summary
Provider contracts and client API
python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/common.py, python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/client.py
Adds the SomeIpOfferedService model and client wrappers for server lifecycle, service offers, RPC responses, events, fields, and introspection.
Server lifecycle and SOME/IP behavior
python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver.py
Adds lazy, thread-safe server management, service offering, canned method handlers, event publication, field updates, introspection, cleanup, and server shutdown.
Provider configuration, documentation, and tests
python/packages/jumpstarter-driver-someip/README.md, python/packages/jumpstarter-driver-someip/examples/exporter.yaml, python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver_test.py
Documents provider usage, adds a server exporter example, and tests provider operations alongside existing payload-format updates.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant SomeIpDriverClient
  participant SomeIp
  participant OsipServer
  Client->>SomeIpDriverClient: configure provider behavior
  SomeIpDriverClient->>SomeIp: call server API
  SomeIp->>OsipServer: start, offer service, register handlers
  OsipServer-->>SomeIp: deliver RPC or subscriber request
  SomeIp->>OsipServer: return canned response or publish event
Loading

Possibly related issues

Possibly related PRs

Suggested reviewers: mangelajo

Poem

A rabbit offers services bright,
With canned replies both wrong and right.
Events hop out, fields softly glow,
Multicast through the clouds they go.
The server rests when duties cease—
Provider burrows into peace.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding server/provider-side SOME/IP support for offering services, answering RPCs, and publishing events.
Description check ✅ Passed The description is directly related to the changeset and accurately describes the new server-side SOME/IP APIs, docs, example, and tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/someip-server

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
python/packages/jumpstarter-driver-someip/examples/exporter.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kirkbrauer

kirkbrauer commented Jul 23, 2026

Copy link
Copy Markdown
Member Author

@vtz — as the original author of this SOME/IP driver, your review would be much appreciated. This adds the server/provider side (offer services via SD, answer RPC with canned responses, publish events) on top of your client-side implementation, wrapping the opensomeip SomeIpServer/SdServer/RpcServer/EventPublisher APIs.

…ublish events)

The SOME/IP driver was client-only. opensomeip already ships a full
server-side API (SomeIpServer / SdServer / RpcServer / EventPublisher),
so expose it through the driver so a Jumpstarter exporter can act as a
simulated ECU that a device-under-test's SOME/IP client talks to.

New exported verbs (driver + client):
- start_server / stop_server: server lifecycle (lazily started on first offer)
- offer_service / stop_offer_service / list_offered_services: SD offering
- set_method_response / clear_method_response: canned RPC responses. RPC
  handlers run in the exporter process and cannot call back to the
  Jumpstarter client per request, so responses are configured declaratively
  per (service_id, method_id); this maps cleanly onto getter-style methods.
- register_event / publish_event / set_field: event group notifications and
  cached field events.

Adds a SomeIpOfferedService model, README "Server / Provider" usage section,
a provider exporter example, and 13 server-side unit tests (83 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kirkbrauer
kirkbrauer force-pushed the feature/someip-server branch from 756f728 to f07ee6b Compare July 23, 2026 01:11

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver.py (1)

359-369: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer try/except ValueError over the enum internal _value2member_map_.

ReturnCode._value2member_map_ is a CPython enum implementation detail. Constructing the enum in a try/except is the documented idiom and is robust to future enum internals.

♻️ Optional refactor
-            payload, return_code = self._method_responses.get(key, (b"", int(ReturnCode.E_OK)))
-            rc = ReturnCode(return_code) if return_code in ReturnCode._value2member_map_ else ReturnCode.E_NOT_OK
+            payload, return_code = self._method_responses.get(key, (b"", int(ReturnCode.E_OK)))
+            try:
+                rc = ReturnCode(return_code)
+            except ValueError:
+                rc = ReturnCode.E_NOT_OK
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver.py`
around lines 359 - 369, Update the ReturnCode conversion in handler to construct
ReturnCode(return_code) inside a try block and catch ValueError to fall back to
ReturnCode.E_NOT_OK. Remove the direct use of ReturnCode._value2member_map_,
while preserving the existing response/error message type behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver.py`:
- Around line 359-369: Update the ReturnCode conversion in handler to construct
ReturnCode(return_code) inside a try block and catch ValueError to fall back to
ReturnCode.E_NOT_OK. Remove the direct use of ReturnCode._value2member_map_,
while preserving the existing response/error message type behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5d0c1305-d16a-4d5a-83aa-e3bbee1e30f0

📥 Commits

Reviewing files that changed from the base of the PR and between e0b0cba and 756f728.

📒 Files selected for processing (6)
  • python/packages/jumpstarter-driver-someip/README.md
  • python/packages/jumpstarter-driver-someip/examples/exporter.yaml
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/client.py
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/common.py
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver.py
  • python/packages/jumpstarter-driver-someip/jumpstarter_driver_someip/driver_test.py

@mangelajo

Copy link
Copy Markdown
Member

I will remove my review to let @vtz come and review.

@mangelajo
mangelajo self-requested a review July 23, 2026 07:35

@vtz vtz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for this. Nice addition. Exposing the provider side so an exporter can act as a simulated ECU fits Open SOME/IP and opensomeip well, and one driver ≈ one ECU is the right Jumpstarter shape.

Inline comments cover the small cleanup/test nits. Separately, worth noting for later (not blockers): Fire&Forget and the full Field getter/setter/notifier model from the spec aren’t in scope here (canned RPC + set_field/events cover the usual simulator path).

Great work!

return SomeIpMessageResponse.model_validate(
self.call("rpc_call", service_id, method_id, msg, timeout)
)
return SomeIpMessageResponse.model_validate(self.call("rpc_call", service_id, method_id, msg, timeout))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is just a formatting change, do we want to change it?

return SomeIpMessageResponse.model_validate(
self.call("receive_message", timeout)
)
return SomeIpMessageResponse.model_validate(self.call("receive_message", timeout))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same as here

return SomeIpEventNotification.model_validate(
self.call("receive_event", timeout)
)
return SomeIpEventNotification.model_validate(self.call("receive_event", timeout))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same as here

def offer_service(
self,
service_id: int,
instance_id: int = 0x0001,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

SOME/IP reserves Instance ID 0x0000 and uses 0xFFFF as “all instances.” Neither should be offered. Consider rejecting those values in offer_service (and optionally on SomeIpOfferedService.instance_id).

Comment on lines +490 to +499
def stop_server(self) -> None:
"""Stop the SOME/IP server, withdrawing all offers."""
if self._osip_server is not None:
try:
self._osip_server.stop()
except Exception:
logger.warning("failed to stop opensomeip server", exc_info=True)
self._osip_server = None
self._registered_methods.clear()
self._registered_events.clear()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

_registered_methods / _registered_events are cleared, but _method_responses is not. After stop + restart, stale payloads remain until overwritten, while handlers are only re-registered on the next set_method_response. Please clear _method_responses too, or document that config intentionally survives stop_server.


@export
@validate_call(validate_return=True)
def publish_event(self, service_id: int, event_id: int, payload: SomeIpPayload) -> None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

service_id is accepted here but never forwarded (opensomeip only takes event_id). Please document that it’s unused for API symmetry, or remove it so callers aren’t misled.

Comment on lines +913 to +920
# =========================================================================
# Server / provider side tests
#
# The server verbs let the endpoint ACT AS an ECU (offer services, answer
# RPC with canned responses, publish events). We patch the opensomeip
# SomeIpServer so these run without real networking, and assert the driver
# drives the underlying server API correctly.
# =========================================================================

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Server coverage is only unit tests against _FakeOsipServer. Please add at least one stateful/loopback-style test (offer + set_method_response + client RPC), similar in spirit to the existing client stateful suite. That would better cover the simulated-ECU use case.

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.

3 participants