grpc_mock 0.3.1 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d717cdc98c3aa591bd9f3681b243c0fe51a80775d8ff2e3f6a4722c717aa0838
4
- data.tar.gz: 2843c56fe8383a8d1bb1bacb2c5f64ed3d6f4342ea884052e1bdbf60aa063ba9
3
+ metadata.gz: cb0de4a6e730f8e575b50ecfa9ee0d92b97dd3380900dc119de0a41abc285457
4
+ data.tar.gz: 912662c5b9ed4398a8377d9207621208f3bcfdf201eff0a4e4cd7ec95e152600
5
5
  SHA512:
6
- metadata.gz: 394cf9c6dfd230e467d10d89933927cbec13273b11c4188358ffacba750dcd8df6eddfd4d546509411962d541c7d99118501d118acdedfbd0004c805d0d94937
7
- data.tar.gz: d85fd1a0f7f73b94e35d8288648f264bb3c57b63a28d5135d3f9648589fc97d60244255741ea8e5e96b5934b7d2535d82ae49977cbf2db67f7e03ccad753b8d6
6
+ metadata.gz: f78e70b411a828142b828ca7348e27b25dbd76a86af5fa8886146fd0459f427598f132c092af084848e90a9b5c35dd921f5b77408b5a94850e8ea4fc6b760e79
7
+ data.tar.gz: 2cabdde68d88771fca38020d2f5b6cd5cf2ec7462ada062a84139252aeda8103f811486bbdb2e1dc4dbaaaa8c9f134e7880525f7dbfbe1a4672c67a1379190a3
data/README.md CHANGED
@@ -28,37 +28,71 @@ require 'grpc_mock/rspec'
28
28
 
29
29
  ## Examples
30
30
 
