Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(framework) Add ClientAppIo servicer test #4001

Merged
merged 29 commits into from
Aug 16, 2024
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
dc1f710
Initial commit
chongshenng Aug 8, 2024
df0ccf8
Merge branch 'add-exec-client-app' into add-multiproc-execution
chongshenng Aug 8, 2024
aef1b3e
Init commit
chongshenng Aug 8, 2024
11ed5cf
Merge branch 'main' into add-exec-client-app
chongshenng Aug 8, 2024
1541f18
Merge branch 'main' into add-exec-client-app
chongshenng Aug 9, 2024
eaed17b
Update internal command to flwr-clientapp
chongshenng Aug 9, 2024
4b32077
Update __init__.py
chongshenng Aug 9, 2024
4e7612a
Merge branch 'main' into add-exec-client-app
chongshenng Aug 9, 2024
a16ab06
Merge branch 'main' into add-exec-client-app
danieljanes Aug 10, 2024
ed64df1
Update src/py/flwr/client/supernode/app.py
danieljanes Aug 10, 2024
1a059ee
Update src/py/flwr/client/supernode/app.py
danieljanes Aug 10, 2024
7c16d32
Merge branch 'main' into add-exec-client-app
chongshenng Aug 11, 2024
e269e2e
Address comments
chongshenng Aug 11, 2024
e3ce501
Merge main
chongshenng Aug 12, 2024
b8c4bc1
Update PR
chongshenng Aug 12, 2024
57d0613
Update PR
chongshenng Aug 12, 2024
d6b5b5d
Address comments
chongshenng Aug 12, 2024
27f2e60
Merge main
chongshenng Aug 13, 2024
5cf506f
Merge branch 'main' into add-multiproc-execution
chongshenng Aug 13, 2024
5d30a7c
Refactor code for tests
chongshenng Aug 13, 2024
18f04e0
Update docstring
chongshenng Aug 13, 2024
808c2fb
Merge main
chongshenng Aug 13, 2024
da2049d
Init
chongshenng Aug 13, 2024
9f31040
Fix import path
chongshenng Aug 13, 2024
abb25cb
Merge main
chongshenng Aug 16, 2024
a37a40a
Bugfix
chongshenng Aug 16, 2024
c0f895a
Merge main, resolve conflicts
chongshenng Aug 16, 2024
9f108a4
Merge branch 'main' into add-clientappio-servicer-test
chongshenng Aug 16, 2024
7ae4645
Switch args
chongshenng Aug 16, 2024
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
78 changes: 78 additions & 0 deletions src/py/flwr/client/process/clientappio_servicer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,25 @@
"""Test the ClientAppIo API servicer."""

import unittest
from unittest.mock import Mock, patch

from flwr.client.process.process import pull_message, push_message
from flwr.common import Context, Message, typing
from flwr.common.serde import (
clientappstatus_from_proto,
clientappstatus_to_proto,
message_to_proto,
)
from flwr.common.serde_test import RecordMaker

# pylint:disable=E0611
from flwr.proto.clientappio_pb2 import (
PullClientAppInputsResponse,
PushClientAppOutputsResponse,
)
from flwr.proto.message_pb2 import Context as ProtoContext
from flwr.proto.run_pb2 import Run as ProtoRun

from .clientappio_servicer import (
ClientAppIoInputs,
ClientAppIoOutputs,
Expand All @@ -33,9 +48,15 @@ def setUp(self) -> None:
"""Initialize."""
self.servicer = ClientAppIoServicer()
self.maker = RecordMaker()
self.mock_stub = Mock()
self.patcher = patch(
"flwr.client.process.process.ClientAppIoStub", return_value=self.mock_stub
)
self.patcher.start()

def tearDown(self) -> None:
"""Cleanup."""
self.patcher.stop()

def test_set_inputs(self) -> None:
"""Test setting ClientApp inputs."""
Expand Down Expand Up @@ -116,3 +137,60 @@ def test_get_outputs(self) -> None:
assert output == client_output
assert self.servicer.clientapp_input is None
assert self.servicer.clientapp_output is None

def test_pull_clientapp_inputs(self) -> None:
"""Test pulling messages from SuperNode."""
# Prepare
mock_message = Message(
metadata=self.maker.metadata(),
content=self.maker.recordset(3, 2, 1),
)
mock_response = PullClientAppInputsResponse(
message=message_to_proto(mock_message),
context=ProtoContext(node_id=123),
run=ProtoRun(run_id=61016, fab_id="mock/mock", fab_version="v1.0.0"),
)
self.mock_stub.PullClientAppInputs.return_value = mock_response

# Execute
message, context, run = pull_message(self.mock_stub, token=456)

# Assert
self.mock_stub.PullClientAppInputs.assert_called_once()
self.assertEqual(len(message.content.parameters_records), 3)
self.assertEqual(len(message.content.metrics_records), 2)
self.assertEqual(len(message.content.configs_records), 1)
self.assertEqual(context.node_id, 123)
self.assertEqual(run.run_id, 61016)
self.assertEqual(run.fab_id, "mock/mock")
self.assertEqual(run.fab_version, "v1.0.0")

def test_push_clientapp_outputs(self) -> None:
"""Test pushing messages to SuperNode."""
# Prepare
message = Message(
metadata=self.maker.metadata(),
content=self.maker.recordset(2, 2, 1),
)
context = Context(
node_id=1,
node_config={"nodeconfig1": 4.2},
state=self.maker.recordset(2, 2, 1),
run_config={"runconfig1": 6.1},
)
code = typing.ClientAppOutputCode.SUCCESS
status_proto = clientappstatus_to_proto(
status=typing.ClientAppOutputStatus(code=code, message="SUCCESS"),
)
mock_response = PushClientAppOutputsResponse(status=status_proto)
self.mock_stub.PushClientAppOutputs.return_value = mock_response

# Execute
res = push_message(
stub=self.mock_stub, token=789, message=message, context=context
)
status = clientappstatus_from_proto(res.status)

# Assert
self.mock_stub.PushClientAppOutputs.assert_called_once()
self.assertEqual(status.message, "SUCCESS")