示例#1
0
 def test_lro_annotation_metadata_change(self):
     lro_output_msg = make_message(
         name=".google.longrunning.Operation",
         full_name=".google.longrunning.Operation",
     )
     method_original = make_method(
         name="Method",
         output_message=lro_output_msg,
         lro_response_type="response_type",
         lro_metadata_type="FooMetadata",
     )
     method_update = make_method(
         name="Method",
         output_message=lro_output_msg,
         lro_response_type="response_type",
         lro_metadata_type="FooMetadataUpdate",
     )
     ServiceComparator(
         make_service(methods=(method_original, )),
         make_service(methods=(method_update, )),
         self.finding_container,
         context="ctx",
     ).compare()
     finding = next(f for f in self.finding_container.get_all_findings()
                    if f.category.name == "LRO_METADATA_CHANGE")
     self.assertEqual(finding.location.proto_file_name, "foo")
示例#2
0
 def test_http_annotation_change(self):
     method_original = make_method(
         name="Method",
         http_uri="http_uri",
         http_body="*",
     )
     method_update = make_method(
         name="Method",
         http_uri="http_uri_update",
         http_body="http_body",
     )
     ServiceComparator(
         make_service(methods=(method_original, )),
         make_service(methods=(method_update, )),
         self.finding_container,
         context="ctx",
     ).compare()
     uri_change_finding = next(
         f for f in self.finding_container.get_all_findings()
         if f.category.name == "HTTP_ANNOTATION_CHANGE"
         and f.type == "http_uri")
     body_change_finding = next(
         f for f in self.finding_container.get_all_findings()
         if f.category.name == "HTTP_ANNOTATION_CHANGE"
         and f.type == "http_body")
     self.assertEqual(
         uri_change_finding.location.proto_file_name,
         "foo",
     )
     self.assertEqual(
         body_change_finding.location.proto_file_name,
         "foo",
     )
示例#3
0
 def test_lro_annotation_invalid(self):
     lro_output_msg = make_message(
         name=".google.longrunning.Operation",
         full_name=".google.longrunning.Operation",
     )
     method_lro = make_method(
         name="Method",
         output_message=lro_output_msg,
         lro_response_type="response_type",
         lro_metadata_type="FooMetadata",
     )
     method_not_lro = make_method(
         name="Method",
         output_message=lro_output_msg,
     )
     # `method_not_lro` returns `google.longrunning.Operation`
     # but is missing a response type or metadata type, the definition
     # is invalid. We still compare the two methods and take it as
     # lro annotation removal.
     ServiceComparator(
         make_service(methods=(method_lro, )),
         make_service(methods=(method_not_lro, )),
         self.finding_container,
         context="ctx",
     ).compare()
     finding = next(f for f in self.finding_container.get_all_findings()
                    if f.category.name == "LRO_ANNOTATION_REMOVAL")
     self.assertTrue(finding)
 def test_service_methods(self):
     input_message = make_message("InputRequest")
     output_message = make_message("OutputResponse")
     service = make_service(
         name="ThingDoer",
         methods=(
             make_method(
                 name="DoThing",
                 input_message=input_message,
                 output_message=output_message,
             ),
             make_method(
                 name="Jump",
                 input_message=input_message,
                 output_message=output_message,
             ),
             make_method(
                 name="Yawn",
                 input_message=input_message,
                 output_message=output_message,
             ),
         ),
     )
     expected_names = ["DoThing", "Jump", "Yawn"]
     self.assertEqual(list(service.methods.keys()), expected_names)
示例#5
0
 def test_method_no_page_field(self):
     # No repeated field in the response message.
     field_next_page_token = make_field(
         name="next_page_token",
         proto_type="TYPE_STRING",
         number=2,
     )
     response_message = make_message(
         name="ResponseMessage",
         fields=[field_next_page_token],
     )
     field_page_size = make_field(
         name="page_size",
         proto_type="TYPE_INT32",
         number=1,
     )
     field_page_token = make_field(
         name="page_token",
         proto_type="TYPE_STRING",
         number=2,
     )
     request_message = make_message(
         name="RequestMessage",
         fields=[field_page_size, field_page_token],
     )
     messages_map = {
         "ResponseMessage": response_message,
         "RequestMessage": request_message,
     }
     method = make_method(
         name="PagedMethod",
         input_message=request_message,
         output_message=response_message,
         messages_map=messages_map,
     )
     self.assertEqual(method.paged_result_field, None)
     # Missing `page_size` in request message.
     request_message_without_page_size = make_message(
         name="RequestMessage",
         fields=[field_page_size],
     )
     method = make_method(
         name="NoPagedMethod",
         input_message=request_message_without_page_size,
         output_message=response_message,
         messages_map=messages_map,
     )
     self.assertEqual(method.paged_result_field, None)
     # Missing `next_page_token` in response message.
     response_message_without_next_page_token = make_message(
         name="ResponseMessage",
     )
     method = make_method(
         name="NoPagedMethod",
         input_message=request_message,
         output_message=response_message_without_next_page_token,
         messages_map=messages_map,
     )
     self.assertEqual(method.paged_result_field, None)
