third_party.pigweed.src/pw_rpc/py/descriptors_test.py
Wyatt Hepler ac357deb34 pw_rpc: Handle duplicate generated proto message types
- google.protobuf.message_factory may generate new, unique message types
  rather than reusing previously generated classes. The new types are
  essentially identical to others and share the same descriptor
  instance. When working with pw_rpc methods, accept any message type
  that shares the same descriptors.
- Move pw_rpc.descriptors.Method tests to a new file and expand them to
  cover this case.

Change-Id: I46a7823e086c0bbf26ecd5db3017bed0f7ae27e0
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/27160
Commit-Queue: Wyatt Hepler <hepler@google.com>
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
2020-12-10 03:41:04 +00:00

92 lines
3.0 KiB
Python

# Copyright 2020 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Tests classes in pw_rpc.descriptors."""
import unittest
from google.protobuf.message_factory import MessageFactory
from pw_protobuf_compiler import python_protos
from pw_rpc import descriptors
TEST_PROTO = """\
syntax = "proto3";
package pw.test1;
message SomeMessage {
uint32 magic_number = 1;
}
message AnotherMessage {
enum Result {
FAILED = 0;
FAILED_MISERABLY = 1;
I_DONT_WANT_TO_TALK_ABOUT_IT = 2;
}
Result result = 1;
string payload = 2;
}
service PublicService {
rpc SomeUnary(SomeMessage) returns (AnotherMessage) {}
rpc SomeServerStreaming(SomeMessage) returns (stream AnotherMessage) {}
rpc SomeClientStreaming(stream SomeMessage) returns (AnotherMessage) {}
rpc SomeBidiStreaming(stream SomeMessage) returns (stream AnotherMessage) {}
}
"""
class MethodTest(unittest.TestCase):
"""Tests pw_rpc.Method."""
def setUp(self):
module, = python_protos.compile_and_import_strings([TEST_PROTO])
service = descriptors.Service.from_descriptor(
module.DESCRIPTOR.services_by_name['PublicService'])
self._method = service.methods['SomeUnary']
def test_get_request_with_both_message_and_kwargs(self):
with self.assertRaisesRegex(TypeError, r'either'):
self._method.get_request(self._method.request_type(),
{'magic_number': 1})
def test_get_request_with_wrong_type(self):
with self.assertRaisesRegex(TypeError, r'pw\.test1\.SomeMessage'):
self._method.get_request('a str!', {})
def test_get_request_with_different_message_type(self):
msg = self._method.response_type()
with self.assertRaisesRegex(TypeError, r'pw\.test1\.SomeMessage'):
self._method.get_request(msg, {})
def test_get_request_with_different_copy_of_same_message_class(self):
some_message_clone = MessageFactory(
self._method.request_type.DESCRIPTOR.file.pool).GetPrototype(
self._method.request_type.DESCRIPTOR)
msg = some_message_clone()
# Protobuf classes obtained with a MessageFactory may or may not be a
# unique type, but will always use the same descriptor instance.
self.assertIsInstance(msg, some_message_clone)
self.assertIs(msg.DESCRIPTOR, self._method.request_type.DESCRIPTOR)
result = self._method.get_request(msg, {})
self.assertIs(result, msg)
if __name__ == '__main__':
unittest.main()