31
- See definition of protocol buffers and gRPC generated code in [spec/exmaples/hello](https://github.com/ganmacs/grpc_mock/tree/master/spec/examples/hello)
31
+ See definition of protocol buffers and gRPC generated code in [spec/examples/hello](https://github.com/ganmacs/grpc_mock/tree/master/spec/examples/hello)
32
32
 
33
- ##### Stubbed request based on path and with the default response
33
+ ### Stubbed request based on path and with the default response
34
34
 
35
35
  ```ruby
36
36
  GrpcMock.stub_request("/hello.hello/Hello").to_return(Hello::HelloResponse.new(msg: 'test'))
37
37
 
38
38
  client = Hello::Hello::Stub.new('localhost:8000', :this_channel_is_insecure)
39
- client = client.hello(Hello::HelloRequest.new(msg: 'hi')) # => Hello::HelloResponse.new(msg: 'test')
39
+ client.hello(Hello::HelloRequest.new(msg: 'hi')) # => Hello::HelloResponse.new(msg: 'test')
40
40
  ```
41
41
 
42
- ##### Stubbing requests based on path and request
42
+ ### Stubbing requests based on path and request
43
43
 
44
44
  ```ruby
45
45
  GrpcMock.stub_request("/hello.hello/Hello").with(Hello::HelloRequest.new(msg: 'hi')).to_return(Hello::HelloResponse.new(msg: 'test'))
46
46
 
47
47
  client = Hello::Hello::Stub.new('localhost:8000', :this_channel_is_insecure)
48
- client = client.hello(Hello::HelloRequest.new(msg: 'hello')) # => send a request to server
49
- client = client.hello(Hello::HelloRequest.new(msg: 'hi')) # => Hello::HelloResponse.new(msg: 'test') (without any requests to server)
48
+ client.hello(Hello::HelloRequest.new(msg: 'hello')) # => send a request to server
49
+ client client.hello(Hello::HelloRequest.new(msg: 'hi')) # => Hello::HelloResponse.new(msg: 'test') (without any requests to server)
50
50
  ```
51
51
 
52
- ##### Real requests to network can be allowed or disabled
52
+ ### Responding dynamically to the stubbed requests
53
+
54
+ ```ruby
55
+ GrpcMock.stub_request("/hello.hello/Hello").to_return do |req, call|
56
+ Hello::HelloResponse.new(msg: "#{req.msg} too")
57
+ end
58
+
59
+ client = Hello::Hello::Stub.new('localhost:8000', :this_channel_is_insecure)
60
+ client.hello(Hello::HelloRequest.new(msg: 'hi')) # => Hello::HelloResponse.new(msg: 'hi too')
61
+ ```
62
+
63
+ ### Real requests to network can be allowed or disabled
53
64
 
54
65
  ```ruby
55
66
  client = Hello::Hello::Stub.new('localhost:8000', :this_channel_is_insecure)
56
67
 
57
68
  GrpcMock.disable_net_connect!
58
- client = client.hello(Hello::HelloRequest.new(msg: 'hello')) # => Raise NetConnectNotAllowedError error
69
+ client.hello(Hello::HelloRequest.new(msg: 'hello')) # => Raise NetConnectNotAllowedError error
59
70
 
60
71
  GrpcMock.allow_net_connect!
61
- client = Hello::Hello::Stub.new('localhost:8000', :this_channel_is_insecure) # => send a request to server
72
+ Hello::Hello::Stub.new('localhost:8000', :this_channel_is_insecure) # => send a request to server
73
+ ```
74
+
75
+ ### Raising errors
76
+
77
+ **Exception declared by class**
78
+
79
+ ```ruby
80
+ GrpcMock.stub_request("/hello.hello/Hello").to_raise(StandardError)
81
+
82
+ client = Hello::Hello::Stub.new('localhost:8000', :this_channel_is_insecure)
83
+ client.hello(Hello::HelloRequest.new(msg: 'hi')) # => Raise StandardError
84
+ ```
85
+
86
+ **or by exception instance**
87
+
88
+ ```ruby
89
+ GrpcMock.stub_request("/hello.hello/Hello").to_raise(StandardError.new("Some error"))
90
+ ```
91
+
92
+ **or by string**
93
+
94
+ ```ruby
95
+ GrpcMock.stub_request("/hello.hello/Hello").to_raise("Some error")
62
96
  ```
63
97
 
64
98
  ## Contributing
@@ -22,12 +22,12 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ['lib']
24
24
 
25
- spec.add_dependency 'grpc', '>= 1.12.0', '< 1.22.0'
25
+ spec.add_dependency 'grpc', '>= 1.12.0', '< 2'
26
26
 
27
27
  spec.add_development_dependency 'bundler'
28
28
  spec.add_development_dependency 'grpc-tools'
29
29
  spec.add_development_dependency 'pry-byebug'
30
- spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rake', '>= 12.3.3'
31
31
  spec.add_development_dependency 'rspec', '~> 3.0'
32
32
  spec.add_development_dependency 'rubocop'
33
33
  end
@@ -2,20 +2,22 @@
2
2
 
3
3
  require 'grpc'
4
4
  require 'grpc_mock/errors'
5
+ require 'grpc_mock/mocked_call'
5
6
 
6
7
  module GrpcMock
7
8
  class GrpcStubAdapter
8
9
  # To make hook point for GRPC::ClientStub
9
10
  # https://github.com/grpc/grpc/blob/bec3b5ada2c5e5d782dff0b7b5018df646b65cb0/src/ruby/lib/grpc/generic/service.rb#L150-L186
10
- class AdapterClass < GRPC::ClientStub
11
- def request_response(method, request, *args)
11
+ module Adapter
12
+ def request_response(method, request, *args, metadata: {}, **kwargs)
12
13
  unless GrpcMock::GrpcStubAdapter.enabled?
13
14
  return super
14
15
  end
15
16
 
16
17
  mock = GrpcMock.stub_registry.response_for_request(method, request)
17
18
  if mock
18
- mock.evaluate
19
+ call = GrpcMock::MockedCall.new(metadata: metadata)
20
+ mock.evaluate(request, call.single_req_view)
19
21
  elsif GrpcMock.config.allow_net_connect
20
22
  super
21
23
  else
@@ -24,7 +26,7 @@ module GrpcMock
24
26
  end
25
27
 
26
28
  # TODO
27
- def client_streamer(method, requests, *args)
29
+ def client_streamer(method, requests, *args, metadata: {}, **kwargs)
28
30
  unless GrpcMock::GrpcStubAdapter.enabled?
29
31
  return super
30
32
  end
@@ -32,7 +34,8 @@ module GrpcMock
32
34
  r = requests.to_a # FIXME: this may not work
33
35
  mock = GrpcMock.stub_registry.response_for_request(method, r)
34
36
  if mock
35
- mock.evaluate
37
+ call = GrpcMock::MockedCall.new(metadata: metadata)
38
+ mock.evaluate(r, call.multi_req_view)
36
39
  elsif GrpcMock.config.allow_net_connect
37
40
  super
38
41
  else
@@ -40,14 +43,15 @@ module GrpcMock
40
43
  end
41
44
  end
42
45
 
43
- def server_streamer(method, request, *args)
46
+ def server_streamer(method, request, *args, metadata: {}, **kwargs)
44
47
  unless GrpcMock::GrpcStubAdapter.enabled?
45
48
  return super
46
49
  end
47
50
 
48
51
  mock = GrpcMock.stub_registry.response_for_request(method, request)
49
52
  if mock
50
- mock.evaluate
53
+ call = GrpcMock::MockedCall.new(metadata: metadata)
54
+ mock.evaluate(request, call.single_req_view)
51
55
  elsif GrpcMock.config.allow_net_connect
52
56
  super
53
57
  else
@@ -55,7 +59,7 @@ module GrpcMock
55
59
  end
56
60
  end
57
61
 
58
- def bidi_streamer(method, requests, *args)
62
+ def bidi_streamer(method, requests, *args, metadata: {}, **kwargs)
59
63
  unless GrpcMock::GrpcStubAdapter.enabled?
60
64
  return super
61
65
  end
@@ -63,7 +67,7 @@ module GrpcMock
63
67
  r = requests.to_a # FIXME: this may not work
64
68
  mock = GrpcMock.stub_registry.response_for_request(method, r)
65
69
  if mock
66
- mock.evaluate
70
+ mock.evaluate(r, nil) # FIXME: provide BidiCall equivalent
67
71
  elsif GrpcMock.config.allow_net_connect
68
72
  super
69
73
  else
@@ -71,8 +75,6 @@ module GrpcMock
71
75
  end
72
76
  end
73
77
  end
74
- GRPC.send(:remove_const, :ClientStub)
75
- GRPC.send(:const_set, :ClientStub, AdapterClass)
76
78
 
77
79
  def self.disable!
78
80
  @enabled = false
@@ -95,3 +97,9 @@ module GrpcMock
95
97
  end
96
98
  end
97
99
  end
100
+
101
+ module GRPC
102
+ class ClientStub
103
+ prepend GrpcMock::GrpcStubAdapter::Adapter
104
+ end
105
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc'
4
+
5
+ module GrpcMock
6
+ class MockedCall
7
+ attr_reader :deadline, :metadata
8
+
9
+ def initialize(metadata: {}, deadline: nil)
10
+ @metadata = sanitize_metadata(metadata)
11
+ @deadline = deadline
12
+ end
13
+
14
+ def multi_req_view
15
+ GRPC::ActiveCall::MultiReqView.new(self)
16
+ end
17
+
18
+ def single_req_view
19
+ GRPC::ActiveCall::SingleReqView.new(self)
20
+ end
21
+
22
+ private
23
+
24
+ def sanitize_metadata(metadata)
25
+ # Largely based on
26
+ # - grpc_rb_md_ary_fill_hash_cb https://github.com/grpc/grpc/blob/v1.29.1/src/ruby/ext/grpc/rb_call.c#L390-L465
27
+ # - grpc_rb_md_ary_convert https://github.com/grpc/grpc/blob/v1.29.1/src/ruby/ext/grpc/rb_call.c#L490-L511
28
+ # - grpc_rb_md_ary_to_h https://github.com/grpc/grpc/blob/v1.29.1/src/ruby/ext/grpc/rb_call.c#L513-L541
29
+ # See also https://github.com/grpc/grpc/blob/v1.29.1/doc/PROTOCOL-HTTP2.md for specification
30
+
31
+ raise TypeError, "got <#{metadata.class}>, want <Hash>" unless metadata.is_a?(Hash)
32
+
33
+ headers = []
34
+ metadata.each do |key, value|
35
+ raise TypeError, "bad type for key parameter" unless key.is_a?(String) || key.is_a?(Symbol)
36
+
37
+ key = key.to_s
38
+ # https://github.com/grpc/grpc/blob/v1.29.1/src/core/lib/surface/validate_metadata.cc#L61-L79
39
+ raise ArgumentError, "'#{key}' is an invalid header key" unless key.match?(/\A[a-z0-9\-_.]+\z/) && key != ''
40
+ raise ArgumentError, "Header values must be of type string or array" unless value.is_a?(String) || value.is_a?(Array)
41
+
42
+ Array(value).each do |elem|
43
+ raise TypeError, "Header value must be of type string" unless elem.is_a?(String)
44
+
45
+ unless key.end_with?('-bin')
46
+ # Non-binary metadata are translated as plain HTTP2 headers, thus this requirement.
47
+ # https://github.com/grpc/grpc/blob/v1.29.1/src/core/lib/surface/validate_metadata.cc#L85-L92
48
+ raise ArgumentError, "Header value '#{elem}' has invalid characters" unless elem.match(/\A[ -~]+\z/)
49
+
50
+ # "ASCII-Value should not have leading or trailing whitespace. If it contains leading or trailing whitespace, it may be stripped."
51
+ # https://github.com/grpc/grpc/blob/v1.29.1/doc/PROTOCOL-HTTP2.md
52
+ elem = elem.strip
53
+ end
54
+ headers << [key, elem]
55
+ end
56
+ end
57
+
58
+ metadata = {}
59
+ headers.each do |key, elem|
60
+ if metadata[key].nil?
61
+ metadata[key] = elem
62
+ elsif metadata[key].is_a?(Array)
63
+ metadata[key] << elem
64
+ else
65
+ metadata[key] = [metadata[key], elem]
66
+ end
67
+ end
68
+
69
+ metadata
70
+ end
71
+ end
72
+ end
@@ -18,8 +18,9 @@ module GrpcMock
18
18
  self
19
19
  end
20
20
 
21
- def to_return(*values)
21
+ def to_return(*values, &block)
22
22
  responses = [*values].flatten.map { |v| Response::Value.new(v) }
23
+ responses << Response::BlockValue.new(block) if block
23
24
  @response_sequence << GrpcMock::ResponsesSequence.new(responses)
24
25
  self
25
26
  end
@@ -16,7 +16,7 @@ module GrpcMock
16
16
  end
17
17
  end
18
18
 
19
- def evaluate
19
+ def evaluate(_request = nil, _call = nil)
20
20
  raise @exception.dup
21
21
  end
22
22
  end
@@ -26,9 +26,19 @@ module GrpcMock
26
26
  @value = value
27
27
  end
28
28
 
29
- def evaluate
29
+ def evaluate(_request = nil, _call = nil)
30
30
  @value.dup
31
31
  end
32
32
  end
33
+
34
+ class BlockValue
35
+ def initialize(block)
36
+ @block = block
37
+ end
38
+
39
+ def evaluate(request, call = nil)
40
+ @block.call(request, call)
41
+ end
42
+ end
33
43
  end
34
44
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GrpcMock
4
- VERSION = '0.3.1'
4
+ VERSION = '0.4.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grpc_mock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuta Iwama
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-21 00:00:00.000000000 Z
11
+ date: 2021-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grpc
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: 1.12.0
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 1.22.0
22
+ version: '2'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: 1.12.0
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 1.22.0
32
+ version: '2'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: bundler
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -76,16 +76,16 @@ dependencies:
76
76
  name: rake
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - "~>"
79
+ - - ">="
80
80
  - !ruby/object:Gem::Version
81
- version: '10.0'
81
+ version: 12.3.3
82
82
  type: :development
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
- - - "~>"
86
+ - - ">="
87
87
  - !ruby/object:Gem::Version
88
- version: '10.0'
88
+ version: 12.3.3
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: rspec
91
91
  requirement: !ruby/object:Gem::Requirement
@@ -140,6 +140,7 @@ files:
140
140
  - lib/grpc_mock/grpc_stub_adapter.rb
141
141
  - lib/grpc_mock/matchers/hash_argument_matcher.rb
142
142
  - lib/grpc_mock/matchers/request_including_matcher.rb
143
+ - lib/grpc_mock/mocked_call.rb
143
144
  - lib/grpc_mock/request_pattern.rb
144
145
  - lib/grpc_mock/request_stub.rb
145
146
  - lib/grpc_mock/response.rb
@@ -151,7 +152,7 @@ homepage: https://github.com/ganmacs/grpc_mock
151
152
  licenses:
152
153
  - MIT
153
154
  metadata: {}
154
- post_install_message:
155
+ post_install_message:
155
156
  rdoc_options: []
156
157
  require_paths:
157
158
  - lib
@@ -167,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
168
  version: '0'
168
169
  requirements: []
169
170
  rubygems_version: 3.0.3
170
- signing_key:
171
+ signing_key:
171
172
  specification_version: 4
172
173
  summary: Library for stubbing grpc in Ruby
173
174
  test_files: []