grpc_mock 0.3.1 → 0.4.4

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 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: []