示例#6
0
 def test_method_signature_removal(self):
     ServiceComparator(
         make_service(methods=(make_method(name="NotInteresting",
                                           signatures=["sig1", "sig2"]), )),
         make_service(methods=(
             make_method(name="NotInteresting", signatures=["sig1"]), )),
         self.finding_container,
         context="ctx",
     ).compare()
     finding = next(f for f in self.finding_container.get_all_findings()
                    if f.category.name == "METHOD_SIGNATURE_REMOVAL")
     self.assertEqual(finding.change_type.name, "MAJOR")
     self.assertEqual(finding.location.proto_file_name, "foo")
示例#7
0
 def test_method_removal(self):
     method_foo = make_method(name="foo")
     method_bar = make_method(name="bar")
     service_original = make_service(methods=(method_foo, method_bar))
     service_update = make_service(methods=(method_foo, ))
     ServiceComparator(service_original,
                       service_update,
                       self.finding_container,
                       context="ctx").compare()
     finding = self.finding_container.get_all_findings()[0]
     self.assertEqual(finding.category.name, "METHOD_REMOVAL")
     self.assertEqual(finding.change_type.name, "MAJOR")
     self.assertEqual(finding.location.proto_file_name, "foo")
示例#8
0
 def test_service_change(self):
     input_message = make_message(name="request",
                                  full_name=".example.v1.request")
     output_message = make_message(name="response",
                                   full_name=".example.v1.response")
     service_original = make_service(methods=[
         make_method(
             name="DoThing",
             input_message=input_message,
             output_message=output_message,
         )
     ])
     service_update = make_service()
     FileSetComparator(
         make_file_set(files=[
             make_file_pb2(
                 services=[service_original],
                 messages=[input_message, output_message],
             )
         ]),
         make_file_set(files=[make_file_pb2(services=[service_update])]),
         self.finding_container,
     ).compare()
     finding = self.finding_container.getAllFindings()[0]
     self.assertEqual(finding.message,
                      "An existing rpc method `DoThing` is removed.")
     self.assertEqual(finding.category.name, "METHOD_REMOVAL")
     self.assertEqual(finding.change_type.name, "MAJOR")
     self.assertEqual(finding.location.proto_file_name, "my_proto.proto")
示例#9
0
 def test_method_types(self):
     input_msg = make_message(name="Input", full_name=".example.v1.input")
     output_msg = make_message(name="Output", full_name=".example.v1.output")
     method = make_method("DoSomething", input_msg, output_msg)
     self.assertEqual(method.name, "DoSomething")
     self.assertEqual(method.input.value, ".example.v1.input")
     self.assertEqual(method.output.value, ".example.v1.output")
示例#10
0
 def test_http_annotation_removal(self):
     method_without_http_annotation = make_method(name="Method", )
     method_with_http_annotation = make_method(
         name="Method",
         http_uri="http_uri_update",
         http_body="http_body",
     )
     ServiceComparator(
         make_service(methods=(method_with_http_annotation, )),
         make_service(methods=(method_without_http_annotation, )),
         self.finding_container,
         context="ctx",
     ).compare()
     finding = self.finding_container.get_all_findings()[0]
     self.assertEqual(finding.category.name, "HTTP_ANNOTATION_REMOVAL")
     self.assertEqual(finding.change_type.name, "MAJOR")
示例#11
0
 def test_method_input_type_change(self):
     message_foo_request = make_message(name="FooRequest",
                                        full_name="FooRequest")
     message_bar_request = make_message(name="BarRequest",
                                        full_name="BarRequest")
     service_original = make_service(methods=(
         make_method(name="Foo", input_message=message_foo_request), ))
     service_update = make_service(methods=(
         make_method(name="Foo", input_message=message_bar_request), ))
     ServiceComparator(service_original,
                       service_update,
                       self.finding_container,
                       context="ctx").compare()
     finding = next(f for f in self.finding_container.get_all_findings()
                    if f.category.name == "METHOD_INPUT_TYPE_CHANGE")
     self.assertEqual(finding.change_type.name, "MAJOR")
     self.assertEqual(finding.location.proto_file_name, "foo")
