From 38a35ea1d62f68dbd1541bb8c6c714698aeb2737 Mon Sep 17 00:00:00 2001 From: Michael Heilmann Date: Fri, 16 Jan 2026 16:53:10 -0500 Subject: [PATCH 1/8] generate representative proto definitions --- priv/protos/common_types.proto | 38 ++++++ priv/protos/custom_prefix_service.proto | 46 ++----- priv/protos/edge_cases.proto | 153 ++++++++++++++++++++++++ priv/protos/empty_service.proto | 5 - priv/protos/helloworld.proto | 27 ----- priv/protos/imports_test.proto | 63 ++++++++++ priv/protos/nested_messages.proto | 90 ++++++++++++++ priv/protos/no_package.proto | 16 +++ priv/protos/package_a.proto | 14 +++ priv/protos/package_b.proto | 20 ++++ priv/protos/proto2_features.proto | 94 +++++++++++++++ priv/protos/scalar_types.proto | 64 ++++++++++ priv/protos/streaming_service.proto | 54 +++++++++ priv/protos/test_service_v2.proto | 41 ------- priv/protos/test_service_v3.proto | 52 -------- priv/protos/well_known_types.proto | 66 ++++++++++ 16 files changed, 683 insertions(+), 160 deletions(-) create mode 100644 priv/protos/common_types.proto create mode 100644 priv/protos/edge_cases.proto delete mode 100644 priv/protos/empty_service.proto delete mode 100644 priv/protos/helloworld.proto create mode 100644 priv/protos/imports_test.proto create mode 100644 priv/protos/nested_messages.proto create mode 100644 priv/protos/no_package.proto create mode 100644 priv/protos/package_a.proto create mode 100644 priv/protos/package_b.proto create mode 100644 priv/protos/proto2_features.proto create mode 100644 priv/protos/scalar_types.proto create mode 100644 priv/protos/streaming_service.proto delete mode 100644 priv/protos/test_service_v2.proto delete mode 100644 priv/protos/test_service_v3.proto create mode 100644 priv/protos/well_known_types.proto diff --git a/priv/protos/common_types.proto b/priv/protos/common_types.proto new file mode 100644 index 0000000..a639319 --- /dev/null +++ b/priv/protos/common_types.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; + +package common; + +// Common messages to be imported by other proto files + +message Address { + string street = 1; + string city = 2; + string state = 3; + string postal_code = 4; + string country = 5; +} + +message Coordinates { + double latitude = 1; + double longitude = 2; + double altitude = 3; +} + +message Money { + string currency_code = 1; + int64 units = 2; + int32 nanos = 3; +} + +enum Priority { + PRIORITY_UNSPECIFIED = 0; + LOW = 1; + MEDIUM = 2; + HIGH = 3; + CRITICAL = 4; +} + +message TimeRange { + int64 start_time = 1; + int64 end_time = 2; +} diff --git a/priv/protos/custom_prefix_service.proto b/priv/protos/custom_prefix_service.proto index 5e1b834..ccc09f2 100644 --- a/priv/protos/custom_prefix_service.proto +++ b/priv/protos/custom_prefix_service.proto @@ -1,44 +1,20 @@ -syntax = "proto2"; +syntax = "proto3"; -import "google/protobuf/timestamp.proto"; -import "google/protobuf/any.proto"; - -package testserviceV2; +package custom_prefix; +// This proto demonstrates Elixir-specific custom module prefix option import "elixirpb.proto"; -option (elixirpb.file).module_prefix = "HLW"; - -service TestService { - rpc CallFunction (TestRequest) returns (TestReply) {} -} - -message TestRequest { - required string name = 1; - optional Enum enum = 2; - oneof test_oneof { - string label = 3; - int32 value = 4; - } - map g = 5; - repeated google.protobuf.Any instrument = 6; - extensions 10 to 20; -} - -message Location { - optional double latitude = 1; - optional double longitude = 2; -} +option (elixirpb.file).module_prefix = "CustomPrefix"; -extend TestRequest { - optional string data = 10; - optional Location location = 11; +// Simple service to test custom module prefix generation +service PrefixService { + rpc Echo (EchoRequest) returns (EchoResponse) {} } -message TestReply { - required google.protobuf.Timestamp today = 2; +message EchoRequest { + string message = 1; } -enum Enum { - A = 0; - B = 1; +message EchoResponse { + string reply = 1; } \ No newline at end of file diff --git a/priv/protos/edge_cases.proto b/priv/protos/edge_cases.proto new file mode 100644 index 0000000..633b931 --- /dev/null +++ b/priv/protos/edge_cases.proto @@ -0,0 +1,153 @@ +syntax = "proto3"; + +package edge_cases; + +// Empty service (no methods) - edge case +service EmptyService { +} + +// Service with unusual but valid patterns +service EdgeCaseService { + // Method names with underscores and different conventions + rpc process_data (Request) returns (Response) {} + rpc ProcessData (Request) returns (Response) {} + rpc PROCESS_DATA (Request) returns (Response) {} + + // Empty request or response + rpc EmptyInput (EmptyMessage) returns (Response) {} + rpc EmptyOutput (Request) returns (EmptyMessage) {} + rpc BothEmpty (EmptyMessage) returns (EmptyMessage) {} +} + +message EmptyMessage { + // Intentionally empty message +} + +message Request { + string data = 1; +} + +message Response { + string result = 1; +} + +// Unusual field numbering +message SparseFieldNumbers { + string field_1 = 1; + string field_536870911 = 536870911; // Max field number (2^29 - 1) +} + +// Many fields +message ManyFields { + string field_001 = 1; + string field_002 = 2; + string field_003 = 3; + string field_004 = 4; + string field_005 = 5; + string field_006 = 6; + string field_007 = 7; + string field_008 = 8; + string field_009 = 9; + string field_010 = 10; + string field_011 = 11; + string field_012 = 12; + string field_013 = 13; + string field_014 = 14; + string field_015 = 15; + string field_016 = 16; + string field_017 = 17; + string field_018 = 18; + string field_019 = 19; + string field_020 = 20; +} + +// Complex enum +enum DetailedStatus { + // Enum with zero value (required in proto3) + DETAILED_STATUS_UNSPECIFIED = 0; + + // Various naming patterns + status_active = 1; + STATUS_INACTIVE = 2; + Status_Pending = 3; + + // Negative enum values (valid but unusual) + ERROR_STATE = -1; + CRITICAL_ERROR = -100; + + // Large enum values + MAX_STATUS = 2147483647; // Max int32 +} + +// Multiple oneofs in one message +message MultipleOneofs { + oneof first_choice { + string option_a1 = 1; + int32 option_a2 = 2; + } + + oneof second_choice { + string option_b1 = 3; + int32 option_b2 = 4; + } + + oneof third_choice { + string option_c1 = 5; + int32 option_c2 = 6; + } + + string regular_field = 7; +} + +// Nested maps +message NestedMaps { + map outer_map = 1; + map int_key_map = 2; + map numeric_map = 3; + map bool_key_map = 4; +} + +message InnerMap { + map data = 1; + map counts = 2; +} + +// Circular reference patterns (different from recursive_message.proto) +message CircularA { + CircularB b_field = 1; + string data = 2; +} + +message CircularB { + CircularC c_field = 1; + string data = 2; +} + +message CircularC { + CircularA a_field = 1; + string data = 2; +} + +// Reserved with various patterns +message WithReservedFields { + string active_field_1 = 1; + + reserved 2, 15, 9 to 11; + reserved "foo", "bar", "old_field"; + + string active_field_16 = 16; + + reserved 100 to max; +} + +// Unicode and special characters in comments +message UnicodeTest { + // Field with emoji in comment: 🚀 rocket + string rocket_field = 1; + + // Mathematical symbols: ∑ ∫ π + double pi_field = 2; + + // Various languages: 你好 مرحبا שלום + string greeting = 3; +} diff --git a/priv/protos/empty_service.proto b/priv/protos/empty_service.proto deleted file mode 100644 index 7af1e8f..0000000 --- a/priv/protos/empty_service.proto +++ /dev/null @@ -1,5 +0,0 @@ -syntax = "proto2"; - -service EmptyService { - -} \ No newline at end of file diff --git a/priv/protos/helloworld.proto b/priv/protos/helloworld.proto deleted file mode 100644 index 1284998..0000000 --- a/priv/protos/helloworld.proto +++ /dev/null @@ -1,27 +0,0 @@ -syntax = "proto3"; - -option java_multiple_files = true; -option java_package = "io.grpc.examples.helloworld"; -option java_outer_classname = "HelloWorldProto"; -option objc_class_prefix = "HLW"; - -import "google/protobuf/timestamp.proto"; - -package helloworld; - -// The greeting service definition. -service Greeter { - // Sends a greeting - rpc SayHello (HelloRequest) returns (HelloReply) {} -} - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message HelloReply { - string message = 1; - google.protobuf.Timestamp today = 2; -} diff --git a/priv/protos/imports_test.proto b/priv/protos/imports_test.proto new file mode 100644 index 0000000..336b402 --- /dev/null +++ b/priv/protos/imports_test.proto @@ -0,0 +1,63 @@ +syntax = "proto3"; + +package imports_test; + +// Import from local proto file +import "common_types.proto"; + +// Import from google protos +import "google/protobuf/timestamp.proto"; + +// Service demonstrating cross-file type usage +service ImportTestService { + rpc CreateUser (UserRequest) returns (UserResponse) {} + rpc UpdateLocation (LocationUpdate) returns (LocationResponse) {} +} + +message UserRequest { + string name = 1; + string email = 2; + + // Using imported type from common_types.proto + common.Address address = 3; + common.Coordinates location = 4; + + // Using imported google type + google.protobuf.Timestamp registered_at = 5; +} + +message UserResponse { + string user_id = 1; + common.Priority priority = 2; + google.protobuf.Timestamp created_at = 3; + + // Nested message that uses imported types + message Profile { + common.Address billing_address = 1; + common.Address shipping_address = 2; + repeated common.Coordinates recent_locations = 3; + } + + Profile profile = 4; +} + +message LocationUpdate { + string user_id = 1; + common.Coordinates new_location = 2; + google.protobuf.Timestamp timestamp = 3; +} + +message LocationResponse { + bool success = 1; + common.Coordinates confirmed_location = 2; + + // Map using imported types + map visit_history = 3; +} + +// Message demonstrating repeated imported types +message BulkOperation { + repeated common.Address addresses = 1; + repeated common.Money transactions = 2; + map task_priorities = 3; +} diff --git a/priv/protos/nested_messages.proto b/priv/protos/nested_messages.proto new file mode 100644 index 0000000..58bb549 --- /dev/null +++ b/priv/protos/nested_messages.proto @@ -0,0 +1,90 @@ +syntax = "proto3"; + +package nested; + +// Service with deeply nested message structures +service NestedService { + rpc ProcessNested (OuterMessage) returns (OuterResponse) {} +} + +// Deeply nested message structure +message OuterMessage { + string outer_field = 1; + + message MiddleMessage { + string middle_field = 1; + + message InnerMessage { + string inner_field = 1; + + message DeepMessage { + string deep_field = 1; + + message VeryDeepMessage { + string very_deep_field = 1; + repeated int32 values = 2; + } + + VeryDeepMessage very_deep = 2; + } + + DeepMessage deep = 2; + } + + InnerMessage inner = 2; + repeated InnerMessage inner_list = 3; + } + + MiddleMessage middle = 2; + repeated MiddleMessage middle_list = 3; + + // Map with nested message value + map nested_map = 4; + + // Oneof with nested messages + oneof nested_oneof { + MiddleMessage option_a = 5; + MiddleMessage.InnerMessage option_b = 6; + string simple_option = 7; + } +} + +message OuterResponse { + // Message referencing nested types from request + OuterMessage.MiddleMessage.InnerMessage.DeepMessage deep_result = 1; + repeated OuterMessage.MiddleMessage middle_results = 2; +} + +// Multiple services in the same file +service AnotherNestedService { + rpc ProcessOuter (OuterMessage) returns (OuterResponse) {} + rpc ProcessMiddle (OuterMessage.MiddleMessage) returns (OuterMessage.MiddleMessage) {} + rpc ProcessInner (OuterMessage.MiddleMessage.InnerMessage) returns (OuterMessage.MiddleMessage.InnerMessage) {} +} + +// Complex message with multiple nested enums +message ComplexNested { + enum Status { + UNKNOWN = 0; + ACTIVE = 1; + INACTIVE = 2; + } + + message Node { + enum NodeType { + LEAF = 0; + BRANCH = 1; + ROOT = 2; + } + + string id = 1; + NodeType type = 2; + repeated Node children = 3; + Node parent = 4; + map named_children = 5; + } + + Status status = 1; + Node root = 2; + repeated Node all_nodes = 3; +} diff --git a/priv/protos/no_package.proto b/priv/protos/no_package.proto new file mode 100644 index 0000000..abb1846 --- /dev/null +++ b/priv/protos/no_package.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +// File with no package declaration - valid but unusual +// Messages and services are in the global namespace + +service GlobalService { + rpc GlobalMethod (GlobalRequest) returns (GlobalResponse) {} +} + +message GlobalRequest { + string data = 1; +} + +message GlobalResponse { + string result = 1; +} diff --git a/priv/protos/package_a.proto b/priv/protos/package_a.proto new file mode 100644 index 0000000..7fcb19d --- /dev/null +++ b/priv/protos/package_a.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package package_a; + +message MessageA { + string field_a = 1; + int32 count = 2; +} + +enum EnumA { + ENUM_A_UNSPECIFIED = 0; + OPTION_1 = 1; + OPTION_2 = 2; +} diff --git a/priv/protos/package_b.proto b/priv/protos/package_b.proto new file mode 100644 index 0000000..098e20d --- /dev/null +++ b/priv/protos/package_b.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package package_b; + +import "package_a.proto"; + +message MessageB { + string field_b = 1; + package_a.MessageA message_from_a = 2; + package_a.EnumA enum_from_a = 3; +} + +service ServiceB { + rpc ProcessB (MessageB) returns (ResponseB) {} + rpc ProcessA (package_a.MessageA) returns (package_a.MessageA) {} +} + +message ResponseB { + repeated package_a.MessageA results = 1; +} diff --git a/priv/protos/proto2_features.proto b/priv/protos/proto2_features.proto new file mode 100644 index 0000000..d077f37 --- /dev/null +++ b/priv/protos/proto2_features.proto @@ -0,0 +1,94 @@ +syntax = "proto2"; + +package proto2_features; + +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +// Service demonstrating proto2-specific features +service Proto2Service { + rpc ProcessProto2 (Proto2Request) returns (Proto2Response) {} +} + +message Proto2Request { + // Required fields (proto2 only) + required string required_field = 1; + required int32 required_id = 2; + + // Optional fields (explicit in proto2) + optional string optional_field = 3; + optional int32 optional_id = 4; + + // Default values (proto2 only) + optional string name = 5 [default = "unknown"]; + optional int32 port = 6 [default = 8080]; + optional bool enabled = 7 [default = true]; + optional Status status = 8 [default = ACTIVE]; + + // Oneof in proto2 + oneof proto2_oneof { + string oneof_string = 9; + int32 oneof_int = 13; + } + + // Groups (proto2 only, deprecated but still valid) + repeated group Result = 10 { + required string url = 11; + optional string title = 12; + } + + // Map in proto2 (added in proto2 v3.0.0) + map metadata_map = 14; + + // Repeated Any in proto2 + repeated google.protobuf.Any any_values = 15; + + // Extensions range + extensions 100 to 199; +} + +enum Status { + UNKNOWN = 0; + ACTIVE = 1; + INACTIVE = 2; +} + +// Extension of Proto2Request +extend Proto2Request { + optional string extended_field = 100; + optional int64 extended_timestamp = 101; + optional ExtensionData extension_data = 102; + optional google.protobuf.Timestamp timestamp_extension = 103; +} + +message ExtensionData { + optional string key = 1; + optional string value = 2; +} + +message Proto2Response { + required bool success = 1; + optional string message = 2; + repeated Proto2Request.Result results = 3; +} + +// Message with extension and nested types +message ExtendableMessage { + required string id = 1; + extensions 1000 to max; + + message NestedInExtendable { + optional string data = 1; + } + + enum ExtendableEnum { + OPTION_A = 0; + OPTION_B = 1; + } +} + +extend ExtendableMessage { + optional string meta_info = 1000; + optional ExtendableMessage.NestedInExtendable nested_extension = 1001; + optional ExtendableMessage.ExtendableEnum enum_extension = 1002; +} diff --git a/priv/protos/scalar_types.proto b/priv/protos/scalar_types.proto new file mode 100644 index 0000000..ef3b66d --- /dev/null +++ b/priv/protos/scalar_types.proto @@ -0,0 +1,64 @@ +syntax = "proto3"; + +package scalar_types; + +// Service demonstrating all scalar field types +service ScalarService { + rpc ProcessScalars (ScalarRequest) returns (ScalarReply) {} +} + +// Message containing all protobuf scalar types +message ScalarRequest { + // Numeric types + double double_field = 1; + float float_field = 2; + int32 int32_field = 3; + int64 int64_field = 4; + uint32 uint32_field = 5; + uint64 uint64_field = 6; + sint32 sint32_field = 7; + sint64 sint64_field = 8; + fixed32 fixed32_field = 9; + fixed64 fixed64_field = 10; + sfixed32 sfixed32_field = 11; + sfixed64 sfixed64_field = 12; + + // Boolean type + bool bool_field = 13; + + // String types + string string_field = 14; + bytes bytes_field = 15; + + // Proto3 optional (added in protobuf 3.15) - generates presence tracking + optional string optional_string = 18; + optional int32 optional_int = 19; + + // Large field numbers to test range handling + string sparse_field_1 = 100; + string sparse_field_2 = 1000; + string sparse_field_3 = 10000; + + // Reserved fields and ranges + reserved 16, 17, 20 to 25; + reserved "old_field", "deprecated_field"; +} + +message ScalarReply { + // Repeated scalars + repeated double double_list = 1; + repeated float float_list = 2; + repeated int32 int32_list = 3; + repeated int64 int64_list = 4; + repeated uint32 uint32_list = 5; + repeated uint64 uint64_list = 6; + repeated sint32 sint32_list = 7; + repeated sint64 sint64_list = 8; + repeated fixed32 fixed32_list = 9; + repeated fixed64 fixed64_list = 10; + repeated sfixed32 sfixed32_list = 11; + repeated sfixed64 sfixed64_list = 12; + repeated bool bool_list = 13; + repeated string string_list = 14; + repeated bytes bytes_list = 15; +} diff --git a/priv/protos/streaming_service.proto b/priv/protos/streaming_service.proto new file mode 100644 index 0000000..5dfbde2 --- /dev/null +++ b/priv/protos/streaming_service.proto @@ -0,0 +1,54 @@ +syntax = "proto3"; + +package streaming; + +// Service demonstrating all four RPC streaming patterns +service StreamingService { + // Unary RPC: single request, single response + rpc UnaryCall (StreamRequest) returns (StreamResponse) {} + + // Server streaming: single request, stream of responses + rpc ServerStreamingCall (StreamRequest) returns (stream StreamResponse) {} + + // Client streaming: stream of requests, single response + rpc ClientStreamingCall (stream StreamRequest) returns (StreamResponse) {} + + // Bidirectional streaming: stream of requests and responses + rpc BidirectionalStreamingCall (stream StreamRequest) returns (stream StreamResponse) {} +} + +message StreamRequest { + string message = 1; + int32 sequence = 2; +} + +message StreamResponse { + string result = 1; + int32 sequence = 2; + bool is_final = 3; +} + +// Service with multiple streaming methods showing different patterns +service MultiStreamService { + rpc UploadData (stream DataChunk) returns (UploadStatus) {} + rpc DownloadData (DownloadRequest) returns (stream DataChunk) {} + rpc SyncData (stream DataChunk) returns (stream DataChunk) {} +} + +message DataChunk { + bytes data = 1; + int64 offset = 2; + int32 size = 3; +} + +message UploadStatus { + bool success = 1; + int64 total_bytes = 2; + string checksum = 3; +} + +message DownloadRequest { + string file_id = 1; + int64 start_offset = 2; + int64 max_bytes = 3; +} diff --git a/priv/protos/test_service_v2.proto b/priv/protos/test_service_v2.proto deleted file mode 100644 index 859ccd3..0000000 --- a/priv/protos/test_service_v2.proto +++ /dev/null @@ -1,41 +0,0 @@ -syntax = "proto2"; - -import "google/protobuf/timestamp.proto"; -import "google/protobuf/any.proto"; - -package testserviceV2; - -service TestService { - rpc CallFunction (TestRequest) returns (TestReply) {} -} - -message TestRequest { - required string name = 1; - optional Enum enum = 2; - oneof test_oneof { - string label = 3; - int32 value = 4; - } - map g = 5; - repeated google.protobuf.Any instrument = 6; - extensions 10 to 20; -} - -message Location { - optional double latitude = 1; - optional double longitude = 2; -} - -extend TestRequest { - optional string data = 10; - optional Location location = 11; -} - -message TestReply { - required google.protobuf.Timestamp today = 2; -} - -enum Enum { - A = 0; - B = 1; -} \ No newline at end of file diff --git a/priv/protos/test_service_v3.proto b/priv/protos/test_service_v3.proto deleted file mode 100644 index 2d56b66..0000000 --- a/priv/protos/test_service_v3.proto +++ /dev/null @@ -1,52 +0,0 @@ -syntax = "proto3"; - -import "google/protobuf/timestamp.proto"; -import "google/protobuf/any.proto"; -import "google/protobuf/wrappers.proto"; - -package testserviceV3; - -service TestService { - rpc CallFunction (TestRequest) returns (TestReply) {} -} - -message TestRequest { - string name = 1; - Enum enum = 2; - oneof test_oneof { - string label = 3; - int32 value = 4; - } - map g = 5; - google.protobuf.Any instrument = 6; - - message Payload { - google.protobuf.StringValue data = 1; - - message Location { - double latitude = 1; - double longitude = 2; - } - - Location location = 2; - Token token = 3; - } - - message Token { - string vaule = 1; - } - - Payload payload = 7; -} - -message TestReply { - google.protobuf.Timestamp today = 2; - - google.protobuf.StringValue ext_1 = 3; - google.protobuf.StringValue ext_2 = 4; -} - -enum Enum { - A = 0; - B = 1; -} \ No newline at end of file diff --git a/priv/protos/well_known_types.proto b/priv/protos/well_known_types.proto new file mode 100644 index 0000000..6130da1 --- /dev/null +++ b/priv/protos/well_known_types.proto @@ -0,0 +1,66 @@ +syntax = "proto3"; + +package well_known_types; + +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/field_mask.proto"; + +// Service demonstrating all common google.protobuf well-known types +service WellKnownTypesService { + rpc ProcessWellKnownTypes (WellKnownRequest) returns (WellKnownResponse) {} + rpc EmptyMethod (google.protobuf.Empty) returns (google.protobuf.Empty) {} +} + +message WellKnownRequest { + // Any type - can hold any message + google.protobuf.Any payload = 1; + repeated google.protobuf.Any items = 2; + + // Timestamp - point in time + google.protobuf.Timestamp created_at = 3; + google.protobuf.Timestamp updated_at = 4; + + // Duration - span of time + google.protobuf.Duration timeout = 5; + google.protobuf.Duration retry_delay = 6; + + // Struct - arbitrary JSON-like structure + google.protobuf.Struct metadata = 7; + google.protobuf.Value dynamic_value = 8; + google.protobuf.ListValue list_value = 9; + + // Wrappers - nullable scalar types + google.protobuf.StringValue nullable_string = 10; + google.protobuf.Int32Value nullable_int32 = 11; + google.protobuf.Int64Value nullable_int64 = 12; + google.protobuf.UInt32Value nullable_uint32 = 13; + google.protobuf.UInt64Value nullable_uint64 = 14; + google.protobuf.FloatValue nullable_float = 15; + google.protobuf.DoubleValue nullable_double = 16; + google.protobuf.BoolValue nullable_bool = 17; + google.protobuf.BytesValue nullable_bytes = 18; + + // FieldMask - specify which fields to return/update + google.protobuf.FieldMask field_mask = 19; +} + +message WellKnownResponse { + google.protobuf.Timestamp processed_at = 1; + google.protobuf.Duration elapsed_time = 2; + google.protobuf.Struct result = 3; + + // Repeated wrappers + repeated google.protobuf.StringValue string_values = 4; + repeated google.protobuf.Int32Value int_values = 5; +} + +// Message to be packed into Any +message CustomPayload { + string data = 1; + int32 version = 2; +} From ec54c47ce49f47a7c9010ff3e02f17b0cb0d3b0f Mon Sep 17 00:00:00 2001 From: mjheilmann Date: Sun, 5 Apr 2026 21:49:28 -0400 Subject: [PATCH 2/8] generate proto pb files, and start rewriting tests --- priv/protos/custom_prefix_service.proto | 2 +- test/custom_prefix_test.exs | 171 ++ test/support/greeter_server.ex | 20 - test/support/grpc_case.ex | 85 +- test/support/protos/common_types.pb.ex | 359 +++ .../protos/custom_prefix_service.pb.ex | 49 +- test/support/protos/edge_cases.pb.ex | 1958 +++++++++++++++++ ...st_service_v3.pb.ex => imports_test.pb.ex} | 756 ++++--- test/support/protos/nested_messages.pb.ex | 1777 +++++++++++++++ .../{helloworld.pb.ex => no_package.pb.ex} | 63 +- test/support/protos/package_a.pb.ex | 102 + test/support/protos/package_b.pb.ex | 174 ++ test/support/protos/proto2_features.pb.ex | 868 ++++++++ .../protos/proto2_features/pb_extension.pb.ex | 41 + test/support/protos/scalar_types.pb.ex | 644 ++++++ test/support/protos/streaming_service.pb.ex | 523 +++++ test/support/protos/well_known_types.pb.ex | 539 +++++ 17 files changed, 7699 insertions(+), 432 deletions(-) create mode 100644 test/custom_prefix_test.exs delete mode 100644 test/support/greeter_server.ex create mode 100644 test/support/protos/common_types.pb.ex create mode 100644 test/support/protos/edge_cases.pb.ex rename test/support/protos/{test_service_v3.pb.ex => imports_test.pb.ex} (58%) create mode 100644 test/support/protos/nested_messages.pb.ex rename test/support/protos/{helloworld.pb.ex => no_package.pb.ex} (59%) create mode 100644 test/support/protos/package_a.pb.ex create mode 100644 test/support/protos/package_b.pb.ex create mode 100644 test/support/protos/proto2_features.pb.ex create mode 100644 test/support/protos/proto2_features/pb_extension.pb.ex create mode 100644 test/support/protos/scalar_types.pb.ex create mode 100644 test/support/protos/streaming_service.pb.ex create mode 100644 test/support/protos/well_known_types.pb.ex diff --git a/priv/protos/custom_prefix_service.proto b/priv/protos/custom_prefix_service.proto index ccc09f2..ea34505 100644 --- a/priv/protos/custom_prefix_service.proto +++ b/priv/protos/custom_prefix_service.proto @@ -4,7 +4,7 @@ package custom_prefix; // This proto demonstrates Elixir-specific custom module prefix option import "elixirpb.proto"; -option (elixirpb.file).module_prefix = "CustomPrefix"; +option (elixirpb.file).module_prefix = "CustomizedPrefix"; // Simple service to test custom module prefix generation service PrefixService { diff --git a/test/custom_prefix_test.exs b/test/custom_prefix_test.exs new file mode 100644 index 0000000..9f5cd25 --- /dev/null +++ b/test/custom_prefix_test.exs @@ -0,0 +1,171 @@ +defmodule GrpcReflection.CustomPrefixServiceTest do + @moduledoc """ + Test suite covering types, cases and services from custom_prefix_service.proto + """ + + use GrpcCase, service: CustomizedPrefix.PrefixService.Service + + describe "v1" do + setup :stub_v1_server + + test "unsupported call is rejected", ctx do + message = {:file_containing_extension, %Grpc.Reflection.V1.ExtensionRequest{}} + assert {:error, _} = run_request(message, ctx) + end + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["custom_prefix.PrefixService"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "custom_prefix.PrefixService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "custom_prefix", + dependency: ["custom_prefix.EchoRequest.proto", "custom_prefix.EchoResponse.proto"], + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "PrefixService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "Echo", + input_type: ".custom_prefix.EchoRequest", + output_type: ".custom_prefix.EchoResponse" + } + ] + } + ] + } = response + end + + test "should return the service when requesting a method on the service", ctx do + message = {:file_containing_symbol, "custom_prefix.PrefixService.Echo"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "PrefixService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "Echo" + } + ] + } + ] + } = response + end + + test "should resolve a type", ctx do + message = {:file_containing_symbol, ".custom_prefix.EchoRequest"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + message_type: [ + %Google.Protobuf.DescriptorProto{ + name: "EchoRequest", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "message" + } + ] + } + ] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + call: "custom_prefix.PrefixService.Echo", + service: "custom_prefix.PrefixService" + ] + end + end + + describe "v1alpha" do + setup :stub_v1alpha_server + + test "unsupported call is rejected", ctx do + message = {:file_containing_extension, %Grpc.Reflection.V1alpha.ExtensionRequest{}} + assert {:error, _} = run_request(message, ctx) + end + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["custom_prefix.PrefixService"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "custom_prefix.PrefixService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "custom_prefix", + dependency: ["custom_prefix.EchoRequest.proto", "custom_prefix.EchoResponse.proto"], + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "PrefixService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "Echo", + input_type: ".custom_prefix.EchoRequest", + output_type: ".custom_prefix.EchoResponse" + } + ] + } + ] + } = response + end + + test "should return the service when requesting a method on the service", ctx do + message = {:file_containing_symbol, "custom_prefix.PrefixService.Echo"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "PrefixService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "Echo" + } + ] + } + ] + } = response + end + + test "should resolve a type", ctx do + message = {:file_containing_symbol, ".custom_prefix.EchoRequest"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + message_type: [ + %Google.Protobuf.DescriptorProto{ + name: "EchoRequest", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "message" + } + ] + } + ] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + call: "custom_prefix.PrefixService.Echo", + service: "custom_prefix.PrefixService" + ] + end + end +end diff --git a/test/support/greeter_server.ex b/test/support/greeter_server.ex deleted file mode 100644 index a115d83..0000000 --- a/test/support/greeter_server.ex +++ /dev/null @@ -1,20 +0,0 @@ -defmodule Helloworld.Greeter.Server do - use GRPC.Server, service: Helloworld.Greeter.Service - - @spec say_hello(Helloworld.HelloRequest.t(), GRPC.Server.Stream.t()) :: - Helloworld.HelloReply.t() - def say_hello(request, _stream) do - %Helloworld.HelloReply{ - message: "Hello #{request.name}", - today: today() - } - end - - defp today do - nanos_epoch = System.system_time() |> System.convert_time_unit(:native, :nanosecond) - seconds = div(nanos_epoch, 1_000_000_000) - nanos = nanos_epoch - seconds * 1_000_000_000 - - %Google.Protobuf.Timestamp{seconds: seconds, nanos: nanos} - end -end diff --git a/test/support/grpc_case.ex b/test/support/grpc_case.ex index 70f171a..c6baf90 100644 --- a/test/support/grpc_case.ex +++ b/test/support/grpc_case.ex @@ -1,9 +1,78 @@ defmodule GrpcCase do use ExUnit.CaseTemplate - using do + using(service: service) do quote do import GrpcCase + + setup_all do + Protobuf.load_extensions() + end + + defmodule V1Server do + use GrpcReflection.Server, version: :v1, services: [unquote(service)] + end + + defmodule V1Server.Stub do + use GRPC.Stub, service: Grpc.Reflection.V1.ServerReflection.Service + end + + defmodule V1AlphaServer do + use GrpcReflection.Server, version: :v1alpha, services: [unquote(service)] + end + + defmodule V1AlphaServer.Stub do + use GRPC.Stub, service: Grpc.Reflection.V1alpha.ServerReflection.Service + end + + defmodule Endpoint do + use GRPC.Endpoint + + run(V1Server) + run(V1AlphaServer) + end + + defp stub_v1_server(_) do + # %{endpoint: Endpoint, stub: V1Server.Stub} + + {:ok, _pid, port} = GRPC.Server.start_endpoint(Endpoint, 0) + on_exit(fn -> :ok = GRPC.Server.stop_endpoint(Endpoint, []) end) + start_supervised({GRPC.Client.Supervisor, []}) + + host = "localhost:#{port}" + {:ok, channel} = GRPC.Stub.connect(host) + + req = %Grpc.Reflection.V1.ServerReflectionRequest{host: host} + + %{ + channel: channel, + req: req, + version: :v1, + host: host, + endpoint: Endpoint, + stub: V1Server.Stub + } + end + + defp stub_v1alpha_server(_) do + {:ok, _pid, port} = GRPC.Server.start_endpoint(Endpoint, 0) + on_exit(fn -> :ok = GRPC.Server.stop_endpoint(Endpoint, []) end) + start_supervised({GRPC.Client.Supervisor, []}) + + host = "localhost:#{port}" + {:ok, channel} = GRPC.Stub.connect(host) + + req = %Grpc.Reflection.V1alpha.ServerReflectionRequest{host: host} + + %{ + channel: channel, + req: req, + version: :v1alpha, + host: host, + endpoint: Endpoint, + stub: V1AlphaServer.Stub + } + end end end @@ -14,20 +83,6 @@ defmodule GrpcCase do :ok end - def assert_response(%{service: [service]}) do - assert service.name == "Greeter" - assert %{method: [method]} = service - assert method.name == "SayHello" - assert method.input_type == ".helloworld.HelloRequest" - assert method.output_type == ".helloworld.HelloReply" - end - - def assert_response(%{message_type: [%{name: "HelloRequest"} = type]}) do - assert %{field: [field]} = type - assert field.name == "name" - assert field.type == :TYPE_STRING - end - def run_request(message_request, ctx) do stream = ctx.stub.server_reflection_info(ctx.channel) request = %{ctx.req | message_request: message_request} diff --git a/test/support/protos/common_types.pb.ex b/test/support/protos/common_types.pb.ex new file mode 100644 index 0000000..4a30dd4 --- /dev/null +++ b/test/support/protos/common_types.pb.ex @@ -0,0 +1,359 @@ +defmodule Common.Priority do + @moduledoc false + + use Protobuf, + enum: true, + full_name: "common.Priority", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.EnumDescriptorProto{ + name: "Priority", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "PRIORITY_UNSPECIFIED", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "LOW", + number: 1, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "MEDIUM", + number: 2, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "HIGH", + number: 3, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "CRITICAL", + number: 4, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :PRIORITY_UNSPECIFIED, 0 + field :LOW, 1 + field :MEDIUM, 2 + field :HIGH, 3 + field :CRITICAL, 4 +end + +defmodule Common.Address do + @moduledoc false + + use Protobuf, full_name: "common.Address", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "Address", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "street", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "street", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "city", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "city", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "state", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "state", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "postal_code", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "postalCode", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "country", + extendee: nil, + number: 5, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "country", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :street, 1, type: :string + field :city, 2, type: :string + field :state, 3, type: :string + field :postal_code, 4, type: :string, json_name: "postalCode" + field :country, 5, type: :string +end + +defmodule Common.Coordinates do + @moduledoc false + + use Protobuf, + full_name: "common.Coordinates", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "Coordinates", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "latitude", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_DOUBLE, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "latitude", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "longitude", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_DOUBLE, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "longitude", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "altitude", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_DOUBLE, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "altitude", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :latitude, 1, type: :double + field :longitude, 2, type: :double + field :altitude, 3, type: :double +end + +defmodule Common.Money do + @moduledoc false + + use Protobuf, full_name: "common.Money", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "Money", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "currency_code", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "currencyCode", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "units", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "units", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nanos", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nanos", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :currency_code, 1, type: :string, json_name: "currencyCode" + field :units, 2, type: :int64 + field :nanos, 3, type: :int32 +end + +defmodule Common.TimeRange do + @moduledoc false + + use Protobuf, + full_name: "common.TimeRange", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "TimeRange", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "start_time", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "startTime", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "end_time", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "endTime", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :start_time, 1, type: :int64, json_name: "startTime" + field :end_time, 2, type: :int64, json_name: "endTime" +end diff --git a/test/support/protos/custom_prefix_service.pb.ex b/test/support/protos/custom_prefix_service.pb.ex index f913d22..4ce675c 100644 --- a/test/support/protos/custom_prefix_service.pb.ex +++ b/test/support/protos/custom_prefix_service.pb.ex @@ -1,4 +1,4 @@ -defmodule HLW.Enum do +defmodule CustomizedPrefix.EchoRequest do @moduledoc false use Protobuf, @@ -48,10 +48,10 @@ defmodule HLW.TestRequest.GEntry do def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "GEntry", + name: "EchoRequest", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "key", + name: "message", extendee: nil, number: 1, label: :LABEL_OPTIONAL, @@ -347,34 +347,33 @@ defmodule HLW.Location do } end - field :latitude, 1, optional: true, type: :double - field :longitude, 2, optional: true, type: :double + field :message, 1, type: :string end -defmodule HLW.TestReply do +defmodule CustomizedPrefix.EchoResponse do @moduledoc false use Protobuf, - full_name: "testserviceV2.TestReply", + full_name: "custom_prefix.EchoResponse", protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 + syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "TestReply", + name: "EchoResponse", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "today", + name: "reply", extendee: nil, - number: 2, - label: :LABEL_REQUIRED, - type: :TYPE_MESSAGE, - type_name: ".google.protobuf.Timestamp", + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, default_value: nil, options: nil, oneof_index: nil, - json_name: "today", + json_name: "reply", proto3_optional: nil, __unknown_fields__: [] } @@ -391,23 +390,23 @@ defmodule HLW.TestReply do } end - field :today, 2, required: true, type: Google.Protobuf.Timestamp + field :reply, 1, type: :string end -defmodule HLW.TestService.Service do +defmodule CustomizedPrefix.PrefixService.Service do @moduledoc false - use GRPC.Service, name: "testserviceV2.TestService", protoc_gen_elixir_version: "0.16.0" + use GRPC.Service, name: "custom_prefix.PrefixService", protoc_gen_elixir_version: "0.16.0" def descriptor do # credo:disable-for-next-line %Google.Protobuf.ServiceDescriptorProto{ - name: "TestService", + name: "PrefixService", method: [ %Google.Protobuf.MethodDescriptorProto{ - name: "CallFunction", - input_type: ".testserviceV2.TestRequest", - output_type: ".testserviceV2.TestReply", + name: "Echo", + input_type: ".custom_prefix.EchoRequest", + output_type: ".custom_prefix.EchoResponse", options: %Google.Protobuf.MethodOptions{ deprecated: false, idempotency_level: :IDEMPOTENCY_UNKNOWN, @@ -426,11 +425,11 @@ defmodule HLW.TestService.Service do } end - rpc :CallFunction, HLW.TestRequest, HLW.TestReply + rpc :Echo, CustomizedPrefix.EchoRequest, CustomizedPrefix.EchoResponse end -defmodule HLW.TestService.Stub do +defmodule CustomizedPrefix.PrefixService.Stub do @moduledoc false - use GRPC.Stub, service: HLW.TestService.Service + use GRPC.Stub, service: CustomizedPrefix.PrefixService.Service end diff --git a/test/support/protos/edge_cases.pb.ex b/test/support/protos/edge_cases.pb.ex new file mode 100644 index 0000000..45ae88c --- /dev/null +++ b/test/support/protos/edge_cases.pb.ex @@ -0,0 +1,1958 @@ +defmodule EdgeCases.DetailedStatus do + @moduledoc false + + use Protobuf, + enum: true, + full_name: "edge_cases.DetailedStatus", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.EnumDescriptorProto{ + name: "DetailedStatus", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "DETAILED_STATUS_UNSPECIFIED", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "status_active", + number: 1, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "STATUS_INACTIVE", + number: 2, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "Status_Pending", + number: 3, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "ERROR_STATE", + number: -1, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "CRITICAL_ERROR", + number: -100, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "MAX_STATUS", + number: 2_147_483_647, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :DETAILED_STATUS_UNSPECIFIED, 0 + field :status_active, 1 + field :STATUS_INACTIVE, 2 + field :Status_Pending, 3 + field :ERROR_STATE, -1 + field :CRITICAL_ERROR, -100 + field :MAX_STATUS, 2_147_483_647 +end + +defmodule EdgeCases.EmptyMessage do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.EmptyMessage", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "EmptyMessage", + field: [], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end +end + +defmodule EdgeCases.Request do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.Request", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "Request", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "data", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "data", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :data, 1, type: :string +end + +defmodule EdgeCases.Response do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.Response", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "Response", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "result", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "result", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :result, 1, type: :string +end + +defmodule EdgeCases.SparseFieldNumbers do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.SparseFieldNumbers", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "SparseFieldNumbers", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "field_1", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field1", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_536870911", + extendee: nil, + number: 536_870_911, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field536870911", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :field_1, 1, type: :string, json_name: "field1" + field :field_536870911, 536_870_911, type: :string, json_name: "field536870911" +end + +defmodule EdgeCases.ManyFields do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.ManyFields", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "ManyFields", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "field_001", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field001", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_002", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field002", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_003", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field003", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_004", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field004", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_005", + extendee: nil, + number: 5, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field005", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_006", + extendee: nil, + number: 6, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field006", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_007", + extendee: nil, + number: 7, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field007", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_008", + extendee: nil, + number: 8, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field008", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_009", + extendee: nil, + number: 9, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field009", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_010", + extendee: nil, + number: 10, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field010", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_011", + extendee: nil, + number: 11, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field011", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_012", + extendee: nil, + number: 12, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field012", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_013", + extendee: nil, + number: 13, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field013", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_014", + extendee: nil, + number: 14, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field014", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_015", + extendee: nil, + number: 15, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field015", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_016", + extendee: nil, + number: 16, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field016", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_017", + extendee: nil, + number: 17, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field017", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_018", + extendee: nil, + number: 18, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field018", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_019", + extendee: nil, + number: 19, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field019", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_020", + extendee: nil, + number: 20, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "field020", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :field_001, 1, type: :string, json_name: "field001" + field :field_002, 2, type: :string, json_name: "field002" + field :field_003, 3, type: :string, json_name: "field003" + field :field_004, 4, type: :string, json_name: "field004" + field :field_005, 5, type: :string, json_name: "field005" + field :field_006, 6, type: :string, json_name: "field006" + field :field_007, 7, type: :string, json_name: "field007" + field :field_008, 8, type: :string, json_name: "field008" + field :field_009, 9, type: :string, json_name: "field009" + field :field_010, 10, type: :string, json_name: "field010" + field :field_011, 11, type: :string, json_name: "field011" + field :field_012, 12, type: :string, json_name: "field012" + field :field_013, 13, type: :string, json_name: "field013" + field :field_014, 14, type: :string, json_name: "field014" + field :field_015, 15, type: :string, json_name: "field015" + field :field_016, 16, type: :string, json_name: "field016" + field :field_017, 17, type: :string, json_name: "field017" + field :field_018, 18, type: :string, json_name: "field018" + field :field_019, 19, type: :string, json_name: "field019" + field :field_020, 20, type: :string, json_name: "field020" +end + +defmodule EdgeCases.MultipleOneofs do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.MultipleOneofs", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "MultipleOneofs", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "option_a1", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 0, + json_name: "optionA1", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "option_a2", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 0, + json_name: "optionA2", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "option_b1", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 1, + json_name: "optionB1", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "option_b2", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 1, + json_name: "optionB2", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "option_c1", + extendee: nil, + number: 5, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 2, + json_name: "optionC1", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "option_c2", + extendee: nil, + number: 6, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 2, + json_name: "optionC2", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "regular_field", + extendee: nil, + number: 7, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "regularField", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [ + %Google.Protobuf.OneofDescriptorProto{ + name: "first_choice", + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.OneofDescriptorProto{ + name: "second_choice", + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.OneofDescriptorProto{ + name: "third_choice", + options: nil, + __unknown_fields__: [] + } + ], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + oneof :first_choice, 0 + + oneof :second_choice, 1 + + oneof :third_choice, 2 + + field :option_a1, 1, type: :string, json_name: "optionA1", oneof: 0 + field :option_a2, 2, type: :int32, json_name: "optionA2", oneof: 0 + field :option_b1, 3, type: :string, json_name: "optionB1", oneof: 1 + field :option_b2, 4, type: :int32, json_name: "optionB2", oneof: 1 + field :option_c1, 5, type: :string, json_name: "optionC1", oneof: 2 + field :option_c2, 6, type: :int32, json_name: "optionC2", oneof: 2 + field :regular_field, 7, type: :string, json_name: "regularField" +end + +defmodule EdgeCases.NestedMaps.OuterMapEntry do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.NestedMaps.OuterMapEntry", + map: true, + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "OuterMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.InnerMap", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, type: :string + field :value, 2, type: EdgeCases.InnerMap +end + +defmodule EdgeCases.NestedMaps.IntKeyMapEntry do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.NestedMaps.IntKeyMapEntry", + map: true, + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "IntKeyMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, type: :int32 + field :value, 2, type: :string +end + +defmodule EdgeCases.NestedMaps.NumericMapEntry do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.NestedMaps.NumericMapEntry", + map: true, + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "NumericMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, type: :int64 + field :value, 2, type: :int64 +end + +defmodule EdgeCases.NestedMaps.BoolKeyMapEntry do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.NestedMaps.BoolKeyMapEntry", + map: true, + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "BoolKeyMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_BOOL, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, type: :bool + field :value, 2, type: :string +end + +defmodule EdgeCases.NestedMaps do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.NestedMaps", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "NestedMaps", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "outer_map", + extendee: nil, + number: 1, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.NestedMaps.OuterMapEntry", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "outerMap", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "int_key_map", + extendee: nil, + number: 2, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.NestedMaps.IntKeyMapEntry", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "intKeyMap", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "numeric_map", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.NestedMaps.NumericMapEntry", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "numericMap", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "bool_key_map", + extendee: nil, + number: 4, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.NestedMaps.BoolKeyMapEntry", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "boolKeyMap", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "OuterMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.InnerMap", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + }, + %Google.Protobuf.DescriptorProto{ + name: "IntKeyMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + }, + %Google.Protobuf.DescriptorProto{ + name: "NumericMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + }, + %Google.Protobuf.DescriptorProto{ + name: "BoolKeyMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_BOOL, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :outer_map, 1, + repeated: true, + type: EdgeCases.NestedMaps.OuterMapEntry, + json_name: "outerMap", + map: true + + field :int_key_map, 2, + repeated: true, + type: EdgeCases.NestedMaps.IntKeyMapEntry, + json_name: "intKeyMap", + map: true + + field :numeric_map, 3, + repeated: true, + type: EdgeCases.NestedMaps.NumericMapEntry, + json_name: "numericMap", + map: true + + field :bool_key_map, 4, + repeated: true, + type: EdgeCases.NestedMaps.BoolKeyMapEntry, + json_name: "boolKeyMap", + map: true +end + +defmodule EdgeCases.InnerMap.DataEntry do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.InnerMap.DataEntry", + map: true, + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "DataEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, type: :string + field :value, 2, type: :string +end + +defmodule EdgeCases.InnerMap.CountsEntry do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.InnerMap.CountsEntry", + map: true, + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "CountsEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, type: :string + field :value, 2, type: :int32 +end + +defmodule EdgeCases.InnerMap do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.InnerMap", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "InnerMap", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "data", + extendee: nil, + number: 1, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.InnerMap.DataEntry", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "data", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "counts", + extendee: nil, + number: 2, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.InnerMap.CountsEntry", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "counts", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "DataEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + }, + %Google.Protobuf.DescriptorProto{ + name: "CountsEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :data, 1, repeated: true, type: EdgeCases.InnerMap.DataEntry, map: true + field :counts, 2, repeated: true, type: EdgeCases.InnerMap.CountsEntry, map: true +end + +defmodule EdgeCases.CircularA do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.CircularA", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "CircularA", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "b_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.CircularB", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "bField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "data", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "data", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :b_field, 1, type: EdgeCases.CircularB, json_name: "bField" + field :data, 2, type: :string +end + +defmodule EdgeCases.CircularB do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.CircularB", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "CircularB", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "c_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.CircularC", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "cField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "data", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "data", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :c_field, 1, type: EdgeCases.CircularC, json_name: "cField" + field :data, 2, type: :string +end + +defmodule EdgeCases.CircularC do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.CircularC", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "CircularC", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "a_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.CircularA", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "aField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "data", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "data", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :a_field, 1, type: EdgeCases.CircularA, json_name: "aField" + field :data, 2, type: :string +end + +defmodule EdgeCases.WithReservedFields do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.WithReservedFields", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "WithReservedFields", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "active_field_1", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "activeField1", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "active_field_16", + extendee: nil, + number: 16, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "activeField16", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [ + %Google.Protobuf.DescriptorProto.ReservedRange{start: 2, end: 3, __unknown_fields__: []}, + %Google.Protobuf.DescriptorProto.ReservedRange{ + start: 15, + end: 16, + __unknown_fields__: [] + }, + %Google.Protobuf.DescriptorProto.ReservedRange{start: 9, end: 12, __unknown_fields__: []}, + %Google.Protobuf.DescriptorProto.ReservedRange{ + start: 100, + end: 536_870_912, + __unknown_fields__: [] + } + ], + reserved_name: ["foo", "bar", "old_field"], + __unknown_fields__: [] + } + end + + field :active_field_1, 1, type: :string, json_name: "activeField1" + field :active_field_16, 16, type: :string, json_name: "activeField16" +end + +defmodule EdgeCases.UnicodeTest do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.UnicodeTest", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "UnicodeTest", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "rocket_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "rocketField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "pi_field", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_DOUBLE, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "piField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "greeting", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "greeting", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :rocket_field, 1, type: :string, json_name: "rocketField" + field :pi_field, 2, type: :double, json_name: "piField" + field :greeting, 3, type: :string +end + +defmodule EdgeCases.EmptyService.Service do + @moduledoc false + + use GRPC.Service, name: "edge_cases.EmptyService", protoc_gen_elixir_version: "0.16.0" + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.ServiceDescriptorProto{ + name: "EmptyService", + method: [], + options: nil, + __unknown_fields__: [] + } + end +end + +defmodule EdgeCases.EmptyService.Stub do + @moduledoc false + + use GRPC.Stub, service: EdgeCases.EmptyService.Service +end diff --git a/test/support/protos/test_service_v3.pb.ex b/test/support/protos/imports_test.pb.ex similarity index 58% rename from test/support/protos/test_service_v3.pb.ex rename to test/support/protos/imports_test.pb.ex index 60464fc..ccee1da 100644 --- a/test/support/protos/test_service_v3.pb.ex +++ b/test/support/protos/imports_test.pb.ex @@ -1,57 +1,18 @@ -defmodule TestserviceV3.Enum do +defmodule ImportsTest.UserRequest do @moduledoc false use Protobuf, - enum: true, - full_name: "testserviceV3.Enum", - protoc_gen_elixir_version: "0.16.0", - syntax: :proto3 - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.EnumDescriptorProto{ - name: "Enum", - value: [ - %Google.Protobuf.EnumValueDescriptorProto{ - name: "A", - number: 0, - options: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.EnumValueDescriptorProto{ - name: "B", - number: 1, - options: nil, - __unknown_fields__: [] - } - ], - options: nil, - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - end - - field :A, 0 - field :B, 1 -end - -defmodule TestserviceV3.TestRequest.GEntry do - @moduledoc false - - use Protobuf, - full_name: "testserviceV3.TestRequest.GEntry", - map: true, + full_name: "imports_test.UserRequest", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "GEntry", + name: "UserRequest", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "key", + name: "name", extendee: nil, number: 1, label: :LABEL_OPTIONAL, @@ -60,21 +21,63 @@ defmodule TestserviceV3.TestRequest.GEntry do default_value: nil, options: nil, oneof_index: nil, - json_name: "key", + json_name: "name", proto3_optional: nil, __unknown_fields__: [] }, %Google.Protobuf.FieldDescriptorProto{ - name: "value", + name: "email", extendee: nil, number: 2, label: :LABEL_OPTIONAL, - type: :TYPE_INT32, + type: :TYPE_STRING, type_name: nil, default_value: nil, options: nil, oneof_index: nil, - json_name: "value", + json_name: "email", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "address", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".common.Address", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "address", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "location", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".common.Coordinates", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "location", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "registered_at", + extendee: nil, + number: 5, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Timestamp", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "registeredAt", proto3_optional: nil, __unknown_fields__: [] } @@ -83,17 +86,7 @@ defmodule TestserviceV3.TestRequest.GEntry do enum_type: [], extension_range: [], extension: [], - options: %Google.Protobuf.MessageOptions{ - message_set_wire_format: false, - no_standard_descriptor_accessor: false, - deprecated: false, - map_entry: true, - deprecated_legacy_json_field_conflicts: nil, - features: nil, - uninterpreted_option: [], - __pb_extensions__: %{}, - __unknown_fields__: [] - }, + options: nil, oneof_decl: [], reserved_range: [], reserved_name: [], @@ -101,48 +94,65 @@ defmodule TestserviceV3.TestRequest.GEntry do } end - field :key, 1, type: :string - field :value, 2, type: :int32 + field :name, 1, type: :string + field :email, 2, type: :string + field :address, 3, type: Common.Address + field :location, 4, type: Common.Coordinates + field :registered_at, 5, type: Google.Protobuf.Timestamp, json_name: "registeredAt" end -defmodule TestserviceV3.TestRequest.Payload.Location do +defmodule ImportsTest.UserResponse.Profile do @moduledoc false use Protobuf, - full_name: "testserviceV3.TestRequest.Payload.Location", + full_name: "imports_test.UserResponse.Profile", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "Location", + name: "Profile", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "latitude", + name: "billing_address", extendee: nil, number: 1, label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - type_name: nil, + type: :TYPE_MESSAGE, + type_name: ".common.Address", default_value: nil, options: nil, oneof_index: nil, - json_name: "latitude", + json_name: "billingAddress", proto3_optional: nil, __unknown_fields__: [] }, %Google.Protobuf.FieldDescriptorProto{ - name: "longitude", + name: "shipping_address", extendee: nil, number: 2, label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - type_name: nil, + type: :TYPE_MESSAGE, + type_name: ".common.Address", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "shippingAddress", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "recent_locations", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".common.Coordinates", default_value: nil, options: nil, oneof_index: nil, - json_name: "longitude", + json_name: "recentLocations", proto3_optional: nil, __unknown_fields__: [] } @@ -159,95 +169,128 @@ defmodule TestserviceV3.TestRequest.Payload.Location do } end - field :latitude, 1, type: :double - field :longitude, 2, type: :double + field :billing_address, 1, type: Common.Address, json_name: "billingAddress" + field :shipping_address, 2, type: Common.Address, json_name: "shippingAddress" + + field :recent_locations, 3, + repeated: true, + type: Common.Coordinates, + json_name: "recentLocations" end -defmodule TestserviceV3.TestRequest.Payload do +defmodule ImportsTest.UserResponse do @moduledoc false use Protobuf, - full_name: "testserviceV3.TestRequest.Payload", + full_name: "imports_test.UserResponse", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "Payload", + name: "UserResponse", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "data", + name: "user_id", extendee: nil, number: 1, label: :LABEL_OPTIONAL, - type: :TYPE_MESSAGE, - type_name: ".google.protobuf.StringValue", + type: :TYPE_STRING, + type_name: nil, default_value: nil, options: nil, oneof_index: nil, - json_name: "data", + json_name: "userId", proto3_optional: nil, __unknown_fields__: [] }, %Google.Protobuf.FieldDescriptorProto{ - name: "location", + name: "priority", extendee: nil, number: 2, label: :LABEL_OPTIONAL, - type: :TYPE_MESSAGE, - type_name: ".testserviceV3.TestRequest.Payload.Location", + type: :TYPE_ENUM, + type_name: ".common.Priority", default_value: nil, options: nil, oneof_index: nil, - json_name: "location", + json_name: "priority", proto3_optional: nil, __unknown_fields__: [] }, %Google.Protobuf.FieldDescriptorProto{ - name: "token", + name: "created_at", extendee: nil, number: 3, label: :LABEL_OPTIONAL, type: :TYPE_MESSAGE, - type_name: ".testserviceV3.TestRequest.Token", + type_name: ".google.protobuf.Timestamp", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "createdAt", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "profile", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".imports_test.UserResponse.Profile", default_value: nil, options: nil, oneof_index: nil, - json_name: "token", + json_name: "profile", proto3_optional: nil, __unknown_fields__: [] } ], nested_type: [ %Google.Protobuf.DescriptorProto{ - name: "Location", + name: "Profile", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "latitude", + name: "billing_address", extendee: nil, number: 1, label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - type_name: nil, + type: :TYPE_MESSAGE, + type_name: ".common.Address", default_value: nil, options: nil, oneof_index: nil, - json_name: "latitude", + json_name: "billingAddress", proto3_optional: nil, __unknown_fields__: [] }, %Google.Protobuf.FieldDescriptorProto{ - name: "longitude", + name: "shipping_address", extendee: nil, number: 2, label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - type_name: nil, + type: :TYPE_MESSAGE, + type_name: ".common.Address", default_value: nil, options: nil, oneof_index: nil, - json_name: "longitude", + json_name: "shippingAddress", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "recent_locations", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".common.Coordinates", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "recentLocations", proto3_optional: nil, __unknown_fields__: [] } @@ -274,26 +317,27 @@ defmodule TestserviceV3.TestRequest.Payload do } end - field :data, 1, type: Google.Protobuf.StringValue - field :location, 2, type: TestserviceV3.TestRequest.Payload.Location - field :token, 3, type: TestserviceV3.TestRequest.Token + field :user_id, 1, type: :string, json_name: "userId" + field :priority, 2, type: Common.Priority, enum: true + field :created_at, 3, type: Google.Protobuf.Timestamp, json_name: "createdAt" + field :profile, 4, type: ImportsTest.UserResponse.Profile end -defmodule TestserviceV3.TestRequest.Token do +defmodule ImportsTest.LocationUpdate do @moduledoc false use Protobuf, - full_name: "testserviceV3.TestRequest.Token", + full_name: "imports_test.LocationUpdate", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "Token", + name: "LocationUpdate", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "vaule", + name: "user_id", extendee: nil, number: 1, label: :LABEL_OPTIONAL, @@ -302,7 +346,35 @@ defmodule TestserviceV3.TestRequest.Token do default_value: nil, options: nil, oneof_index: nil, - json_name: "vaule", + json_name: "userId", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "new_location", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".common.Coordinates", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "newLocation", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "timestamp", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Timestamp", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "timestamp", proto3_optional: nil, __unknown_fields__: [] } @@ -319,24 +391,27 @@ defmodule TestserviceV3.TestRequest.Token do } end - field :vaule, 1, type: :string + field :user_id, 1, type: :string, json_name: "userId" + field :new_location, 2, type: Common.Coordinates, json_name: "newLocation" + field :timestamp, 3, type: Google.Protobuf.Timestamp end -defmodule TestserviceV3.TestRequest do +defmodule ImportsTest.LocationResponse.VisitHistoryEntry do @moduledoc false use Protobuf, - full_name: "testserviceV3.TestRequest", + full_name: "imports_test.LocationResponse.VisitHistoryEntry", + map: true, protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "TestRequest", + name: "VisitHistoryEntry", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "name", + name: "key", extendee: nil, number: 1, label: :LABEL_OPTIONAL, @@ -345,98 +420,110 @@ defmodule TestserviceV3.TestRequest do default_value: nil, options: nil, oneof_index: nil, - json_name: "name", + json_name: "key", proto3_optional: nil, __unknown_fields__: [] }, %Google.Protobuf.FieldDescriptorProto{ - name: "enum", + name: "value", extendee: nil, number: 2, label: :LABEL_OPTIONAL, - type: :TYPE_ENUM, - type_name: ".testserviceV3.Enum", + type: :TYPE_MESSAGE, + type_name: ".common.TimeRange", default_value: nil, options: nil, oneof_index: nil, - json_name: "enum", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "label", - extendee: nil, - number: 3, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: 0, - json_name: "label", + json_name: "value", proto3_optional: nil, __unknown_fields__: [] - }, + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, type: :string + field :value, 2, type: Common.TimeRange +end + +defmodule ImportsTest.LocationResponse do + @moduledoc false + + use Protobuf, + full_name: "imports_test.LocationResponse", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "LocationResponse", + field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "value", + name: "success", extendee: nil, - number: 4, + number: 1, label: :LABEL_OPTIONAL, - type: :TYPE_INT32, + type: :TYPE_BOOL, type_name: nil, default_value: nil, options: nil, - oneof_index: 0, - json_name: "value", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "g", - extendee: nil, - number: 5, - label: :LABEL_REPEATED, - type: :TYPE_MESSAGE, - type_name: ".testserviceV3.TestRequest.GEntry", - default_value: nil, - options: nil, oneof_index: nil, - json_name: "g", + json_name: "success", proto3_optional: nil, __unknown_fields__: [] }, %Google.Protobuf.FieldDescriptorProto{ - name: "instrument", + name: "confirmed_location", extendee: nil, - number: 6, + number: 2, label: :LABEL_OPTIONAL, type: :TYPE_MESSAGE, - type_name: ".google.protobuf.Any", + type_name: ".common.Coordinates", default_value: nil, options: nil, oneof_index: nil, - json_name: "instrument", + json_name: "confirmedLocation", proto3_optional: nil, __unknown_fields__: [] }, %Google.Protobuf.FieldDescriptorProto{ - name: "payload", + name: "visit_history", extendee: nil, - number: 7, - label: :LABEL_OPTIONAL, + number: 3, + label: :LABEL_REPEATED, type: :TYPE_MESSAGE, - type_name: ".testserviceV3.TestRequest.Payload", + type_name: ".imports_test.LocationResponse.VisitHistoryEntry", default_value: nil, options: nil, oneof_index: nil, - json_name: "payload", + json_name: "visitHistory", proto3_optional: nil, __unknown_fields__: [] } ], nested_type: [ %Google.Protobuf.DescriptorProto{ - name: "GEntry", + name: "VisitHistoryEntry", field: [ %Google.Protobuf.FieldDescriptorProto{ name: "key", @@ -457,8 +544,8 @@ defmodule TestserviceV3.TestRequest do extendee: nil, number: 2, label: :LABEL_OPTIONAL, - type: :TYPE_INT32, - type_name: nil, + type: :TYPE_MESSAGE, + type_name: ".common.TimeRange", default_value: nil, options: nil, oneof_index: nil, @@ -486,220 +573,208 @@ defmodule TestserviceV3.TestRequest do reserved_range: [], reserved_name: [], __unknown_fields__: [] - }, - %Google.Protobuf.DescriptorProto{ - name: "Payload", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "data", - extendee: nil, - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_MESSAGE, - type_name: ".google.protobuf.StringValue", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "data", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "location", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_MESSAGE, - type_name: ".testserviceV3.TestRequest.Payload.Location", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "location", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "token", - extendee: nil, - number: 3, - label: :LABEL_OPTIONAL, - type: :TYPE_MESSAGE, - type_name: ".testserviceV3.TestRequest.Token", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "token", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [ - %Google.Protobuf.DescriptorProto{ - name: "Location", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "latitude", - extendee: nil, - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "latitude", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "longitude", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "longitude", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [], - enum_type: [], - extension_range: [], - extension: [], - options: nil, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - ], - enum_type: [], - extension_range: [], - extension: [], - options: nil, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - }, - %Google.Protobuf.DescriptorProto{ - name: "Token", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "vaule", - extendee: nil, - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "vaule", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [], - enum_type: [], - extension_range: [], - extension: [], - options: nil, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] } ], enum_type: [], extension_range: [], extension: [], options: nil, - oneof_decl: [ - %Google.Protobuf.OneofDescriptorProto{ - name: "test_oneof", + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :success, 1, type: :bool + field :confirmed_location, 2, type: Common.Coordinates, json_name: "confirmedLocation" + + field :visit_history, 3, + repeated: true, + type: ImportsTest.LocationResponse.VisitHistoryEntry, + json_name: "visitHistory", + map: true +end + +defmodule ImportsTest.BulkOperation.TaskPrioritiesEntry do + @moduledoc false + + use Protobuf, + full_name: "imports_test.BulkOperation.TaskPrioritiesEntry", + map: true, + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "TaskPrioritiesEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_ENUM, + type_name: ".common.Priority", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, __unknown_fields__: [] } ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], reserved_range: [], reserved_name: [], __unknown_fields__: [] } end - oneof :test_oneof, 0 - - field :name, 1, type: :string - field :enum, 2, type: TestserviceV3.Enum, enum: true - field :label, 3, type: :string, oneof: 0 - field :value, 4, type: :int32, oneof: 0 - field :g, 5, repeated: true, type: TestserviceV3.TestRequest.GEntry, map: true - field :instrument, 6, type: Google.Protobuf.Any - field :payload, 7, type: TestserviceV3.TestRequest.Payload + field :key, 1, type: :string + field :value, 2, type: Common.Priority, enum: true end -defmodule TestserviceV3.TestReply do +defmodule ImportsTest.BulkOperation do @moduledoc false use Protobuf, - full_name: "testserviceV3.TestReply", + full_name: "imports_test.BulkOperation", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "TestReply", + name: "BulkOperation", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "today", + name: "addresses", extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, + number: 1, + label: :LABEL_REPEATED, type: :TYPE_MESSAGE, - type_name: ".google.protobuf.Timestamp", + type_name: ".common.Address", default_value: nil, options: nil, oneof_index: nil, - json_name: "today", + json_name: "addresses", proto3_optional: nil, __unknown_fields__: [] }, %Google.Protobuf.FieldDescriptorProto{ - name: "ext_1", + name: "transactions", extendee: nil, - number: 3, - label: :LABEL_OPTIONAL, + number: 2, + label: :LABEL_REPEATED, type: :TYPE_MESSAGE, - type_name: ".google.protobuf.StringValue", + type_name: ".common.Money", default_value: nil, options: nil, oneof_index: nil, - json_name: "ext1", + json_name: "transactions", proto3_optional: nil, __unknown_fields__: [] }, %Google.Protobuf.FieldDescriptorProto{ - name: "ext_2", + name: "task_priorities", extendee: nil, - number: 4, - label: :LABEL_OPTIONAL, + number: 3, + label: :LABEL_REPEATED, type: :TYPE_MESSAGE, - type_name: ".google.protobuf.StringValue", + type_name: ".imports_test.BulkOperation.TaskPrioritiesEntry", default_value: nil, options: nil, oneof_index: nil, - json_name: "ext2", + json_name: "taskPriorities", proto3_optional: nil, __unknown_fields__: [] } ], - nested_type: [], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "TaskPrioritiesEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_ENUM, + type_name: ".common.Priority", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], enum_type: [], extension_range: [], extension: [], @@ -711,25 +786,46 @@ defmodule TestserviceV3.TestReply do } end - field :today, 2, type: Google.Protobuf.Timestamp - field :ext_1, 3, type: Google.Protobuf.StringValue, json_name: "ext1" - field :ext_2, 4, type: Google.Protobuf.StringValue, json_name: "ext2" + field :addresses, 1, repeated: true, type: Common.Address + field :transactions, 2, repeated: true, type: Common.Money + + field :task_priorities, 3, + repeated: true, + type: ImportsTest.BulkOperation.TaskPrioritiesEntry, + json_name: "taskPriorities", + map: true end -defmodule TestserviceV3.TestService.Service do +defmodule ImportsTest.ImportTestService.Service do @moduledoc false - use GRPC.Service, name: "testserviceV3.TestService", protoc_gen_elixir_version: "0.16.0" + use GRPC.Service, name: "imports_test.ImportTestService", protoc_gen_elixir_version: "0.16.0" def descriptor do # credo:disable-for-next-line %Google.Protobuf.ServiceDescriptorProto{ - name: "TestService", + name: "ImportTestService", method: [ %Google.Protobuf.MethodDescriptorProto{ - name: "CallFunction", - input_type: ".testserviceV3.TestRequest", - output_type: ".testserviceV3.TestReply", + name: "CreateUser", + input_type: ".imports_test.UserRequest", + output_type: ".imports_test.UserResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "UpdateLocation", + input_type: ".imports_test.LocationUpdate", + output_type: ".imports_test.LocationResponse", options: %Google.Protobuf.MethodOptions{ deprecated: false, idempotency_level: :IDEMPOTENCY_UNKNOWN, @@ -748,11 +844,13 @@ defmodule TestserviceV3.TestService.Service do } end - rpc :CallFunction, TestserviceV3.TestRequest, TestserviceV3.TestReply + rpc :CreateUser, ImportsTest.UserRequest, ImportsTest.UserResponse + + rpc :UpdateLocation, ImportsTest.LocationUpdate, ImportsTest.LocationResponse end -defmodule TestserviceV3.TestService.Stub do +defmodule ImportsTest.ImportTestService.Stub do @moduledoc false - use GRPC.Stub, service: TestserviceV3.TestService.Service + use GRPC.Stub, service: ImportsTest.ImportTestService.Service end diff --git a/test/support/protos/nested_messages.pb.ex b/test/support/protos/nested_messages.pb.ex new file mode 100644 index 0000000..2de8fa6 --- /dev/null +++ b/test/support/protos/nested_messages.pb.ex @@ -0,0 +1,1777 @@ +defmodule Nested.ComplexNested.Status do + @moduledoc false + + use Protobuf, + enum: true, + full_name: "nested.ComplexNested.Status", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.EnumDescriptorProto{ + name: "Status", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "UNKNOWN", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "ACTIVE", + number: 1, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "INACTIVE", + number: 2, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :UNKNOWN, 0 + field :ACTIVE, 1 + field :INACTIVE, 2 +end + +defmodule Nested.ComplexNested.Node.NodeType do + @moduledoc false + + use Protobuf, + enum: true, + full_name: "nested.ComplexNested.Node.NodeType", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.EnumDescriptorProto{ + name: "NodeType", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "LEAF", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "BRANCH", + number: 1, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "ROOT", + number: 2, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :LEAF, 0 + field :BRANCH, 1 + field :ROOT, 2 +end + +defmodule Nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage.VeryDeepMessage do + @moduledoc false + + use Protobuf, + full_name: "nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage.VeryDeepMessage", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "VeryDeepMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "very_deep_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "veryDeepField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "values", + extendee: nil, + number: 2, + label: :LABEL_REPEATED, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "values", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :very_deep_field, 1, type: :string, json_name: "veryDeepField" + field :values, 2, repeated: true, type: :int32 +end + +defmodule Nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage do + @moduledoc false + + use Protobuf, + full_name: "nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "DeepMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "deep_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "deepField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "very_deep", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: + ".nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage.VeryDeepMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "veryDeep", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "VeryDeepMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "very_deep_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "veryDeepField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "values", + extendee: nil, + number: 2, + label: :LABEL_REPEATED, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "values", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :deep_field, 1, type: :string, json_name: "deepField" + + field :very_deep, 2, + type: Nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage.VeryDeepMessage, + json_name: "veryDeep" +end + +defmodule Nested.OuterMessage.MiddleMessage.InnerMessage do + @moduledoc false + + use Protobuf, + full_name: "nested.OuterMessage.MiddleMessage.InnerMessage", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "InnerMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "inner_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "innerField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "deep", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "deep", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "DeepMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "deep_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "deepField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "very_deep", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: + ".nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage.VeryDeepMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "veryDeep", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "VeryDeepMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "very_deep_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "veryDeepField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "values", + extendee: nil, + number: 2, + label: :LABEL_REPEATED, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "values", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :inner_field, 1, type: :string, json_name: "innerField" + field :deep, 2, type: Nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage +end + +defmodule Nested.OuterMessage.MiddleMessage do + @moduledoc false + + use Protobuf, + full_name: "nested.OuterMessage.MiddleMessage", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "MiddleMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "middle_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "middleField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "inner", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage.InnerMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "inner", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "inner_list", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage.InnerMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "innerList", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "InnerMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "inner_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "innerField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "deep", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "deep", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "DeepMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "deep_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "deepField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "very_deep", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: + ".nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage.VeryDeepMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "veryDeep", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "VeryDeepMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "very_deep_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "veryDeepField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "values", + extendee: nil, + number: 2, + label: :LABEL_REPEATED, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "values", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :middle_field, 1, type: :string, json_name: "middleField" + field :inner, 2, type: Nested.OuterMessage.MiddleMessage.InnerMessage + + field :inner_list, 3, + repeated: true, + type: Nested.OuterMessage.MiddleMessage.InnerMessage, + json_name: "innerList" +end + +defmodule Nested.OuterMessage.NestedMapEntry do + @moduledoc false + + use Protobuf, + full_name: "nested.OuterMessage.NestedMapEntry", + map: true, + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "NestedMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, type: :string + field :value, 2, type: Nested.OuterMessage.MiddleMessage +end + +defmodule Nested.OuterMessage do + @moduledoc false + + use Protobuf, + full_name: "nested.OuterMessage", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "OuterMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "outer_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "outerField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "middle", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "middle", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "middle_list", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "middleList", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nested_map", + extendee: nil, + number: 4, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.NestedMapEntry", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nestedMap", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "option_a", + extendee: nil, + number: 5, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage", + default_value: nil, + options: nil, + oneof_index: 0, + json_name: "optionA", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "option_b", + extendee: nil, + number: 6, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage.InnerMessage", + default_value: nil, + options: nil, + oneof_index: 0, + json_name: "optionB", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "simple_option", + extendee: nil, + number: 7, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 0, + json_name: "simpleOption", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "MiddleMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "middle_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "middleField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "inner", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage.InnerMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "inner", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "inner_list", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage.InnerMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "innerList", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "InnerMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "inner_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "innerField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "deep", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "deep", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "DeepMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "deep_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "deepField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "very_deep", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: + ".nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage.VeryDeepMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "veryDeep", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "VeryDeepMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "very_deep_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "veryDeepField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "values", + extendee: nil, + number: 2, + label: :LABEL_REPEATED, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "values", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + }, + %Google.Protobuf.DescriptorProto{ + name: "NestedMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [ + %Google.Protobuf.OneofDescriptorProto{ + name: "nested_oneof", + options: nil, + __unknown_fields__: [] + } + ], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + oneof :nested_oneof, 0 + + field :outer_field, 1, type: :string, json_name: "outerField" + field :middle, 2, type: Nested.OuterMessage.MiddleMessage + + field :middle_list, 3, + repeated: true, + type: Nested.OuterMessage.MiddleMessage, + json_name: "middleList" + + field :nested_map, 4, + repeated: true, + type: Nested.OuterMessage.NestedMapEntry, + json_name: "nestedMap", + map: true + + field :option_a, 5, type: Nested.OuterMessage.MiddleMessage, json_name: "optionA", oneof: 0 + + field :option_b, 6, + type: Nested.OuterMessage.MiddleMessage.InnerMessage, + json_name: "optionB", + oneof: 0 + + field :simple_option, 7, type: :string, json_name: "simpleOption", oneof: 0 +end + +defmodule Nested.OuterResponse do + @moduledoc false + + use Protobuf, + full_name: "nested.OuterResponse", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "OuterResponse", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "deep_result", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "deepResult", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "middle_results", + extendee: nil, + number: 2, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".nested.OuterMessage.MiddleMessage", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "middleResults", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :deep_result, 1, + type: Nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage, + json_name: "deepResult" + + field :middle_results, 2, + repeated: true, + type: Nested.OuterMessage.MiddleMessage, + json_name: "middleResults" +end + +defmodule Nested.ComplexNested.Node.NamedChildrenEntry do + @moduledoc false + + use Protobuf, + full_name: "nested.ComplexNested.Node.NamedChildrenEntry", + map: true, + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "NamedChildrenEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, type: :string + field :value, 2, type: Nested.ComplexNested.Node +end + +defmodule Nested.ComplexNested.Node do + @moduledoc false + + use Protobuf, + full_name: "nested.ComplexNested.Node", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "Node", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "id", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "id", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "type", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_ENUM, + type_name: ".nested.ComplexNested.Node.NodeType", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "type", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "children", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "children", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "parent", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "parent", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "named_children", + extendee: nil, + number: 5, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node.NamedChildrenEntry", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "namedChildren", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "NamedChildrenEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [ + %Google.Protobuf.EnumDescriptorProto{ + name: "NodeType", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "LEAF", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "BRANCH", + number: 1, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "ROOT", + number: 2, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :id, 1, type: :string + field :type, 2, type: Nested.ComplexNested.Node.NodeType, enum: true + field :children, 3, repeated: true, type: Nested.ComplexNested.Node + field :parent, 4, type: Nested.ComplexNested.Node + + field :named_children, 5, + repeated: true, + type: Nested.ComplexNested.Node.NamedChildrenEntry, + json_name: "namedChildren", + map: true +end + +defmodule Nested.ComplexNested do + @moduledoc false + + use Protobuf, + full_name: "nested.ComplexNested", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "ComplexNested", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "status", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_ENUM, + type_name: ".nested.ComplexNested.Status", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "status", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "root", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "root", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "all_nodes", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "allNodes", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "Node", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "id", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "id", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "type", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_ENUM, + type_name: ".nested.ComplexNested.Node.NodeType", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "type", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "children", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "children", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "parent", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "parent", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "named_children", + extendee: nil, + number: 5, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node.NamedChildrenEntry", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "namedChildren", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "NamedChildrenEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".nested.ComplexNested.Node", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [ + %Google.Protobuf.EnumDescriptorProto{ + name: "NodeType", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "LEAF", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "BRANCH", + number: 1, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "ROOT", + number: 2, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [ + %Google.Protobuf.EnumDescriptorProto{ + name: "Status", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "UNKNOWN", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "ACTIVE", + number: 1, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "INACTIVE", + number: 2, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :status, 1, type: Nested.ComplexNested.Status, enum: true + field :root, 2, type: Nested.ComplexNested.Node + field :all_nodes, 3, repeated: true, type: Nested.ComplexNested.Node, json_name: "allNodes" +end + +defmodule Nested.NestedService.Service do + @moduledoc false + + use GRPC.Service, name: "nested.NestedService", protoc_gen_elixir_version: "0.16.0" + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.ServiceDescriptorProto{ + name: "NestedService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessNested", + input_type: ".nested.OuterMessage", + output_type: ".nested.OuterResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + } + ], + options: nil, + __unknown_fields__: [] + } + end + + rpc :ProcessNested, Nested.OuterMessage, Nested.OuterResponse +end + +defmodule Nested.NestedService.Stub do + @moduledoc false + + use GRPC.Stub, service: Nested.NestedService.Service +end + +defmodule Nested.AnotherNestedService.Service do + @moduledoc false + + use GRPC.Service, name: "nested.AnotherNestedService", protoc_gen_elixir_version: "0.16.0" + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.ServiceDescriptorProto{ + name: "AnotherNestedService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessOuter", + input_type: ".nested.OuterMessage", + output_type: ".nested.OuterResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessMiddle", + input_type: ".nested.OuterMessage.MiddleMessage", + output_type: ".nested.OuterMessage.MiddleMessage", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessInner", + input_type: ".nested.OuterMessage.MiddleMessage.InnerMessage", + output_type: ".nested.OuterMessage.MiddleMessage.InnerMessage", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + } + ], + options: nil, + __unknown_fields__: [] + } + end + + rpc :ProcessOuter, Nested.OuterMessage, Nested.OuterResponse + + rpc :ProcessMiddle, Nested.OuterMessage.MiddleMessage, Nested.OuterMessage.MiddleMessage + + rpc :ProcessInner, + Nested.OuterMessage.MiddleMessage.InnerMessage, + Nested.OuterMessage.MiddleMessage.InnerMessage +end + +defmodule Nested.AnotherNestedService.Stub do + @moduledoc false + + use GRPC.Stub, service: Nested.AnotherNestedService.Service +end diff --git a/test/support/protos/helloworld.pb.ex b/test/support/protos/no_package.pb.ex similarity index 59% rename from test/support/protos/helloworld.pb.ex rename to test/support/protos/no_package.pb.ex index 23fc694..d5f66bd 100644 --- a/test/support/protos/helloworld.pb.ex +++ b/test/support/protos/no_package.pb.ex @@ -1,18 +1,15 @@ -defmodule Helloworld.HelloRequest do +defmodule GlobalRequest do @moduledoc false - use Protobuf, - full_name: "helloworld.HelloRequest", - protoc_gen_elixir_version: "0.16.0", - syntax: :proto3 + use Protobuf, full_name: "GlobalRequest", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "HelloRequest", + name: "GlobalRequest", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "name", + name: "data", extendee: nil, number: 1, label: :LABEL_OPTIONAL, @@ -21,7 +18,7 @@ defmodule Helloworld.HelloRequest do default_value: nil, options: nil, oneof_index: nil, - json_name: "name", + json_name: "data", proto3_optional: nil, __unknown_fields__: [] } @@ -38,24 +35,21 @@ defmodule Helloworld.HelloRequest do } end - field :name, 1, type: :string + field :data, 1, type: :string end -defmodule Helloworld.HelloReply do +defmodule GlobalResponse do @moduledoc false - use Protobuf, - full_name: "helloworld.HelloReply", - protoc_gen_elixir_version: "0.16.0", - syntax: :proto3 + use Protobuf, full_name: "GlobalResponse", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "HelloReply", + name: "GlobalResponse", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "message", + name: "result", extendee: nil, number: 1, label: :LABEL_OPTIONAL, @@ -64,21 +58,7 @@ defmodule Helloworld.HelloReply do default_value: nil, options: nil, oneof_index: nil, - json_name: "message", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "today", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_MESSAGE, - type_name: ".google.protobuf.Timestamp", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "today", + json_name: "result", proto3_optional: nil, __unknown_fields__: [] } @@ -95,24 +75,23 @@ defmodule Helloworld.HelloReply do } end - field :message, 1, type: :string - field :today, 2, type: Google.Protobuf.Timestamp + field :result, 1, type: :string end -defmodule Helloworld.Greeter.Service do +defmodule GlobalService.Service do @moduledoc false - use GRPC.Service, name: "helloworld.Greeter", protoc_gen_elixir_version: "0.16.0" + use GRPC.Service, name: "GlobalService", protoc_gen_elixir_version: "0.16.0" def descriptor do # credo:disable-for-next-line %Google.Protobuf.ServiceDescriptorProto{ - name: "Greeter", + name: "GlobalService", method: [ %Google.Protobuf.MethodDescriptorProto{ - name: "SayHello", - input_type: ".helloworld.HelloRequest", - output_type: ".helloworld.HelloReply", + name: "GlobalMethod", + input_type: ".GlobalRequest", + output_type: ".GlobalResponse", options: %Google.Protobuf.MethodOptions{ deprecated: false, idempotency_level: :IDEMPOTENCY_UNKNOWN, @@ -131,11 +110,11 @@ defmodule Helloworld.Greeter.Service do } end - rpc :SayHello, Helloworld.HelloRequest, Helloworld.HelloReply + rpc :GlobalMethod, GlobalRequest, GlobalResponse end -defmodule Helloworld.Greeter.Stub do +defmodule GlobalService.Stub do @moduledoc false - use GRPC.Stub, service: Helloworld.Greeter.Service + use GRPC.Stub, service: GlobalService.Service end diff --git a/test/support/protos/package_a.pb.ex b/test/support/protos/package_a.pb.ex new file mode 100644 index 0000000..5dfc84b --- /dev/null +++ b/test/support/protos/package_a.pb.ex @@ -0,0 +1,102 @@ +defmodule PackageA.EnumA do + @moduledoc false + + use Protobuf, + enum: true, + full_name: "package_a.EnumA", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.EnumDescriptorProto{ + name: "EnumA", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "ENUM_A_UNSPECIFIED", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "OPTION_1", + number: 1, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "OPTION_2", + number: 2, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :ENUM_A_UNSPECIFIED, 0 + field :OPTION_1, 1 + field :OPTION_2, 2 +end + +defmodule PackageA.MessageA do + @moduledoc false + + use Protobuf, + full_name: "package_a.MessageA", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "MessageA", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "field_a", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "fieldA", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "count", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "count", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :field_a, 1, type: :string, json_name: "fieldA" + field :count, 2, type: :int32 +end diff --git a/test/support/protos/package_b.pb.ex b/test/support/protos/package_b.pb.ex new file mode 100644 index 0000000..beb8244 --- /dev/null +++ b/test/support/protos/package_b.pb.ex @@ -0,0 +1,174 @@ +defmodule PackageB.MessageB do + @moduledoc false + + use Protobuf, + full_name: "package_b.MessageB", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "MessageB", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "field_b", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "fieldB", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "message_from_a", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".package_a.MessageA", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "messageFromA", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "enum_from_a", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_ENUM, + type_name: ".package_a.EnumA", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "enumFromA", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :field_b, 1, type: :string, json_name: "fieldB" + field :message_from_a, 2, type: PackageA.MessageA, json_name: "messageFromA" + field :enum_from_a, 3, type: PackageA.EnumA, json_name: "enumFromA", enum: true +end + +defmodule PackageB.ResponseB do + @moduledoc false + + use Protobuf, + full_name: "package_b.ResponseB", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "ResponseB", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "results", + extendee: nil, + number: 1, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".package_a.MessageA", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "results", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :results, 1, repeated: true, type: PackageA.MessageA +end + +defmodule PackageB.ServiceB.Service do + @moduledoc false + + use GRPC.Service, name: "package_b.ServiceB", protoc_gen_elixir_version: "0.16.0" + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.ServiceDescriptorProto{ + name: "ServiceB", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessB", + input_type: ".package_b.MessageB", + output_type: ".package_b.ResponseB", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessA", + input_type: ".package_a.MessageA", + output_type: ".package_a.MessageA", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + } + ], + options: nil, + __unknown_fields__: [] + } + end + + rpc :ProcessB, PackageB.MessageB, PackageB.ResponseB + + rpc :ProcessA, PackageA.MessageA, PackageA.MessageA +end + +defmodule PackageB.ServiceB.Stub do + @moduledoc false + + use GRPC.Stub, service: PackageB.ServiceB.Service +end diff --git a/test/support/protos/proto2_features.pb.ex b/test/support/protos/proto2_features.pb.ex new file mode 100644 index 0000000..ae33fa6 --- /dev/null +++ b/test/support/protos/proto2_features.pb.ex @@ -0,0 +1,868 @@ +defmodule Proto2Features.Status do + @moduledoc false + + use Protobuf, + enum: true, + full_name: "proto2_features.Status", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto2 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.EnumDescriptorProto{ + name: "Status", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "UNKNOWN", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "ACTIVE", + number: 1, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "INACTIVE", + number: 2, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :UNKNOWN, 0 + field :ACTIVE, 1 + field :INACTIVE, 2 +end + +defmodule Proto2Features.ExtendableMessage.ExtendableEnum do + @moduledoc false + + use Protobuf, + enum: true, + full_name: "proto2_features.ExtendableMessage.ExtendableEnum", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto2 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.EnumDescriptorProto{ + name: "ExtendableEnum", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "OPTION_A", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "OPTION_B", + number: 1, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :OPTION_A, 0 + field :OPTION_B, 1 +end + +defmodule Proto2Features.Proto2Request.Result do + @moduledoc false + + use Protobuf, + full_name: "proto2_features.Proto2Request.Result", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto2 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "Result", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "url", + extendee: nil, + number: 11, + label: :LABEL_REQUIRED, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "url", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "title", + extendee: nil, + number: 12, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "title", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :url, 11, required: true, type: :string + field :title, 12, optional: true, type: :string +end + +defmodule Proto2Features.Proto2Request.MetadataMapEntry do + @moduledoc false + + use Protobuf, + full_name: "proto2_features.Proto2Request.MetadataMapEntry", + map: true, + protoc_gen_elixir_version: "0.16.0", + syntax: :proto2 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "MetadataMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, optional: true, type: :string + field :value, 2, optional: true, type: :int32 +end + +defmodule Proto2Features.Proto2Request do + @moduledoc false + + use Protobuf, + full_name: "proto2_features.Proto2Request", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto2 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "Proto2Request", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "required_field", + extendee: nil, + number: 1, + label: :LABEL_REQUIRED, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "requiredField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "required_id", + extendee: nil, + number: 2, + label: :LABEL_REQUIRED, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "requiredId", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "optional_field", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "optionalField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "optional_id", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "optionalId", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "name", + extendee: nil, + number: 5, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: "unknown", + options: nil, + oneof_index: nil, + json_name: "name", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "port", + extendee: nil, + number: 6, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: "8080", + options: nil, + oneof_index: nil, + json_name: "port", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "enabled", + extendee: nil, + number: 7, + label: :LABEL_OPTIONAL, + type: :TYPE_BOOL, + type_name: nil, + default_value: "true", + options: nil, + oneof_index: nil, + json_name: "enabled", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "status", + extendee: nil, + number: 8, + label: :LABEL_OPTIONAL, + type: :TYPE_ENUM, + type_name: ".proto2_features.Status", + default_value: "ACTIVE", + options: nil, + oneof_index: nil, + json_name: "status", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "oneof_string", + extendee: nil, + number: 9, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 0, + json_name: "oneofString", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "oneof_int", + extendee: nil, + number: 13, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 0, + json_name: "oneofInt", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "result", + extendee: nil, + number: 10, + label: :LABEL_REPEATED, + type: :TYPE_GROUP, + type_name: ".proto2_features.Proto2Request.Result", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "result", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "metadata_map", + extendee: nil, + number: 14, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".proto2_features.Proto2Request.MetadataMapEntry", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "metadataMap", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "any_values", + extendee: nil, + number: 15, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Any", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "anyValues", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "Result", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "url", + extendee: nil, + number: 11, + label: :LABEL_REQUIRED, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "url", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "title", + extendee: nil, + number: 12, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "title", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + }, + %Google.Protobuf.DescriptorProto{ + name: "MetadataMapEntry", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: %Google.Protobuf.MessageOptions{ + message_set_wire_format: false, + no_standard_descriptor_accessor: false, + deprecated: false, + map_entry: true, + deprecated_legacy_json_field_conflicts: nil, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [], + extension_range: [ + %Google.Protobuf.DescriptorProto.ExtensionRange{ + start: 100, + end: 200, + options: nil, + __unknown_fields__: [] + } + ], + extension: [], + options: nil, + oneof_decl: [ + %Google.Protobuf.OneofDescriptorProto{ + name: "proto2_oneof", + options: nil, + __unknown_fields__: [] + } + ], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + oneof :proto2_oneof, 0 + + field :required_field, 1, required: true, type: :string, json_name: "requiredField" + field :required_id, 2, required: true, type: :int32, json_name: "requiredId" + field :optional_field, 3, optional: true, type: :string, json_name: "optionalField" + field :optional_id, 4, optional: true, type: :int32, json_name: "optionalId" + field :name, 5, optional: true, type: :string, default: "unknown" + field :port, 6, optional: true, type: :int32, default: 8080 + field :enabled, 7, optional: true, type: :bool, default: true + field :status, 8, optional: true, type: Proto2Features.Status, default: :ACTIVE, enum: true + field :oneof_string, 9, optional: true, type: :string, json_name: "oneofString", oneof: 0 + field :oneof_int, 13, optional: true, type: :int32, json_name: "oneofInt", oneof: 0 + field :result, 10, repeated: true, type: :group + + field :metadata_map, 14, + repeated: true, + type: Proto2Features.Proto2Request.MetadataMapEntry, + json_name: "metadataMap", + map: true + + field :any_values, 15, repeated: true, type: Google.Protobuf.Any, json_name: "anyValues" + + extensions [{100, 200}] +end + +defmodule Proto2Features.ExtensionData do + @moduledoc false + + use Protobuf, + full_name: "proto2_features.ExtensionData", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto2 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "ExtensionData", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "key", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "key", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "value", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "value", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :key, 1, optional: true, type: :string + field :value, 2, optional: true, type: :string +end + +defmodule Proto2Features.Proto2Response do + @moduledoc false + + use Protobuf, + full_name: "proto2_features.Proto2Response", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto2 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "Proto2Response", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "success", + extendee: nil, + number: 1, + label: :LABEL_REQUIRED, + type: :TYPE_BOOL, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "success", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "message", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "message", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "results", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".proto2_features.Proto2Request.Result", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "results", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :success, 1, required: true, type: :bool + field :message, 2, optional: true, type: :string + field :results, 3, repeated: true, type: Proto2Features.Proto2Request.Result +end + +defmodule Proto2Features.ExtendableMessage.NestedInExtendable do + @moduledoc false + + use Protobuf, + full_name: "proto2_features.ExtendableMessage.NestedInExtendable", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto2 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "NestedInExtendable", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "data", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "data", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :data, 1, optional: true, type: :string +end + +defmodule Proto2Features.ExtendableMessage do + @moduledoc false + + use Protobuf, + full_name: "proto2_features.ExtendableMessage", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto2 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "ExtendableMessage", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "id", + extendee: nil, + number: 1, + label: :LABEL_REQUIRED, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "id", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [ + %Google.Protobuf.DescriptorProto{ + name: "NestedInExtendable", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "data", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "data", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + enum_type: [ + %Google.Protobuf.EnumDescriptorProto{ + name: "ExtendableEnum", + value: [ + %Google.Protobuf.EnumValueDescriptorProto{ + name: "OPTION_A", + number: 0, + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.EnumValueDescriptorProto{ + name: "OPTION_B", + number: 1, + options: nil, + __unknown_fields__: [] + } + ], + options: nil, + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + ], + extension_range: [ + %Google.Protobuf.DescriptorProto.ExtensionRange{ + start: 1000, + end: 536_870_912, + options: nil, + __unknown_fields__: [] + } + ], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :id, 1, required: true, type: :string + + extensions [{1000, Protobuf.Extension.max()}] +end + +defmodule Proto2Features.Proto2Service.Service do + @moduledoc false + + use GRPC.Service, name: "proto2_features.Proto2Service", protoc_gen_elixir_version: "0.16.0" + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.ServiceDescriptorProto{ + name: "Proto2Service", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessProto2", + input_type: ".proto2_features.Proto2Request", + output_type: ".proto2_features.Proto2Response", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + } + ], + options: nil, + __unknown_fields__: [] + } + end + + rpc :ProcessProto2, Proto2Features.Proto2Request, Proto2Features.Proto2Response +end + +defmodule Proto2Features.Proto2Service.Stub do + @moduledoc false + + use GRPC.Stub, service: Proto2Features.Proto2Service.Service +end diff --git a/test/support/protos/proto2_features/pb_extension.pb.ex b/test/support/protos/proto2_features/pb_extension.pb.ex new file mode 100644 index 0000000..ba5c1a4 --- /dev/null +++ b/test/support/protos/proto2_features/pb_extension.pb.ex @@ -0,0 +1,41 @@ +defmodule Proto2Features.PbExtension do + @moduledoc false + + use Protobuf, protoc_gen_elixir_version: "0.16.0" + + extend Proto2Features.Proto2Request, :extended_field, 100, + optional: true, + type: :string, + json_name: "extendedField" + + extend Proto2Features.Proto2Request, :extended_timestamp, 101, + optional: true, + type: :int64, + json_name: "extendedTimestamp" + + extend Proto2Features.Proto2Request, :extension_data, 102, + optional: true, + type: Proto2Features.ExtensionData, + json_name: "extensionData" + + extend Proto2Features.Proto2Request, :timestamp_extension, 103, + optional: true, + type: Google.Protobuf.Timestamp, + json_name: "timestampExtension" + + extend Proto2Features.ExtendableMessage, :meta_info, 1000, + optional: true, + type: :string, + json_name: "metaInfo" + + extend Proto2Features.ExtendableMessage, :nested_extension, 1001, + optional: true, + type: Proto2Features.ExtendableMessage.NestedInExtendable, + json_name: "nestedExtension" + + extend Proto2Features.ExtendableMessage, :enum_extension, 1002, + optional: true, + type: Proto2Features.ExtendableMessage.ExtendableEnum, + json_name: "enumExtension", + enum: true +end diff --git a/test/support/protos/scalar_types.pb.ex b/test/support/protos/scalar_types.pb.ex new file mode 100644 index 0000000..570aab2 --- /dev/null +++ b/test/support/protos/scalar_types.pb.ex @@ -0,0 +1,644 @@ +defmodule ScalarTypes.ScalarRequest do + @moduledoc false + + use Protobuf, + full_name: "scalar_types.ScalarRequest", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "ScalarRequest", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "double_field", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_DOUBLE, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "doubleField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "float_field", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_FLOAT, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "floatField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "int32_field", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "int32Field", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "int64_field", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "int64Field", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "uint32_field", + extendee: nil, + number: 5, + label: :LABEL_OPTIONAL, + type: :TYPE_UINT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "uint32Field", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "uint64_field", + extendee: nil, + number: 6, + label: :LABEL_OPTIONAL, + type: :TYPE_UINT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "uint64Field", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sint32_field", + extendee: nil, + number: 7, + label: :LABEL_OPTIONAL, + type: :TYPE_SINT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sint32Field", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sint64_field", + extendee: nil, + number: 8, + label: :LABEL_OPTIONAL, + type: :TYPE_SINT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sint64Field", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "fixed32_field", + extendee: nil, + number: 9, + label: :LABEL_OPTIONAL, + type: :TYPE_FIXED32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "fixed32Field", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "fixed64_field", + extendee: nil, + number: 10, + label: :LABEL_OPTIONAL, + type: :TYPE_FIXED64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "fixed64Field", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sfixed32_field", + extendee: nil, + number: 11, + label: :LABEL_OPTIONAL, + type: :TYPE_SFIXED32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sfixed32Field", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sfixed64_field", + extendee: nil, + number: 12, + label: :LABEL_OPTIONAL, + type: :TYPE_SFIXED64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sfixed64Field", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "bool_field", + extendee: nil, + number: 13, + label: :LABEL_OPTIONAL, + type: :TYPE_BOOL, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "boolField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "string_field", + extendee: nil, + number: 14, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "stringField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "bytes_field", + extendee: nil, + number: 15, + label: :LABEL_OPTIONAL, + type: :TYPE_BYTES, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "bytesField", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "optional_string", + extendee: nil, + number: 18, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 0, + json_name: "optionalString", + proto3_optional: true, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "optional_int", + extendee: nil, + number: 19, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: 1, + json_name: "optionalInt", + proto3_optional: true, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sparse_field_1", + extendee: nil, + number: 100, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sparseField1", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sparse_field_2", + extendee: nil, + number: 1000, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sparseField2", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sparse_field_3", + extendee: nil, + number: 10000, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sparseField3", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [ + %Google.Protobuf.OneofDescriptorProto{ + name: "_optional_string", + options: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.OneofDescriptorProto{ + name: "_optional_int", + options: nil, + __unknown_fields__: [] + } + ], + reserved_range: [ + %Google.Protobuf.DescriptorProto.ReservedRange{ + start: 16, + end: 17, + __unknown_fields__: [] + }, + %Google.Protobuf.DescriptorProto.ReservedRange{ + start: 17, + end: 18, + __unknown_fields__: [] + }, + %Google.Protobuf.DescriptorProto.ReservedRange{start: 20, end: 26, __unknown_fields__: []} + ], + reserved_name: ["old_field", "deprecated_field"], + __unknown_fields__: [] + } + end + + field :double_field, 1, type: :double, json_name: "doubleField" + field :float_field, 2, type: :float, json_name: "floatField" + field :int32_field, 3, type: :int32, json_name: "int32Field" + field :int64_field, 4, type: :int64, json_name: "int64Field" + field :uint32_field, 5, type: :uint32, json_name: "uint32Field" + field :uint64_field, 6, type: :uint64, json_name: "uint64Field" + field :sint32_field, 7, type: :sint32, json_name: "sint32Field" + field :sint64_field, 8, type: :sint64, json_name: "sint64Field" + field :fixed32_field, 9, type: :fixed32, json_name: "fixed32Field" + field :fixed64_field, 10, type: :fixed64, json_name: "fixed64Field" + field :sfixed32_field, 11, type: :sfixed32, json_name: "sfixed32Field" + field :sfixed64_field, 12, type: :sfixed64, json_name: "sfixed64Field" + field :bool_field, 13, type: :bool, json_name: "boolField" + field :string_field, 14, type: :string, json_name: "stringField" + field :bytes_field, 15, type: :bytes, json_name: "bytesField" + field :optional_string, 18, proto3_optional: true, type: :string, json_name: "optionalString" + field :optional_int, 19, proto3_optional: true, type: :int32, json_name: "optionalInt" + field :sparse_field_1, 100, type: :string, json_name: "sparseField1" + field :sparse_field_2, 1000, type: :string, json_name: "sparseField2" + field :sparse_field_3, 10000, type: :string, json_name: "sparseField3" +end + +defmodule ScalarTypes.ScalarReply do + @moduledoc false + + use Protobuf, + full_name: "scalar_types.ScalarReply", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "ScalarReply", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "double_list", + extendee: nil, + number: 1, + label: :LABEL_REPEATED, + type: :TYPE_DOUBLE, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "doubleList", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "float_list", + extendee: nil, + number: 2, + label: :LABEL_REPEATED, + type: :TYPE_FLOAT, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "floatList", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "int32_list", + extendee: nil, + number: 3, + label: :LABEL_REPEATED, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "int32List", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "int64_list", + extendee: nil, + number: 4, + label: :LABEL_REPEATED, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "int64List", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "uint32_list", + extendee: nil, + number: 5, + label: :LABEL_REPEATED, + type: :TYPE_UINT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "uint32List", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "uint64_list", + extendee: nil, + number: 6, + label: :LABEL_REPEATED, + type: :TYPE_UINT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "uint64List", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sint32_list", + extendee: nil, + number: 7, + label: :LABEL_REPEATED, + type: :TYPE_SINT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sint32List", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sint64_list", + extendee: nil, + number: 8, + label: :LABEL_REPEATED, + type: :TYPE_SINT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sint64List", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "fixed32_list", + extendee: nil, + number: 9, + label: :LABEL_REPEATED, + type: :TYPE_FIXED32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "fixed32List", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "fixed64_list", + extendee: nil, + number: 10, + label: :LABEL_REPEATED, + type: :TYPE_FIXED64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "fixed64List", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sfixed32_list", + extendee: nil, + number: 11, + label: :LABEL_REPEATED, + type: :TYPE_SFIXED32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sfixed32List", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sfixed64_list", + extendee: nil, + number: 12, + label: :LABEL_REPEATED, + type: :TYPE_SFIXED64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sfixed64List", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "bool_list", + extendee: nil, + number: 13, + label: :LABEL_REPEATED, + type: :TYPE_BOOL, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "boolList", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "string_list", + extendee: nil, + number: 14, + label: :LABEL_REPEATED, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "stringList", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "bytes_list", + extendee: nil, + number: 15, + label: :LABEL_REPEATED, + type: :TYPE_BYTES, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "bytesList", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :double_list, 1, repeated: true, type: :double, json_name: "doubleList" + field :float_list, 2, repeated: true, type: :float, json_name: "floatList" + field :int32_list, 3, repeated: true, type: :int32, json_name: "int32List" + field :int64_list, 4, repeated: true, type: :int64, json_name: "int64List" + field :uint32_list, 5, repeated: true, type: :uint32, json_name: "uint32List" + field :uint64_list, 6, repeated: true, type: :uint64, json_name: "uint64List" + field :sint32_list, 7, repeated: true, type: :sint32, json_name: "sint32List" + field :sint64_list, 8, repeated: true, type: :sint64, json_name: "sint64List" + field :fixed32_list, 9, repeated: true, type: :fixed32, json_name: "fixed32List" + field :fixed64_list, 10, repeated: true, type: :fixed64, json_name: "fixed64List" + field :sfixed32_list, 11, repeated: true, type: :sfixed32, json_name: "sfixed32List" + field :sfixed64_list, 12, repeated: true, type: :sfixed64, json_name: "sfixed64List" + field :bool_list, 13, repeated: true, type: :bool, json_name: "boolList" + field :string_list, 14, repeated: true, type: :string, json_name: "stringList" + field :bytes_list, 15, repeated: true, type: :bytes, json_name: "bytesList" +end + +defmodule ScalarTypes.ScalarService.Service do + @moduledoc false + + use GRPC.Service, name: "scalar_types.ScalarService", protoc_gen_elixir_version: "0.16.0" + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.ServiceDescriptorProto{ + name: "ScalarService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessScalars", + input_type: ".scalar_types.ScalarRequest", + output_type: ".scalar_types.ScalarReply", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + } + ], + options: nil, + __unknown_fields__: [] + } + end + + rpc :ProcessScalars, ScalarTypes.ScalarRequest, ScalarTypes.ScalarReply +end + +defmodule ScalarTypes.ScalarService.Stub do + @moduledoc false + + use GRPC.Stub, service: ScalarTypes.ScalarService.Service +end diff --git a/test/support/protos/streaming_service.pb.ex b/test/support/protos/streaming_service.pb.ex new file mode 100644 index 0000000..002a722 --- /dev/null +++ b/test/support/protos/streaming_service.pb.ex @@ -0,0 +1,523 @@ +defmodule Streaming.StreamRequest do + @moduledoc false + + use Protobuf, + full_name: "streaming.StreamRequest", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "StreamRequest", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "message", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "message", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sequence", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sequence", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :message, 1, type: :string + field :sequence, 2, type: :int32 +end + +defmodule Streaming.StreamResponse do + @moduledoc false + + use Protobuf, + full_name: "streaming.StreamResponse", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "StreamResponse", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "result", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "result", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "sequence", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "sequence", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "is_final", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_BOOL, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "isFinal", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :result, 1, type: :string + field :sequence, 2, type: :int32 + field :is_final, 3, type: :bool, json_name: "isFinal" +end + +defmodule Streaming.DataChunk do + @moduledoc false + + use Protobuf, + full_name: "streaming.DataChunk", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "DataChunk", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "data", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_BYTES, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "data", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "offset", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "offset", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "size", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "size", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :data, 1, type: :bytes + field :offset, 2, type: :int64 + field :size, 3, type: :int32 +end + +defmodule Streaming.UploadStatus do + @moduledoc false + + use Protobuf, + full_name: "streaming.UploadStatus", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "UploadStatus", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "success", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_BOOL, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "success", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "total_bytes", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "totalBytes", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "checksum", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "checksum", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :success, 1, type: :bool + field :total_bytes, 2, type: :int64, json_name: "totalBytes" + field :checksum, 3, type: :string +end + +defmodule Streaming.DownloadRequest do + @moduledoc false + + use Protobuf, + full_name: "streaming.DownloadRequest", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "DownloadRequest", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "file_id", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "fileId", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "start_offset", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "startOffset", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "max_bytes", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "maxBytes", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :file_id, 1, type: :string, json_name: "fileId" + field :start_offset, 2, type: :int64, json_name: "startOffset" + field :max_bytes, 3, type: :int64, json_name: "maxBytes" +end + +defmodule Streaming.StreamingService.Service do + @moduledoc false + + use GRPC.Service, name: "streaming.StreamingService", protoc_gen_elixir_version: "0.16.0" + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.ServiceDescriptorProto{ + name: "StreamingService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "UnaryCall", + input_type: ".streaming.StreamRequest", + output_type: ".streaming.StreamResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "ServerStreamingCall", + input_type: ".streaming.StreamRequest", + output_type: ".streaming.StreamResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: true, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "ClientStreamingCall", + input_type: ".streaming.StreamRequest", + output_type: ".streaming.StreamResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: true, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "BidirectionalStreamingCall", + input_type: ".streaming.StreamRequest", + output_type: ".streaming.StreamResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: true, + server_streaming: true, + __unknown_fields__: [] + } + ], + options: nil, + __unknown_fields__: [] + } + end + + rpc :UnaryCall, Streaming.StreamRequest, Streaming.StreamResponse + + rpc :ServerStreamingCall, Streaming.StreamRequest, stream(Streaming.StreamResponse) + + rpc :ClientStreamingCall, stream(Streaming.StreamRequest), Streaming.StreamResponse + + rpc :BidirectionalStreamingCall, + stream(Streaming.StreamRequest), + stream(Streaming.StreamResponse) +end + +defmodule Streaming.StreamingService.Stub do + @moduledoc false + + use GRPC.Stub, service: Streaming.StreamingService.Service +end + +defmodule Streaming.MultiStreamService.Service do + @moduledoc false + + use GRPC.Service, name: "streaming.MultiStreamService", protoc_gen_elixir_version: "0.16.0" + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.ServiceDescriptorProto{ + name: "MultiStreamService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "UploadData", + input_type: ".streaming.DataChunk", + output_type: ".streaming.UploadStatus", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: true, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "DownloadData", + input_type: ".streaming.DownloadRequest", + output_type: ".streaming.DataChunk", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: true, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "SyncData", + input_type: ".streaming.DataChunk", + output_type: ".streaming.DataChunk", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: true, + server_streaming: true, + __unknown_fields__: [] + } + ], + options: nil, + __unknown_fields__: [] + } + end + + rpc :UploadData, stream(Streaming.DataChunk), Streaming.UploadStatus + + rpc :DownloadData, Streaming.DownloadRequest, stream(Streaming.DataChunk) + + rpc :SyncData, stream(Streaming.DataChunk), stream(Streaming.DataChunk) +end + +defmodule Streaming.MultiStreamService.Stub do + @moduledoc false + + use GRPC.Stub, service: Streaming.MultiStreamService.Service +end diff --git a/test/support/protos/well_known_types.pb.ex b/test/support/protos/well_known_types.pb.ex new file mode 100644 index 0000000..97f6954 --- /dev/null +++ b/test/support/protos/well_known_types.pb.ex @@ -0,0 +1,539 @@ +defmodule WellKnownTypes.WellKnownRequest do + @moduledoc false + + use Protobuf, + full_name: "well_known_types.WellKnownRequest", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "WellKnownRequest", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "payload", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Any", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "payload", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "items", + extendee: nil, + number: 2, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Any", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "items", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "created_at", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Timestamp", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "createdAt", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "updated_at", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Timestamp", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "updatedAt", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "timeout", + extendee: nil, + number: 5, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Duration", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "timeout", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "retry_delay", + extendee: nil, + number: 6, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Duration", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "retryDelay", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "metadata", + extendee: nil, + number: 7, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Struct", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "metadata", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "dynamic_value", + extendee: nil, + number: 8, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Value", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "dynamicValue", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "list_value", + extendee: nil, + number: 9, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.ListValue", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "listValue", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nullable_string", + extendee: nil, + number: 10, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.StringValue", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nullableString", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nullable_int32", + extendee: nil, + number: 11, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Int32Value", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nullableInt32", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nullable_int64", + extendee: nil, + number: 12, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Int64Value", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nullableInt64", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nullable_uint32", + extendee: nil, + number: 13, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.UInt32Value", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nullableUint32", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nullable_uint64", + extendee: nil, + number: 14, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.UInt64Value", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nullableUint64", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nullable_float", + extendee: nil, + number: 15, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.FloatValue", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nullableFloat", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nullable_double", + extendee: nil, + number: 16, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.DoubleValue", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nullableDouble", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nullable_bool", + extendee: nil, + number: 17, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.BoolValue", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nullableBool", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nullable_bytes", + extendee: nil, + number: 18, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.BytesValue", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nullableBytes", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "field_mask", + extendee: nil, + number: 19, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.FieldMask", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "fieldMask", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :payload, 1, type: Google.Protobuf.Any + field :items, 2, repeated: true, type: Google.Protobuf.Any + field :created_at, 3, type: Google.Protobuf.Timestamp, json_name: "createdAt" + field :updated_at, 4, type: Google.Protobuf.Timestamp, json_name: "updatedAt" + field :timeout, 5, type: Google.Protobuf.Duration + field :retry_delay, 6, type: Google.Protobuf.Duration, json_name: "retryDelay" + field :metadata, 7, type: Google.Protobuf.Struct + field :dynamic_value, 8, type: Google.Protobuf.Value, json_name: "dynamicValue" + field :list_value, 9, type: Google.Protobuf.ListValue, json_name: "listValue" + field :nullable_string, 10, type: Google.Protobuf.StringValue, json_name: "nullableString" + field :nullable_int32, 11, type: Google.Protobuf.Int32Value, json_name: "nullableInt32" + field :nullable_int64, 12, type: Google.Protobuf.Int64Value, json_name: "nullableInt64" + field :nullable_uint32, 13, type: Google.Protobuf.UInt32Value, json_name: "nullableUint32" + field :nullable_uint64, 14, type: Google.Protobuf.UInt64Value, json_name: "nullableUint64" + field :nullable_float, 15, type: Google.Protobuf.FloatValue, json_name: "nullableFloat" + field :nullable_double, 16, type: Google.Protobuf.DoubleValue, json_name: "nullableDouble" + field :nullable_bool, 17, type: Google.Protobuf.BoolValue, json_name: "nullableBool" + field :nullable_bytes, 18, type: Google.Protobuf.BytesValue, json_name: "nullableBytes" + field :field_mask, 19, type: Google.Protobuf.FieldMask, json_name: "fieldMask" +end + +defmodule WellKnownTypes.WellKnownResponse do + @moduledoc false + + use Protobuf, + full_name: "well_known_types.WellKnownResponse", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "WellKnownResponse", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "processed_at", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Timestamp", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "processedAt", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "elapsed_time", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Duration", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "elapsedTime", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "result", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Struct", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "result", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "string_values", + extendee: nil, + number: 4, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.StringValue", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "stringValues", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "int_values", + extendee: nil, + number: 5, + label: :LABEL_REPEATED, + type: :TYPE_MESSAGE, + type_name: ".google.protobuf.Int32Value", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "intValues", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :processed_at, 1, type: Google.Protobuf.Timestamp, json_name: "processedAt" + field :elapsed_time, 2, type: Google.Protobuf.Duration, json_name: "elapsedTime" + field :result, 3, type: Google.Protobuf.Struct + + field :string_values, 4, + repeated: true, + type: Google.Protobuf.StringValue, + json_name: "stringValues" + + field :int_values, 5, repeated: true, type: Google.Protobuf.Int32Value, json_name: "intValues" +end + +defmodule WellKnownTypes.CustomPayload do + @moduledoc false + + use Protobuf, + full_name: "well_known_types.CustomPayload", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "CustomPayload", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "data", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "data", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "version", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_INT32, + type_name: nil, + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "version", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :data, 1, type: :string + field :version, 2, type: :int32 +end + +defmodule WellKnownTypes.WellKnownTypesService.Service do + @moduledoc false + + use GRPC.Service, + name: "well_known_types.WellKnownTypesService", + protoc_gen_elixir_version: "0.16.0" + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.ServiceDescriptorProto{ + name: "WellKnownTypesService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessWellKnownTypes", + input_type: ".well_known_types.WellKnownRequest", + output_type: ".well_known_types.WellKnownResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "EmptyMethod", + input_type: ".google.protobuf.Empty", + output_type: ".google.protobuf.Empty", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + } + ], + options: nil, + __unknown_fields__: [] + } + end + + rpc :ProcessWellKnownTypes, WellKnownTypes.WellKnownRequest, WellKnownTypes.WellKnownResponse + + rpc :EmptyMethod, Google.Protobuf.Empty, Google.Protobuf.Empty +end + +defmodule WellKnownTypes.WellKnownTypesService.Stub do + @moduledoc false + + use GRPC.Stub, service: WellKnownTypes.WellKnownTypesService.Service +end From f6502875735398a98b15de0adc587113960ab8a3 Mon Sep 17 00:00:00 2001 From: mjheilmann Date: Sun, 5 Apr 2026 22:29:28 -0400 Subject: [PATCH 3/8] add specialized test for empty_service case --- priv/protos/edge_cases.proto | 64 ++- priv/protos/empty_service.proto | 6 + test/{ => case}/custom_prefix_test.exs | 6 +- test/case/empty_service_test.exs | 78 +++ test/support/client.ex | 6 +- .../protos/custom_prefix_service.pb.ex | 315 +----------- test/support/protos/edge_cases.pb.ex | 483 +++++++++++++++++- test/support/protos/empty.pb.ex | 21 + test/support/protos/empty_service.pb.ex | 8 +- 9 files changed, 630 insertions(+), 357 deletions(-) create mode 100644 priv/protos/empty_service.proto rename test/{ => case}/custom_prefix_test.exs (97%) create mode 100644 test/case/empty_service_test.exs create mode 100644 test/support/protos/empty.pb.ex diff --git a/priv/protos/edge_cases.proto b/priv/protos/edge_cases.proto index 633b931..350c7e9 100644 --- a/priv/protos/edge_cases.proto +++ b/priv/protos/edge_cases.proto @@ -2,39 +2,67 @@ syntax = "proto3"; package edge_cases; -// Empty service (no methods) - edge case -service EmptyService { -} + // Service with unusual but valid patterns service EdgeCaseService { // Method names with underscores and different conventions - rpc process_data (Request) returns (Response) {} - rpc ProcessData (Request) returns (Response) {} - rpc PROCESS_DATA (Request) returns (Response) {} + // protoc compiles these fine, but the GRPC upstream stub does not + // rpc process_data (Request) returns (Response) {} + // rpc ProcessData (Request) returns (Response) {} + // rpc PROCESS_DATA (Request) returns (Response) {} // Empty request or response - rpc EmptyInput (EmptyMessage) returns (Response) {} - rpc EmptyOutput (Request) returns (EmptyMessage) {} - rpc BothEmpty (EmptyMessage) returns (EmptyMessage) {} + rpc EmptyInput(EmptyInputRequest) returns (EmptyInputResponse) {} + rpc EmptyOutput(EmptyOutputRequest) returns (EmptyOutputResponse) {} + rpc BothEmpty(BothEmptyRequest) returns (BothEmptyResponse) {} + rpc Complicated(ComplicatedRequest) returns (ComplicatedResponse) {} } -message EmptyMessage { - // Intentionally empty message +message EmptyInputRequest {} +message EmptyInputResponse { + string data = 1; } - -message Request { +message EmptyOutputRequest { string data = 1; } - -message Response { - string result = 1; +message EmptyOutputResponse {} +message BothEmptyRequest {} +message BothEmptyResponse {} + +// message Request { +// string data = 1; +// } + +// message Response { +// string result = 1; +// } + +message ComplicatedRequest { + SparseFieldNumbers numbers = 1; + ManyFields fields = 2; + DetailedStatus status = 3; + MultipleOneofs oneofs = 4; + NestedMaps nested_maps = 5; + CircularA circular = 6; + WithReservedFields reserved_fields = 7; + UnicodeTest unicode_test = 8; +} +message ComplicatedResponse { + SparseFieldNumbers numbers = 1; + ManyFields fields = 2; + DetailedStatus status = 3; + MultipleOneofs oneofs = 4; + NestedMaps nested_maps = 5; + CircularA circular = 6; + WithReservedFields reserved_fields = 7; + UnicodeTest unicode_test = 8; } // Unusual field numbering message SparseFieldNumbers { string field_1 = 1; - string field_536870911 = 536870911; // Max field number (2^29 - 1) + string field_536870911 = 536870911; // Max field number (2^29 - 1) } // Many fields @@ -76,7 +104,7 @@ enum DetailedStatus { CRITICAL_ERROR = -100; // Large enum values - MAX_STATUS = 2147483647; // Max int32 + MAX_STATUS = 2147483647; // Max int32 } // Multiple oneofs in one message diff --git a/priv/protos/empty_service.proto b/priv/protos/empty_service.proto new file mode 100644 index 0000000..77df50b --- /dev/null +++ b/priv/protos/empty_service.proto @@ -0,0 +1,6 @@ +syntax = "proto3"; + +package empty_service; + +// Empty service (no methods) - edge case +service EmptyService {} diff --git a/test/custom_prefix_test.exs b/test/case/custom_prefix_test.exs similarity index 97% rename from test/custom_prefix_test.exs rename to test/case/custom_prefix_test.exs index 9f5cd25..0c4fa9c 100644 --- a/test/custom_prefix_test.exs +++ b/test/case/custom_prefix_test.exs @@ -1,7 +1,5 @@ -defmodule GrpcReflection.CustomPrefixServiceTest do - @moduledoc """ - Test suite covering types, cases and services from custom_prefix_service.proto - """ +defmodule GrpcReflection.Case.CustomPrefixServiceTest do + @moduledoc false use GrpcCase, service: CustomizedPrefix.PrefixService.Service diff --git a/test/case/empty_service_test.exs b/test/case/empty_service_test.exs new file mode 100644 index 0000000..163b537 --- /dev/null +++ b/test/case/empty_service_test.exs @@ -0,0 +1,78 @@ +defmodule GrpcReflection.Case.EmptyServiceTest do + @moduledoc false + + use GrpcCase, service: EmptyService.EmptyService.Service + + describe "v1" do + setup :stub_v1_server + + test "unsupported call is rejected", ctx do + message = {:file_containing_extension, %Grpc.Reflection.V1.ExtensionRequest{}} + assert {:error, _} = run_request(message, ctx) + end + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["empty_service.EmptyService"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "empty_service.EmptyService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "empty_service", + dependency: [], + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "EmptyService", + method: [] + } + ] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + assert ops == [service: "empty_service.EmptyService"] + end + end + + describe "v1alpha" do + setup :stub_v1alpha_server + + test "unsupported call is rejected", ctx do + message = {:file_containing_extension, %Grpc.Reflection.V1alpha.ExtensionRequest{}} + assert {:error, _} = run_request(message, ctx) + end + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["empty_service.EmptyService"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "empty_service.EmptyService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "empty_service", + dependency: [], + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "EmptyService", + method: [] + } + ] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [service: "empty_service.EmptyService"] + end + end +end diff --git a/test/support/client.ex b/test/support/client.ex index 3b5ea65..1073542 100644 --- a/test/support/client.ex +++ b/test/support/client.ex @@ -189,7 +189,11 @@ defmodule GrpcReflection.TestClient do result |> String.split("\n") |> Enum.reject(&(&1 == "")) - |> Enum.map(&{:call, &1}) + |> Enum.map(fn + "(No methods)" -> nil + name -> {:call, name} + end) + |> Enum.reject(&is_nil(&1)) end defp grpcurl_describe_call(%{host: host}, call) do diff --git a/test/support/protos/custom_prefix_service.pb.ex b/test/support/protos/custom_prefix_service.pb.ex index 4ce675c..baa47e5 100644 --- a/test/support/protos/custom_prefix_service.pb.ex +++ b/test/support/protos/custom_prefix_service.pb.ex @@ -2,48 +2,9 @@ defmodule CustomizedPrefix.EchoRequest do @moduledoc false use Protobuf, - enum: true, - full_name: "testserviceV2.Enum", + full_name: "custom_prefix.EchoRequest", protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.EnumDescriptorProto{ - name: "Enum", - value: [ - %Google.Protobuf.EnumValueDescriptorProto{ - name: "A", - number: 0, - options: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.EnumValueDescriptorProto{ - name: "B", - number: 1, - options: nil, - __unknown_fields__: [] - } - ], - options: nil, - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - end - - field :A, 0 - field :B, 1 -end - -defmodule HLW.TestRequest.GEntry do - @moduledoc false - - use Protobuf, - full_name: "testserviceV2.TestRequest.GEntry", - map: true, - protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 + syntax: :proto3 def descriptor do # credo:disable-for-next-line @@ -60,277 +21,7 @@ defmodule HLW.TestRequest.GEntry do default_value: nil, options: nil, oneof_index: nil, - json_name: "key", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "value", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_INT32, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "value", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [], - enum_type: [], - extension_range: [], - extension: [], - options: %Google.Protobuf.MessageOptions{ - message_set_wire_format: false, - no_standard_descriptor_accessor: false, - deprecated: false, - map_entry: true, - deprecated_legacy_json_field_conflicts: nil, - features: nil, - uninterpreted_option: [], - __pb_extensions__: %{}, - __unknown_fields__: [] - }, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - end - - field :key, 1, optional: true, type: :string - field :value, 2, optional: true, type: :int32 -end - -defmodule HLW.TestRequest do - @moduledoc false - - use Protobuf, - full_name: "testserviceV2.TestRequest", - protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.DescriptorProto{ - name: "TestRequest", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "name", - extendee: nil, - number: 1, - label: :LABEL_REQUIRED, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "name", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "enum", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_ENUM, - type_name: ".testserviceV2.Enum", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "enum", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "label", - extendee: nil, - number: 3, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: 0, - json_name: "label", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "value", - extendee: nil, - number: 4, - label: :LABEL_OPTIONAL, - type: :TYPE_INT32, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: 0, - json_name: "value", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "g", - extendee: nil, - number: 5, - label: :LABEL_REPEATED, - type: :TYPE_MESSAGE, - type_name: ".testserviceV2.TestRequest.GEntry", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "g", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "instrument", - extendee: nil, - number: 6, - label: :LABEL_REPEATED, - type: :TYPE_MESSAGE, - type_name: ".google.protobuf.Any", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "instrument", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [ - %Google.Protobuf.DescriptorProto{ - name: "GEntry", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "key", - extendee: nil, - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "key", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "value", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_INT32, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "value", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [], - enum_type: [], - extension_range: [], - extension: [], - options: %Google.Protobuf.MessageOptions{ - message_set_wire_format: false, - no_standard_descriptor_accessor: false, - deprecated: false, - map_entry: true, - deprecated_legacy_json_field_conflicts: nil, - features: nil, - uninterpreted_option: [], - __pb_extensions__: %{}, - __unknown_fields__: [] - }, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - ], - enum_type: [], - extension_range: [ - %Google.Protobuf.DescriptorProto.ExtensionRange{ - start: 10, - end: 21, - options: nil, - __unknown_fields__: [] - } - ], - extension: [], - options: nil, - oneof_decl: [ - %Google.Protobuf.OneofDescriptorProto{ - name: "test_oneof", - options: nil, - __unknown_fields__: [] - } - ], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - end - - oneof :test_oneof, 0 - - field :name, 1, required: true, type: :string - field :enum, 2, optional: true, type: HLW.Enum, enum: true - field :label, 3, optional: true, type: :string, oneof: 0 - field :value, 4, optional: true, type: :int32, oneof: 0 - field :g, 5, repeated: true, type: HLW.TestRequest.GEntry, map: true - field :instrument, 6, repeated: true, type: Google.Protobuf.Any - - extensions [{10, 21}] -end - -defmodule HLW.Location do - @moduledoc false - - use Protobuf, - full_name: "testserviceV2.Location", - protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.DescriptorProto{ - name: "Location", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "latitude", - extendee: nil, - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "latitude", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "longitude", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "longitude", + json_name: "message", proto3_optional: nil, __unknown_fields__: [] } diff --git a/test/support/protos/edge_cases.pb.ex b/test/support/protos/edge_cases.pb.ex index 45ae88c..10b945b 100644 --- a/test/support/protos/edge_cases.pb.ex +++ b/test/support/protos/edge_cases.pb.ex @@ -71,18 +71,18 @@ defmodule EdgeCases.DetailedStatus do field :MAX_STATUS, 2_147_483_647 end -defmodule EdgeCases.EmptyMessage do +defmodule EdgeCases.EmptyInputRequest do @moduledoc false use Protobuf, - full_name: "edge_cases.EmptyMessage", + full_name: "edge_cases.EmptyInputRequest", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "EmptyMessage", + name: "EmptyInputRequest", field: [], nested_type: [], enum_type: [], @@ -97,18 +97,18 @@ defmodule EdgeCases.EmptyMessage do end end -defmodule EdgeCases.Request do +defmodule EdgeCases.EmptyInputResponse do @moduledoc false use Protobuf, - full_name: "edge_cases.Request", + full_name: "edge_cases.EmptyInputResponse", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "Request", + name: "EmptyInputResponse", field: [ %Google.Protobuf.FieldDescriptorProto{ name: "data", @@ -140,21 +140,21 @@ defmodule EdgeCases.Request do field :data, 1, type: :string end -defmodule EdgeCases.Response do +defmodule EdgeCases.EmptyOutputRequest do @moduledoc false use Protobuf, - full_name: "edge_cases.Response", + full_name: "edge_cases.EmptyOutputRequest", protoc_gen_elixir_version: "0.16.0", syntax: :proto3 def descriptor do # credo:disable-for-next-line %Google.Protobuf.DescriptorProto{ - name: "Response", + name: "EmptyOutputRequest", field: [ %Google.Protobuf.FieldDescriptorProto{ - name: "result", + name: "data", extendee: nil, number: 1, label: :LABEL_OPTIONAL, @@ -163,7 +163,7 @@ defmodule EdgeCases.Response do default_value: nil, options: nil, oneof_index: nil, - json_name: "result", + json_name: "data", proto3_optional: nil, __unknown_fields__: [] } @@ -180,7 +180,381 @@ defmodule EdgeCases.Response do } end - field :result, 1, type: :string + field :data, 1, type: :string +end + +defmodule EdgeCases.EmptyOutputResponse do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.EmptyOutputResponse", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "EmptyOutputResponse", + field: [], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end +end + +defmodule EdgeCases.BothEmptyRequest do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.BothEmptyRequest", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "BothEmptyRequest", + field: [], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end +end + +defmodule EdgeCases.BothEmptyResponse do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.BothEmptyResponse", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "BothEmptyResponse", + field: [], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end +end + +defmodule EdgeCases.ComplicatedRequest do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.ComplicatedRequest", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "ComplicatedRequest", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "numbers", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.SparseFieldNumbers", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "numbers", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "fields", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.ManyFields", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "fields", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "status", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_ENUM, + type_name: ".edge_cases.DetailedStatus", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "status", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "oneofs", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.MultipleOneofs", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "oneofs", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nested_maps", + extendee: nil, + number: 5, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.NestedMaps", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nestedMaps", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "circular", + extendee: nil, + number: 6, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.CircularA", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "circular", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "reserved_fields", + extendee: nil, + number: 7, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.WithReservedFields", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "reservedFields", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "unicode_test", + extendee: nil, + number: 8, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.UnicodeTest", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "unicodeTest", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :numbers, 1, type: EdgeCases.SparseFieldNumbers + field :fields, 2, type: EdgeCases.ManyFields + field :status, 3, type: EdgeCases.DetailedStatus, enum: true + field :oneofs, 4, type: EdgeCases.MultipleOneofs + field :nested_maps, 5, type: EdgeCases.NestedMaps, json_name: "nestedMaps" + field :circular, 6, type: EdgeCases.CircularA + field :reserved_fields, 7, type: EdgeCases.WithReservedFields, json_name: "reservedFields" + field :unicode_test, 8, type: EdgeCases.UnicodeTest, json_name: "unicodeTest" +end + +defmodule EdgeCases.ComplicatedResponse do + @moduledoc false + + use Protobuf, + full_name: "edge_cases.ComplicatedResponse", + protoc_gen_elixir_version: "0.16.0", + syntax: :proto3 + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.DescriptorProto{ + name: "ComplicatedResponse", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "numbers", + extendee: nil, + number: 1, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.SparseFieldNumbers", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "numbers", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "fields", + extendee: nil, + number: 2, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.ManyFields", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "fields", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "status", + extendee: nil, + number: 3, + label: :LABEL_OPTIONAL, + type: :TYPE_ENUM, + type_name: ".edge_cases.DetailedStatus", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "status", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "oneofs", + extendee: nil, + number: 4, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.MultipleOneofs", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "oneofs", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "nested_maps", + extendee: nil, + number: 5, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.NestedMaps", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "nestedMaps", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "circular", + extendee: nil, + number: 6, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.CircularA", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "circular", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "reserved_fields", + extendee: nil, + number: 7, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.WithReservedFields", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "reservedFields", + proto3_optional: nil, + __unknown_fields__: [] + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "unicode_test", + extendee: nil, + number: 8, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: ".edge_cases.UnicodeTest", + default_value: nil, + options: nil, + oneof_index: nil, + json_name: "unicodeTest", + proto3_optional: nil, + __unknown_fields__: [] + } + ], + nested_type: [], + enum_type: [], + extension_range: [], + extension: [], + options: nil, + oneof_decl: [], + reserved_range: [], + reserved_name: [], + __unknown_fields__: [] + } + end + + field :numbers, 1, type: EdgeCases.SparseFieldNumbers + field :fields, 2, type: EdgeCases.ManyFields + field :status, 3, type: EdgeCases.DetailedStatus, enum: true + field :oneofs, 4, type: EdgeCases.MultipleOneofs + field :nested_maps, 5, type: EdgeCases.NestedMaps, json_name: "nestedMaps" + field :circular, 6, type: EdgeCases.CircularA + field :reserved_fields, 7, type: EdgeCases.WithReservedFields, json_name: "reservedFields" + field :unicode_test, 8, type: EdgeCases.UnicodeTest, json_name: "unicodeTest" end defmodule EdgeCases.SparseFieldNumbers do @@ -1935,24 +2309,97 @@ defmodule EdgeCases.UnicodeTest do field :greeting, 3, type: :string end -defmodule EdgeCases.EmptyService.Service do +defmodule EdgeCases.EdgeCaseService.Service do @moduledoc false - use GRPC.Service, name: "edge_cases.EmptyService", protoc_gen_elixir_version: "0.16.0" + use GRPC.Service, name: "edge_cases.EdgeCaseService", protoc_gen_elixir_version: "0.16.0" def descriptor do # credo:disable-for-next-line %Google.Protobuf.ServiceDescriptorProto{ - name: "EmptyService", - method: [], + name: "EdgeCaseService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "EmptyInput", + input_type: ".edge_cases.EmptyInputRequest", + output_type: ".edge_cases.EmptyInputResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "EmptyOutput", + input_type: ".edge_cases.EmptyOutputRequest", + output_type: ".edge_cases.EmptyOutputResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "BothEmpty", + input_type: ".edge_cases.BothEmptyRequest", + output_type: ".edge_cases.BothEmptyResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "Complicated", + input_type: ".edge_cases.ComplicatedRequest", + output_type: ".edge_cases.ComplicatedResponse", + options: %Google.Protobuf.MethodOptions{ + deprecated: false, + idempotency_level: :IDEMPOTENCY_UNKNOWN, + features: nil, + uninterpreted_option: [], + __pb_extensions__: %{}, + __unknown_fields__: [] + }, + client_streaming: false, + server_streaming: false, + __unknown_fields__: [] + } + ], options: nil, __unknown_fields__: [] } end + + rpc :EmptyInput, EdgeCases.EmptyInputRequest, EdgeCases.EmptyInputResponse + + rpc :EmptyOutput, EdgeCases.EmptyOutputRequest, EdgeCases.EmptyOutputResponse + + rpc :BothEmpty, EdgeCases.BothEmptyRequest, EdgeCases.BothEmptyResponse + + rpc :Complicated, EdgeCases.ComplicatedRequest, EdgeCases.ComplicatedResponse end -defmodule EdgeCases.EmptyService.Stub do +defmodule EdgeCases.EdgeCaseService.Stub do @moduledoc false - use GRPC.Stub, service: EdgeCases.EmptyService.Service + use GRPC.Stub, service: EdgeCases.EdgeCaseService.Service end diff --git a/test/support/protos/empty.pb.ex b/test/support/protos/empty.pb.ex new file mode 100644 index 0000000..4fad29a --- /dev/null +++ b/test/support/protos/empty.pb.ex @@ -0,0 +1,21 @@ +defmodule Empty.EmptyService.Service do + @moduledoc false + + use GRPC.Service, name: "empty.EmptyService", protoc_gen_elixir_version: "0.16.0" + + def descriptor do + # credo:disable-for-next-line + %Google.Protobuf.ServiceDescriptorProto{ + name: "EmptyService", + method: [], + options: nil, + __unknown_fields__: [] + } + end +end + +defmodule Empty.EmptyService.Stub do + @moduledoc false + + use GRPC.Stub, service: Empty.EmptyService.Service +end diff --git a/test/support/protos/empty_service.pb.ex b/test/support/protos/empty_service.pb.ex index 7396599..119eba6 100644 --- a/test/support/protos/empty_service.pb.ex +++ b/test/support/protos/empty_service.pb.ex @@ -1,7 +1,7 @@ -defmodule EmptyService.Service do +defmodule EmptyService.EmptyService.Service do @moduledoc false - use GRPC.Service, name: "EmptyService", protoc_gen_elixir_version: "0.16.0" + use GRPC.Service, name: "empty_service.EmptyService", protoc_gen_elixir_version: "0.16.0" def descriptor do # credo:disable-for-next-line @@ -14,8 +14,8 @@ defmodule EmptyService.Service do end end -defmodule EmptyService.Stub do +defmodule EmptyService.EmptyService.Stub do @moduledoc false - use GRPC.Stub, service: EmptyService.Service + use GRPC.Stub, service: EmptyService.EmptyService.Service end From 7113224d9fb35ad3d29ec6677a972b97a2d03af9 Mon Sep 17 00:00:00 2001 From: mjheilmann Date: Sun, 26 Apr 2026 16:01:00 -0400 Subject: [PATCH 4/8] DRY and simplify cases --- test/case/custom_prefix_test.exs | 240 +++++++++++-------------------- test/case/empty_service_test.exs | 102 +++++-------- 2 files changed, 112 insertions(+), 230 deletions(-) diff --git a/test/case/custom_prefix_test.exs b/test/case/custom_prefix_test.exs index 0c4fa9c..425fc1e 100644 --- a/test/case/custom_prefix_test.exs +++ b/test/case/custom_prefix_test.exs @@ -3,167 +3,87 @@ defmodule GrpcReflection.Case.CustomPrefixServiceTest do use GrpcCase, service: CustomizedPrefix.PrefixService.Service - describe "v1" do - setup :stub_v1_server - - test "unsupported call is rejected", ctx do - message = {:file_containing_extension, %Grpc.Reflection.V1.ExtensionRequest{}} - assert {:error, _} = run_request(message, ctx) - end - - test "should list services", ctx do - message = {:list_services, ""} - assert {:ok, %{service: service_list}} = run_request(message, ctx) - assert Enum.map(service_list, &Map.get(&1, :name)) == ["custom_prefix.PrefixService"] - end - - test "should list methods on our service", ctx do - message = {:file_containing_symbol, "custom_prefix.PrefixService"} - assert {:ok, response} = run_request(message, ctx) - - assert %Google.Protobuf.FileDescriptorProto{ - package: "custom_prefix", - dependency: ["custom_prefix.EchoRequest.proto", "custom_prefix.EchoResponse.proto"], - service: [ - %Google.Protobuf.ServiceDescriptorProto{ - name: "PrefixService", - method: [ - %Google.Protobuf.MethodDescriptorProto{ - name: "Echo", - input_type: ".custom_prefix.EchoRequest", - output_type: ".custom_prefix.EchoResponse" - } - ] - } - ] - } = response - end - - test "should return the service when requesting a method on the service", ctx do - message = {:file_containing_symbol, "custom_prefix.PrefixService.Echo"} - assert {:ok, response} = run_request(message, ctx) - - assert %Google.Protobuf.FileDescriptorProto{ - service: [ - %Google.Protobuf.ServiceDescriptorProto{ - name: "PrefixService", - method: [ - %Google.Protobuf.MethodDescriptorProto{ - name: "Echo" - } - ] - } - ] - } = response - end - - test "should resolve a type", ctx do - message = {:file_containing_symbol, ".custom_prefix.EchoRequest"} - assert {:ok, response} = run_request(message, ctx) - - assert %Google.Protobuf.FileDescriptorProto{ - message_type: [ - %Google.Protobuf.DescriptorProto{ - name: "EchoRequest", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "message" - } - ] - } - ] - } = response - end - - test "reflection graph is traversable using grpcurl", ctx do - ops = GrpcReflection.TestClient.grpcurl_service(ctx) - - assert ops == [ - call: "custom_prefix.PrefixService.Echo", - service: "custom_prefix.PrefixService" - ] - end - end - - describe "v1alpha" do - setup :stub_v1alpha_server - - test "unsupported call is rejected", ctx do - message = {:file_containing_extension, %Grpc.Reflection.V1alpha.ExtensionRequest{}} - assert {:error, _} = run_request(message, ctx) - end - - test "should list services", ctx do - message = {:list_services, ""} - assert {:ok, %{service: service_list}} = run_request(message, ctx) - assert Enum.map(service_list, &Map.get(&1, :name)) == ["custom_prefix.PrefixService"] - end - - test "should list methods on our service", ctx do - message = {:file_containing_symbol, "custom_prefix.PrefixService"} - assert {:ok, response} = run_request(message, ctx) - - assert %Google.Protobuf.FileDescriptorProto{ - package: "custom_prefix", - dependency: ["custom_prefix.EchoRequest.proto", "custom_prefix.EchoResponse.proto"], - service: [ - %Google.Protobuf.ServiceDescriptorProto{ - name: "PrefixService", - method: [ - %Google.Protobuf.MethodDescriptorProto{ - name: "Echo", - input_type: ".custom_prefix.EchoRequest", - output_type: ".custom_prefix.EchoResponse" - } - ] - } + versions = ["v1alpha", "v1"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["custom_prefix.PrefixService"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "custom_prefix.PrefixService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "custom_prefix", + dependency: [ + "custom_prefix.EchoRequest.proto", + "custom_prefix.EchoResponse.proto" + ], + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "PrefixService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "Echo", + input_type: ".custom_prefix.EchoRequest", + output_type: ".custom_prefix.EchoResponse" + } + ] + } + ] + } = response + end + + test "should return the service when requesting a method on the service", ctx do + message = {:file_containing_symbol, "custom_prefix.PrefixService.Echo"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "PrefixService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "Echo" + } + ] + } + ] + } = response + end + + test "should resolve a type", ctx do + message = {:file_containing_symbol, ".custom_prefix.EchoRequest"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + message_type: [ + %Google.Protobuf.DescriptorProto{ + name: "EchoRequest", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "message" + } + ] + } + ] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + call: "custom_prefix.PrefixService.Echo", + service: "custom_prefix.PrefixService" ] - } = response - end - - test "should return the service when requesting a method on the service", ctx do - message = {:file_containing_symbol, "custom_prefix.PrefixService.Echo"} - assert {:ok, response} = run_request(message, ctx) - - assert %Google.Protobuf.FileDescriptorProto{ - service: [ - %Google.Protobuf.ServiceDescriptorProto{ - name: "PrefixService", - method: [ - %Google.Protobuf.MethodDescriptorProto{ - name: "Echo" - } - ] - } - ] - } = response - end - - test "should resolve a type", ctx do - message = {:file_containing_symbol, ".custom_prefix.EchoRequest"} - assert {:ok, response} = run_request(message, ctx) - - assert %Google.Protobuf.FileDescriptorProto{ - message_type: [ - %Google.Protobuf.DescriptorProto{ - name: "EchoRequest", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "message" - } - ] - } - ] - } = response - end - - test "reflection graph is traversable using grpcurl", ctx do - ops = GrpcReflection.TestClient.grpcurl_service(ctx) - - assert ops == [ - call: "custom_prefix.PrefixService.Echo", - service: "custom_prefix.PrefixService" - ] + end end end end diff --git a/test/case/empty_service_test.exs b/test/case/empty_service_test.exs index 163b537..60ffe37 100644 --- a/test/case/empty_service_test.exs +++ b/test/case/empty_service_test.exs @@ -3,76 +3,38 @@ defmodule GrpcReflection.Case.EmptyServiceTest do use GrpcCase, service: EmptyService.EmptyService.Service - describe "v1" do - setup :stub_v1_server - - test "unsupported call is rejected", ctx do - message = {:file_containing_extension, %Grpc.Reflection.V1.ExtensionRequest{}} - assert {:error, _} = run_request(message, ctx) - end - - test "should list services", ctx do - message = {:list_services, ""} - assert {:ok, %{service: service_list}} = run_request(message, ctx) - assert Enum.map(service_list, &Map.get(&1, :name)) == ["empty_service.EmptyService"] - end - - test "should list methods on our service", ctx do - message = {:file_containing_symbol, "empty_service.EmptyService"} - assert {:ok, response} = run_request(message, ctx) - - assert %Google.Protobuf.FileDescriptorProto{ - package: "empty_service", - dependency: [], - service: [ - %Google.Protobuf.ServiceDescriptorProto{ - name: "EmptyService", - method: [] - } - ] - } = response - end - - test "reflection graph is traversable using grpcurl", ctx do - ops = GrpcReflection.TestClient.grpcurl_service(ctx) - assert ops == [service: "empty_service.EmptyService"] - end - end - - describe "v1alpha" do - setup :stub_v1alpha_server - - test "unsupported call is rejected", ctx do - message = {:file_containing_extension, %Grpc.Reflection.V1alpha.ExtensionRequest{}} - assert {:error, _} = run_request(message, ctx) - end - - test "should list services", ctx do - message = {:list_services, ""} - assert {:ok, %{service: service_list}} = run_request(message, ctx) - assert Enum.map(service_list, &Map.get(&1, :name)) == ["empty_service.EmptyService"] - end - - test "should list methods on our service", ctx do - message = {:file_containing_symbol, "empty_service.EmptyService"} - assert {:ok, response} = run_request(message, ctx) - - assert %Google.Protobuf.FileDescriptorProto{ - package: "empty_service", - dependency: [], - service: [ - %Google.Protobuf.ServiceDescriptorProto{ - name: "EmptyService", - method: [] - } - ] - } = response - end - - test "reflection graph is traversable using grpcurl", ctx do - ops = GrpcReflection.TestClient.grpcurl_service(ctx) - - assert ops == [service: "empty_service.EmptyService"] + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["empty_service.EmptyService"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "empty_service.EmptyService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "empty_service", + dependency: [], + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "EmptyService", + method: [] + } + ] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + assert ops == [service: "empty_service.EmptyService"] + end end end end From 7c5dbb72cd9c08d41346f9c253f7561256a63ffc Mon Sep 17 00:00:00 2001 From: mjheilmann Date: Thu, 30 Apr 2026 09:48:51 -0400 Subject: [PATCH 5/8] start stubbing tests --- priv/protos/edge_cases.proto | 5 +- priv/protos/proto2_features.proto | 7 -- test/case/edge_cases_test.exs | 44 ++++++++ test/case/global_test.exs | 30 +++++ test/case/imports_test_test.exs | 43 +++++++ test/case/multistream_service_test.exs | 43 +++++++ test/case/proto2_features_test.exs | 37 ++++++ test/case/scalar_types_test.exs | 47 ++++++++ test/case/streaming_service_test.exs | 43 +++++++ test/support/protos/edge_cases.pb.ex | 18 --- test/support/protos/proto2_features.pb.ex | 130 ---------------------- 11 files changed, 289 insertions(+), 158 deletions(-) create mode 100644 test/case/edge_cases_test.exs create mode 100644 test/case/global_test.exs create mode 100644 test/case/imports_test_test.exs create mode 100644 test/case/multistream_service_test.exs create mode 100644 test/case/proto2_features_test.exs create mode 100644 test/case/scalar_types_test.exs create mode 100644 test/case/streaming_service_test.exs diff --git a/priv/protos/edge_cases.proto b/priv/protos/edge_cases.proto index 350c7e9..7e24dd1 100644 --- a/priv/protos/edge_cases.proto +++ b/priv/protos/edge_cases.proto @@ -2,8 +2,6 @@ syntax = "proto3"; package edge_cases; - - // Service with unusual but valid patterns service EdgeCaseService { // Method names with underscores and different conventions @@ -16,7 +14,8 @@ service EdgeCaseService { rpc EmptyInput(EmptyInputRequest) returns (EmptyInputResponse) {} rpc EmptyOutput(EmptyOutputRequest) returns (EmptyOutputResponse) {} rpc BothEmpty(BothEmptyRequest) returns (BothEmptyResponse) {} - rpc Complicated(ComplicatedRequest) returns (ComplicatedResponse) {} + // We don't handle circular relations yet + // rpc Complicated(ComplicatedRequest) returns (ComplicatedResponse) {} } message EmptyInputRequest {} diff --git a/priv/protos/proto2_features.proto b/priv/protos/proto2_features.proto index d077f37..8ee388d 100644 --- a/priv/protos/proto2_features.proto +++ b/priv/protos/proto2_features.proto @@ -31,12 +31,6 @@ message Proto2Request { int32 oneof_int = 13; } - // Groups (proto2 only, deprecated but still valid) - repeated group Result = 10 { - required string url = 11; - optional string title = 12; - } - // Map in proto2 (added in proto2 v3.0.0) map metadata_map = 14; @@ -69,7 +63,6 @@ message ExtensionData { message Proto2Response { required bool success = 1; optional string message = 2; - repeated Proto2Request.Result results = 3; } // Message with extension and nested types diff --git a/test/case/edge_cases_test.exs b/test/case/edge_cases_test.exs new file mode 100644 index 0000000..155bb94 --- /dev/null +++ b/test/case/edge_cases_test.exs @@ -0,0 +1,44 @@ +defmodule GrpcReflection.Case.EdgeCasesTest do + @moduledoc false + + use GrpcCase, service: EdgeCases.EdgeCaseService.Service + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["edge_cases.EdgeCaseService"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "edge_cases.EdgeCaseService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "edge_cases", + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "EdgeCaseService" + } + ] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + {:call, "edge_cases.EdgeCaseService.BothEmpty"}, + {:call, "edge_cases.EdgeCaseService.EmptyInput"}, + {:call, "edge_cases.EdgeCaseService.EmptyOutput"}, + {:service, "edge_cases.EdgeCaseService"} + ] + end + end + end +end diff --git a/test/case/global_test.exs b/test/case/global_test.exs new file mode 100644 index 0000000..87e3305 --- /dev/null +++ b/test/case/global_test.exs @@ -0,0 +1,30 @@ +defmodule GrpcReflection.Case.GlobalTest do + @moduledoc false + + use GrpcCase, service: GlobalService.Service + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["GlobalService"] + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + {:call, "GlobalService.GlobalMethod"}, + {:service, "GlobalService"}, + {:type, ".GlobalRequest"}, + {:type, ".GlobalResponse"} + ] + end + end + end +end diff --git a/test/case/imports_test_test.exs b/test/case/imports_test_test.exs new file mode 100644 index 0000000..b749a8f --- /dev/null +++ b/test/case/imports_test_test.exs @@ -0,0 +1,43 @@ +defmodule GrpcReflection.Case.ImportsTestServiceTest do + @moduledoc false + + use GrpcCase, service: ImportsTest.ImportTestService.Service + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["imports_test.ImportTestService"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "imports_test.ImportTestService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "imports_test", + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "ImportTestService" + } + ] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + {:call, "imports_test.ImportTestService.CreateUser"}, + {:call, "imports_test.ImportTestService.UpdateLocation"}, + {:service, "imports_test.ImportTestService"} + ] + end + end + end +end diff --git a/test/case/multistream_service_test.exs b/test/case/multistream_service_test.exs new file mode 100644 index 0000000..01381a5 --- /dev/null +++ b/test/case/multistream_service_test.exs @@ -0,0 +1,43 @@ +defmodule GrpcReflection.Case.MultiStreamingTest do + @moduledoc false + + use GrpcCase, service: Streaming.MultiStreamService.Service + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + expected_services = ["streaming.MultiStreamService"] + assert Enum.map(service_list, &Map.get(&1, :name)) == expected_services + end + + test "should list methods on StreamingService", ctx do + message = {:file_containing_symbol, "streaming.MultiStreamService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "streaming" + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + {:call, "streaming.MultiStreamService.DownloadData"}, + {:call, "streaming.MultiStreamService.SyncData"}, + {:call, "streaming.MultiStreamService.UploadData"}, + {:service, "streaming.MultiStreamService"}, + {:type, ".streaming.DataChunk"}, + {:type, ".streaming.DownloadRequest"}, + {:type, ".streaming.UploadStatus"} + ] + end + end + end +end diff --git a/test/case/proto2_features_test.exs b/test/case/proto2_features_test.exs new file mode 100644 index 0000000..58e3e08 --- /dev/null +++ b/test/case/proto2_features_test.exs @@ -0,0 +1,37 @@ +defmodule GrpcReflection.Case.Proto2FeaturesTest do + @moduledoc false + + use GrpcCase, service: Proto2Features.Proto2Service.Service + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["proto2_features.Proto2Service"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "proto2_features.Proto2Service"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "proto2_features" + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + {:call, "proto2_features.Proto2Service.ProcessProto2"}, + {:service, "proto2_features.Proto2Service"} + ] + end + end + end +end diff --git a/test/case/scalar_types_test.exs b/test/case/scalar_types_test.exs new file mode 100644 index 0000000..a25eab9 --- /dev/null +++ b/test/case/scalar_types_test.exs @@ -0,0 +1,47 @@ +defmodule GrpcReflection.Case.ScalarTypesTest do + @moduledoc false + + use GrpcCase, service: ScalarTypes.ScalarService.Service + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["scalar_types.ScalarService"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "scalar_types.ScalarService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "scalar_types", + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "ScalarService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessScalars" + } + ] + } + ] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + {:call, "scalar_types.ScalarService.ProcessScalars"}, + {:service, "scalar_types.ScalarService"} + ] + end + end + end +end diff --git a/test/case/streaming_service_test.exs b/test/case/streaming_service_test.exs new file mode 100644 index 0000000..f61030b --- /dev/null +++ b/test/case/streaming_service_test.exs @@ -0,0 +1,43 @@ +defmodule GrpcReflection.Case.StreamingTest do + @moduledoc false + + use GrpcCase, service: Streaming.StreamingService.Service + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + expected_services = ["streaming.StreamingService"] + assert Enum.map(service_list, &Map.get(&1, :name)) == expected_services + end + + test "should list methods on StreamingService", ctx do + message = {:file_containing_symbol, "streaming.StreamingService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "streaming" + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + {:call, "streaming.StreamingService.BidirectionalStreamingCall"}, + {:call, "streaming.StreamingService.ClientStreamingCall"}, + {:call, "streaming.StreamingService.ServerStreamingCall"}, + {:call, "streaming.StreamingService.UnaryCall"}, + {:service, "streaming.StreamingService"}, + {:type, ".streaming.StreamRequest"}, + {:type, ".streaming.StreamResponse"} + ] + end + end + end +end diff --git a/test/support/protos/edge_cases.pb.ex b/test/support/protos/edge_cases.pb.ex index 10b945b..01bcf93 100644 --- a/test/support/protos/edge_cases.pb.ex +++ b/test/support/protos/edge_cases.pb.ex @@ -2366,22 +2366,6 @@ defmodule EdgeCases.EdgeCaseService.Service do client_streaming: false, server_streaming: false, __unknown_fields__: [] - }, - %Google.Protobuf.MethodDescriptorProto{ - name: "Complicated", - input_type: ".edge_cases.ComplicatedRequest", - output_type: ".edge_cases.ComplicatedResponse", - options: %Google.Protobuf.MethodOptions{ - deprecated: false, - idempotency_level: :IDEMPOTENCY_UNKNOWN, - features: nil, - uninterpreted_option: [], - __pb_extensions__: %{}, - __unknown_fields__: [] - }, - client_streaming: false, - server_streaming: false, - __unknown_fields__: [] } ], options: nil, @@ -2394,8 +2378,6 @@ defmodule EdgeCases.EdgeCaseService.Service do rpc :EmptyOutput, EdgeCases.EmptyOutputRequest, EdgeCases.EmptyOutputResponse rpc :BothEmpty, EdgeCases.BothEmptyRequest, EdgeCases.BothEmptyResponse - - rpc :Complicated, EdgeCases.ComplicatedRequest, EdgeCases.ComplicatedResponse end defmodule EdgeCases.EdgeCaseService.Stub do diff --git a/test/support/protos/proto2_features.pb.ex b/test/support/protos/proto2_features.pb.ex index ae33fa6..14a89c1 100644 --- a/test/support/protos/proto2_features.pb.ex +++ b/test/support/protos/proto2_features.pb.ex @@ -81,64 +81,6 @@ defmodule Proto2Features.ExtendableMessage.ExtendableEnum do field :OPTION_B, 1 end -defmodule Proto2Features.Proto2Request.Result do - @moduledoc false - - use Protobuf, - full_name: "proto2_features.Proto2Request.Result", - protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.DescriptorProto{ - name: "Result", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "url", - extendee: nil, - number: 11, - label: :LABEL_REQUIRED, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "url", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "title", - extendee: nil, - number: 12, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "title", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [], - enum_type: [], - extension_range: [], - extension: [], - options: nil, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - end - - field :url, 11, required: true, type: :string - field :title, 12, optional: true, type: :string -end - defmodule Proto2Features.Proto2Request.MetadataMapEntry do @moduledoc false @@ -361,20 +303,6 @@ defmodule Proto2Features.Proto2Request do proto3_optional: nil, __unknown_fields__: [] }, - %Google.Protobuf.FieldDescriptorProto{ - name: "result", - extendee: nil, - number: 10, - label: :LABEL_REPEATED, - type: :TYPE_GROUP, - type_name: ".proto2_features.Proto2Request.Result", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "result", - proto3_optional: nil, - __unknown_fields__: [] - }, %Google.Protobuf.FieldDescriptorProto{ name: "metadata_map", extendee: nil, @@ -405,48 +333,6 @@ defmodule Proto2Features.Proto2Request do } ], nested_type: [ - %Google.Protobuf.DescriptorProto{ - name: "Result", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "url", - extendee: nil, - number: 11, - label: :LABEL_REQUIRED, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "url", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "title", - extendee: nil, - number: 12, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "title", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [], - enum_type: [], - extension_range: [], - extension: [], - options: nil, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - }, %Google.Protobuf.DescriptorProto{ name: "MetadataMapEntry", field: [ @@ -536,7 +422,6 @@ defmodule Proto2Features.Proto2Request do field :status, 8, optional: true, type: Proto2Features.Status, default: :ACTIVE, enum: true field :oneof_string, 9, optional: true, type: :string, json_name: "oneofString", oneof: 0 field :oneof_int, 13, optional: true, type: :int32, json_name: "oneofInt", oneof: 0 - field :result, 10, repeated: true, type: :group field :metadata_map, 14, repeated: true, @@ -647,20 +532,6 @@ defmodule Proto2Features.Proto2Response do json_name: "message", proto3_optional: nil, __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "results", - extendee: nil, - number: 3, - label: :LABEL_REPEATED, - type: :TYPE_MESSAGE, - type_name: ".proto2_features.Proto2Request.Result", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "results", - proto3_optional: nil, - __unknown_fields__: [] } ], nested_type: [], @@ -677,7 +548,6 @@ defmodule Proto2Features.Proto2Response do field :success, 1, required: true, type: :bool field :message, 2, optional: true, type: :string - field :results, 3, repeated: true, type: Proto2Features.Proto2Request.Result end defmodule Proto2Features.ExtendableMessage.NestedInExtendable do From 7af6aef00327c99d8e7ad327126712ba2551cff2 Mon Sep 17 00:00:00 2001 From: Michael Heilmann Date: Thu, 30 Apr 2026 12:58:28 -0400 Subject: [PATCH 6/8] complete stubbing and cleanup --- mix.exs | 21 +- ...{no_package.proto => global_service.proto} | 0 test/case/cross_package_test.exs | 63 +++ test/case/global_test.exs | 21 + test/case/nested_enum_conflict_test.exs | 68 +++ test/case/nested_messages_test.exs | 68 +++ test/case/proto2_features_test.exs | 61 +++ test/case/recursive_message_test.exs | 30 ++ test/case/well_known_types_test.exs | 65 +++ test/integration/v1_reflection_test.exs | 457 +---------------- test/integration/v1alpha_reflection_test.exs | 460 +----------------- test/service/builder/util_test.exs | 42 +- test/service/builder_test.exs | 110 ++--- test/service/server_test.exs | 20 +- test/support/endpoint.ex | 17 +- test/support/grpc_case.ex | 138 +++--- test/support/protos/empty.pb.ex | 21 - ...{no_package.pb.ex => global_service.pb.ex} | 0 test/support/protos/hlw/pb_extension.pb.ex | 9 - test/support/protos/test_service_v2.pb.ex | 436 ----------------- .../protos/testservice_v2/pb_extension.pb.ex | 9 - 21 files changed, 540 insertions(+), 1576 deletions(-) rename priv/protos/{no_package.proto => global_service.proto} (100%) create mode 100644 test/case/cross_package_test.exs create mode 100644 test/case/nested_enum_conflict_test.exs create mode 100644 test/case/nested_messages_test.exs create mode 100644 test/case/recursive_message_test.exs create mode 100644 test/case/well_known_types_test.exs delete mode 100644 test/support/protos/empty.pb.ex rename test/support/protos/{no_package.pb.ex => global_service.pb.ex} (100%) delete mode 100644 test/support/protos/hlw/pb_extension.pb.ex delete mode 100644 test/support/protos/test_service_v2.pb.ex delete mode 100644 test/support/protos/testservice_v2/pb_extension.pb.ex diff --git a/mix.exs b/mix.exs index 950c28b..86a4782 100644 --- a/mix.exs +++ b/mix.exs @@ -20,9 +20,24 @@ defmodule GrpcReflection.MixProject do test_coverage: [ ignore_modules: [ ~r/^Grpc\./, - ~r/^Helloworld\./, - ~r/^TestserviceV2\./, - ~r/^TestserviceV3\./, + ~r/^Google\./, + ~r/^ScalarTypes\./, + ~r/^Streaming\./, + ~r/^EmptyService\./, + ~r/^EdgeCases\./, + ~r/^Proto2Features\./, + ~r/^CustomizedPrefix\./, + ~r/^ImportsTest\./, + ~r/^CommonTypes\./, + ~r/^GlobalService$/, + ~r/^GlobalRequest$/, + ~r/^GlobalResponse$/, + ~r/^Nested\./, + ~r/^WellKnownTypes\./, + ~r/^PackageA\./, + ~r/^PackageB\./, + ~r/^NestedEnumConflict\./, + ~r/^RecursiveMessage\./, GrpcReflection.TestEndpoint, GrpcReflection.TestEndpoint.Endpoint ] diff --git a/priv/protos/no_package.proto b/priv/protos/global_service.proto similarity index 100% rename from priv/protos/no_package.proto rename to priv/protos/global_service.proto diff --git a/test/case/cross_package_test.exs b/test/case/cross_package_test.exs new file mode 100644 index 0000000..baa7e11 --- /dev/null +++ b/test/case/cross_package_test.exs @@ -0,0 +1,63 @@ +defmodule GrpcReflection.Case.CrossPackageTest do + @moduledoc false + + use GrpcCase, service: PackageB.ServiceB.Service + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["package_b.ServiceB"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "package_b.ServiceB"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "package_b", + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "ServiceB", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessB", + input_type: ".package_b.MessageB", + output_type: ".package_b.ResponseB" + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessA", + input_type: ".package_a.MessageA", + output_type: ".package_a.MessageA" + } + ] + } + ] + } = response + end + + test "cross-package type is resolvable by symbol", ctx do + message = {:file_containing_symbol, "package_a.MessageA"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "package_a", + message_type: [%Google.Protobuf.DescriptorProto{name: "MessageA"}] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert {:call, "package_b.ServiceB.ProcessB"} in ops + assert {:call, "package_b.ServiceB.ProcessA"} in ops + assert {:service, "package_b.ServiceB"} in ops + end + end + end +end diff --git a/test/case/global_test.exs b/test/case/global_test.exs index 87e3305..ce3c55f 100644 --- a/test/case/global_test.exs +++ b/test/case/global_test.exs @@ -15,6 +15,27 @@ defmodule GrpcReflection.Case.GlobalTest do assert Enum.map(service_list, &Map.get(&1, :name)) == ["GlobalService"] end + test "should list methods on service with no package", ctx do + message = {:file_containing_symbol, "GlobalService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "", + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "GlobalService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "GlobalMethod", + input_type: ".GlobalRequest", + output_type: ".GlobalResponse" + } + ] + } + ] + } = response + end + test "reflection graph is traversable using grpcurl", ctx do ops = GrpcReflection.TestClient.grpcurl_service(ctx) diff --git a/test/case/nested_enum_conflict_test.exs b/test/case/nested_enum_conflict_test.exs new file mode 100644 index 0000000..b95d5fd --- /dev/null +++ b/test/case/nested_enum_conflict_test.exs @@ -0,0 +1,68 @@ +defmodule GrpcReflection.Case.NestedEnumConflictTest do + @moduledoc false + + use GrpcCase, service: NestedEnumConflict.ConflictService.Service + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + + assert Enum.map(service_list, &Map.get(&1, :name)) == [ + "nestedEnumConflict.ConflictService" + ] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "nestedEnumConflict.ConflictService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "nestedEnumConflict", + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "ConflictService", + method: [ + %Google.Protobuf.MethodDescriptorProto{name: "ListFoos"}, + %Google.Protobuf.MethodDescriptorProto{name: "ListBars"} + ] + } + ] + } = response + end + + test "messages with identically-named nested enums are each resolvable", ctx do + for symbol <- [ + "nestedEnumConflict.ListFoosRequest", + "nestedEnumConflict.ListBarsRequest" + ] do + message = {:file_containing_symbol, symbol} + + assert {:ok, %Google.Protobuf.FileDescriptorProto{package: "nestedEnumConflict"}} = + run_request(message, ctx) + end + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert ops == [ + {:call, "nestedEnumConflict.ConflictService.ListBars"}, + {:call, "nestedEnumConflict.ConflictService.ListFoos"}, + {:service, "nestedEnumConflict.ConflictService"}, + {:type, ".nestedEnumConflict.ListBarsRequest"}, + {:type, ".nestedEnumConflict.ListBarsRequest.SortOrder"}, + {:type, ".nestedEnumConflict.ListBarsResponse"}, + {:type, ".nestedEnumConflict.ListFoosRequest"}, + {:type, ".nestedEnumConflict.ListFoosRequest.SortOrder"}, + {:type, ".nestedEnumConflict.ListFoosResponse"} + ] + end + end + end +end diff --git a/test/case/nested_messages_test.exs b/test/case/nested_messages_test.exs new file mode 100644 index 0000000..1c0494d --- /dev/null +++ b/test/case/nested_messages_test.exs @@ -0,0 +1,68 @@ +defmodule GrpcReflection.Case.NestedMessagesTest do + @moduledoc false + + use GrpcCase, service: Nested.NestedService.Service + + # nested_messages.proto defines two services sharing the same deeply nested types. + # The builder raises a symbol conflict when processing the second traversal of + # OuterMessage.MiddleMessage.InnerMessage via AnotherNestedService. + # Tagged skip until the library supports multi-service files with shared nested types. + @moduletag :skip + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["nested.NestedService"] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "nested.NestedService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "nested", + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "NestedService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "ProcessNested", + input_type: ".nested.OuterMessage", + output_type: ".nested.OuterResponse" + } + ] + } + ] + } = response + end + + test "should resolve a deeply nested type by symbol", ctx do + message = {:file_containing_symbol, "nested.OuterMessage"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "nested", + message_type: [ + %Google.Protobuf.DescriptorProto{ + name: "OuterMessage", + nested_type: [_ | _] + } + ] + } = response + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert {:call, "nested.NestedService.ProcessNested"} in ops + assert {:service, "nested.NestedService"} in ops + end + end + end +end diff --git a/test/case/proto2_features_test.exs b/test/case/proto2_features_test.exs index 58e3e08..fbdc6aa 100644 --- a/test/case/proto2_features_test.exs +++ b/test/case/proto2_features_test.exs @@ -24,6 +24,67 @@ defmodule GrpcReflection.Case.Proto2FeaturesTest do } = response end + test "should return extension numbers for an extendable type", ctx do + message = {:all_extension_numbers_of_type, "proto2_features.Proto2Request"} + assert {:ok, response} = run_request(message, ctx) + assert response.base_type_name == "proto2_features.Proto2Request" + assert response.extension_number == [100, 101, 102, 103] + end + + test "should resolve the file containing a specific extension", ctx do + extension_request_mod = + case ctx.version do + :v1 -> Grpc.Reflection.V1.ExtensionRequest + :v1alpha -> Grpc.Reflection.V1alpha.ExtensionRequest + end + + message = + {:file_containing_extension, + struct(extension_request_mod, %{ + containing_type: "proto2_features.Proto2Request", + extension_number: 100 + })} + + assert {:ok, response} = run_request(message, ctx) + assert response.package == "proto2_features" + assert response.dependency == ["proto2_features.Proto2Request.proto"] + + assert [ + %Google.Protobuf.FieldDescriptorProto{ + name: "extended_field", + extendee: "proto2_features.Proto2Request", + number: 100, + label: :LABEL_OPTIONAL, + type: :TYPE_STRING, + type_name: nil + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "extended_timestamp", + extendee: "proto2_features.Proto2Request", + number: 101, + label: :LABEL_OPTIONAL, + type: :TYPE_INT64, + type_name: nil + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "extension_data", + extendee: "proto2_features.Proto2Request", + number: 102, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: "proto2Features.ExtensionData" + }, + %Google.Protobuf.FieldDescriptorProto{ + name: "timestamp_extension", + extendee: "proto2_features.Proto2Request", + number: 103, + label: :LABEL_OPTIONAL, + type: :TYPE_MESSAGE, + type_name: "google.protobuf.Timestamp" + } + ] = response.extension + end + test "reflection graph is traversable using grpcurl", ctx do ops = GrpcReflection.TestClient.grpcurl_service(ctx) diff --git a/test/case/recursive_message_test.exs b/test/case/recursive_message_test.exs new file mode 100644 index 0000000..887579e --- /dev/null +++ b/test/case/recursive_message_test.exs @@ -0,0 +1,30 @@ +defmodule GrpcReflection.Case.RecursiveMessageTest do + @moduledoc false + + use GrpcCase, service: RecursiveMessage.Service.Service + + # Recursive message structures cause infinite loops in the builder's graph traversal. + # Tracked for future fix; protos and tests are in place to validate when resolved. + @moduletag :skip + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + assert Enum.map(service_list, &Map.get(&1, :name)) == ["recursive_message.Service"] + end + + test "reflection graph is traversable using grpcurl", ctx do + ops = GrpcReflection.TestClient.grpcurl_service(ctx) + + assert {:call, "recursive_message.Service.call"} in ops + assert {:service, "recursive_message.Service"} in ops + end + end + end +end diff --git a/test/case/well_known_types_test.exs b/test/case/well_known_types_test.exs new file mode 100644 index 0000000..0096602 --- /dev/null +++ b/test/case/well_known_types_test.exs @@ -0,0 +1,65 @@ +defmodule GrpcReflection.Case.WellKnownTypesTest do + @moduledoc false + + use GrpcCase, service: WellKnownTypes.WellKnownTypesService.Service + + versions = ["v1", "v1alpha"] + + for version <- versions do + describe version do + setup String.to_existing_atom("stub_#{version}_server") + + test "should list services", ctx do + message = {:list_services, ""} + assert {:ok, %{service: service_list}} = run_request(message, ctx) + + assert Enum.map(service_list, &Map.get(&1, :name)) == [ + "well_known_types.WellKnownTypesService" + ] + end + + test "should list methods on our service", ctx do + message = {:file_containing_symbol, "well_known_types.WellKnownTypesService"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "well_known_types", + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "WellKnownTypesService", + method: [ + %Google.Protobuf.MethodDescriptorProto{name: "ProcessWellKnownTypes"}, + %Google.Protobuf.MethodDescriptorProto{name: "EmptyMethod"} + ] + } + ] + } = response + end + + test "well-known type dependencies are resolvable by filename", ctx do + message = {:file_by_filename, "google.protobuf.Timestamp.proto"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + name: "google.protobuf.Timestamp.proto", + package: "google.protobuf", + message_type: [%Google.Protobuf.DescriptorProto{name: "Timestamp"}] + } = response + end + + test "well-known types are resolvable by symbol", ctx do + message = {:file_containing_symbol, ".google.protobuf.Timestamp"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "google.protobuf", + message_type: [%Google.Protobuf.DescriptorProto{name: "Timestamp"}] + } = response + end + + # Well-known types contain circular references that cause an infinite loop in our + # reflection tree builder, which grpcurl exposes as a stack overflow. Out of scope + # for now; the reflection API itself is verified via the symbol/filename tests above. + end + end +end diff --git a/test/integration/v1_reflection_test.exs b/test/integration/v1_reflection_test.exs index 3f7d5eb..120e2da 100644 --- a/test/integration/v1_reflection_test.exs +++ b/test/integration/v1_reflection_test.exs @@ -11,473 +11,22 @@ defmodule GrpcReflection.V1ReflectionTest do assert {:error, _} = run_request(message, ctx) end - test "listing services", ctx do - message = {:list_services, ""} - assert {:ok, %{service: service_list}} = run_request(message, ctx) - names = Enum.map(service_list, &Map.get(&1, :name)) - - assert names == [ - "helloworld.Greeter", - "testserviceV2.TestService", - "testserviceV3.TestService", - "grpc.reflection.v1.ServerReflection", - "grpc.reflection.v1alpha.ServerReflection" - ] - end - describe "symbol queries" do - test "ushould reject nknown symbol", ctx do + test "should reject unknown symbol", ctx do message = {:file_containing_symbol, "other.Rejecter"} assert {:error, _} = run_request(message, ctx) end - test "should list methods on our service", ctx do - message = {:file_containing_symbol, "helloworld.Greeter"} - assert {:ok, response} = run_request(message, ctx) - assert_response(response) - end - - test "should return a method on the service", ctx do - message = {:file_containing_symbol, "helloworld.Greeter.SayHello"} - assert {:ok, response} = run_request(message, ctx) - assert_response(response) - end - test "should return not found for an invalid method", ctx do - # SayHellp is not a method on the service - message = {:file_containing_symbol, "helloworld.Greeter.SayHellp"} + message = {:file_containing_symbol, "scalar_types.ScalarService.NoSuchMethod"} assert {:error, _} = run_request(message, ctx) end - - test "should resolve a type", ctx do - message = {:file_containing_symbol, "helloworld.HelloRequest"} - assert {:ok, response} = run_request(message, ctx) - assert_response(response) - end - - test "should return the containing file for a nested message", ctx do - message = {:file_containing_symbol, "testserviceV3.TestRequest.Payload"} - assert {:ok, response} = run_request(message, ctx) - assert response.name == "testserviceV3.TestRequest.proto" - end - - test "should resolve types with the leading period", ctx do - message = {:file_containing_symbol, ".helloworld.HelloRequest"} - assert {:ok, response} = run_request(message, ctx) - assert_response(response) - end end describe "filename queries" do - test "should list methods on our service", ctx do - message = {:file_containing_symbol, "helloworld.Greeter"} - assert {:ok, response} = run_request(message, ctx) - assert_response(response) - - # we pretend all modules are in different files, dependencies are listed - assert response.dependency == [ - "helloworld.HelloRequest.proto", - "helloworld.HelloReply.proto" - ] - end - test "should reject an unrecognized filename", ctx do - filename = "does.not.exist.proto" - message = {:file_by_filename, filename} + message = {:file_by_filename, "does.not.exist.proto"} assert {:error, _} = run_request(message, ctx) end - - test "should resolve by filename", ctx do - filename = "helloworld.HelloReply.proto" - message = {:file_by_filename, filename} - assert {:ok, response} = run_request(message, ctx) - assert response.name == filename - assert response.package == "helloworld" - assert response.dependency == ["google.protobuf.Timestamp.proto"] - - assert [ - %Google.Protobuf.DescriptorProto{ - name: "HelloReply", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "message", - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - json_name: "message" - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "today", - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_MESSAGE, - type_name: ".google.protobuf.Timestamp", - json_name: "today" - } - ] - } - ] = response.message_type - end - - test "should resolve external dependency types", ctx do - filename = "google.protobuf.Timestamp.proto" - message = {:file_by_filename, filename} - assert {:ok, response} = run_request(message, ctx) - assert response.name == filename - assert response.package == "google.protobuf" - assert response.dependency == [] - - assert [ - %Google.Protobuf.DescriptorProto{ - field: [ - %Google.Protobuf.FieldDescriptorProto{ - json_name: "seconds", - label: :LABEL_OPTIONAL, - name: "seconds", - number: 1, - type: :TYPE_INT64 - }, - %Google.Protobuf.FieldDescriptorProto{ - json_name: "nanos", - label: :LABEL_OPTIONAL, - name: "nanos", - number: 2, - type: :TYPE_INT32 - } - ], - name: "Timestamp" - } - ] = response.message_type - end - - test "should not duplicate dependencies in the file descriptor", ctx do - filename = "testserviceV3.TestReply.proto" - message = {:file_by_filename, filename} - assert {:ok, response} = run_request(message, ctx) - assert response.name == filename - assert response.package == "testserviceV3" - - assert response.dependency == [ - "google.protobuf.Timestamp.proto", - "google.protobuf.StringValue.proto" - ] - end - - test "should exclude nested types from dependenciy list", ctx do - filename = "testserviceV3.TestRequest.proto" - message = {:file_by_filename, filename} - assert {:ok, response} = run_request(message, ctx) - assert response.name == filename - assert response.package == "testserviceV3" - - assert response.dependency == [ - "testserviceV3.Enum.proto", - "google.protobuf.Any.proto", - "google.protobuf.StringValue.proto" - ] - end - end - - describe "proto2 extensions" do - test "should get all extension numbers by type", ctx do - type = "testserviceV2.TestRequest" - message = {:all_extension_numbers_of_type, type} - assert {:ok, response} = run_request(message, ctx) - assert response.base_type_name == type - assert response.extension_number == [10, 11] - end - - test "should get extension descriptor file by extendee", ctx do - extendee = "testserviceV2.TestRequest" - - message = - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{containing_type: extendee, extension_number: 10}} - - assert {:ok, response} = run_request(message, ctx) - assert response.name == extendee <> "Extension.proto" - assert response.package == "testserviceV2" - assert response.dependency == [extendee <> ".proto"] - - assert response.extension == [ - %Google.Protobuf.FieldDescriptorProto{ - name: "data", - extendee: extendee, - number: 10, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "location", - extendee: extendee, - number: 11, - label: :LABEL_OPTIONAL, - type: :TYPE_MESSAGE, - type_name: "testserviceV2.Location" - } - ] - - assert response.message_type == [ - %Google.Protobuf.DescriptorProto{ - name: "Location", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "latitude", - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - json_name: "latitude" - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "longitude", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - json_name: "longitude" - } - ] - } - ] - end - end - - test "reflection graph is traversable", ctx do - ops = GrpcReflection.TestClient.traverse_service(ctx) - - assert ops == [ - {:file_by_filename, "google.protobuf.Any.proto"}, - {:file_by_filename, "google.protobuf.StringValue.proto"}, - {:file_by_filename, "google.protobuf.Timestamp.proto"}, - {:file_by_filename, "grpc.reflection.v1.ErrorResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1.ExtensionNumberResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1.ExtensionRequest.proto"}, - {:file_by_filename, "grpc.reflection.v1.FileDescriptorResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1.ListServiceResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1.ServerReflectionRequest.proto"}, - {:file_by_filename, "grpc.reflection.v1.ServerReflectionResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1.ServiceResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ErrorResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ExtensionNumberResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ExtensionRequest.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.FileDescriptorResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ListServiceResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ServerReflectionRequest.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ServerReflectionResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ServiceResponse.proto"}, - {:file_by_filename, "helloworld.HelloReply.proto"}, - {:file_by_filename, "helloworld.HelloRequest.proto"}, - {:file_by_filename, "testserviceV2.Enum.proto"}, - {:file_by_filename, "testserviceV2.TestReply.proto"}, - {:file_by_filename, "testserviceV2.TestRequest.proto"}, - {:file_by_filename, "testserviceV3.Enum.proto"}, - {:file_by_filename, "testserviceV3.TestReply.proto"}, - {:file_by_filename, "testserviceV3.TestRequest.proto"}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 10, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 11, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 12, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 13, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 14, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 15, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 16, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 17, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 18, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 19, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 20, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 21, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 10, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 11, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 12, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 13, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 14, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 15, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 16, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 17, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 18, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 19, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 20, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 21, - __unknown_fields__: [] - }}, - {:file_containing_symbol, ".grpc.reflection.v1.ServerReflectionRequest"}, - {:file_containing_symbol, ".grpc.reflection.v1.ServerReflectionResponse"}, - {:file_containing_symbol, ".grpc.reflection.v1alpha.ServerReflectionRequest"}, - {:file_containing_symbol, ".grpc.reflection.v1alpha.ServerReflectionResponse"}, - {:file_containing_symbol, ".helloworld.HelloReply"}, - {:file_containing_symbol, ".helloworld.HelloRequest"}, - {:file_containing_symbol, ".testserviceV2.TestReply"}, - {:file_containing_symbol, ".testserviceV2.TestRequest"}, - {:file_containing_symbol, ".testserviceV3.TestReply"}, - {:file_containing_symbol, ".testserviceV3.TestRequest"}, - {:file_containing_symbol, "grpc.reflection.v1.ServerReflection"}, - {:file_containing_symbol, "grpc.reflection.v1alpha.ServerReflection"}, - {:file_containing_symbol, "helloworld.Greeter"}, - {:file_containing_symbol, "testserviceV2.TestService"}, - {:file_containing_symbol, "testserviceV3.TestService"}, - {:list_services, ""} - ] - end - - test "reflection graph is traversable using grpcurl", ctx do - ops = GrpcReflection.TestClient.grpcurl_service(ctx) - - assert ops == [ - {:call, "grpc.reflection.v1.ServerReflection.ServerReflectionInfo"}, - {:call, "grpc.reflection.v1alpha.ServerReflection.ServerReflectionInfo"}, - {:call, "helloworld.Greeter.SayHello"}, - {:call, "testserviceV2.TestService.CallFunction"}, - {:call, "testserviceV3.TestService.CallFunction"}, - {:service, "grpc.reflection.v1.ServerReflection"}, - {:service, "grpc.reflection.v1alpha.ServerReflection"}, - {:service, "helloworld.Greeter"}, - {:service, "testserviceV2.TestService"}, - {:service, "testserviceV3.TestService"}, - {:type, ".google.protobuf.Any"}, - {:type, ".google.protobuf.StringValue"}, - {:type, ".google.protobuf.Timestamp"}, - {:type, ".grpc.reflection.v1.ErrorResponse"}, - {:type, ".grpc.reflection.v1.ExtensionNumberResponse"}, - {:type, ".grpc.reflection.v1.ExtensionRequest"}, - {:type, ".grpc.reflection.v1.FileDescriptorResponse"}, - {:type, ".grpc.reflection.v1.ListServiceResponse"}, - {:type, ".grpc.reflection.v1.ServerReflectionRequest"}, - {:type, ".grpc.reflection.v1.ServerReflectionResponse"}, - {:type, ".grpc.reflection.v1.ServiceResponse"}, - {:type, ".grpc.reflection.v1alpha.ErrorResponse"}, - {:type, ".grpc.reflection.v1alpha.ExtensionNumberResponse"}, - {:type, ".grpc.reflection.v1alpha.ExtensionRequest"}, - {:type, ".grpc.reflection.v1alpha.FileDescriptorResponse"}, - {:type, ".grpc.reflection.v1alpha.ListServiceResponse"}, - {:type, ".grpc.reflection.v1alpha.ServerReflectionRequest"}, - {:type, ".grpc.reflection.v1alpha.ServerReflectionResponse"}, - {:type, ".grpc.reflection.v1alpha.ServiceResponse"}, - {:type, ".helloworld.HelloReply"}, - {:type, ".helloworld.HelloRequest"}, - {:type, ".testserviceV2.Enum"}, - {:type, ".testserviceV2.TestReply"}, - {:type, ".testserviceV2.TestRequest"}, - {:type, ".testserviceV3.Enum"}, - {:type, ".testserviceV3.TestReply"}, - {:type, ".testserviceV3.TestRequest"} - ] end end diff --git a/test/integration/v1alpha_reflection_test.exs b/test/integration/v1alpha_reflection_test.exs index 1997e3c..d13be81 100644 --- a/test/integration/v1alpha_reflection_test.exs +++ b/test/integration/v1alpha_reflection_test.exs @@ -11,476 +11,22 @@ defmodule GrpcReflection.V1alphaReflectionTest do assert {:error, _} = run_request(message, ctx) end - test "listing services", ctx do - message = {:list_services, ""} - assert {:ok, %{service: service_list}} = run_request(message, ctx) - names = Enum.map(service_list, &Map.get(&1, :name)) - - assert names == [ - "helloworld.Greeter", - "testserviceV2.TestService", - "testserviceV3.TestService", - "grpc.reflection.v1.ServerReflection", - "grpc.reflection.v1alpha.ServerReflection" - ] - end - describe "symbol queries" do test "should reject unknown symbol", ctx do message = {:file_containing_symbol, "other.Rejecter"} assert {:error, _} = run_request(message, ctx) end - test "should list methods on our service", ctx do - message = {:file_containing_symbol, "helloworld.Greeter"} - assert {:ok, response} = run_request(message, ctx) - assert_response(response) - end - - test "should resolve the service when describing a method", ctx do - message = {:file_containing_symbol, "helloworld.Greeter.SayHello"} - assert {:ok, response} = run_request(message, ctx) - assert_response(response) - end - test "should return not found for an invalid method", ctx do - # SayHellp is not a method on the service - message = {:file_containing_symbol, "helloworld.Greeter.SayHellp"} + message = {:file_containing_symbol, "scalar_types.ScalarService.NoSuchMethod"} assert {:error, _} = run_request(message, ctx) end - - test "should return the type when it is the root typy", ctx do - message = {:file_containing_symbol, "helloworld.HelloRequest"} - assert {:ok, response} = run_request(message, ctx) - assert_response(response) - end - - test "should return the containing type for a query on a nested type", ctx do - message = {:file_containing_symbol, "testserviceV3.TestRequest.Payload"} - assert {:ok, response} = run_request(message, ctx) - assert response.name == "testserviceV3.TestRequest.proto" - end - - test "should also resove with leading period", ctx do - message = {:file_containing_symbol, ".helloworld.HelloRequest"} - assert {:ok, response} = run_request(message, ctx) - assert_response(response) - end end describe "filename queries" do - test "should list methods on our service", ctx do - message = {:file_containing_symbol, "helloworld.Greeter"} - assert {:ok, response} = run_request(message, ctx) - assert_response(response) - - # we pretend all modules are in different files, dependencies are listed - assert response.dependency == [ - "helloworld.HelloRequest.proto", - "helloworld.HelloReply.proto" - ] - end - - test "should reject a filename that isn't recognized", ctx do - filename = "does.not.exist.proto" - message = {:file_by_filename, filename} + test "should reject an unrecognized filename", ctx do + message = {:file_by_filename, "does.not.exist.proto"} assert {:error, _} = run_request(message, ctx) end - - test "gshould resolve by filename", ctx do - filename = "helloworld.HelloReply.proto" - message = {:file_by_filename, filename} - assert {:ok, response} = run_request(message, ctx) - assert response.name == filename - assert response.package == "helloworld" - assert response.dependency == ["google.protobuf.Timestamp.proto"] - - assert [ - %Google.Protobuf.DescriptorProto{ - name: "HelloReply", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "message", - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - json_name: "message" - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "today", - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_MESSAGE, - type_name: ".google.protobuf.Timestamp", - json_name: "today" - } - ] - } - ] = response.message_type - end - - test "should resolve third party messages by filename", ctx do - filename = "google.protobuf.Timestamp.proto" - message = {:file_by_filename, filename} - assert {:ok, response} = run_request(message, ctx) - assert response.name == filename - assert response.package == "google.protobuf" - assert response.dependency == [] - - assert [ - %Google.Protobuf.DescriptorProto{ - field: [ - %Google.Protobuf.FieldDescriptorProto{ - json_name: "seconds", - label: :LABEL_OPTIONAL, - name: "seconds", - number: 1, - type: :TYPE_INT64 - }, - %Google.Protobuf.FieldDescriptorProto{ - json_name: "nanos", - label: :LABEL_OPTIONAL, - name: "nanos", - number: 2, - type: :TYPE_INT32 - } - ], - name: "Timestamp" - } - ] = response.message_type - end - - test "should not duplicate dependencies", ctx do - filename = "testserviceV3.TestReply.proto" - message = {:file_by_filename, filename} - assert {:ok, response} = run_request(message, ctx) - assert response.name == filename - assert response.package == "testserviceV3" - - assert response.dependency == [ - "google.protobuf.Timestamp.proto", - "google.protobuf.StringValue.proto" - ] - end - - test "should not treat a nested type as a dependency", ctx do - filename = "testserviceV3.TestRequest.proto" - message = {:file_by_filename, filename} - assert {:ok, response} = run_request(message, ctx) - assert response.name == filename - assert response.package == "testserviceV3" - - assert response.dependency == [ - "testserviceV3.Enum.proto", - "google.protobuf.Any.proto", - "google.protobuf.StringValue.proto" - ] - end - end - - describe "proto2 extensions" do - test "should get all extension numbers by type", ctx do - type = "testserviceV2.TestRequest" - message = {:all_extension_numbers_of_type, type} - assert {:ok, response} = run_request(message, ctx) - assert response.base_type_name == type - assert response.extension_number == [10, 11] - end - - test "should get extension descriptor file by extendee", ctx do - extendee = "testserviceV2.TestRequest" - - message = - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: extendee, - extension_number: 10 - }} - - assert {:ok, response} = run_request(message, ctx) - assert response.name == extendee <> "Extension.proto" - assert response.package == "testserviceV2" - assert response.dependency == [extendee <> ".proto"] - - assert response.extension == [ - %Google.Protobuf.FieldDescriptorProto{ - name: "data", - extendee: extendee, - number: 10, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "location", - extendee: extendee, - number: 11, - label: :LABEL_OPTIONAL, - type: :TYPE_MESSAGE, - type_name: "testserviceV2.Location" - } - ] - - assert response.message_type == [ - %Google.Protobuf.DescriptorProto{ - name: "Location", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "latitude", - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - json_name: "latitude" - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "longitude", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - json_name: "longitude" - } - ] - } - ] - end - end - - test "reflection graph is traversable", ctx do - ops = GrpcReflection.TestClient.traverse_service(ctx) - - assert ops == [ - {:file_by_filename, "google.protobuf.Any.proto"}, - {:file_by_filename, "google.protobuf.StringValue.proto"}, - {:file_by_filename, "google.protobuf.Timestamp.proto"}, - {:file_by_filename, "grpc.reflection.v1.ErrorResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1.ExtensionNumberResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1.ExtensionRequest.proto"}, - {:file_by_filename, "grpc.reflection.v1.FileDescriptorResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1.ListServiceResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1.ServerReflectionRequest.proto"}, - {:file_by_filename, "grpc.reflection.v1.ServerReflectionResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1.ServiceResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ErrorResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ExtensionNumberResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ExtensionRequest.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.FileDescriptorResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ListServiceResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ServerReflectionRequest.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ServerReflectionResponse.proto"}, - {:file_by_filename, "grpc.reflection.v1alpha.ServiceResponse.proto"}, - {:file_by_filename, "helloworld.HelloReply.proto"}, - {:file_by_filename, "helloworld.HelloRequest.proto"}, - {:file_by_filename, "testserviceV2.Enum.proto"}, - {:file_by_filename, "testserviceV2.TestReply.proto"}, - {:file_by_filename, "testserviceV2.TestRequest.proto"}, - {:file_by_filename, "testserviceV3.Enum.proto"}, - {:file_by_filename, "testserviceV3.TestReply.proto"}, - {:file_by_filename, "testserviceV3.TestRequest.proto"}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 10, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 11, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 12, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 13, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 14, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 15, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 16, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 17, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 18, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 19, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 20, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest", - extension_number: 21, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 10, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 11, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 12, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 13, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 14, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 15, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 16, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 17, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 18, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 19, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 20, - __unknown_fields__: [] - }}, - {:file_containing_extension, - %Grpc.Reflection.V1alpha.ExtensionRequest{ - containing_type: "testserviceV2.TestRequest.GEntry", - extension_number: 21, - __unknown_fields__: [] - }}, - {:file_containing_symbol, ".grpc.reflection.v1.ServerReflectionRequest"}, - {:file_containing_symbol, ".grpc.reflection.v1.ServerReflectionResponse"}, - {:file_containing_symbol, ".grpc.reflection.v1alpha.ServerReflectionRequest"}, - {:file_containing_symbol, ".grpc.reflection.v1alpha.ServerReflectionResponse"}, - {:file_containing_symbol, ".helloworld.HelloReply"}, - {:file_containing_symbol, ".helloworld.HelloRequest"}, - {:file_containing_symbol, ".testserviceV2.TestReply"}, - {:file_containing_symbol, ".testserviceV2.TestRequest"}, - {:file_containing_symbol, ".testserviceV3.TestReply"}, - {:file_containing_symbol, ".testserviceV3.TestRequest"}, - {:file_containing_symbol, "grpc.reflection.v1.ServerReflection"}, - {:file_containing_symbol, "grpc.reflection.v1alpha.ServerReflection"}, - {:file_containing_symbol, "helloworld.Greeter"}, - {:file_containing_symbol, "testserviceV2.TestService"}, - {:file_containing_symbol, "testserviceV3.TestService"}, - {:list_services, ""} - ] - end - - test "reflection graph is traversable using grpcurl", ctx do - ops = GrpcReflection.TestClient.grpcurl_service(ctx) - - assert ops == [ - {:call, "grpc.reflection.v1.ServerReflection.ServerReflectionInfo"}, - {:call, "grpc.reflection.v1alpha.ServerReflection.ServerReflectionInfo"}, - {:call, "helloworld.Greeter.SayHello"}, - {:call, "testserviceV2.TestService.CallFunction"}, - {:call, "testserviceV3.TestService.CallFunction"}, - {:service, "grpc.reflection.v1.ServerReflection"}, - {:service, "grpc.reflection.v1alpha.ServerReflection"}, - {:service, "helloworld.Greeter"}, - {:service, "testserviceV2.TestService"}, - {:service, "testserviceV3.TestService"}, - {:type, ".google.protobuf.Any"}, - {:type, ".google.protobuf.StringValue"}, - {:type, ".google.protobuf.Timestamp"}, - {:type, ".grpc.reflection.v1.ErrorResponse"}, - {:type, ".grpc.reflection.v1.ExtensionNumberResponse"}, - {:type, ".grpc.reflection.v1.ExtensionRequest"}, - {:type, ".grpc.reflection.v1.FileDescriptorResponse"}, - {:type, ".grpc.reflection.v1.ListServiceResponse"}, - {:type, ".grpc.reflection.v1.ServerReflectionRequest"}, - {:type, ".grpc.reflection.v1.ServerReflectionResponse"}, - {:type, ".grpc.reflection.v1.ServiceResponse"}, - {:type, ".grpc.reflection.v1alpha.ErrorResponse"}, - {:type, ".grpc.reflection.v1alpha.ExtensionNumberResponse"}, - {:type, ".grpc.reflection.v1alpha.ExtensionRequest"}, - {:type, ".grpc.reflection.v1alpha.FileDescriptorResponse"}, - {:type, ".grpc.reflection.v1alpha.ListServiceResponse"}, - {:type, ".grpc.reflection.v1alpha.ServerReflectionRequest"}, - {:type, ".grpc.reflection.v1alpha.ServerReflectionResponse"}, - {:type, ".grpc.reflection.v1alpha.ServiceResponse"}, - {:type, ".helloworld.HelloReply"}, - {:type, ".helloworld.HelloRequest"}, - {:type, ".testserviceV2.Enum"}, - {:type, ".testserviceV2.TestReply"}, - {:type, ".testserviceV2.TestRequest"}, - {:type, ".testserviceV3.Enum"}, - {:type, ".testserviceV3.TestReply"}, - {:type, ".testserviceV3.TestRequest"} - ] end end diff --git a/test/service/builder/util_test.exs b/test/service/builder/util_test.exs index 29ed309..4bf081e 100644 --- a/test/service/builder/util_test.exs +++ b/test/service/builder/util_test.exs @@ -11,14 +11,11 @@ defmodule GrpcReflection.Service.Builder.UtilTest do describe "common utils" do test "get package from module" do - assert "testserviceV3" == - Util.get_package("testserviceV3.TestRequest") + assert "scalar_types" == + Util.get_package("scalar_types.ScalarRequest") - assert "testserviceV3" == - Util.get_package("testserviceV3.TestRequest.Payload.Location") - - assert "testserviceV3" == - Util.get_package("testserviceV3.TestService") + assert "scalar_types" == + Util.get_package("scalar_types.ScalarService") assert "grpc.reflection.v1alpha" == Util.get_package("grpc.reflection.v1alpha.FileDescriptorResponse") @@ -30,30 +27,31 @@ defmodule GrpcReflection.Service.Builder.UtilTest do test "get all nested types" do assert [ - "testserviceV3.TestRequest.Token", - "testserviceV3.TestRequest.Payload.Location", - "testserviceV3.TestRequest.Payload", - "testserviceV3.TestRequest.GEntry" + "nested.OuterMessage.NestedMapEntry", + "nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage.VeryDeepMessage", + "nested.OuterMessage.MiddleMessage.InnerMessage.DeepMessage", + "nested.OuterMessage.MiddleMessage.InnerMessage", + "nested.OuterMessage.MiddleMessage" ] == Util.get_nested_types( - "testserviceV3.TestRequest", - TestserviceV3.TestRequest.descriptor() + "nested.OuterMessage", + Nested.OuterMessage.descriptor() ) end end describe "utils for dealing with proto2 only" do test "convert %Google.Protobuf.FieldProps{} to %Google.Protobuf.FieldDescriptorProto{}" do - extendee = TestserviceV2.TestRequest + extendee = Proto2Features.Proto2Request - # test for a POD(aka Plain Old Data) type - extension_number = 10 + # test for a plain scalar type + extension_number = 100 - assert {TestserviceV2.PbExtension, extension} = + assert {Proto2Features.PbExtension, extension} = Protobuf.Extension.get_extension_props_by_tag(extendee, extension_number) assert %Google.Protobuf.FieldDescriptorProto{ - name: "data", + name: "extended_field", extendee: ^extendee, number: ^extension_number, label: 1 @@ -63,20 +61,20 @@ defmodule GrpcReflection.Service.Builder.UtilTest do assert nil == result.type_name # test for a message type - extension_number = 11 + extension_number = 102 - assert {TestserviceV2.PbExtension, extension} = + assert {Proto2Features.PbExtension, extension} = Protobuf.Extension.get_extension_props_by_tag(extendee, extension_number) assert %Google.Protobuf.FieldDescriptorProto{ - name: "location", + name: "extension_data", extendee: ^extendee, number: ^extension_number, label: 1 } = result = Util.convert_to_field_descriptor(extendee, extension) assert Google.Protobuf.FieldDescriptorProto.Type.mapping()[:TYPE_MESSAGE] == result.type - assert "testserviceV2.Location" == result.type_name + assert "proto2Features.ExtensionData" == result.type_name end end end diff --git a/test/service/builder_test.exs b/test/service/builder_test.exs index 593054b..cedc4f6 100644 --- a/test/service/builder_test.exs +++ b/test/service/builder_test.exs @@ -6,35 +6,25 @@ defmodule GrpcReflection.Service.BuilderTest do alias GrpcReflection.Service.Builder alias GrpcReflection.Service.State - test "supports all reflection types in proto3" do - assert {:ok, tree} = Builder.build_reflection_tree([TestserviceV3.TestService.Service]) - assert %State{services: [TestserviceV3.TestService.Service]} = tree + setup_all do + Protobuf.load_extensions() + end + + test "supports proto3 services" do + assert {:ok, tree} = Builder.build_reflection_tree([ScalarTypes.ScalarService.Service]) + assert %State{services: [ScalarTypes.ScalarService.Service]} = tree assert Map.keys(tree.files) == [ - "google.protobuf.Any.proto", - "google.protobuf.StringValue.proto", - "google.protobuf.Timestamp.proto", - "testserviceV3.Enum.proto", - "testserviceV3.TestReply.proto", - "testserviceV3.TestRequest.Payload.proto", - "testserviceV3.TestRequest.Token.proto", - "testserviceV3.TestRequest.proto", - "testserviceV3.TestService.proto" + "scalar_types.ScalarReply.proto", + "scalar_types.ScalarRequest.proto", + "scalar_types.ScalarService.proto" ] assert Map.keys(tree.symbols) == [ - "google.protobuf.Any", - "google.protobuf.StringValue", - "google.protobuf.Timestamp", - "testserviceV3.Enum", - "testserviceV3.TestReply", - "testserviceV3.TestRequest", - "testserviceV3.TestRequest.GEntry", - "testserviceV3.TestRequest.Payload", - "testserviceV3.TestRequest.Payload.Location", - "testserviceV3.TestRequest.Token", - "testserviceV3.TestService", - "testserviceV3.TestService.CallFunction" + "scalar_types.ScalarReply", + "scalar_types.ScalarRequest", + "scalar_types.ScalarService", + "scalar_types.ScalarService.ProcessScalars" ] Enum.each(Map.values(tree.files), fn payload -> @@ -42,37 +32,9 @@ defmodule GrpcReflection.Service.BuilderTest do end) end - test "supports all reflection types in proto2" do - assert {:ok, tree} = Builder.build_reflection_tree([TestserviceV2.TestService.Service]) - assert %State{services: [TestserviceV2.TestService.Service]} = tree - - assert Map.keys(tree.files) == [ - "google.protobuf.Any.proto", - "google.protobuf.Timestamp.proto", - "testserviceV2.Enum.proto", - "testserviceV2.TestReply.proto", - "testserviceV2.TestRequest.proto", - "testserviceV2.TestRequestExtension.proto", - "testserviceV2.TestService.proto" - ] - - assert Map.keys(tree.symbols) == [ - "google.protobuf.Any", - "google.protobuf.Timestamp", - "testserviceV2.Enum", - "testserviceV2.TestReply", - "testserviceV2.TestRequest", - "testserviceV2.TestRequest.GEntry", - "testserviceV2.TestService", - "testserviceV2.TestService.CallFunction" - ] - - assert %{ - "testserviceV2.TestRequest" => extensions - } = tree.extensions - - # this is a bitstring that may contain whitespace characters - assert extensions |> to_string() |> String.trim() == "" + test "supports proto2 services" do + assert {:ok, tree} = Builder.build_reflection_tree([Proto2Features.Proto2Service.Service]) + assert %State{services: [Proto2Features.Proto2Service.Service]} = tree Enum.each(Map.values(tree.files), fn %{name: "google" <> _, syntax: syntax} -> assert syntax == "proto3" @@ -80,13 +42,17 @@ defmodule GrpcReflection.Service.BuilderTest do end) end + test "proto2 services expose extension numbers" do + assert {:ok, tree} = Builder.build_reflection_tree([Proto2Features.Proto2Service.Service]) + + assert %{"proto2_features.Proto2Request" => _} = tree.extensions + end + test "handles an empty service" do - assert {:ok, tree} = Builder.build_reflection_tree([EmptyService.Service]) - assert %State{services: [EmptyService.Service]} = tree + assert {:ok, tree} = Builder.build_reflection_tree([EmptyService.EmptyService.Service]) + assert %State{services: [EmptyService.EmptyService.Service]} = tree Enum.each(Map.values(tree.files), fn payload -> - # empty services default to proto2 - assert payload.syntax == "proto2" assert payload.dependency == [] assert payload.message_type == [] assert payload.enum_type == [] @@ -102,20 +68,18 @@ defmodule GrpcReflection.Service.BuilderTest do end) end - test "handles a service with a custom prefix" do - assert {:ok, tree} = Builder.build_reflection_tree([HLW.TestService.Service]) - assert %State{services: [HLW.TestService.Service]} = tree + test "handles a service with a custom module prefix" do + assert {:ok, tree} = + Builder.build_reflection_tree([CustomizedPrefix.PrefixService.Service]) + + assert %State{services: [CustomizedPrefix.PrefixService.Service]} = tree - names = Enum.map(Map.values(tree.files), & &1.name) + names = tree.files |> Map.values() |> Enum.map(& &1.name) |> Enum.sort() assert names == [ - "google.protobuf.Any.proto", - "google.protobuf.Timestamp.proto", - "testserviceV2.Enum.proto", - "testserviceV2.TestReply.proto", - "testserviceV2.TestRequest.proto", - "testserviceV2.TestRequestExtension.proto", - "testserviceV2.TestService.proto" + "custom_prefix.EchoRequest.proto", + "custom_prefix.EchoResponse.proto", + "custom_prefix.PrefixService.proto" ] end @@ -152,10 +116,12 @@ defmodule GrpcReflection.Service.BuilderTest do # fake a service module here to test unwrapping logic defmodule WrappedService do def __meta__(:name), do: "WrappedService" - defdelegate __rpc_calls__, to: EmptyService.Service + defdelegate __rpc_calls__, to: EmptyService.EmptyService.Service def descriptor do - %Google.Protobuf.FileDescriptorProto{service: [EmptyService.Service.descriptor()]} + %Google.Protobuf.FileDescriptorProto{ + service: [EmptyService.EmptyService.Service.descriptor()] + } end end diff --git a/test/service/server_test.exs b/test/service/server_test.exs index 3b23719..14c7cbc 100644 --- a/test/service/server_test.exs +++ b/test/service/server_test.exs @@ -10,18 +10,18 @@ defmodule GrpcReflection.ServerTest do test "adding a service changes responses" do assert Service.list_services() == [] - assert Service.get_filename_by_symbol("helloworld.Greeter") == + assert Service.get_filename_by_symbol("scalar_types.ScalarService") == {:error, "symbol not found"} - assert Service.get_by_filename("helloworld.Greeter.proto") == + assert Service.get_by_filename("scalar_types.ScalarService.proto") == {:error, "filename not found"} - assert :ok == Service.put_services([Helloworld.Greeter.Service]) + assert :ok == Service.put_services([ScalarTypes.ScalarService.Service]) - assert Service.list_services() == ["helloworld.Greeter"] + assert Service.list_services() == ["scalar_types.ScalarService"] assert {:ok, filename} = - Service.get_filename_by_symbol("helloworld.Greeter") + Service.get_filename_by_symbol("scalar_types.ScalarService") assert {:ok, %Google.Protobuf.FileDescriptorProto{name: ^filename}} = Service.get_by_filename(filename) @@ -30,7 +30,7 @@ defmodule GrpcReflection.ServerTest do describe "reflection state testing" do setup do Service.put_services([ - Helloworld.Greeter.Service, + ScalarTypes.ScalarService.Service, Grpc.Reflection.V1.ServerReflection.Service, Grpc.Reflection.V1alpha.ServerReflection.Service ]) @@ -38,7 +38,7 @@ defmodule GrpcReflection.ServerTest do test "expected services are present" do assert Service.list_services() == [ - "helloworld.Greeter", + "scalar_types.ScalarService", "grpc.reflection.v1.ServerReflection", "grpc.reflection.v1alpha.ServerReflection" ] @@ -46,7 +46,7 @@ defmodule GrpcReflection.ServerTest do test "method files return service descriptors" do assert {:ok, filename} = - Service.get_filename_by_symbol("helloworld.Greeter") + Service.get_filename_by_symbol("scalar_types.ScalarService") assert {:ok, %Google.Protobuf.FileDescriptorProto{name: ^filename}} = Service.get_by_filename(filename) @@ -54,7 +54,7 @@ defmodule GrpcReflection.ServerTest do test "describing a type returns the type" do assert {:ok, filename} = - Service.get_filename_by_symbol("helloworld.HelloRequest") + Service.get_filename_by_symbol("scalar_types.ScalarRequest") assert {:ok, %Google.Protobuf.FileDescriptorProto{name: ^filename}} = Service.get_by_filename(filename) @@ -62,7 +62,7 @@ defmodule GrpcReflection.ServerTest do test "type with leading period still resolves" do assert {:ok, filename} = - Service.get_filename_by_symbol(".helloworld.HelloRequest") + Service.get_filename_by_symbol(".scalar_types.ScalarRequest") assert {:ok, %Google.Protobuf.FileDescriptorProto{name: ^filename}} = Service.get_by_filename(filename) diff --git a/test/support/endpoint.ex b/test/support/endpoint.ex index 1393295..c3b4ef8 100644 --- a/test/support/endpoint.ex +++ b/test/support/endpoint.ex @@ -2,13 +2,7 @@ defmodule GrpcReflection.TestEndpoint do defmodule V1Server do use GrpcReflection.Server, version: :v1, - services: [ - Helloworld.Greeter.Service, - TestserviceV2.TestService.Service, - TestserviceV3.TestService.Service, - Grpc.Reflection.V1.ServerReflection.Service, - Grpc.Reflection.V1alpha.ServerReflection.Service - ] + services: [ScalarTypes.ScalarService.Service] end defmodule V1Server.Stub do @@ -18,13 +12,7 @@ defmodule GrpcReflection.TestEndpoint do defmodule V1AlphaServer do use GrpcReflection.Server, version: :v1alpha, - services: [ - Helloworld.Greeter.Service, - TestserviceV2.TestService.Service, - TestserviceV3.TestService.Service, - Grpc.Reflection.V1.ServerReflection.Service, - Grpc.Reflection.V1alpha.ServerReflection.Service - ] + services: [ScalarTypes.ScalarService.Service] end defmodule V1AlphaServer.Stub do @@ -34,7 +22,6 @@ defmodule GrpcReflection.TestEndpoint do defmodule Endpoint do use GRPC.Endpoint - run(Helloworld.Greeter.Server) run(V1Server) run(V1AlphaServer) end diff --git a/test/support/grpc_case.ex b/test/support/grpc_case.ex index c6baf90..d468e19 100644 --- a/test/support/grpc_case.ex +++ b/test/support/grpc_case.ex @@ -1,77 +1,79 @@ defmodule GrpcCase do use ExUnit.CaseTemplate - using(service: service) do + using opts do + service = Keyword.get(opts, :service) + quote do import GrpcCase - setup_all do - Protobuf.load_extensions() - end - - defmodule V1Server do - use GrpcReflection.Server, version: :v1, services: [unquote(service)] - end - - defmodule V1Server.Stub do - use GRPC.Stub, service: Grpc.Reflection.V1.ServerReflection.Service - end - - defmodule V1AlphaServer do - use GrpcReflection.Server, version: :v1alpha, services: [unquote(service)] - end - - defmodule V1AlphaServer.Stub do - use GRPC.Stub, service: Grpc.Reflection.V1alpha.ServerReflection.Service - end - - defmodule Endpoint do - use GRPC.Endpoint - - run(V1Server) - run(V1AlphaServer) - end - - defp stub_v1_server(_) do - # %{endpoint: Endpoint, stub: V1Server.Stub} - - {:ok, _pid, port} = GRPC.Server.start_endpoint(Endpoint, 0) - on_exit(fn -> :ok = GRPC.Server.stop_endpoint(Endpoint, []) end) - start_supervised({GRPC.Client.Supervisor, []}) - - host = "localhost:#{port}" - {:ok, channel} = GRPC.Stub.connect(host) - - req = %Grpc.Reflection.V1.ServerReflectionRequest{host: host} - - %{ - channel: channel, - req: req, - version: :v1, - host: host, - endpoint: Endpoint, - stub: V1Server.Stub - } - end - - defp stub_v1alpha_server(_) do - {:ok, _pid, port} = GRPC.Server.start_endpoint(Endpoint, 0) - on_exit(fn -> :ok = GRPC.Server.stop_endpoint(Endpoint, []) end) - start_supervised({GRPC.Client.Supervisor, []}) - - host = "localhost:#{port}" - {:ok, channel} = GRPC.Stub.connect(host) - - req = %Grpc.Reflection.V1alpha.ServerReflectionRequest{host: host} - - %{ - channel: channel, - req: req, - version: :v1alpha, - host: host, - endpoint: Endpoint, - stub: V1AlphaServer.Stub - } + if unquote(service) do + setup_all do + Protobuf.load_extensions() + end + + defmodule V1Server do + use GrpcReflection.Server, version: :v1, services: [unquote(service)] + end + + defmodule V1Server.Stub do + use GRPC.Stub, service: Grpc.Reflection.V1.ServerReflection.Service + end + + defmodule V1AlphaServer do + use GrpcReflection.Server, version: :v1alpha, services: [unquote(service)] + end + + defmodule V1AlphaServer.Stub do + use GRPC.Stub, service: Grpc.Reflection.V1alpha.ServerReflection.Service + end + + defmodule Endpoint do + use GRPC.Endpoint + + run(V1Server) + run(V1AlphaServer) + end + + defp stub_v1_server(_) do + {:ok, _pid, port} = GRPC.Server.start_endpoint(Endpoint, 0) + on_exit(fn -> :ok = GRPC.Server.stop_endpoint(Endpoint, []) end) + start_supervised({GRPC.Client.Supervisor, []}) + + host = "localhost:#{port}" + {:ok, channel} = GRPC.Stub.connect(host) + + req = %Grpc.Reflection.V1.ServerReflectionRequest{host: host} + + %{ + channel: channel, + req: req, + version: :v1, + host: host, + endpoint: Endpoint, + stub: V1Server.Stub + } + end + + defp stub_v1alpha_server(_) do + {:ok, _pid, port} = GRPC.Server.start_endpoint(Endpoint, 0) + on_exit(fn -> :ok = GRPC.Server.stop_endpoint(Endpoint, []) end) + start_supervised({GRPC.Client.Supervisor, []}) + + host = "localhost:#{port}" + {:ok, channel} = GRPC.Stub.connect(host) + + req = %Grpc.Reflection.V1alpha.ServerReflectionRequest{host: host} + + %{ + channel: channel, + req: req, + version: :v1alpha, + host: host, + endpoint: Endpoint, + stub: V1AlphaServer.Stub + } + end end end end diff --git a/test/support/protos/empty.pb.ex b/test/support/protos/empty.pb.ex deleted file mode 100644 index 4fad29a..0000000 --- a/test/support/protos/empty.pb.ex +++ /dev/null @@ -1,21 +0,0 @@ -defmodule Empty.EmptyService.Service do - @moduledoc false - - use GRPC.Service, name: "empty.EmptyService", protoc_gen_elixir_version: "0.16.0" - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.ServiceDescriptorProto{ - name: "EmptyService", - method: [], - options: nil, - __unknown_fields__: [] - } - end -end - -defmodule Empty.EmptyService.Stub do - @moduledoc false - - use GRPC.Stub, service: Empty.EmptyService.Service -end diff --git a/test/support/protos/no_package.pb.ex b/test/support/protos/global_service.pb.ex similarity index 100% rename from test/support/protos/no_package.pb.ex rename to test/support/protos/global_service.pb.ex diff --git a/test/support/protos/hlw/pb_extension.pb.ex b/test/support/protos/hlw/pb_extension.pb.ex deleted file mode 100644 index a38c83d..0000000 --- a/test/support/protos/hlw/pb_extension.pb.ex +++ /dev/null @@ -1,9 +0,0 @@ -defmodule HLW.PbExtension do - @moduledoc false - - use Protobuf, protoc_gen_elixir_version: "0.16.0" - - extend HLW.TestRequest, :data, 10, optional: true, type: :string - - extend HLW.TestRequest, :location, 11, optional: true, type: HLW.Location -end diff --git a/test/support/protos/test_service_v2.pb.ex b/test/support/protos/test_service_v2.pb.ex deleted file mode 100644 index 923aa71..0000000 --- a/test/support/protos/test_service_v2.pb.ex +++ /dev/null @@ -1,436 +0,0 @@ -defmodule TestserviceV2.Enum do - @moduledoc false - - use Protobuf, - enum: true, - full_name: "testserviceV2.Enum", - protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.EnumDescriptorProto{ - name: "Enum", - value: [ - %Google.Protobuf.EnumValueDescriptorProto{ - name: "A", - number: 0, - options: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.EnumValueDescriptorProto{ - name: "B", - number: 1, - options: nil, - __unknown_fields__: [] - } - ], - options: nil, - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - end - - field :A, 0 - field :B, 1 -end - -defmodule TestserviceV2.TestRequest.GEntry do - @moduledoc false - - use Protobuf, - full_name: "testserviceV2.TestRequest.GEntry", - map: true, - protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.DescriptorProto{ - name: "GEntry", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "key", - extendee: nil, - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "key", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "value", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_INT32, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "value", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [], - enum_type: [], - extension_range: [], - extension: [], - options: %Google.Protobuf.MessageOptions{ - message_set_wire_format: false, - no_standard_descriptor_accessor: false, - deprecated: false, - map_entry: true, - deprecated_legacy_json_field_conflicts: nil, - features: nil, - uninterpreted_option: [], - __pb_extensions__: %{}, - __unknown_fields__: [] - }, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - end - - field :key, 1, optional: true, type: :string - field :value, 2, optional: true, type: :int32 -end - -defmodule TestserviceV2.TestRequest do - @moduledoc false - - use Protobuf, - full_name: "testserviceV2.TestRequest", - protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.DescriptorProto{ - name: "TestRequest", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "name", - extendee: nil, - number: 1, - label: :LABEL_REQUIRED, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "name", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "enum", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_ENUM, - type_name: ".testserviceV2.Enum", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "enum", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "label", - extendee: nil, - number: 3, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: 0, - json_name: "label", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "value", - extendee: nil, - number: 4, - label: :LABEL_OPTIONAL, - type: :TYPE_INT32, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: 0, - json_name: "value", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "g", - extendee: nil, - number: 5, - label: :LABEL_REPEATED, - type: :TYPE_MESSAGE, - type_name: ".testserviceV2.TestRequest.GEntry", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "g", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "instrument", - extendee: nil, - number: 6, - label: :LABEL_REPEATED, - type: :TYPE_MESSAGE, - type_name: ".google.protobuf.Any", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "instrument", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [ - %Google.Protobuf.DescriptorProto{ - name: "GEntry", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "key", - extendee: nil, - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_STRING, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "key", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "value", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_INT32, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "value", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [], - enum_type: [], - extension_range: [], - extension: [], - options: %Google.Protobuf.MessageOptions{ - message_set_wire_format: false, - no_standard_descriptor_accessor: false, - deprecated: false, - map_entry: true, - deprecated_legacy_json_field_conflicts: nil, - features: nil, - uninterpreted_option: [], - __pb_extensions__: %{}, - __unknown_fields__: [] - }, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - ], - enum_type: [], - extension_range: [ - %Google.Protobuf.DescriptorProto.ExtensionRange{ - start: 10, - end: 21, - options: nil, - __unknown_fields__: [] - } - ], - extension: [], - options: nil, - oneof_decl: [ - %Google.Protobuf.OneofDescriptorProto{ - name: "test_oneof", - options: nil, - __unknown_fields__: [] - } - ], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - end - - oneof :test_oneof, 0 - - field :name, 1, required: true, type: :string - field :enum, 2, optional: true, type: TestserviceV2.Enum, enum: true - field :label, 3, optional: true, type: :string, oneof: 0 - field :value, 4, optional: true, type: :int32, oneof: 0 - field :g, 5, repeated: true, type: TestserviceV2.TestRequest.GEntry, map: true - field :instrument, 6, repeated: true, type: Google.Protobuf.Any - - extensions [{10, 21}] -end - -defmodule TestserviceV2.Location do - @moduledoc false - - use Protobuf, - full_name: "testserviceV2.Location", - protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.DescriptorProto{ - name: "Location", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "latitude", - extendee: nil, - number: 1, - label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "latitude", - proto3_optional: nil, - __unknown_fields__: [] - }, - %Google.Protobuf.FieldDescriptorProto{ - name: "longitude", - extendee: nil, - number: 2, - label: :LABEL_OPTIONAL, - type: :TYPE_DOUBLE, - type_name: nil, - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "longitude", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [], - enum_type: [], - extension_range: [], - extension: [], - options: nil, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - end - - field :latitude, 1, optional: true, type: :double - field :longitude, 2, optional: true, type: :double -end - -defmodule TestserviceV2.TestReply do - @moduledoc false - - use Protobuf, - full_name: "testserviceV2.TestReply", - protoc_gen_elixir_version: "0.16.0", - syntax: :proto2 - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.DescriptorProto{ - name: "TestReply", - field: [ - %Google.Protobuf.FieldDescriptorProto{ - name: "today", - extendee: nil, - number: 2, - label: :LABEL_REQUIRED, - type: :TYPE_MESSAGE, - type_name: ".google.protobuf.Timestamp", - default_value: nil, - options: nil, - oneof_index: nil, - json_name: "today", - proto3_optional: nil, - __unknown_fields__: [] - } - ], - nested_type: [], - enum_type: [], - extension_range: [], - extension: [], - options: nil, - oneof_decl: [], - reserved_range: [], - reserved_name: [], - __unknown_fields__: [] - } - end - - field :today, 2, required: true, type: Google.Protobuf.Timestamp -end - -defmodule TestserviceV2.TestService.Service do - @moduledoc false - - use GRPC.Service, name: "testserviceV2.TestService", protoc_gen_elixir_version: "0.16.0" - - def descriptor do - # credo:disable-for-next-line - %Google.Protobuf.ServiceDescriptorProto{ - name: "TestService", - method: [ - %Google.Protobuf.MethodDescriptorProto{ - name: "CallFunction", - input_type: ".testserviceV2.TestRequest", - output_type: ".testserviceV2.TestReply", - options: %Google.Protobuf.MethodOptions{ - deprecated: false, - idempotency_level: :IDEMPOTENCY_UNKNOWN, - features: nil, - uninterpreted_option: [], - __pb_extensions__: %{}, - __unknown_fields__: [] - }, - client_streaming: false, - server_streaming: false, - __unknown_fields__: [] - } - ], - options: nil, - __unknown_fields__: [] - } - end - - rpc :CallFunction, TestserviceV2.TestRequest, TestserviceV2.TestReply -end - -defmodule TestserviceV2.TestService.Stub do - @moduledoc false - - use GRPC.Stub, service: TestserviceV2.TestService.Service -end diff --git a/test/support/protos/testservice_v2/pb_extension.pb.ex b/test/support/protos/testservice_v2/pb_extension.pb.ex deleted file mode 100644 index 86b53bb..0000000 --- a/test/support/protos/testservice_v2/pb_extension.pb.ex +++ /dev/null @@ -1,9 +0,0 @@ -defmodule TestserviceV2.PbExtension do - @moduledoc false - - use Protobuf, protoc_gen_elixir_version: "0.16.0" - - extend TestserviceV2.TestRequest, :data, 10, optional: true, type: :string - - extend TestserviceV2.TestRequest, :location, 11, optional: true, type: TestserviceV2.Location -end From 9da6fd3f43361a61f3a3d51d9ca3dc0edff2d337 Mon Sep 17 00:00:00 2001 From: Michael Heilmann Date: Thu, 30 Apr 2026 13:54:33 -0400 Subject: [PATCH 7/8] flesh out test coverage --- test/case/edge_cases_test.exs | 32 +++++++++ test/case/imports_test_test.exs | 58 ++++++++++++++++- test/case/multistream_service_test.exs | 16 ++++- test/case/proto2_features_test.exs | 38 +++++++++++ test/case/scalar_types_test.exs | 90 +++++++++++++++++++++++++- test/case/streaming_service_test.exs | 19 +++++- 6 files changed, 247 insertions(+), 6 deletions(-) diff --git a/test/case/edge_cases_test.exs b/test/case/edge_cases_test.exs index 155bb94..be30046 100644 --- a/test/case/edge_cases_test.exs +++ b/test/case/edge_cases_test.exs @@ -29,6 +29,38 @@ defmodule GrpcReflection.Case.EdgeCasesTest do } = response end + test "empty request message has no fields", ctx do + message = {:file_containing_symbol, "edge_cases.EmptyInputRequest"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + message_type: [ + %Google.Protobuf.DescriptorProto{name: "EmptyInputRequest", field: []} + ] + } = response + end + + test "message with only a response field reflects correctly", ctx do + message = {:file_containing_symbol, "edge_cases.EmptyInputResponse"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + message_type: [ + %Google.Protobuf.DescriptorProto{ + name: "EmptyInputResponse", + field: [ + %Google.Protobuf.FieldDescriptorProto{ + name: "data", + number: 1, + type: :TYPE_STRING, + label: :LABEL_OPTIONAL + } + ] + } + ] + } = response + end + test "reflection graph is traversable using grpcurl", ctx do ops = GrpcReflection.TestClient.grpcurl_service(ctx) diff --git a/test/case/imports_test_test.exs b/test/case/imports_test_test.exs index b749a8f..c398164 100644 --- a/test/case/imports_test_test.exs +++ b/test/case/imports_test_test.exs @@ -23,12 +23,68 @@ defmodule GrpcReflection.Case.ImportsTestServiceTest do package: "imports_test", service: [ %Google.Protobuf.ServiceDescriptorProto{ - name: "ImportTestService" + name: "ImportTestService", + method: [ + %Google.Protobuf.MethodDescriptorProto{ + name: "CreateUser", + input_type: ".imports_test.UserRequest", + output_type: ".imports_test.UserResponse" + }, + %Google.Protobuf.MethodDescriptorProto{ + name: "UpdateLocation", + input_type: ".imports_test.LocationUpdate", + output_type: ".imports_test.LocationResponse" + } + ] } ] } = response end + test "imported type from common_types is resolvable by symbol", ctx do + message = {:file_containing_symbol, "common.Address"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "common", + message_type: [ + %Google.Protobuf.DescriptorProto{ + name: "Address", + field: fields + } + ] + } = response + + by_name = Map.new(fields, &{&1.name, &1}) + assert %{type: :TYPE_STRING, number: 1} = by_name["street"] + assert %{type: :TYPE_STRING, number: 2} = by_name["city"] + assert %{type: :TYPE_STRING, number: 5} = by_name["country"] + end + + test "request message lists its cross-package dependencies", ctx do + message = {:file_by_filename, "imports_test.UserRequest.proto"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + name: "imports_test.UserRequest.proto", + package: "imports_test" + } = response + + assert "common.Address.proto" in response.dependency + assert "common.Coordinates.proto" in response.dependency + assert "google.protobuf.Timestamp.proto" in response.dependency + end + + test "imported google type is resolvable by symbol", ctx do + message = {:file_containing_symbol, "google.protobuf.Timestamp"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "google.protobuf", + message_type: [%Google.Protobuf.DescriptorProto{name: "Timestamp"}] + } = response + end + test "reflection graph is traversable using grpcurl", ctx do ops = GrpcReflection.TestClient.grpcurl_service(ctx) diff --git a/test/case/multistream_service_test.exs b/test/case/multistream_service_test.exs index 01381a5..680462e 100644 --- a/test/case/multistream_service_test.exs +++ b/test/case/multistream_service_test.exs @@ -16,13 +16,25 @@ defmodule GrpcReflection.Case.MultiStreamingTest do assert Enum.map(service_list, &Map.get(&1, :name)) == expected_services end - test "should list methods on StreamingService", ctx do + test "should list methods on MultiStreamService with correct streaming flags", ctx do message = {:file_containing_symbol, "streaming.MultiStreamService"} assert {:ok, response} = run_request(message, ctx) assert %Google.Protobuf.FileDescriptorProto{ - package: "streaming" + package: "streaming", + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "MultiStreamService", + method: methods + } + ] } = response + + by_name = Map.new(methods, &{&1.name, &1}) + + assert %{client_streaming: true, server_streaming: false} = by_name["UploadData"] + assert %{client_streaming: false, server_streaming: true} = by_name["DownloadData"] + assert %{client_streaming: true, server_streaming: true} = by_name["SyncData"] end test "reflection graph is traversable using grpcurl", ctx do diff --git a/test/case/proto2_features_test.exs b/test/case/proto2_features_test.exs index fbdc6aa..e9da6c2 100644 --- a/test/case/proto2_features_test.exs +++ b/test/case/proto2_features_test.exs @@ -24,6 +24,44 @@ defmodule GrpcReflection.Case.Proto2FeaturesTest do } = response end + test "proto2 required fields have LABEL_REQUIRED", ctx do + message = {:file_containing_symbol, "proto2_features.Proto2Request"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + message_type: [ + %Google.Protobuf.DescriptorProto{name: "Proto2Request", field: fields} + ] + } = response + + by_name = Map.new(fields, &{&1.name, &1}) + + assert %{label: :LABEL_REQUIRED, type: :TYPE_STRING, number: 1} = + by_name["required_field"] + + assert %{label: :LABEL_REQUIRED, type: :TYPE_INT32, number: 2} = by_name["required_id"] + + assert %{label: :LABEL_OPTIONAL, type: :TYPE_STRING, number: 3} = + by_name["optional_field"] + + assert %{label: :LABEL_OPTIONAL, type: :TYPE_INT32, number: 4} = by_name["optional_id"] + end + + test "proto2 response required fields have LABEL_REQUIRED", ctx do + message = {:file_containing_symbol, "proto2_features.Proto2Response"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + message_type: [ + %Google.Protobuf.DescriptorProto{name: "Proto2Response", field: fields} + ] + } = response + + by_name = Map.new(fields, &{&1.name, &1}) + assert %{label: :LABEL_REQUIRED, type: :TYPE_BOOL, number: 1} = by_name["success"] + assert %{label: :LABEL_OPTIONAL, type: :TYPE_STRING, number: 2} = by_name["message"] + end + test "should return extension numbers for an extendable type", ctx do message = {:all_extension_numbers_of_type, "proto2_features.Proto2Request"} assert {:ok, response} = run_request(message, ctx) diff --git a/test/case/scalar_types_test.exs b/test/case/scalar_types_test.exs index a25eab9..c37ad13 100644 --- a/test/case/scalar_types_test.exs +++ b/test/case/scalar_types_test.exs @@ -26,7 +26,11 @@ defmodule GrpcReflection.Case.ScalarTypesTest do name: "ScalarService", method: [ %Google.Protobuf.MethodDescriptorProto{ - name: "ProcessScalars" + name: "ProcessScalars", + input_type: ".scalar_types.ScalarRequest", + output_type: ".scalar_types.ScalarReply", + client_streaming: false, + server_streaming: false } ] } @@ -34,6 +38,90 @@ defmodule GrpcReflection.Case.ScalarTypesTest do } = response end + test "should reflect all scalar field types on ScalarRequest", ctx do + message = {:file_containing_symbol, "scalar_types.ScalarRequest"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + package: "scalar_types", + message_type: [ + %Google.Protobuf.DescriptorProto{ + name: "ScalarRequest", + field: fields + } + ] + } = response + + by_name = Map.new(fields, &{&1.name, &1}) + + assert %{type: :TYPE_DOUBLE, number: 1, label: :LABEL_OPTIONAL} = by_name["double_field"] + assert %{type: :TYPE_FLOAT, number: 2, label: :LABEL_OPTIONAL} = by_name["float_field"] + assert %{type: :TYPE_INT32, number: 3, label: :LABEL_OPTIONAL} = by_name["int32_field"] + assert %{type: :TYPE_INT64, number: 4, label: :LABEL_OPTIONAL} = by_name["int64_field"] + assert %{type: :TYPE_UINT32, number: 5, label: :LABEL_OPTIONAL} = by_name["uint32_field"] + assert %{type: :TYPE_UINT64, number: 6, label: :LABEL_OPTIONAL} = by_name["uint64_field"] + assert %{type: :TYPE_SINT32, number: 7, label: :LABEL_OPTIONAL} = by_name["sint32_field"] + assert %{type: :TYPE_SINT64, number: 8, label: :LABEL_OPTIONAL} = by_name["sint64_field"] + + assert %{type: :TYPE_FIXED32, number: 9, label: :LABEL_OPTIONAL} = + by_name["fixed32_field"] + + assert %{type: :TYPE_FIXED64, number: 10, label: :LABEL_OPTIONAL} = + by_name["fixed64_field"] + + assert %{type: :TYPE_SFIXED32, number: 11, label: :LABEL_OPTIONAL} = + by_name["sfixed32_field"] + + assert %{type: :TYPE_SFIXED64, number: 12, label: :LABEL_OPTIONAL} = + by_name["sfixed64_field"] + + assert %{type: :TYPE_BOOL, number: 13, label: :LABEL_OPTIONAL} = by_name["bool_field"] + assert %{type: :TYPE_STRING, number: 14, label: :LABEL_OPTIONAL} = by_name["string_field"] + assert %{type: :TYPE_BYTES, number: 15, label: :LABEL_OPTIONAL} = by_name["bytes_field"] + + assert %{type: :TYPE_STRING, number: 100, label: :LABEL_OPTIONAL} = + by_name["sparse_field_1"] + + assert %{type: :TYPE_STRING, number: 1000, label: :LABEL_OPTIONAL} = + by_name["sparse_field_2"] + + assert %{type: :TYPE_STRING, number: 10000, label: :LABEL_OPTIONAL} = + by_name["sparse_field_3"] + end + + test "should reflect proto3 optional fields with presence tracking", ctx do + message = {:file_containing_symbol, "scalar_types.ScalarRequest"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + message_type: [%Google.Protobuf.DescriptorProto{field: fields}] + } = response + + by_name = Map.new(fields, &{&1.name, &1}) + + assert %{type: :TYPE_STRING, number: 18, proto3_optional: true} = + by_name["optional_string"] + + assert %{type: :TYPE_INT32, number: 19, proto3_optional: true} = by_name["optional_int"] + end + + test "should reflect repeated fields on ScalarReply", ctx do + message = {:file_containing_symbol, "scalar_types.ScalarReply"} + assert {:ok, response} = run_request(message, ctx) + + assert %Google.Protobuf.FileDescriptorProto{ + message_type: [ + %Google.Protobuf.DescriptorProto{name: "ScalarReply", field: fields} + ] + } = response + + assert Enum.all?(fields, &(&1.label == :LABEL_REPEATED)) + by_name = Map.new(fields, &{&1.name, &1}) + assert %{type: :TYPE_DOUBLE} = by_name["double_list"] + assert %{type: :TYPE_BYTES} = by_name["bytes_list"] + assert %{type: :TYPE_BOOL} = by_name["bool_list"] + end + test "reflection graph is traversable using grpcurl", ctx do ops = GrpcReflection.TestClient.grpcurl_service(ctx) diff --git a/test/case/streaming_service_test.exs b/test/case/streaming_service_test.exs index f61030b..e0e54ea 100644 --- a/test/case/streaming_service_test.exs +++ b/test/case/streaming_service_test.exs @@ -16,13 +16,28 @@ defmodule GrpcReflection.Case.StreamingTest do assert Enum.map(service_list, &Map.get(&1, :name)) == expected_services end - test "should list methods on StreamingService", ctx do + test "should list methods on StreamingService with correct streaming flags", ctx do message = {:file_containing_symbol, "streaming.StreamingService"} assert {:ok, response} = run_request(message, ctx) assert %Google.Protobuf.FileDescriptorProto{ - package: "streaming" + package: "streaming", + service: [ + %Google.Protobuf.ServiceDescriptorProto{ + name: "StreamingService", + method: methods + } + ] } = response + + by_name = Map.new(methods, &{&1.name, &1}) + + assert %{client_streaming: false, server_streaming: false} = by_name["UnaryCall"] + assert %{client_streaming: false, server_streaming: true} = by_name["ServerStreamingCall"] + assert %{client_streaming: true, server_streaming: false} = by_name["ClientStreamingCall"] + + assert %{client_streaming: true, server_streaming: true} = + by_name["BidirectionalStreamingCall"] end test "reflection graph is traversable using grpcurl", ctx do From 0eca50dd170e6c2d04549555237927264189b516 Mon Sep 17 00:00:00 2001 From: Michael Heilmann Date: Thu, 30 Apr 2026 14:24:45 -0400 Subject: [PATCH 8/8] linting --- test/case/scalar_types_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/case/scalar_types_test.exs b/test/case/scalar_types_test.exs index c37ad13..c975d82 100644 --- a/test/case/scalar_types_test.exs +++ b/test/case/scalar_types_test.exs @@ -85,7 +85,7 @@ defmodule GrpcReflection.Case.ScalarTypesTest do assert %{type: :TYPE_STRING, number: 1000, label: :LABEL_OPTIONAL} = by_name["sparse_field_2"] - assert %{type: :TYPE_STRING, number: 10000, label: :LABEL_OPTIONAL} = + assert %{type: :TYPE_STRING, number: 10_000, label: :LABEL_OPTIONAL} = by_name["sparse_field_3"] end