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 +4 -4
- data/README.md +43 -9
- data/grpc_mock.gemspec +2 -2
- data/lib/grpc_mock/grpc_stub_adapter.rb +19 -11
- data/lib/grpc_mock/mocked_call.rb +72 -0
- data/lib/grpc_mock/request_stub.rb +2 -1
- data/lib/grpc_mock/response.rb +12 -2
- data/lib/grpc_mock/version.rb +1 -1
- metadata +12 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb0de4a6e730f8e575b50ecfa9ee0d92b97dd3380900dc119de0a41abc285457
|
4
|
+
data.tar.gz: 912662c5b9ed4398a8377d9207621208f3bcfdf201eff0a4e4cd7ec95e152600
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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/
|
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
|
-
|
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
|
39
|
+
client.hello(Hello::HelloRequest.new(msg: 'hi')) # => Hello::HelloResponse.new(msg: 'test')
|
40
40
|
```
|
41
41
|
|
42
|
-
|
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
|
49
|
-
client
|
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
|
-
|
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
|
69
|
+
client.hello(Hello::HelloRequest.new(msg: 'hello')) # => Raise NetConnectNotAllowedError error
|
59
70
|
|
60
71
|
GrpcMock.allow_net_connect!
|
61
|
-
|
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
|
data/grpc_mock.gemspec
CHANGED
@@ -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', '<
|
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', '
|
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
|
-
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/grpc_mock/response.rb
CHANGED
@@ -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
|
data/lib/grpc_mock/version.rb
CHANGED
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.
|
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:
|
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:
|
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:
|
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:
|
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:
|
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: []
|