示例#12
0
 def test_basic_properties(self):
     method = make_method("Foo")
     self.assertEqual(method.name, "Foo")
     self.assertEqual(method.proto_file_name, "foo")
     self.assertEqual(method.path, ())
     self.assertEqual(
         method.source_code_line,
         -1,
     )
示例#13
0
 def test_detector_basic(self):
     # Mock original and updated FileDescriptorSet.
     L = desc.SourceCodeInfo.Location
     # fmt: off
     locations = [
         L(path=(6, 0, 2, 0), span=(1, 2, 3, 4)),
         L(
             path=(
                 4,
                 0,
             ),
             span=(5, 6, 7, 8),
         ),
         L(path=(4, 1), span=(11, 12, 13, 14)),
     ]
     # fmt: on
     input_msg = make_message(name="input", full_name=".example.v1.input")
     output_msg = make_message(name="output",
                               full_name=".example.v1.output")
     service_original = make_service(methods=(make_method(
         name="DoThing", input_message=input_msg,
         output_message=output_msg), ))
     service_update = make_service()
     file_set_original = desc.FileDescriptorSet(file=[
         make_file_pb2(
             services=[service_original],
             locations=locations,
             messages=[input_msg, output_msg],
         )
     ])
     file_set_update = desc.FileDescriptorSet(
         file=[make_file_pb2(services=[service_update])])
     with mock.patch("os.path.isdir") as mocked_isdir:
         with mock.patch("os.path.isfile") as mocked_isfile:
             mocked_isdir.return_value = True
             mocked_isfile.return_value = True
             opts = Options(
                 original_api_definition_dirs="c,d",
                 update_api_definition_dirs="a,b",
                 original_proto_files="pf1, pf2",
                 update_proto_files="pf3, pf4",
                 original_descriptor_set_file_path=None,
                 update_descriptor_set_file_path=None,
                 human_readable_message=True,
             )
     with mock.patch("sys.stdout", new=StringIO()) as fake_output:
         result = Detector(file_set_original, file_set_update,
                           opts).detect_breaking_changes()
         self.assertEqual(
             fake_output.getvalue(),
             "my_proto.proto L2: An existing method `DoThing` is removed from service `Placeholder`.\n"
             +
             "my_proto.proto L6: An existing message `input` is removed.\n"
             +
             "my_proto.proto L12: An existing message `output` is removed.\n",
         )
         self.assertEqual(len(result), 3)
示例#14
0
 def test_method_output_type_change(self):
     service_original = make_service(methods=(make_method(
         name="Foo",
         output_message=make_message(name="FooResponse",
                                     full_name=".example.FooResponse"),
     ), ))
     service_update = make_service(methods=(make_method(
         name="Foo",
         output_message=make_message(name="BarResponse",
                                     full_name=".example.BarResponse"),
     ), ))
     ServiceComparator(service_original,
                       service_update,
                       self.finding_container,
                       context="ctx").compare()
     finding = next(f for f in self.finding_container.get_all_findings()
                    if f.category.name == "METHOD_RESPONSE_TYPE_CHANGE")
     self.assertEqual(finding.change_type.name, "MAJOR")
     self.assertEqual(finding.location.proto_file_name, "foo")
示例#15
0
 def test_method_http_annotationn(self):
     method = make_method(
         name="Method",
         http_uri="http_uri",
         http_body="*",
     )
     http_annotation = method.http_annotation.value
     self.assertEqual(http_annotation["http_method"], "get")
     self.assertEqual(http_annotation["http_uri"], "http_uri")
     self.assertEqual(http_annotation["http_body"], "*")
示例#16
0
 def test_method_longrunning(self):
     input_msg = make_message(name="Input", full_name=".example.v1.input")
     output_msg = make_message(
         name=".google.longrunning.Operation",
         full_name=".google.longrunning.Operation",
     )
     method = make_method("DoSomething", input_msg, output_msg)
     self.assertEqual(method.name, "DoSomething")
     self.assertEqual(method.input.value, ".example.v1.input")
     self.assertEqual(method.output.value, ".google.longrunning.Operation")
     self.assertEqual(method.longrunning, True)
