Skip to content

Commit

Permalink
Merge branch 'main' into erik_pypi
Browse files Browse the repository at this point in the history
  • Loading branch information
erikbosch authored Dec 11, 2024
2 parents cefce85 + b526519 commit b8479f9
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 30 deletions.
28 changes: 26 additions & 2 deletions kuksa-client/kuksa_client/grpc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,18 @@ def _prepare_publish_value_request(
value_type = paths_with_required_type.get(update.entry.path)
if value_type is not None:
update.entry.value_type = value_type

for field in update.fields:
if field != Field.VALUE:
raise VSSClientError(
error={
"code": grpc.StatusCode.INVALID_ARGUMENT.value[0],
"reason": grpc.StatusCode.INVALID_ARGUMENT.value[1],
"message": "Cannot use v2 to publish fields other than value",
},
errors=[],
)

req = val_v2.PublishValueRequest(
signal_id=types_v2.SignalID(path=update.entry.path),
data_point=update.entry.value.v2_to_message(update.entry.value_type),
Expand Down Expand Up @@ -863,6 +875,18 @@ def _prepare_subscribev2_request(
paths = []
for entry in entries:
paths.append(entry.path)

for field in entry.fields:
if field != Field.VALUE:
raise VSSClientError(
error={
"code": grpc.StatusCode.INVALID_ARGUMENT.value[0],
"reason": grpc.StatusCode.INVALID_ARGUMENT.value[1],
"message": "Cannot use v2 if specifiying fields other than value",
},
errors=[],
)

req = val_v2.SubscribeRequest(signal_paths=paths)
logger.debug("%s: %s", type(req).__name__, req)
return req
Expand Down Expand Up @@ -1220,7 +1244,7 @@ def get(self, entries: Iterable[EntryRequest], **rpc_kwargs) -> List[DataEntry]:

@check_connected
def set(
self, updates: Collection[EntryUpdate], try_v2: bool = True, **rpc_kwargs
self, updates: Collection[EntryUpdate], try_v2: bool = False, **rpc_kwargs
) -> None:
"""
Parameters:
Expand Down Expand Up @@ -1273,7 +1297,7 @@ def set(

@check_connected
def subscribe(
self, entries: Iterable[SubscribeEntry], try_v2: bool = True, **rpc_kwargs
self, entries: Iterable[SubscribeEntry], try_v2: bool = False, **rpc_kwargs
) -> Iterator[List[EntryUpdate]]:
"""
Parameters:
Expand Down
4 changes: 2 additions & 2 deletions kuksa-client/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def val_servicer_v2_fixture(mocker):
return servicer_v2


@pytest_asyncio.fixture(name="val_server", scope="function")
@pytest_asyncio.fixture(name="mocked_databroker", scope="function")
async def val_server_fixture(unused_tcp_port, val_servicer_v1, val_servicer_v2):
server = grpc.aio.server()
val_v1.add_VALServicer_to_server(val_servicer_v1, server)
Expand All @@ -66,7 +66,7 @@ async def val_server_fixture(unused_tcp_port, val_servicer_v1, val_servicer_v2):
await server.stop(grace=2.0)


@pytest_asyncio.fixture(name="secure_val_server", scope="function")
@pytest_asyncio.fixture(name="secure_mocked_databroker", scope="function")
async def secure_val_server_fixture(
unused_tcp_port, resources_path, val_servicer_v1, val_servicer_v2
):
Expand Down
132 changes: 106 additions & 26 deletions kuksa-client/tests/test_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ def test_to_dict(self, entry, fields, update_dict):
@pytest.mark.asyncio
class TestVSSClient:

@pytest.mark.usefixtures("secure_val_server")
@pytest.mark.usefixtures("secure_mocked_databroker")
async def test_secure_connection(
self, unused_tcp_port, resources_path, val_servicer_v1
):
Expand Down Expand Up @@ -745,7 +745,7 @@ async def subscribe_response_stream(**kwargs):
'Vehicle.Chassis.Height': Metadata(entry_type=EntryType.ATTRIBUTE),
}

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_get_some_entries(self, unused_tcp_port, val_servicer_v1):
val_servicer_v1.Get.return_value = val_v1.GetResponse(
entries=[
Expand Down Expand Up @@ -948,7 +948,7 @@ async def test_get_some_entries(self, unused_tcp_port, val_servicer_v1):
).entries
)

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_get_no_entries_requested(self, unused_tcp_port, val_servicer_v1):
val_servicer_v1.Get.side_effect = generate_error(
grpc.StatusCode.INVALID_ARGUMENT, "No datapoints requested"
Expand All @@ -964,7 +964,7 @@ async def test_get_no_entries_requested(self, unused_tcp_port, val_servicer_v1):
}, errors=[]).args
assert val_servicer_v1.Get.call_args[0][0] == val_v1.GetRequest()

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_get_unset_entries(self, unused_tcp_port, val_servicer_v1):
val_servicer_v1.Get.return_value = val_v1.GetResponse(
entries=[
Expand All @@ -982,7 +982,7 @@ async def test_get_unset_entries(self, unused_tcp_port, val_servicer_v1):
assert entries == [DataEntry('Vehicle.Speed'), DataEntry(
'Vehicle.ADAS.ABS.IsActive')]

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_get_nonexistent_entries(self, unused_tcp_port, val_servicer_v1):
error = types_v1.Error(
code=404, reason="not_found", message="Does.Not.Exist not found"
Expand All @@ -998,7 +998,7 @@ async def test_get_nonexistent_entries(self, unused_tcp_port, val_servicer_v1):
View.CURRENT_VALUE, (Field.VALUE,)),
))

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_set_some_updates_v1(self, unused_tcp_port, val_servicer_v1):
val_servicer_v1.Get.return_value = val_v1.GetResponse(
entries=(
Expand Down Expand Up @@ -1234,7 +1234,7 @@ async def test_set_some_updates_v1(self, unused_tcp_port, val_servicer_v1):
).updates
)

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_set_some_updates_v2(
self, unused_tcp_port, val_servicer_v2, val_servicer_v1
):
Expand Down Expand Up @@ -1313,7 +1313,52 @@ async def test_set_some_updates_v2(
):
assert actual_request == expected_request

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_set_some_updates_v2_target(
self, unused_tcp_port, val_servicer_v2, val_servicer_v1
):
"""
Similar test to above, but trying to update target values using v2
which is not allowed
"""
val_servicer_v1.Get.return_value = val_v1.GetResponse(
entries=(
types_v1.DataEntry(
path="Vehicle.Speed",
metadata=types_v1.Metadata(data_type=types_v1.DATA_TYPE_FLOAT),
),
types_v1.DataEntry(
path="Vehicle.ADAS.ABS.IsActive",
metadata=types_v1.Metadata(data_type=types_v1.DATA_TYPE_BOOLEAN),
),
)
)
_updates = [
EntryUpdate(
DataEntry("Vehicle.Speed", value=Datapoint(value=42.0)),
(Field.ACTUATOR_TARGET,),
),
EntryUpdate(
DataEntry(
"Vehicle.ADAS.ABS.IsActive",
value=Datapoint(value=False),
),
(Field.ACTUATOR_TARGET,),
),
]

async with VSSClient(
"127.0.0.1", unused_tcp_port, ensure_startup_connection=False
) as client:
with pytest.raises(VSSClientError):
await client.set(
updates=_updates,
try_v2=True,
)
assert val_servicer_v1.Get.call_count == 1
assert val_servicer_v2.PublishValue.call_count == 0

@pytest.mark.usefixtures("mocked_databroker")
async def test_set_no_updates_provided(
self, unused_tcp_port, val_servicer_v1, val_servicer_v2
):
Expand Down Expand Up @@ -1354,7 +1399,7 @@ async def test_set_no_updates_provided(
assert val_servicer_v1.Get.call_count == 0
assert val_servicer_v2.PublishValue.call_count == 0

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_set_nonexistent_entries_v1(self, unused_tcp_port, val_servicer_v1):
error = types_v1.Error(
code=404, reason="not_found", message="Does.Not.Exist not found"
Expand Down Expand Up @@ -1400,7 +1445,7 @@ async def test_set_nonexistent_entries_v1(self, unused_tcp_port, val_servicer_v1
) # Get should'nt have been called again
assert val_servicer_v1.Set.call_count == 1

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_set_nonexistent_entries_v2(
self, unused_tcp_port, val_servicer_v2, val_servicer_v1
):
Expand Down Expand Up @@ -1451,7 +1496,7 @@ async def test_set_nonexistent_entries_v2(
) # Get should'nt have been called again
assert val_servicer_v2.PublishValue.call_count == 1

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_authorize_successful(self, unused_tcp_port, val_servicer_v1):
val_servicer_v1.GetServerInfo.return_value = val_v1.GetServerInfoResponse(
name="test_server", version="1.2.3"
Expand Down Expand Up @@ -1486,7 +1531,7 @@ async def test_authorize_successful(self, unused_tcp_port, val_servicer_v1):
assert client.authorization_header == bearer
assert success == "Authenticated"

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_authorize_unsuccessful(self, unused_tcp_port, val_servicer_v1):
val_servicer_v1.GetServerInfo.side_effect = generate_error(
grpc.StatusCode.UNAUTHENTICATED,
Expand All @@ -1497,7 +1542,7 @@ async def test_authorize_unsuccessful(self, unused_tcp_port, val_servicer_v1):
await client.authorize(token='')
assert client.authorization_header is None

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_subscribe_some_entries_v1(
self, mocker, unused_tcp_port, val_servicer_v1
):
Expand Down Expand Up @@ -1588,16 +1633,17 @@ async def test_subscribe_some_entries_v1(
entry
for entry in ( # generator is intentional (Iterable)
EntryRequest(
"Vehicle.Speed", View.CURRENT_VALUE, (Field.VALUE,)
# View is ignored, so we can provide any value
"Vehicle.Speed", View.FIELDS, (Field.VALUE,)
),
EntryRequest(
"Vehicle.ADAS.ABS.IsActive",
View.TARGET_VALUE,
View.UNSPECIFIED,
(Field.ACTUATOR_TARGET,),
),
EntryRequest(
"Vehicle.Chassis.Height",
View.METADATA,
View.UNSPECIFIED,
(Field.METADATA_DATA_TYPE,),
),
)
Expand Down Expand Up @@ -1688,7 +1734,7 @@ async def test_subscribe_some_entries_v1(
],
]

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_subscribe_some_entries_v2(
self, mocker, unused_tcp_port, val_servicer_v2
):
Expand Down Expand Up @@ -1731,7 +1777,8 @@ async def test_subscribe_some_entries_v2(
),
EntryRequest(
"Vehicle.ADAS.ABS.IsActive",
View.CURRENT_VALUE,
# Specified View is ignored so we can use anyone :-)
View.METADATA,
(Field.VALUE,),
),
)
Expand Down Expand Up @@ -1799,7 +1846,40 @@ async def test_subscribe_some_entries_v2(
],
]

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_subscribe_some_entries_v2_target(
self, mocker, unused_tcp_port, val_servicer_v2
):
"""
Similar to above but trying to subscribe to target values which is not possible using v2
"""
async with VSSClient(
"127.0.0.1", unused_tcp_port, ensure_startup_connection=False
) as client:
actual_responses = []

with pytest.raises(VSSClientError):
async for updates in client.subscribe(
entries=(
entry
for entry in ( # generator is intentional (Iterable)
EntryRequest(
"Vehicle.Speed", View.TARGET_VALUE, (Field.ACTUATOR_TARGET,)
),
EntryRequest(
"Vehicle.ADAS.ABS.IsActive",
View.TARGET_VALUE,
(Field.ACTUATOR_TARGET,),
),
)
),
try_v2=True,
):
actual_responses.append(updates)

assert not actual_responses

@pytest.mark.usefixtures("mocked_databroker")
async def test_subscribe_no_entries_requested(
self, mocker, unused_tcp_port, val_servicer_v1, val_servicer_v2
):
Expand All @@ -1823,7 +1903,7 @@ async def test_subscribe_no_entries_requested(
async for _ in client.subscribe(entries=(), try_v2=True):
pass

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_subscribe_nonexistent_entries(
self, mocker, unused_tcp_port, val_servicer_v1, val_servicer_v2
):
Expand Down Expand Up @@ -1859,7 +1939,7 @@ async def test_subscribe_nonexistent_entries(
):
pass

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_get_server_info(self, unused_tcp_port, val_servicer_v1):
val_servicer_v1.GetServerInfo.return_value = val_v1.GetServerInfoResponse(
name="test_server", version="1.2.3"
Expand All @@ -1869,7 +1949,7 @@ async def test_get_server_info(self, unused_tcp_port, val_servicer_v1):
assert server_info == ServerInfo(
name='test_server', version='1.2.3')

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_get_server_info_unavailable(self, unused_tcp_port, val_servicer_v1):
val_servicer_v1.GetServerInfo.side_effect = generate_error(
grpc.StatusCode.UNAVAILABLE, "Unavailable"
Expand All @@ -1882,7 +1962,7 @@ async def test_get_server_info_unavailable(self, unused_tcp_port, val_servicer_v
@pytest.mark.asyncio
class TestSubscriberManager:

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_add_subscriber_v1(self, mocker, unused_tcp_port, val_servicer_v1):
async with VSSClient('127.0.0.1', unused_tcp_port, ensure_startup_connection=False) as client:
subscriber_manager = SubscriberManager(client)
Expand Down Expand Up @@ -1967,7 +2047,7 @@ async def test_add_subscriber_v1(self, mocker, unused_tcp_port, val_servicer_v1)
],
]

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_remove_subscriber_v1(self, mocker, unused_tcp_port, val_servicer_v1):
async with VSSClient(
"127.0.0.1", unused_tcp_port, ensure_startup_connection=False
Expand Down Expand Up @@ -2015,7 +2095,7 @@ async def test_remove_subscriber_v1(self, mocker, unused_tcp_port, val_servicer_
exc_info.value.args[0] == f"Could not find subscription {str(sub_uid)}"
)

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_add_subscriber_v2(self, mocker, unused_tcp_port, val_servicer_v2):
_entries: Dict[str, types_v2.Datapoint] = {
"Vehicle.Speed": types_v2.Datapoint(
Expand Down Expand Up @@ -2085,7 +2165,7 @@ async def test_add_subscriber_v2(self, mocker, unused_tcp_port, val_servicer_v2)
],
]

@pytest.mark.usefixtures("val_server")
@pytest.mark.usefixtures("mocked_databroker")
async def test_remove_subscriber_v2(self, mocker, unused_tcp_port, val_servicer_v2):
async with VSSClient(
"127.0.0.1", unused_tcp_port, ensure_startup_connection=False
Expand Down

0 comments on commit b8479f9

Please sign in to comment.