protobuffy 3.6.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +67 -0
- data/.rubocop_todo.yml +145 -0
- data/.travis.yml +25 -5
- data/CHANGES.md +55 -0
- data/CONTRIBUTING.md +1 -1
- data/LICENSE.txt +17 -9
- data/README.md +13 -12
- data/Rakefile +15 -11
- data/bin/protoc-gen-ruby +8 -3
- data/bin/rpc_server +1 -0
- data/examples/lib/example/reverse-client.rb +2 -2
- data/install-protobuf.sh +28 -0
- data/lib/protobuf.rb +57 -53
- data/lib/protobuf/cli.rb +94 -74
- data/lib/protobuf/code_generator.rb +60 -9
- data/lib/protobuf/decoder.rb +19 -65
- data/lib/protobuf/deprecation.rb +117 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +11 -1
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +55 -3
- data/lib/protobuf/encoder.rb +13 -53
- data/lib/protobuf/enum.rb +58 -63
- data/lib/protobuf/field.rb +4 -4
- data/lib/protobuf/field/base_field.rb +101 -173
- data/lib/protobuf/field/bool_field.rb +17 -11
- data/lib/protobuf/field/bytes_field.rb +21 -35
- data/lib/protobuf/field/double_field.rb +0 -1
- data/lib/protobuf/field/enum_field.rb +23 -22
- data/lib/protobuf/field/field_array.rb +5 -4
- data/lib/protobuf/field/fixed32_field.rb +1 -1
- data/lib/protobuf/field/fixed64_field.rb +0 -1
- data/lib/protobuf/field/float_field.rb +4 -1
- data/lib/protobuf/field/int32_field.rb +0 -1
- data/lib/protobuf/field/int64_field.rb +0 -1
- data/lib/protobuf/field/integer_field.rb +0 -1
- data/lib/protobuf/field/message_field.rb +13 -28
- data/lib/protobuf/field/sfixed32_field.rb +0 -1
- data/lib/protobuf/field/sfixed64_field.rb +0 -1
- data/lib/protobuf/field/signed_integer_field.rb +0 -1
- data/lib/protobuf/field/sint32_field.rb +0 -1
- data/lib/protobuf/field/sint64_field.rb +0 -1
- data/lib/protobuf/field/string_field.rb +2 -4
- data/lib/protobuf/field/uint32_field.rb +0 -1
- data/lib/protobuf/field/uint64_field.rb +0 -1
- data/lib/protobuf/field/varint_field.rb +30 -13
- data/lib/protobuf/generators/base.rb +30 -16
- data/lib/protobuf/generators/enum_generator.rb +6 -9
- data/lib/protobuf/generators/extension_generator.rb +1 -2
- data/lib/protobuf/generators/field_generator.rb +25 -13
- data/lib/protobuf/generators/file_generator.rb +157 -35
- data/lib/protobuf/generators/group_generator.rb +22 -17
- data/lib/protobuf/generators/message_generator.rb +13 -14
- data/lib/protobuf/generators/option_generator.rb +17 -0
- data/lib/protobuf/generators/printable.rb +12 -13
- data/lib/protobuf/generators/service_generator.rb +2 -3
- data/lib/protobuf/http.rb +2 -2
- data/lib/protobuf/lifecycle.rb +20 -33
- data/lib/protobuf/logging.rb +39 -0
- data/lib/protobuf/message.rb +114 -47
- data/lib/protobuf/message/fields.rb +170 -88
- data/lib/protobuf/message/serialization.rb +19 -18
- data/lib/protobuf/optionable.rb +53 -6
- data/lib/protobuf/rpc/buffer.rb +18 -19
- data/lib/protobuf/rpc/client.rb +22 -50
- data/lib/protobuf/rpc/connectors/base.rb +177 -12
- data/lib/protobuf/rpc/connectors/http.rb +14 -9
- data/lib/protobuf/rpc/connectors/ping.rb +89 -0
- data/lib/protobuf/rpc/connectors/socket.rb +13 -8
- data/lib/protobuf/rpc/connectors/zmq.rb +178 -73
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +4 -1
- data/lib/protobuf/rpc/env.rb +12 -12
- data/lib/protobuf/rpc/error.rb +3 -3
- data/lib/protobuf/rpc/error/client_error.rb +4 -4
- data/lib/protobuf/rpc/error/server_error.rb +9 -9
- data/lib/protobuf/rpc/middleware/exception_handler.rb +6 -2
- data/lib/protobuf/rpc/middleware/logger.rb +8 -4
- data/lib/protobuf/rpc/middleware/request_decoder.rb +17 -21
- data/lib/protobuf/rpc/middleware/response_encoder.rb +22 -27
- data/lib/protobuf/rpc/middleware/statsd.rb +3 -3
- data/lib/protobuf/rpc/rpc.pb.rb +4 -1
- data/lib/protobuf/rpc/server.rb +1 -1
- data/lib/protobuf/rpc/servers/http/server.rb +19 -17
- data/lib/protobuf/rpc/servers/socket/server.rb +78 -70
- data/lib/protobuf/rpc/servers/socket/worker.rb +4 -4
- data/lib/protobuf/rpc/servers/socket_runner.rb +27 -15
- data/lib/protobuf/rpc/servers/zmq/broker.rb +70 -31
- data/lib/protobuf/rpc/servers/zmq/server.rb +55 -47
- data/lib/protobuf/rpc/servers/zmq/util.rb +14 -13
- data/lib/protobuf/rpc/servers/zmq/worker.rb +16 -16
- data/lib/protobuf/rpc/servers/zmq_runner.rb +26 -7
- data/lib/protobuf/rpc/service.rb +21 -27
- data/lib/protobuf/rpc/service_directory.rb +43 -27
- data/lib/protobuf/rpc/service_dispatcher.rb +9 -10
- data/lib/protobuf/rpc/service_filters.rb +32 -55
- data/lib/protobuf/rpc/stat.rb +4 -8
- data/lib/protobuf/socket.rb +1 -2
- data/lib/protobuf/tasks/compile.rake +3 -4
- data/lib/protobuf/varint.rb +9 -0
- data/lib/protobuf/varint_pure.rb +13 -0
- data/lib/protobuf/version.rb +1 -1
- data/lib/protobuf/zmq.rb +2 -2
- data/proto/google/protobuf/descriptor.proto +190 -31
- data/protobuffy.gemspec +30 -17
- data/spec/benchmark/tasks.rb +27 -19
- data/spec/bin/protoc-gen-ruby_spec.rb +11 -6
- data/spec/encoding/all_types_spec.rb +96 -84
- data/spec/encoding/extreme_values_spec.rb +0 -0
- data/spec/functional/class_inheritance_spec.rb +52 -0
- data/spec/functional/code_generator_spec.rb +38 -0
- data/spec/functional/socket_server_spec.rb +15 -15
- data/spec/functional/zmq_server_spec.rb +29 -27
- data/spec/lib/protobuf/cli_spec.rb +82 -67
- data/spec/lib/protobuf/code_generator_spec.rb +37 -10
- data/spec/lib/protobuf/enum_spec.rb +77 -46
- data/spec/lib/protobuf/field/bool_field_spec.rb +91 -0
- data/spec/lib/protobuf/field/double_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/enum_field_spec.rb +26 -0
- data/spec/lib/protobuf/field/field_array_spec.rb +69 -0
- data/spec/lib/protobuf/field/fixed32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/fixed64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/float_field_spec.rb +90 -0
- data/spec/lib/protobuf/field/int32_field_spec.rb +114 -1
- data/spec/lib/protobuf/field/int64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/message_field_spec.rb +132 -0
- data/spec/lib/protobuf/field/sfixed32_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sfixed64_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sint32_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sint64_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/string_field_spec.rb +44 -11
- data/spec/lib/protobuf/field/uint32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/uint64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field_spec.rb +4 -6
- data/spec/lib/protobuf/generators/base_spec.rb +80 -13
- data/spec/lib/protobuf/generators/enum_generator_spec.rb +35 -21
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +12 -13
- data/spec/lib/protobuf/generators/field_generator_spec.rb +73 -21
- data/spec/lib/protobuf/generators/file_generator_spec.rb +89 -6
- data/spec/lib/protobuf/generators/service_generator_spec.rb +25 -13
- data/spec/lib/protobuf/lifecycle_spec.rb +25 -20
- data/spec/lib/protobuf/message_spec.rb +578 -79
- data/spec/lib/protobuf/optionable_spec.rb +202 -26
- data/spec/lib/protobuf/rpc/client_spec.rb +16 -16
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +167 -13
- data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +4 -5
- data/spec/lib/protobuf/rpc/connectors/http_spec.rb +13 -11
- data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +6 -7
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +35 -52
- data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +10 -10
- data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +11 -11
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +23 -23
- data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +11 -11
- data/spec/lib/protobuf/rpc/middleware/statsd_spec.rb +6 -6
- data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +47 -44
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +6 -6
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +12 -10
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +11 -11
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +7 -7
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +47 -49
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +8 -25
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +102 -69
- data/spec/lib/protobuf/rpc/service_spec.rb +37 -36
- data/spec/lib/protobuf/rpc/stat_spec.rb +7 -9
- data/spec/lib/protobuf/varint_spec.rb +29 -0
- data/spec/lib/protobuf_spec.rb +55 -28
- data/spec/spec_helper.rb +12 -27
- data/spec/support/all.rb +0 -1
- data/spec/support/packed_field.rb +4 -3
- data/spec/support/{test → protos}/all_types.data.bin +0 -0
- data/spec/support/{test → protos}/all_types.data.txt +0 -0
- data/spec/support/{test → protos}/enum.pb.rb +8 -4
- data/spec/support/{test → protos}/enum.proto +4 -1
- data/spec/support/{test → protos}/extreme_values.data.bin +0 -0
- data/spec/support/protos/google_unittest.bin +0 -0
- data/spec/support/protos/google_unittest.pb.rb +798 -0
- data/spec/support/{test → protos}/google_unittest.proto +237 -66
- data/spec/support/protos/google_unittest_custom_options.bin +0 -0
- data/spec/support/protos/google_unittest_custom_options.pb.rb +268 -0
- data/spec/support/protos/google_unittest_custom_options.proto +424 -0
- data/spec/support/protos/google_unittest_import.pb.rb +55 -0
- data/spec/support/{test → protos}/google_unittest_import.proto +19 -10
- data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
- data/spec/support/{test → protos}/google_unittest_import_public.proto +8 -5
- data/spec/support/{test → protos}/multi_field_extensions.pb.rb +5 -2
- data/spec/support/{test → protos}/multi_field_extensions.proto +2 -0
- data/spec/support/{test → protos}/resource.pb.rb +47 -11
- data/spec/support/{test → protos}/resource.proto +24 -1
- data/spec/support/resource_service.rb +23 -0
- data/spec/support/server.rb +32 -61
- metadata +119 -59
- data/lib/protobuf/deprecator.rb +0 -42
- data/lib/protobuf/logger.rb +0 -93
- data/lib/protobuf/rpc/connector.rb +0 -21
- data/lib/protobuf/rpc/connectors/common.rb +0 -172
- data/spec/data/data.bin +0 -3
- data/spec/data/types.bin +0 -0
- data/spec/lib/protobuf/logger_spec.rb +0 -145
- data/spec/lib/protobuf/rpc/connector_spec.rb +0 -26
- data/spec/lib/protobuf/rpc/connectors/common_spec.rb +0 -170
- data/spec/support/test/defaults.pb.rb +0 -25
- data/spec/support/test/defaults.proto +0 -9
- data/spec/support/test/extended.pb.rb +0 -22
- data/spec/support/test/extended.proto +0 -10
- data/spec/support/test/google_unittest.pb.rb +0 -543
- data/spec/support/test/google_unittest_import.pb.rb +0 -37
- data/spec/support/test/google_unittest_import_public.pb.rb +0 -8
- data/spec/support/test/resource_service.rb +0 -26
- data/spec/support/tolerance_matcher.rb +0 -40
@@ -1,28 +1,28 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Protobuf::Rpc::Middleware::ResponseEncoder do
|
4
|
-
let(:app) {
|
5
|
-
let(:env)
|
3
|
+
RSpec.describe Protobuf::Rpc::Middleware::ResponseEncoder do
|
4
|
+
let(:app) { proc { |env| env.response = response; env } }
|
5
|
+
let(:env) do
|
6
6
|
Protobuf::Rpc::Env.new(
|
7
7
|
'response_type' => Test::Resource,
|
8
8
|
'log_signature' => 'log_signature'
|
9
9
|
)
|
10
|
-
|
10
|
+
end
|
11
11
|
let(:encoded_response) { response_wrapper.encode }
|
12
12
|
let(:response) { Test::Resource.new(:name => 'required') }
|
13
|
-
let(:response_wrapper) { Protobuf::Socketrpc::Response.new(:response_proto => response) }
|
13
|
+
let(:response_wrapper) { ::Protobuf::Socketrpc::Response.new(:response_proto => response) }
|
14
14
|
|
15
15
|
subject { described_class.new(app) }
|
16
16
|
|
17
17
|
describe "#call" do
|
18
18
|
it "encodes the response" do
|
19
19
|
stack_env = subject.call(env)
|
20
|
-
stack_env.encoded_response.
|
20
|
+
expect(stack_env.encoded_response).to eq encoded_response
|
21
21
|
end
|
22
22
|
|
23
23
|
it "calls the stack" do
|
24
24
|
stack_env = subject.call(env)
|
25
|
-
stack_env.response.
|
25
|
+
expect(stack_env.response).to eq response
|
26
26
|
end
|
27
27
|
|
28
28
|
context "when response is responds to :to_hash" do
|
@@ -31,7 +31,7 @@ describe Protobuf::Rpc::Middleware::ResponseEncoder do
|
|
31
31
|
|
32
32
|
it "sets Env#response" do
|
33
33
|
stack_env = subject.call(env)
|
34
|
-
stack_env.response.
|
34
|
+
expect(stack_env.response).to eq response
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -41,7 +41,7 @@ describe Protobuf::Rpc::Middleware::ResponseEncoder do
|
|
41
41
|
|
42
42
|
it "sets Env#response" do
|
43
43
|
stack_env = subject.call(env)
|
44
|
-
stack_env.response.
|
44
|
+
expect(stack_env.response).to eq response
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -60,12 +60,12 @@ describe Protobuf::Rpc::Middleware::ResponseEncoder do
|
|
60
60
|
|
61
61
|
it "wraps and encodes the response" do
|
62
62
|
stack_env = subject.call(env)
|
63
|
-
stack_env.encoded_response.
|
63
|
+
expect(stack_env.encoded_response).to eq encoded_response
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
67
|
context "when encoding fails" do
|
68
|
-
before { Protobuf::Socketrpc::Response.
|
68
|
+
before { allow_any_instance_of(::Protobuf::Socketrpc::Response).to receive(:encode).and_raise(RuntimeError) }
|
69
69
|
|
70
70
|
it "raises a bad request data exception" do
|
71
71
|
expect { subject.call(env) }.to raise_exception(Protobuf::Rpc::PbError)
|
@@ -2,8 +2,8 @@ require 'spec_helper'
|
|
2
2
|
require 'timecop'
|
3
3
|
|
4
4
|
describe Protobuf::Rpc::Middleware::Statsd do
|
5
|
-
let(:app) {
|
6
|
-
let(:env)
|
5
|
+
let(:app) { proc { |inner_env| Timecop.freeze(Time.now + call_time); inner_env } }
|
6
|
+
let(:env) do
|
7
7
|
Protobuf::Rpc::Env.new(
|
8
8
|
'client_host' => 'client_host.test.co',
|
9
9
|
'encoded_request' => request_wrapper.encode,
|
@@ -15,19 +15,19 @@ describe Protobuf::Rpc::Middleware::Statsd do
|
|
15
15
|
'response_type' => rpc_method.response_type,
|
16
16
|
'rpc_method' => rpc_method,
|
17
17
|
'rpc_service' => service_class,
|
18
|
-
'service_name' => service_name
|
18
|
+
'service_name' => service_name
|
19
19
|
)
|
20
|
-
|
20
|
+
end
|
21
21
|
let(:method_name) { :find }
|
22
22
|
let(:request) { request_type.new(:name => 'required') }
|
23
23
|
let(:request_type) { rpc_method.request_type }
|
24
|
-
let(:request_wrapper)
|
24
|
+
let(:request_wrapper) do
|
25
25
|
Protobuf::Socketrpc::Request.new(
|
26
26
|
:service_name => service_name,
|
27
27
|
:method_name => method_name.to_s,
|
28
28
|
:request_proto => request
|
29
29
|
)
|
30
|
-
|
30
|
+
end
|
31
31
|
let(:response) { rpc_method.response_type.new(:name => 'required') }
|
32
32
|
let(:response_wrapper) { Protobuf::Socketrpc::Response.new(:response_proto => response) }
|
33
33
|
let(:rpc_method) { service_class.rpcs[method_name] }
|
@@ -17,8 +17,9 @@ module ReverseModule
|
|
17
17
|
rpc :reverse, ReverseRequest, ReverseResponse
|
18
18
|
def reverse
|
19
19
|
respond_with :reversed => request.input.reverse,
|
20
|
-
:some_reversed_header => env.parent_env.
|
21
|
-
|
20
|
+
:some_reversed_header => if env.parent_env.key?('X-SOME-HEADER')
|
21
|
+
env.parent_env['X-SOME-HEADER'].reverse
|
22
|
+
end
|
22
23
|
end
|
23
24
|
end
|
24
25
|
end
|
@@ -33,79 +34,81 @@ describe Protobuf::Rpc::Http::Server do
|
|
33
34
|
end
|
34
35
|
|
35
36
|
it 'should return the correct response for ReverseModule::ReverseService.reverse' do
|
36
|
-
response = client.post "/ReverseModule%3A%3AReverseService/reverse", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode
|
37
|
-
response.status.
|
38
|
-
response.headers['content-type'].
|
39
|
-
response.headers['x-protobuf-error'].
|
40
|
-
response.headers['x-protobuf-error-reason'].
|
41
|
-
response.body.
|
37
|
+
response = client.post "/ReverseModule%3A%3AReverseService/reverse", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode
|
38
|
+
expect(response.status).to eq 200
|
39
|
+
expect(response.headers['content-type']).to eq "application/x-protobuf"
|
40
|
+
expect(response.headers['x-protobuf-error']).to be_nil
|
41
|
+
expect(response.headers['x-protobuf-error-reason']).to be_nil
|
42
|
+
expect(response.body).to eq ReverseModule::ReverseResponse.new(:reversed => "hello world".reverse).encode
|
42
43
|
end
|
43
44
|
|
44
45
|
it 'should return the correct response for ReverseModule::ReverseService.reverse when some header is passed' do
|
45
46
|
response = client.post "/ReverseModule%3A%3AReverseService/reverse",
|
46
|
-
:input => ReverseModule::ReverseRequest.new(:input => "hello world").encode
|
47
|
+
:input => ReverseModule::ReverseRequest.new(:input => "hello world").encode,
|
47
48
|
"X-SOME-HEADER" => "yes i am"
|
48
|
-
response.status.
|
49
|
-
response.headers['content-type'].
|
50
|
-
response.headers['x-protobuf-error'].
|
51
|
-
response.headers['x-protobuf-error-reason'].
|
52
|
-
response.body.
|
53
|
-
|
49
|
+
expect(response.status).to eq 200
|
50
|
+
expect(response.headers['content-type']).to eq "application/x-protobuf"
|
51
|
+
expect(response.headers['x-protobuf-error']).to be_nil
|
52
|
+
expect(response.headers['x-protobuf-error-reason']).to be_nil
|
53
|
+
expect(response.body).to eq ReverseModule::ReverseResponse.new(
|
54
|
+
:reversed => "hello world".reverse,
|
55
|
+
:some_reversed_header => "yes i am".reverse
|
56
|
+
).encode
|
54
57
|
end
|
55
58
|
|
56
59
|
it 'should return METHOD_NOT_FOUND for ReverseModule::ReverseService.bobloblaw' do
|
57
|
-
response = client.post "/ReverseModule%3A%3AReverseService/bobloblaw", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode
|
58
|
-
response.status.
|
59
|
-
response.headers['content-type'].
|
60
|
-
response.headers['x-protobuf-error'].
|
61
|
-
response.headers['x-protobuf-error-reason'].
|
62
|
-
response.body.
|
60
|
+
response = client.post "/ReverseModule%3A%3AReverseService/bobloblaw", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode
|
61
|
+
expect(response.status).to eq 404
|
62
|
+
expect(response.headers['content-type']).to eq "application/x-protobuf"
|
63
|
+
expect(response.headers['x-protobuf-error']).to eq "ReverseModule::ReverseService#bobloblaw is not a defined RPC method."
|
64
|
+
expect(response.headers['x-protobuf-error-reason']).to eq Protobuf::Socketrpc::ErrorReason::METHOD_NOT_FOUND.to_s
|
65
|
+
expect(response.body).to eq ""
|
63
66
|
end
|
64
67
|
|
65
68
|
it 'should return SERVICE_NOT_FOUND for Bar::ReverseService.reverse' do
|
66
|
-
response = client.post "/Bar%3A%3AReverseService/reverse", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode
|
67
|
-
response.status.
|
68
|
-
response.headers['content-type'].
|
69
|
-
response.headers['x-protobuf-error'].
|
70
|
-
response.headers['x-protobuf-error-reason'].
|
71
|
-
response.body.
|
69
|
+
response = client.post "/Bar%3A%3AReverseService/reverse", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode
|
70
|
+
expect(response.status).to eq 404
|
71
|
+
expect(response.headers['content-type']).to eq "application/x-protobuf"
|
72
|
+
expect(response.headers['x-protobuf-error']).to eq "Service class Bar::ReverseService is not defined."
|
73
|
+
expect(response.headers['x-protobuf-error-reason']).to eq Protobuf::Socketrpc::ErrorReason::SERVICE_NOT_FOUND.to_s
|
74
|
+
expect(response.body).to eq ""
|
72
75
|
end
|
73
76
|
|
74
77
|
it 'should return RPC_FAILED for missing input' do
|
75
78
|
response = client.post "/ReverseModule%3A%3AReverseService/reverse", :input => ""
|
76
|
-
response.status.
|
77
|
-
response.headers['content-type'].
|
78
|
-
response.headers['x-protobuf-error-reason'].
|
79
|
-
response.body.
|
79
|
+
expect(response.status).to eq 400
|
80
|
+
expect(response.headers['content-type']).to eq "application/x-protobuf"
|
81
|
+
expect(response.headers['x-protobuf-error-reason']).to eq Protobuf::Socketrpc::ErrorReason::BAD_REQUEST_DATA.to_s
|
82
|
+
expect(response.body).to eq ""
|
80
83
|
end
|
81
84
|
|
82
85
|
it 'should return RPC_ERROR for invalid input' do
|
83
86
|
response = client.post "/ReverseModule%3A%3AReverseService/reverse", :input => "\\n\\x03foo"
|
84
|
-
response.status.
|
85
|
-
response.headers['content-type'].
|
86
|
-
response.headers['x-protobuf-error-reason'].
|
87
|
-
response.body.
|
87
|
+
expect(response.status).to eq 400
|
88
|
+
expect(response.headers['content-type']).to eq "application/x-protobuf"
|
89
|
+
expect(response.headers['x-protobuf-error-reason']).to eq Protobuf::Socketrpc::ErrorReason::BAD_REQUEST_DATA.to_s
|
90
|
+
expect(response.body).to eq ""
|
88
91
|
end
|
89
92
|
|
90
93
|
it 'should return INVALID_REQUEST_PROTO for invalid URL' do
|
91
|
-
response = client.post "/foo", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode
|
92
|
-
response.status.
|
93
|
-
response.headers['content-type'].
|
94
|
-
|
95
|
-
response.headers['x-protobuf-error-reason'].
|
96
|
-
response.body.
|
94
|
+
response = client.post "/foo", :input => ReverseModule::ReverseRequest.new(:input => "hello world").encode
|
95
|
+
expect(response.status).to eq 400
|
96
|
+
expect(response.headers['content-type']).to eq "application/x-protobuf"
|
97
|
+
expect(response.headers['x-protobuf-error']).to eq "Expected path format /CLASS/METHOD"
|
98
|
+
expect(response.headers['x-protobuf-error-reason']).to eq Protobuf::Socketrpc::ErrorReason::INVALID_REQUEST_PROTO.to_s
|
99
|
+
expect(response.body).to eq ""
|
97
100
|
end
|
98
101
|
end
|
99
102
|
|
100
103
|
describe '.running?' do
|
101
104
|
it 'returns true if running' do
|
102
105
|
subject.instance_variable_set(:@running, true)
|
103
|
-
subject.running
|
106
|
+
expect(subject.running?).to be true
|
104
107
|
end
|
105
108
|
|
106
109
|
it 'returns false if not running' do
|
107
110
|
subject.instance_variable_set(:@running, false)
|
108
|
-
subject.running
|
111
|
+
expect(subject.running?).to be false
|
109
112
|
end
|
110
113
|
end
|
111
114
|
|
@@ -113,7 +116,7 @@ describe Protobuf::Rpc::Http::Server do
|
|
113
116
|
it 'sets running to false' do
|
114
117
|
# subject.instance_variable_set(:@workers, [])
|
115
118
|
subject.stop
|
116
|
-
subject.instance_variable_get(:@running).
|
119
|
+
expect(subject.instance_variable_get(:@running)).to be_falsey
|
117
120
|
end
|
118
121
|
end
|
119
122
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'spec/support/test/resource_service'
|
3
2
|
require 'protobuf/rpc/servers/socket_runner'
|
4
3
|
require 'protobuf/socket'
|
4
|
+
require SUPPORT_PATH.join('resource_service')
|
5
5
|
|
6
|
-
describe Protobuf::Rpc::Socket::Server do
|
6
|
+
RSpec.describe Protobuf::Rpc::Socket::Server do
|
7
7
|
before(:each) do
|
8
8
|
load 'protobuf/socket.rb'
|
9
9
|
end
|
@@ -14,7 +14,7 @@ describe Protobuf::Rpc::Socket::Server do
|
|
14
14
|
@options = OpenStruct.new(:host => "127.0.0.1", :port => 9399, :backlog => 100, :threshold => 100)
|
15
15
|
@runner = ::Protobuf::Rpc::SocketRunner.new(@options)
|
16
16
|
@server = @runner.instance_variable_get(:@server)
|
17
|
-
@server_thread = Thread.new(@runner
|
17
|
+
@server_thread = Thread.new(@runner, &:run)
|
18
18
|
Thread.pass until @server.running?
|
19
19
|
end
|
20
20
|
|
@@ -24,15 +24,15 @@ describe Protobuf::Rpc::Socket::Server do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
it "Runner provides a stop method" do
|
27
|
-
@runner.
|
27
|
+
expect(@runner).to respond_to(:stop)
|
28
28
|
end
|
29
29
|
|
30
30
|
it "provides a stop method" do
|
31
|
-
@server.
|
31
|
+
expect(@server).to respond_to(:stop)
|
32
32
|
end
|
33
33
|
|
34
34
|
it "signals the Server is running" do
|
35
|
-
@server.
|
35
|
+
expect(@server).to be_running
|
36
36
|
end
|
37
37
|
|
38
38
|
end
|
@@ -1,15 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'protobuf/rpc/servers/zmq/server'
|
3
3
|
|
4
|
-
describe Protobuf::Rpc::Zmq::Server do
|
4
|
+
RSpec.describe Protobuf::Rpc::Zmq::Server do
|
5
5
|
subject { described_class.new(options) }
|
6
6
|
|
7
|
-
let(:options)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
let(:options) do
|
8
|
+
{
|
9
|
+
:host => '127.0.0.1',
|
10
|
+
:port => 9399,
|
11
|
+
:worker_port => 9400,
|
12
|
+
:workers_only => true,
|
13
|
+
}
|
14
|
+
end
|
13
15
|
|
14
16
|
before do
|
15
17
|
load 'protobuf/zmq.rb'
|
@@ -22,12 +24,12 @@ describe Protobuf::Rpc::Zmq::Server do
|
|
22
24
|
describe '.running?' do
|
23
25
|
it 'returns true if running' do
|
24
26
|
subject.instance_variable_set(:@running, true)
|
25
|
-
subject.running
|
27
|
+
expect(subject.running?).to be true
|
26
28
|
end
|
27
29
|
|
28
30
|
it 'returns false if not running' do
|
29
31
|
subject.instance_variable_set(:@running, false)
|
30
|
-
subject.running
|
32
|
+
expect(subject.running?).to be false
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
@@ -35,7 +37,7 @@ describe Protobuf::Rpc::Zmq::Server do
|
|
35
37
|
it 'sets running to false' do
|
36
38
|
subject.instance_variable_set(:@workers, [])
|
37
39
|
subject.stop
|
38
|
-
subject.instance_variable_get(:@running).
|
40
|
+
expect(subject.instance_variable_get(:@running)).to be false
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
@@ -4,7 +4,7 @@ class UtilTest
|
|
4
4
|
include ::Protobuf::Rpc::Zmq::Util
|
5
5
|
end
|
6
6
|
|
7
|
-
describe ::Protobuf::Rpc::Zmq::Util do
|
7
|
+
RSpec.describe ::Protobuf::Rpc::Zmq::Util do
|
8
8
|
before(:each) do
|
9
9
|
load 'protobuf/zmq.rb'
|
10
10
|
end
|
@@ -12,34 +12,34 @@ describe ::Protobuf::Rpc::Zmq::Util do
|
|
12
12
|
subject { UtilTest.new }
|
13
13
|
describe '#zmq_error_check' do
|
14
14
|
it 'raises when the error code is less than 0' do
|
15
|
-
expect
|
15
|
+
expect do
|
16
16
|
subject.zmq_error_check(-1, :test)
|
17
|
-
|
17
|
+
end.to raise_error(/test/)
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'retrieves the error string from ZeroMQ' do
|
21
|
-
ZMQ::Util.
|
22
|
-
expect
|
21
|
+
allow(ZMQ::Util).to receive(:error_string).and_return('an error from zmq')
|
22
|
+
expect do
|
23
23
|
subject.zmq_error_check(-1, :test)
|
24
|
-
|
24
|
+
end.to raise_error(RuntimeError, /an error from zmq/i)
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'does nothing if the error code is > 0' do
|
28
|
-
expect
|
28
|
+
expect do
|
29
29
|
subject.zmq_error_check(1, :test)
|
30
|
-
|
30
|
+
end.to_not raise_error
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'does nothing if the error code is == 0' do
|
34
|
-
expect
|
34
|
+
expect do
|
35
35
|
subject.zmq_error_check(0, :test)
|
36
|
-
|
36
|
+
end.to_not raise_error
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
describe '#log_signature' do
|
41
41
|
it 'returns the signature for the log' do
|
42
|
-
subject.log_signature.
|
42
|
+
expect(subject.log_signature).to include('server', 'UtilTest')
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
@@ -1,20 +1,20 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe ::Protobuf::Rpc::Zmq::Worker do
|
4
|
-
before(:each) do
|
3
|
+
RSpec.describe ::Protobuf::Rpc::Zmq::Worker do
|
4
|
+
before(:each) do
|
5
5
|
load 'protobuf/zmq.rb'
|
6
6
|
|
7
7
|
fake_socket = double
|
8
|
-
fake_socket.
|
9
|
-
fake_socket.
|
8
|
+
expect(fake_socket).to receive(:connect).and_return(0)
|
9
|
+
expect(fake_socket).to receive(:send_string).and_return(0)
|
10
10
|
|
11
11
|
fake_context = double
|
12
|
-
fake_context.
|
13
|
-
::ZMQ::Context.
|
12
|
+
expect(fake_context).to receive(:socket).and_return(fake_socket)
|
13
|
+
expect(::ZMQ::Context).to receive(:new).and_return(fake_context)
|
14
14
|
end
|
15
15
|
|
16
16
|
subject do
|
17
|
-
described_class.new(
|
17
|
+
described_class.new(:host => '127.0.0.1', :port => 9400)
|
18
18
|
end
|
19
19
|
|
20
20
|
describe '#run' do
|
@@ -2,48 +2,48 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
require 'protobuf/rpc/service_directory'
|
4
4
|
|
5
|
-
describe ::Protobuf::Rpc::ServiceDirectory do
|
5
|
+
RSpec.describe ::Protobuf::Rpc::ServiceDirectory do
|
6
6
|
subject { described_class.instance }
|
7
7
|
|
8
|
-
let(:echo_server)
|
8
|
+
let(:echo_server) do
|
9
9
|
::Protobuf::Rpc::DynamicDiscovery::Server.new(
|
10
10
|
:uuid => 'echo',
|
11
11
|
:address => '127.0.0.1',
|
12
12
|
:port => '1111',
|
13
13
|
:ttl => 10,
|
14
|
-
:services => %w
|
14
|
+
:services => %w(EchoService)
|
15
15
|
)
|
16
|
-
|
16
|
+
end
|
17
17
|
|
18
|
-
let(:hello_server)
|
18
|
+
let(:hello_server) do
|
19
19
|
::Protobuf::Rpc::DynamicDiscovery::Server.new(
|
20
20
|
:uuid => "hello",
|
21
21
|
:address => '127.0.0.1',
|
22
22
|
:port => "1112",
|
23
23
|
:ttl => 10,
|
24
|
-
:services => %w
|
24
|
+
:services => %w(HelloService)
|
25
25
|
)
|
26
|
-
|
26
|
+
end
|
27
27
|
|
28
|
-
let(:hello_server_with_short_ttl)
|
28
|
+
let(:hello_server_with_short_ttl) do
|
29
29
|
::Protobuf::Rpc::DynamicDiscovery::Server.new(
|
30
30
|
:uuid => "hello_server_with_short_ttl",
|
31
31
|
:address => '127.0.0.1',
|
32
32
|
:port => '1113',
|
33
33
|
:ttl => 1,
|
34
|
-
:services => %w
|
34
|
+
:services => %w(HelloService)
|
35
35
|
)
|
36
|
-
|
36
|
+
end
|
37
37
|
|
38
|
-
let(:combo_server)
|
38
|
+
let(:combo_server) do
|
39
39
|
::Protobuf::Rpc::DynamicDiscovery::Server.new(
|
40
40
|
:uuid => "combo",
|
41
41
|
:address => '127.0.0.1',
|
42
42
|
:port => '1114',
|
43
43
|
:ttl => 10,
|
44
|
-
:services => %w
|
44
|
+
:services => %w(HelloService EchoService)
|
45
45
|
)
|
46
|
-
|
46
|
+
end
|
47
47
|
|
48
48
|
before(:all) do
|
49
49
|
@address = "127.0.0.1"
|
@@ -56,10 +56,8 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def expect_event_trigger(event)
|
59
|
-
::ActiveSupport::Notifications
|
60
|
-
.
|
61
|
-
.with(event, hash_including(:listing => an_instance_of(::Protobuf::Rpc::ServiceDirectory::Listing)))
|
62
|
-
.once
|
59
|
+
expect(::ActiveSupport::Notifications).to receive(:instrument)
|
60
|
+
.with(event, hash_including(:listing => an_instance_of(::Protobuf::Rpc::ServiceDirectory::Listing))).once
|
63
61
|
end
|
64
62
|
|
65
63
|
def send_beacon(type, server)
|
@@ -74,29 +72,29 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
74
72
|
end
|
75
73
|
|
76
74
|
it "should be a singleton" do
|
77
|
-
subject.
|
75
|
+
expect(subject).to be_a_kind_of(Singleton)
|
78
76
|
end
|
79
77
|
|
80
78
|
it "should be configured to listen to address 127.0.0.1" do
|
81
|
-
described_class.address.
|
79
|
+
expect(described_class.address).to eq '127.0.0.1'
|
82
80
|
end
|
83
81
|
|
84
82
|
it "should be configured to listen to port 33333" do
|
85
|
-
described_class.port.
|
83
|
+
expect(described_class.port).to eq 33333
|
86
84
|
end
|
87
85
|
|
88
86
|
it "should defer .start to the instance#start" do
|
89
|
-
described_class.instance.
|
87
|
+
expect(described_class.instance).to receive(:start)
|
90
88
|
described_class.start
|
91
89
|
end
|
92
90
|
|
93
91
|
it "should yeild itself to blocks passed to .start" do
|
94
|
-
described_class.instance.
|
92
|
+
allow(described_class.instance).to receive(:start)
|
95
93
|
expect { |b| described_class.start(&b) }.to yield_with_args(described_class)
|
96
94
|
end
|
97
95
|
|
98
96
|
it "should defer .stop to the instance#stop" do
|
99
|
-
described_class.instance.
|
97
|
+
expect(described_class.instance).to receive(:stop)
|
100
98
|
described_class.stop
|
101
99
|
end
|
102
100
|
|
@@ -106,20 +104,20 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
106
104
|
describe "#lookup" do
|
107
105
|
it "should return nil" do
|
108
106
|
send_beacon(:heartbeat, echo_server)
|
109
|
-
subject.lookup("EchoService").
|
107
|
+
expect(subject.lookup("EchoService")).to be_nil
|
110
108
|
end
|
111
109
|
end
|
112
110
|
|
113
111
|
describe "#restart" do
|
114
112
|
it "should start the service" do
|
115
113
|
subject.restart
|
116
|
-
subject.
|
114
|
+
expect(subject).to be_running
|
117
115
|
end
|
118
116
|
end
|
119
117
|
|
120
118
|
describe "#running" do
|
121
119
|
it "should be false" do
|
122
|
-
subject.
|
120
|
+
expect(subject).to_not be_running
|
123
121
|
end
|
124
122
|
end
|
125
123
|
|
@@ -134,7 +132,7 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
134
132
|
before { subject.start }
|
135
133
|
after { subject.stop }
|
136
134
|
|
137
|
-
|
135
|
+
specify { expect(subject).to be_running }
|
138
136
|
|
139
137
|
it "should trigger added events" do
|
140
138
|
expect_event_trigger("directory.listing.added")
|
@@ -159,13 +157,13 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
159
157
|
send_beacon(:heartbeat, hello_server)
|
160
158
|
send_beacon(:heartbeat, combo_server)
|
161
159
|
|
162
|
-
subject.all_listings_for("HelloService").size.
|
160
|
+
expect(subject.all_listings_for("HelloService").size).to eq(2)
|
163
161
|
end
|
164
162
|
end
|
165
163
|
|
166
164
|
context "when no listings are present" do
|
167
165
|
it "returns and empty array" do
|
168
|
-
subject.all_listings_for("HelloService").size.
|
166
|
+
expect(subject.all_listings_for("HelloService").size).to eq(0)
|
169
167
|
end
|
170
168
|
end
|
171
169
|
end
|
@@ -176,16 +174,16 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
176
174
|
send_beacon(:heartbeat, echo_server)
|
177
175
|
send_beacon(:heartbeat, combo_server)
|
178
176
|
|
179
|
-
expect
|
177
|
+
expect do |block|
|
180
178
|
subject.each_listing(&block)
|
181
|
-
|
179
|
+
end.to yield_control.exactly(3).times
|
182
180
|
end
|
183
181
|
end
|
184
182
|
|
185
183
|
describe "#lookup" do
|
186
184
|
it "should provide listings by service" do
|
187
185
|
send_beacon(:heartbeat, hello_server)
|
188
|
-
subject.lookup("HelloService").to_hash.
|
186
|
+
expect(subject.lookup("HelloService").to_hash).to eq hello_server.to_hash
|
189
187
|
end
|
190
188
|
|
191
189
|
it "should return random listings" do
|
@@ -193,14 +191,14 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
193
191
|
send_beacon(:heartbeat, combo_server)
|
194
192
|
|
195
193
|
uuids = 100.times.map { subject.lookup("HelloService").uuid }
|
196
|
-
uuids.count("hello").
|
197
|
-
uuids.count("combo").
|
194
|
+
expect(uuids.count("hello")).to be_within(25).of(50)
|
195
|
+
expect(uuids.count("combo")).to be_within(25).of(50)
|
198
196
|
end
|
199
197
|
|
200
198
|
it "should not return expired listings" do
|
201
199
|
send_beacon(:heartbeat, hello_server_with_short_ttl)
|
202
|
-
sleep
|
203
|
-
subject.lookup("HelloService").
|
200
|
+
sleep 5
|
201
|
+
expect(subject.lookup("HelloService")).to be_nil
|
204
202
|
end
|
205
203
|
|
206
204
|
it "should not return flatlined servers" do
|
@@ -209,7 +207,7 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
209
207
|
send_beacon(:flatline, echo_server)
|
210
208
|
|
211
209
|
uuids = 100.times.map { subject.lookup("EchoService").uuid }
|
212
|
-
uuids.count("combo").
|
210
|
+
expect(uuids.count("combo")).to eq 100
|
213
211
|
end
|
214
212
|
|
215
213
|
it "should return up-to-date listings" do
|
@@ -217,13 +215,13 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
217
215
|
echo_server.port = "7777"
|
218
216
|
send_beacon(:heartbeat, echo_server)
|
219
217
|
|
220
|
-
subject.lookup("EchoService").port.
|
218
|
+
expect(subject.lookup("EchoService").port).to eq "7777"
|
221
219
|
end
|
222
220
|
|
223
221
|
context 'when given service identifier is a class name' do
|
224
222
|
it 'returns the listing corresponding to the class name' do
|
225
223
|
send_beacon(:heartbeat, echo_server)
|
226
|
-
subject.lookup(EchoService).uuid.
|
224
|
+
expect(subject.lookup(EchoService).uuid).to eq echo_server.uuid
|
227
225
|
end
|
228
226
|
end
|
229
227
|
end
|
@@ -233,13 +231,13 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
233
231
|
send_beacon(:heartbeat, echo_server)
|
234
232
|
send_beacon(:heartbeat, combo_server)
|
235
233
|
subject.restart
|
236
|
-
subject.lookup("EchoService").
|
234
|
+
expect(subject.lookup("EchoService")).to be_nil
|
237
235
|
end
|
238
236
|
end
|
239
237
|
|
240
238
|
describe "#running" do
|
241
239
|
it "should be true" do
|
242
|
-
subject.
|
240
|
+
expect(subject).to be_running
|
243
241
|
end
|
244
242
|
end
|
245
243
|
|
@@ -248,29 +246,29 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
248
246
|
send_beacon(:heartbeat, echo_server)
|
249
247
|
send_beacon(:heartbeat, combo_server)
|
250
248
|
subject.stop
|
251
|
-
subject.lookup("EchoService").
|
249
|
+
expect(subject.lookup("EchoService")).to be_nil
|
252
250
|
end
|
253
251
|
|
254
252
|
it "should stop the server" do
|
255
253
|
subject.stop
|
256
|
-
subject.
|
254
|
+
expect(subject).to_not be_running
|
257
255
|
end
|
258
256
|
end
|
259
257
|
end
|
260
258
|
|
261
259
|
if ENV.key?("BENCH")
|
262
260
|
context "performance" do
|
263
|
-
let(:servers)
|
264
|
-
100.times.
|
261
|
+
let(:servers) do
|
262
|
+
100.times.map do |x|
|
265
263
|
::Protobuf::Rpc::DynamicDiscovery::Server.new(
|
266
264
|
:uuid => "performance_server#{x + 1}",
|
267
265
|
:address => '127.0.0.1',
|
268
266
|
:port => (5555 + x).to_s,
|
269
267
|
:ttl => rand(1..5),
|
270
|
-
:services => 10.times.
|
268
|
+
:services => 10.times.map { |y| "PerformanceService#{y}" }
|
271
269
|
)
|
272
270
|
end
|
273
|
-
|
271
|
+
end
|
274
272
|
|
275
273
|
before do
|
276
274
|
require 'benchmark'
|
@@ -285,8 +283,8 @@ describe ::Protobuf::Rpc::ServiceDirectory do
|
|
285
283
|
it "should perform lookups in constant time" do
|
286
284
|
print "\n\n"
|
287
285
|
Benchmark.bm(17) do |x|
|
288
|
-
x.report(" 1_000 lookups:") {
|
289
|
-
x.report(" 10_000 lookups:") {
|
286
|
+
x.report(" 1_000 lookups:") { 1_000.times { subject.lookup("PerformanceService#{rand(0..9)}") } }
|
287
|
+
x.report(" 10_000 lookups:") { 10_000.times { subject.lookup("PerformanceService#{rand(0..9)}") } }
|
290
288
|
x.report("100_000 lookups:") { 100_000.times { subject.lookup("PerformanceService#{rand(0..9)}") } }
|
291
289
|
end
|
292
290
|
end
|