示例#17
0
    def test_method_streaming_state_change(self):
        service_original = make_service(
            methods=(make_method(name="Bar", client_streaming=True), ))
        service_update = make_service(
            methods=(make_method(name="Bar", server_streaming=True), ))
        ServiceComparator(service_original,
                          service_update,
                          self.finding_container,
                          context="ctx").compare()

        client_streaming_finding = next(
            f for f in self.finding_container.get_all_findings()
            if f.category.name == "METHOD_CLIENT_STREAMING_CHANGE")
        self.assertEqual(client_streaming_finding.location.proto_file_name,
                         "foo")
        server_streaming_finding = next(
            f for f in self.finding_container.get_all_findings()
            if f.category.name == "METHOD_SERVER_STREAMING_CHANGE")
        self.assertEqual(server_streaming_finding.change_type.name, "MAJOR")
        self.assertEqual(server_streaming_finding.location.proto_file_name,
                         "foo")
示例#18
0
 def test_lro_annotation_removal(self):
     lro_output_msg = make_message(
         name=".google.longrunning.Operation",
         full_name=".google.longrunning.Operation",
     )
     method_lro = make_method(
         name="Method",
         output_message=lro_output_msg,
         lro_response_type="response_type",
         lro_metadata_type="FooMetadata",
     )
     method_not_lro = make_method(name="Method", )
     ServiceComparator(
         make_service(methods=(method_lro, )),
         make_service(methods=(method_not_lro, )),
         self.finding_container,
         context="ctx",
     ).compare()
     finding = next(f for f in self.finding_container.get_all_findings()
                    if f.category.name == "LRO_ANNOTATION_REMOVAL")
     self.assertTrue(finding)
示例#19
0
 def test_http_annotation_minor_version_update(self):
     method_original = make_method(
         name="Method",
         http_uri="/v1/{name=projects/*}",
         http_body="*",
     )
     method_update = make_method(
         name="Method",
         http_uri="/v1alpha/{name=projects/*}",
         http_body="*",
     )
     ServiceComparator(
         make_service(methods=(method_original, ), api_version="v1"),
         make_service(methods=(method_update, ), api_version="v1alpha"),
         self.finding_container,
         context="ctx",
     ).compare()
     findings_map = {
         f.message: f
         for f in self.finding_container.get_all_findings()
     }
     # No breaking changes, since only minor version update in the http URI.
     self.assertFalse(findings_map)
示例#20
0
 def test_method_lro_annotationn(self):
     input_msg = make_message(name="Input", full_name=".example.v1.input")
     output_msg = make_message(
         name=".google.longrunning.Operation",
         full_name=".google.longrunning.Operation",
     )
     method = make_method(
         name="Method",
         input_message=input_msg,
         output_message=output_msg,
         lro_response_type="response_type",
         lro_metadata_type="metadata_type",
     )
     lro_annotation = method.lro_annotation.value
     self.assertEqual(lro_annotation["response_type"], "response_type")
     self.assertEqual(lro_annotation["metadata_type"], "metadata_type")
