grpc_mock 0.3.0 → 0.4.3

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: 64d71ca90aa6a226e3adabaaeb57706fca0c0f64d2a1067ce6e43096325309dd
4
- data.tar.gz: 31d13e31248b47d0fbef1e2b6a684c14e09849b9f122788154701f3df44c4acb
3
+ metadata.gz: 1d9ce22e13c7dae6452813ff348fab4e0b894f21b33fdff005600334df3f77d8
4
+ data.tar.gz: 4dfd66d56c40ac155d0d2d67c88f7f97dbb7931a34e93d1df0ce37a2e069cd18
5
5
  SHA512:
6
- metadata.gz: 1da4555681fd8e75403c2cad300793c3a7732671258a09ee57426e4cf5b3df5ce68d8d1e8bf5db7ca8122e52997030dbc81de74984f2ff011dc053842de4cd90
7
- data.tar.gz: c40cfd23df2b2106d13e752c882e1dfe809aed80f9bdc41723d632a7b77f9390bf9e20ebd524c7d65857bd5e7bfe527f4cf5eae7c0e04afc92fc28c429a6827b
6
+ metadata.gz: 4bb6164d3b3afa78b6bd8e85bb0c7864aea6b52c78038c3f1bc810faf944adfe60901d832df4b6bd6ce3cdad3a98b890974dc9a620e2ba81ecdbe82d58b05b71
7
+ data.tar.gz: 8b3385763458fe785ad159f4ca5601ff24fd8773f7c8ae3607429c388aef745e2504adcf966ae359af117001f894111f92f1f92a84dc43c4448c3e5f1ea78bfa
data/README.md CHANGED
@@ -30,35 +30,69 @@ require 'grpc_mock/rspec'
30
30
 
31
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)
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.21.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
11
  class AdapterClass < GRPC::ClientStub
11
- def request_response(method, request, *args)
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
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
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
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
70
+ mock.evaluate(r, nil) # FIXME: provide BidiCall equivalent
67
71
  elsif GrpcMock.config.allow_net_connect
68
72
  super
69
73
  else
@@ -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
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'grpc_mock/request_pattern'
4
- require 'grpc_mock/resopnse_sequence'
4
+ require 'grpc_mock/response'
5
+ require 'grpc_mock/response_sequence'
5
6
  require 'grpc_mock/errors'
6
7
 
7
8
  module GrpcMock
@@ -17,8 +18,16 @@ module GrpcMock
17
18
  self
18
19
  end
19
20
 
20
- def to_return(*resp)
21
- @response_sequence << GrpcMock::ResponsesSequence.new(resp)
21
+ def to_return(*values, &block)
22
+ responses = [*values].flatten.map { |v| Response::Value.new(v) }
23
+ responses << Response::BlockValue.new(block) if block
24
+ @response_sequence << GrpcMock::ResponsesSequence.new(responses)
25
+ self
26
+ end
27
+
28
+ def to_raise(*exceptions)
29
+ responses = [*exceptions].flatten.map { |e| Response::ExceptionValue.new(e) }
30
+ @response_sequence << GrpcMock::ResponsesSequence.new(responses)
22
31
  self
23
32
  end
24
33
 
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GrpcMock
4
+ module Response
5
+ class ExceptionValue
6
+ def initialize(exception)
7
+ @exception = case exception
8
+ when String
9
+ StandardError.new(exception)
10
+ when Class
11
+ exception.new('Exception from GrpcMock')
12
+ when Exception
13
+ exception
14
+ else
15
+ raise ArgumentError.new(message: "Invalid exception class: #{exception.class}")
16
+ end
17
+ end
18
+
19
+ def evaluate(_request = nil, _call = nil)
20
+ raise @exception.dup
21
+ end
22
+ end
23
+
24
+ class Value
25
+ def initialize(value)
26
+ @value = value
27
+ end
28
+
29
+ def evaluate(_request = nil, _call = nil)
30
+ @value.dup
31
+ end
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
43
+ end
44
+ end
@@ -24,7 +24,7 @@ module GrpcMock
24
24
  end
25
25
 
26
26
  if rstub
27
- rstub.response.dup
27
+ rstub.response
28
28
  end
29
29
  end
30
30
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GrpcMock
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.3'
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.0
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuta Iwama
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-23 00:00:00.000000000 Z
11
+ date: 2020-06-23 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.21.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.21.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,9 +140,11 @@ 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
- - lib/grpc_mock/resopnse_sequence.rb
146
+ - lib/grpc_mock/response.rb
147
+ - lib/grpc_mock/response_sequence.rb
146
148
  - lib/grpc_mock/rspec.rb
147
149
  - lib/grpc_mock/stub_registry.rb
148
150
  - lib/grpc_mock/version.rb