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
13 changes: 8 additions & 5 deletions src/viam/robot/service.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import asyncio
from typing import Any, Dict, Iterable, List
from typing import Any, Dict, Iterable, List, Set

from grpclib.server import Stream

Expand Down Expand Up @@ -49,15 +49,16 @@

class RobotService(RobotServiceBase, ResourceRPCServiceBase):
def _generate_metadata(self) -> List[ResourceName]:
md: List[ResourceName] = []
md: Set[ResourceName] = set()

for component in self.manager.resources.values():
md.extend(resource_names_for_resource(component))
md.update(resource_names_for_resource(component))

return md
return list(md)

async def _generate_status(self, resource_names: Iterable[ResourceName]) -> List[Status]:
statuses: List[Status] = []
seen_resource_names: Set[ResourceName] = set()

for component in self.manager.resources.values():
for registration in Registry.REGISTERED_SUBTYPES().values():
Expand All @@ -66,7 +67,9 @@ async def _generate_status(self, resource_names: Iterable[ResourceName]) -> List
continue
try:
status = await registration.create_status(component)
statuses.append(status)
if status.name not in seen_resource_names:
seen_resource_names.add(status.name)
statuses.append(status)
except ViamGRPCError as e:
raise e.grpc_error

Expand Down
42 changes: 35 additions & 7 deletions tests/test_robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
from grpclib.testing import ChannelFor

from viam.components.arm import Arm
from viam.components.movement_sensor import MovementSensor
from viam.components.arm.client import ArmClient
from viam.components.motor import Motor
from viam.resource.manager import ResourceManager
from viam.errors import ResourceNotFoundError
from viam.proto.common import Pose, PoseInFrame, ResourceName, Transform
from viam.proto.common import Pose, PoseInFrame, ResourceName, Transform, GeoPoint, Vector3, Orientation
from viam.proto.component.arm import JointPositions
from viam.proto.component.arm import Status as ArmStatus
from viam.proto.component.motor import Status as MotorStatus
Expand Down Expand Up @@ -50,12 +51,14 @@
from viam.services.motion.client import MotionClient
from viam.utils import dict_to_struct, message_to_struct, struct_to_message

from .mocks.components import MockArm, MockCamera, MockMotor, MockSensor
from .mocks.components import MockArm, MockCamera, MockMotor, MockMovementSensor, MockSensor

RESOURCE_NAMES = [
ResourceName(namespace="rdk", type="component", subtype="arm", name="arm1"),
ResourceName(namespace="rdk", type="component", subtype="camera", name="camera1"),
ResourceName(namespace="rdk", type="component", subtype="motor", name="motor1"),
ResourceName(namespace="rdk", type="component", subtype="movement_sensor", name="movement_sensor1"),
ResourceName(namespace="rdk", type="component", subtype="sensor", name="movement_sensor1"),
]

ARM_STATUS = ArmStatus(
Expand Down Expand Up @@ -85,6 +88,10 @@
name=ResourceName(namespace="rdk", type="component", subtype="motor", name="motor1"),
status=message_to_struct(MotorStatus(is_powered=False, position=0, is_moving=False)),
),
Status(
name=ResourceName(namespace="rdk", type="component", subtype="movement_sensor", name="movement_sensor1"),
status=Struct(),
),
]

CONFIG_RESPONSE = [
Expand Down Expand Up @@ -129,6 +136,24 @@ def service() -> RobotService:
MockArm(name="arm1"),
MockCamera(name="camera1"),
MockMotor(name="motor1"),
MockMovementSensor(
name="movement_sensor1",
coordinates=GeoPoint(latitude=40.664679865782624, longitude=-73.97668056188789),
altitude=15,
lin_vel=Vector3(x=1, y=2, z=3),
ang_vel=Vector3(x=1, y=2, z=3),
lin_acc=Vector3(x=1, y=2, z=3),
heading=182,
orientation=Orientation(o_x=1, o_y=2, o_z=3, theta=5),
properties=MovementSensor.Properties(
linear_acceleration_supported=False,
linear_velocity_supported=False,
angular_velocity_supported=True,
orientation_supported=False,
position_supported=True,
compass_heading_supported=False),
accuracy={"foo": 0.1, "bar": 2, "baz": 3.14}
),
]

async def Config(stream: Stream[FrameSystemConfigRequest, FrameSystemConfigResponse]) -> None:
Expand Down Expand Up @@ -171,7 +196,8 @@ async def test_resource_names(self, service: RobotService):
async with ChannelFor([service]) as channel:
client = RobotServiceStub(channel)
response: ResourceNamesResponse = await client.ResourceNames(ResourceNamesRequest())
assert list(response.resources) == RESOURCE_NAMES
assert len(response.resources) == len(RESOURCE_NAMES)
assert set(response.resources) == set(RESOURCE_NAMES)

@pytest.mark.asyncio
async def test_get_status(self, service: RobotService):
Expand Down Expand Up @@ -248,11 +274,12 @@ class TestRobotClient:
async def test_refresh(self, service: RobotService):
async with ChannelFor([service]) as channel:
client = await RobotClient.with_channel(channel, RobotClient.Options())
assert client._resource_names == RESOURCE_NAMES
assert len(client._resource_names) == len(RESOURCE_NAMES)
assert set(client._resource_names) == set(RESOURCE_NAMES)

service.manager.register(MockSensor("sensor1"))
await client.refresh()
assert client._resource_names == RESOURCE_NAMES + [MockSensor.get_resource_name("sensor1")]
assert set(client._resource_names) == set(RESOURCE_NAMES + [MockSensor.get_resource_name("sensor1")])
await client.close()

@pytest.mark.asyncio
Expand Down Expand Up @@ -282,11 +309,12 @@ async def test_close(self, service: RobotService):
async def test_resource_names(self, service: RobotService):
async with ChannelFor([service]) as channel:
client = await RobotClient.with_channel(channel, RobotClient.Options())
assert client.resource_names == RESOURCE_NAMES
assert len(client._resource_names) == len(RESOURCE_NAMES)
assert set(client._resource_names) == set(RESOURCE_NAMES)

service.manager.register(MockSensor("sensor1"))
await client.refresh()
assert client._resource_names == RESOURCE_NAMES + [MockSensor.get_resource_name("sensor1")]
assert set(client._resource_names) == set(RESOURCE_NAMES + [MockSensor.get_resource_name("sensor1")])
await client.close()

@pytest.mark.asyncio
Expand Down