示例#21
0
 def test_method_paged(self):
     field_next_page_token = make_field(
         name="next_page_token",
         proto_type="TYPE_STRING",
         number=2,
     )
     field_repeated = make_field(
         name="repeated_field",
         proto_type="TYPE_STRING",
         repeated=True,
         number=1,
     )
     response_message = make_message(
         name="ResponseMessage",
         fields=[field_repeated, field_next_page_token],
         full_name=".example.v1.ResponseMessage",
     )
     field_page_size = make_field(
         name="page_size",
         proto_type="TYPE_INT32",
         number=1,
     )
     field_page_token = make_field(
         name="page_token",
         proto_type="TYPE_STRING",
         number=2,
     )
     request_message = make_message(
         name="RequestMessage",
         fields=[field_page_size, field_page_token],
         full_name=".example.v1.RequestMessage",
     )
     messages_map = {
         ".example.v1.ResponseMessage": response_message,
         ".example.v1.RequestMessage": request_message,
     }
     method = make_method(
         name="PagedMethod",
         input_message=request_message,
         output_message=response_message,
         messages_map=messages_map,
     )
     self.assertEqual(method.paged_result_field.name, "repeated_field")
     self.assertEqual(method.longrunning, False)
 def test_file_set_properties(self):
     input_message = make_message(name="request",
                                  full_name=".example.v1.request")
     output_message = make_message(name="response",
                                   full_name=".example.v1.response")
     messages = [
         make_message(
             "InnerMessage",
             fields=(make_field(name="hidden_message",
                                number=1,
                                type_name=".example.v1.request"), ),
             full_name=".example.v1.InnerMessage",
         ),
         input_message,
         output_message,
     ]
     services = [
         make_service(
             name="ThingDoer",
             methods=(make_method(
                 name="DoThing",
                 input_message=input_message,
                 output_message=output_message,
             ), ),
         )
     ]
     enums = [
         make_enum(
             name="Irrelevant",
             values=(
                 ("RED", 1),
                 ("GREEN", 2),
                 ("BLUE", 3),
             ),
         )
     ]
     file_foo = make_file_pb2(
         name="foo.proto",
         package="example.v1",
         services=services,
         enums=enums,
         dependency=["bar.proto"],
     )
     file_bar = make_file_pb2(name="bar.proto",
                              package="example.v1",
                              messages=messages)
     file_set = make_file_set(files=[file_bar, file_foo])
     # Default to be empty.
     self.assertFalse(file_set.packaging_options_map)
     self.assertEqual(
         list(file_set.messages_map.keys()),
         [
             ".example.v1.InnerMessage", ".example.v1.request",
             ".example.v1.response"
         ],
     )
     self.assertEqual(list(file_set.enums_map.keys()),
                      [".example.v1.Irrelevant"])
     self.assertEqual(list(file_set.services_map.keys()), ["ThingDoer"])
     self.assertEqual(
         file_set.messages_map[".example.v1.InnerMessage"].fields[1].name,
         "hidden_message",
     )
     self.assertEqual(
         file_set.enums_map[".example.v1.Irrelevant"].values[2].name,
         "GREEN")
     self.assertEqual(
         list(file_set.services_map["ThingDoer"].methods.keys()),
         ["DoThing"],
     )
     self.assertEqual(list(file_set.global_enums_map.keys()),
                      [".example.v1.Irrelevant"])
     self.assertEqual(
         list(file_set.global_messages_map.keys()),
         [
             ".example.v1.response", ".example.v1.request",
             ".example.v1.InnerMessage"
         ],
     )
示例#23
0
 def test_method_streaming(self):
     method = make_method("F", client_streaming=True, server_streaming=True)
     self.assertEqual(method.client_streaming.value, True)
     self.assertEqual(method.server_streaming.value, True)
示例#24
0
 def test_method_signatures(self):
     method = make_method("Method", signatures=["sig1", "sig2"])
     self.assertEqual(method.method_signatures.value, ["sig1", "sig2"])
示例#25
0
 def test_method_paginated_state_change(self):
     paginated_response_message = make_message(
         name="PaginatedResponseMessage",
         fields=[
             make_field(
                 name="repeated_field",
                 proto_type="TYPE_STRING",
                 repeated=True,
                 number=1,
             ),
             make_field(
                 name="next_page_token",
                 proto_type="TYPE_STRING",
                 number=2,
             ),
         ],
         full_name=".example.v1.PaginatedResponseMessage",
     )
     paginated_request_message = make_message(
         name="PaginatedRequestMessage",
         fields=[
             make_field(
                 name="page_size",
                 proto_type="TYPE_INT32",
                 number=1,
             ),
             make_field(
                 name="page_token",
                 proto_type="TYPE_STRING",
                 number=2,
             ),
         ],
         full_name=".example.v1.PaginatedRequestMessage",
     )
     messages_map_original = {
         ".example.v1.PaginatedResponseMessage": paginated_response_message,
         ".example.v1.PaginatedRequestMessage": paginated_request_message,
     }
     paged_method = make_method(
         name="NotInteresting",
         input_message=paginated_request_message,
         output_message=paginated_response_message,
     )
     messages_map_update = {
         ".example.v1alpha.MethodInput":
         make_message(name="MethodInput",
                      full_name=".example.v1alpha.MethodInput"),
         ".example.v1alpha.MethodOutput":
         make_message(name="MethodOutput",
                      full_name=".example.v1alpha.MethodOutput"),
     }
     non_paged_method = make_method(name="NotInteresting")
     service_original = make_service(methods=(paged_method, ),
                                     messages_map=messages_map_original)
     service_update = make_service(methods=(non_paged_method, ),
                                   messages_map=messages_map_update)
     ServiceComparator(service_original,
                       service_update,
                       self.finding_container,
                       context="ctx").compare()
     finding = next(
         f for f in self.finding_container.get_all_findings()
         if f.category.name == "METHOD_PAGINATED_RESPONSE_CHANGE")
     self.assertEqual(finding.location.proto_file_name, "foo")