runcite-gruf-rspec 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f607712911860632d9179a549daca3d08aeacd39623ecfbab881d9199c38d60d
4
+ data.tar.gz: ba30bcbd6d17b775c7cc19d141a855b298c8cd1f24f4f86745d32f3c3abb7477
5
+ SHA512:
6
+ metadata.gz: d50618bb226b4e821bde4a152393950a0d01a295ddcb5e6bfc467b627b88b083f3e8a4f199aff3863063e03c5fba7f707501eadf32984501deef53912bfc1364
7
+ data.tar.gz: 6e850ec18c41f4115770d35c08f36341392b96b2bc203c710d0479279ee5d9066046e6875b98f149c8b0edf4e803dec922ace7fe37b800b31b663a9139810894
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ Changelog for the gruf-rspec gem.
2
+
3
+ ### Pending release
4
+
5
+ ### 0.1.2
6
+
7
+ * Fix issue with RSPEC_NAMESPACE conflicts with other gems
8
+
9
+ ### 0.1.1
10
+
11
+ * Add be_a_successful_rpc matcher that matches on success and the appropriate response class
12
+
13
+ ### 0.1.0
14
+
15
+ * Initial release
@@ -0,0 +1,46 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ ## Our Standards
8
+
9
+ Examples of behavior that contributes to creating a positive environment include:
10
+
11
+ * Using welcoming and inclusive language
12
+ * Being respectful of differing viewpoints and experiences
13
+ * Gracefully accepting constructive criticism
14
+ * Focusing on what is best for the community
15
+ * Showing empathy towards other community members
16
+
17
+ Examples of unacceptable behavior by participants include:
18
+
19
+ * The use of sexualized language or imagery and unwelcome sexual attention or advances
20
+ * Trolling, insulting/derogatory comments, and personal or political attacks
21
+ * Public or private harassment
22
+ * Publishing others' private information, such as a physical or electronic address, without explicit permission
23
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
24
+
25
+ ## Our Responsibilities
26
+
27
+ Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28
+
29
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30
+
31
+ ## Scope
32
+
33
+ This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34
+
35
+ ## Enforcement
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at engineering@bigcommerce.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38
+
39
+ Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40
+
41
+ ## Attribution
42
+
43
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44
+
45
+ [homepage]: http://contributor-covenant.org
46
+ [version]: http://contributor-covenant.org/version/1/4/
data/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # gruf-rspec
2
+
3
+ [![CircleCI](https://circleci.com/gh/bigcommerce/gruf-rspec/tree/master.svg?style=svg)](https://circleci.com/gh/bigcommerce/gruf-rspec/tree/master) [![Gem Version](https://badge.fury.io/rb/gruf-rspec.svg)](https://badge.fury.io/rb/gruf-rspec) [![Documentation](https://inch-ci.org/github/bigcommerce/gruf-rspec.svg?branch=master)](https://inch-ci.org/github/bigcommerce/gruf-rspec?branch=master)
4
+
5
+ Assistance helpers and custom type for easy testing [Gruf](https://github.com/bigcommerce/gruf) controllers with
6
+ [RSpec](https://github.com/rspec/rspec).
7
+
8
+ ## Installation
9
+
10
+ ```ruby
11
+ gem 'gruf-rspec'
12
+ ```
13
+
14
+ Then add the following code to your `spec_helper.rb`:
15
+
16
+ ```ruby
17
+ require 'gruf/rspec'
18
+ ```
19
+
20
+ Note that this gem requires at least Gruf 2.5.1+ and RSpec 3.8+.
21
+
22
+ ## Usage
23
+
24
+ * Add a test for a Gruf controller in `spec/rpc`
25
+ * Run the `run_rpc` method with two args: The gRPC method name, and the request object
26
+ * Validate the response
27
+
28
+ ## Example
29
+
30
+ Let's assume you have a gruf controller named `ThingController` that is bound to the gRPC
31
+ service `Rpc::Things::Service`. That has a method `GetThing`:
32
+
33
+ ```ruby
34
+ class ThingController < Gruf::Controllers::Base
35
+ bind ::Rpc::Things::Service
36
+
37
+ def get_thing
38
+ Rpc::GetThingResponse.new(id: request.message.id)
39
+ end
40
+ end
41
+ ```
42
+
43
+ To test it, you'd create `spec/rpc/thing_controller_spec.rb`:
44
+
45
+ ```ruby
46
+ describe ThingController do
47
+ describe '.get_thing' do
48
+ let(:request_proto) { Rpc::GetThingRequest.new(id: rand(1..100)) }
49
+
50
+ subject { run_rpc(:GetThing, request_proto) }
51
+
52
+ it 'will return the thing' do
53
+ expect(subject).to be_a(Rpc::GetThingResponse)
54
+ expect(subject.id).to eq request_proto.id
55
+ end
56
+ end
57
+ end
58
+ ```
59
+
60
+ Alternatively, you can pass a block:
61
+
62
+ ```ruby
63
+ it 'will return the thing' do
64
+ run_rpc(:GetThing, request_proto) do |resp|
65
+ expect(resp).to be_a(Rpc::GetThingResponse)
66
+ expect(resp.id).to eq request_proto.id
67
+ end
68
+ end
69
+ ```
70
+
71
+ ### Accessing the Bound Service
72
+
73
+ Note that you can also access the bound gRPC service class:
74
+
75
+ ```ruby
76
+ it 'binds the service correctly' do
77
+ expect(grpc_bound_service).to eq Rpc::Things::Service
78
+ end
79
+ ```
80
+
81
+ ### Matching Errors
82
+
83
+ You can match against errors as well:
84
+
85
+ ```ruby
86
+ describe 'testing an error' do
87
+ let(:request_proto) { Rpc::GetThingRequest.new(id: rand(1..100)) }
88
+
89
+ subject { run_rpc(:GetThing, request_proto) }
90
+
91
+ it 'should fail with the appropriate error' do
92
+ expect { subject }.to raise_rpc_error(GRPC::InvalidArgument)
93
+ end
94
+ end
95
+ ```
96
+
97
+ Or further, even check your serialized error that is passed in metadata:
98
+
99
+ ```ruby
100
+ it 'should fail with the appropriate error code' do
101
+ expect { subject }.to raise_rpc_error(GRPC::InvalidArgument).with_serialized { |err|
102
+ expect(err).to be_a(MyCustomErrorClass)
103
+ expect(err.error_code).to eq 'invalid_request'
104
+
105
+ fe = err.field_errors.first
106
+ expect(fe.field_name).to eq 'name'
107
+ expect(fe.error_code).to eq 'invalid_name'
108
+ expect(fe.error_message).to eq
109
+ }
110
+ end
111
+ ```
112
+
113
+ Note that when using `with_serialized`, you _must_ pass the block with `{ }`, not using
114
+ `do` and `end`.
115
+
116
+
117
+ ### RSpec Controller Matcher Configuration
118
+
119
+ By default, the type matcher for Gruf controllers matches in `/spec/rpc`. You can customize this by configuring it
120
+ in the `Gruf::Rspec` confiugration block like so:
121
+
122
+ ```ruby
123
+ Gruf::Rspec.configure do |c|
124
+ c.rpc_spec_path = '/spec/rpc_controllers'
125
+ end
126
+ ```
127
+
128
+ ## License
129
+
130
+ Copyright (c) 2018-present, BigCommerce Pty. Ltd. All rights reserved
131
+
132
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
133
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
134
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
135
+ persons to whom the Software is furnished to do so, subject to the following conditions:
136
+
137
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
138
+ Software.
139
+
140
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
141
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
142
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
143
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2018-present, BigCommerce Pty. Ltd. All rights reserved
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
7
+ #
8
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ # Software.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ #
16
+ lib = File.expand_path('../lib', __FILE__)
17
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
18
+ require 'gruf/rspec/version'
19
+
20
+ Gem::Specification.new do |spec|
21
+ spec.name = 'runcite-gruf-rspec'
22
+ spec.version = Gruf::Rspec::VERSION
23
+ spec.authors = ['Shaun McCormick']
24
+ spec.email = ['splittingred@gmail.com']
25
+ spec.license = 'MIT'
26
+
27
+ spec.summary = %q{RSpec assistance library for gruf}
28
+ spec.description = %q{RSpec assistance library for gruf, including testing helpers}
29
+ spec.homepage = 'https://github.com/runciteassociates/gruf-rspec'
30
+
31
+ # Specify which files should be added to the gem when it is released.
32
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
33
+ spec.files = Dir['README.md', 'CHANGELOG.md', 'CODE_OF_CONDUCT.md', 'lib/**/*', 'gruf-rspec.gemspec']
34
+ spec.require_paths = ['lib']
35
+
36
+ spec.add_development_dependency 'bundler', '~> 1.16'
37
+ spec.add_development_dependency 'rake', '~> 10.0'
38
+ spec.add_development_dependency 'pry'
39
+
40
+ spec.add_dependency 'gruf', '~> 2.5', '>= 2.5.1'
41
+ spec.add_dependency 'rspec', '~> 3.8'
42
+ end
data/lib/gruf/rspec.rb ADDED
@@ -0,0 +1,103 @@
1
+ # Copyright (c) 2018-present, BigCommerce Pty. Ltd. All rights reserved
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
7
+ #
8
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ # Software.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ #
16
+ begin
17
+ require 'rspec/core'
18
+ require 'rspec/expectations'
19
+ GRUF_RSPEC_NAMESPACE = RSpec
20
+ GRUF_RSPEC_RUNNER = RSpec
21
+ rescue LoadError # old rspec compat
22
+ require 'spec'
23
+ GRUF_RSPEC_NAMESPACE = Spec
24
+ GRUF_RSPEC_RUNNER = Spec::Runner
25
+ end
26
+
27
+ require_relative 'rspec/version'
28
+ require_relative 'rspec/configuration'
29
+ require_relative 'rspec/helpers'
30
+ require_relative 'rspec/error_matcher'
31
+
32
+ module Gruf
33
+ module Rspec
34
+ extend Gruf::Rspec::Configuration
35
+ end
36
+ end
37
+
38
+ Gruf::Rspec.reset # initial reset
39
+
40
+ GRUF_RSPEC_RUNNER.configure do |config|
41
+ config.include Gruf::Rspec::Helpers
42
+
43
+ config.define_derived_metadata(file_path: Regexp.new(Gruf::Rspec.rpc_spec_path)) do |metadata|
44
+ metadata[:type] = :gruf_controller
45
+ end
46
+
47
+ config.before(:each, type: :gruf_controller) do
48
+ define_singleton_method :run_rpc do |method_name, request, metadata = {}, &block|
49
+ @gruf_controller = described_class.new(
50
+ method_key: method_name.to_s.underscore.to_sym,
51
+ service: grpc_bound_service,
52
+ rpc_desc: grpc_bound_service.rpc_descs[method_name.to_sym],
53
+ active_call: grpc_active_call(metadata),
54
+ message: request
55
+ )
56
+ resp = @gruf_controller.call(@gruf_controller.request.method_key)
57
+ block.call(resp) if block && block.is_a?(Proc)
58
+ resp
59
+ end
60
+
61
+ define_singleton_method :grpc_bound_service do
62
+ described_class.bound_service
63
+ end
64
+
65
+ define_singleton_method :gruf_controller do
66
+ @gruf_controller
67
+ end
68
+ end
69
+ end
70
+
71
+ GRUF_RSPEC_NAMESPACE::Matchers.define :raise_rpc_error do |expected_error_class|
72
+ supports_block_expectations
73
+
74
+ def with_serialized(&block)
75
+ @serialized_block = block
76
+ self
77
+ end
78
+
79
+ match do |rpc_call_proc|
80
+ @error_matcher = Gruf::Rspec::ErrorMatcher.new(
81
+ rpc_call_proc: rpc_call_proc,
82
+ expected_error_class: expected_error_class,
83
+ serialized_block: @serialized_block
84
+ )
85
+ @error_matcher.valid?
86
+ end
87
+
88
+ failure_message do |_|
89
+ @error_matcher.error_message
90
+ end
91
+ end
92
+
93
+ GRUF_RSPEC_NAMESPACE::Matchers.define :be_a_successful_rpc do |_|
94
+ match do |actual|
95
+ if !gruf_controller || actual.is_a?(GRPC::BadStatus) || actual.is_a?(GRPC::Core::CallError)
96
+ false
97
+ else
98
+ method_key = gruf_controller.request.method_key.to_s.camelcase.to_sym
99
+ expected_class = gruf_controller.class.bound_service.rpc_descs[method_key].output
100
+ expected_class == actual.class
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,40 @@
1
+ # Copyright (c) 2018-present, BigCommerce Pty. Ltd. All rights reserved
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
7
+ #
8
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ # Software.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ #
16
+ module Gruf
17
+ module Rspec
18
+ module AuthenticationHydrators
19
+ ##
20
+ # Base authentication hydration class, performs a NOOP on hydration
21
+ #
22
+ class Base
23
+ ##
24
+ # @param [Hash] options
25
+ #
26
+ def initialize(options = {})
27
+ @options = options || {}
28
+ end
29
+
30
+ ##
31
+ # @param [Hash] metadata The incoming request metadata
32
+ # @return [Hash] The hydrated metadata
33
+ #
34
+ def hydrate(metadata)
35
+ metadata
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,45 @@
1
+ # Copyright (c) 2018-present, BigCommerce Pty. Ltd. All rights reserved
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
7
+ #
8
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ # Software.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ #
16
+ require 'base64'
17
+
18
+ module Gruf
19
+ module Rspec
20
+ module AuthenticationHydrators
21
+ ##
22
+ # Automatically hydrate request metadata with basic authentication options
23
+ #
24
+ class Basic < ::Gruf::Rspec::AuthenticationHydrators::Base
25
+ ##
26
+ # @param [Hash] metadata The incoming request metadata
27
+ # @return [Hash] The hydrated metadata
28
+ #
29
+ def hydrate(metadata)
30
+ username = auth_opts.fetch(:username, '')
31
+ password = auth_opts.fetch(:password, '')
32
+ auth_string = username.to_s.empty? ? password : "#{username}:#{password}"
33
+ metadata[auth_opts.fetch(:header_key, 'authorization').to_s] = "Basic #{::Base64.encode64(auth_string)}" unless auth_string.empty?
34
+ metadata
35
+ end
36
+
37
+ private
38
+
39
+ def auth_opts
40
+ @auth_opts ||= @options.fetch(:authentication_options, {})
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,79 @@
1
+ # Copyright (c) 2018-present, BigCommerce Pty. Ltd. All rights reserved
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
7
+ #
8
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ # Software.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ #
16
+ require_relative 'authentication_hydrators/base'
17
+ require_relative 'authentication_hydrators/basic'
18
+
19
+ module Gruf
20
+ module Rspec
21
+ ##
22
+ # Represents configuration settings for the system
23
+ #
24
+ module Configuration
25
+ VALID_CONFIG_KEYS = {
26
+ authentication_hydrators: {
27
+ base: Gruf::Rspec::AuthenticationHydrators::Base,
28
+ basic: Gruf::Rspec::AuthenticationHydrators::Basic
29
+ },
30
+ rpc_spec_path: '/spec/rpc/'.freeze
31
+ }.freeze
32
+
33
+ attr_accessor *VALID_CONFIG_KEYS.keys
34
+
35
+ ##
36
+ # Whenever this is extended into a class, setup the defaults
37
+ #
38
+ def self.extended(base)
39
+ base.reset
40
+ end
41
+
42
+ ##
43
+ # Yield self for ruby-style initialization
44
+ #
45
+ # @yields [Gruf::Rspec::Configuration] The configuration object for gruf
46
+ # @return [Gruf::Rspec::Configuration] The configuration object for gruf
47
+ #
48
+ def configure
49
+ yield self
50
+ end
51
+
52
+ ##
53
+ # Return the current configuration options as a Hash
54
+ #
55
+ # @return [Hash] The configuration for gruf, represented as a Hash
56
+ #
57
+ def options
58
+ opts = {}
59
+ VALID_CONFIG_KEYS.each_key do |k|
60
+ opts.merge!(k => send(k))
61
+ end
62
+ opts
63
+ end
64
+
65
+ ##
66
+ # Set the default configuration onto the extended class
67
+ #
68
+ # @return [Hash] options The reset options hash
69
+ #
70
+ def reset
71
+ VALID_CONFIG_KEYS.each do |k, v|
72
+ send((k.to_s + '='), v)
73
+ end
74
+ self.rpc_spec_path = '/spec/rpc/'.freeze
75
+ options
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,117 @@
1
+ # Copyright (c) 2018-present, BigCommerce Pty. Ltd. All rights reserved
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
7
+ #
8
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ # Software.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ #
16
+ module Gruf
17
+ module Rspec
18
+ ##
19
+ # Match errors and properly handle validations
20
+ #
21
+ class ErrorMatcher
22
+ attr_writer :serialized_block
23
+ attr_reader :serialized_block_errors
24
+
25
+ ##
26
+ # @param [Proc] rpc_call_proc The underlying yielded controller proc to call
27
+ # @param [Class] expected_error_class The expected error class to occur
28
+ # @param [Proc|lambda|Nil] serialized_block If passed, the serialized block for inspecting errors
29
+ #
30
+ def initialize(rpc_call_proc:,
31
+ expected_error_class:,
32
+ serialized_block:)
33
+ @rpc_call_proc = rpc_call_proc
34
+ @expected_error_class = expected_error_class
35
+ @serialized_block = serialized_block
36
+
37
+ @error_class_matched = false
38
+ @error_serializer = Gruf.error_serializer
39
+ @serialized_block_errors = []
40
+ end
41
+
42
+ ##
43
+ # @return [Boolean]
44
+ #
45
+ def valid?
46
+ run_rpc_call
47
+ run_serialized_block
48
+ error_class_matched? && !serialized_block_errors?
49
+ end
50
+
51
+ ##
52
+ # @return [String]
53
+ #
54
+ def error_message
55
+ if serialized_block_errors?
56
+ "Failed with serialized error validations: #{@serialized_block_errors.join("\n")}"
57
+ else
58
+ "Response class #{@rpc_response.class} did not match expected error class #{@expected_error_class}"
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ ##
65
+ # Did the error class match?
66
+ #
67
+ def error_class_matched?
68
+ @error_class_matched
69
+ end
70
+
71
+ ##
72
+ # Were there any downstream errors in the serialized block chain?
73
+ #
74
+ def serialized_block_errors?
75
+ @serialized_block_errors.any?
76
+ end
77
+
78
+ ##
79
+ # Was the method chain called with .with_serialized
80
+ #
81
+ # @return [Boolean]
82
+ #
83
+ def serialized_block?
84
+ @serialized_block
85
+ end
86
+
87
+ ##
88
+ # Run the actual rpc call
89
+ #
90
+ def run_rpc_call
91
+ @rpc_response = @rpc_call_proc.call
92
+ rescue StandardError => e
93
+ @error_class_matched = e.is_a?(@expected_error_class)
94
+ @rpc_response = e
95
+ end
96
+
97
+ ##
98
+ # Run the serialized block, if any, and if the error class matches
99
+ #
100
+ def run_serialized_block
101
+ return unless error_class_matched? && serialized_block?
102
+
103
+ @serialized_block.call(deserialize_error)
104
+ true
105
+ rescue ::RSpec::Expectations::ExpectationNotMetError, ::RSpec::Expectations::MultipleExpectationsNotMetError => e
106
+ @serialized_block_errors << e.message
107
+ end
108
+
109
+ ##
110
+ # Deserialize the error from the response
111
+ #
112
+ def deserialize_error
113
+ @error_serializer.new(@rpc_response.to_status.metadata[Gruf.error_metadata_key.to_sym]).deserialize if @error_serializer
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,40 @@
1
+ # Copyright (c) 2018-present, BigCommerce Pty. Ltd. All rights reserved
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
7
+ #
8
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ # Software.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ #
16
+ require_relative 'metadata_factory'
17
+
18
+ module Gruf
19
+ module Rspec
20
+ module Helpers
21
+ ##
22
+ # @param [Hash] options
23
+ # @return [Double] The mocked call
24
+ #
25
+ def grpc_active_call(options = {})
26
+ md = _build_active_call_metadata(options)
27
+ double(:grpc_active_call, metadata: md, output_metadata: options.fetch(:output_metadata, {}))
28
+ end
29
+
30
+ private
31
+
32
+ ##
33
+ # @param [Hash] options
34
+ #
35
+ def _build_active_call_metadata(options)
36
+ Gruf::Rspec::MetadataFactory.new(options).build(options.fetch(:metadata, {}))
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,53 @@
1
+ # Copyright (c) 2018-present, BigCommerce Pty. Ltd. All rights reserved
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
7
+ #
8
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ # Software.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ #
16
+ module Gruf
17
+ module Rspec
18
+ ##
19
+ # Factory for building metadata in an incoming controller request
20
+ #
21
+ class MetadataFactory
22
+ ##
23
+ # @param [Hash] options
24
+ #
25
+ def initialize(options = {})
26
+ @options = options || {}
27
+ end
28
+
29
+ ##
30
+ # @param [Hash] metadata
31
+ # @return [Hash]
32
+ #
33
+ def build(metadata = {})
34
+ metadata ||= {}
35
+ authentication_hydrator.hydrate(metadata)
36
+ end
37
+
38
+ private
39
+
40
+ ##
41
+ # @return [Gruf::Rspec::AuthenticationHydrator::Base]
42
+ #
43
+ def authentication_hydrator
44
+ unless @authentication_hydrator
45
+ auth_type = @options.fetch(:authentication_type, :basic).to_sym
46
+ auth_type = :base unless Gruf::Rspec.authentication_hydrators.key?(auth_type)
47
+ @authentication_hydrator = Gruf::Rspec.authentication_hydrators[auth_type].new(@options)
48
+ end
49
+ @authentication_hydrator
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright (c) 2018-present, BigCommerce Pty. Ltd. All rights reserved
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
7
+ #
8
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ # Software.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ #
16
+ module Gruf
17
+ module Rspec
18
+ VERSION = '0.1.2'.freeze
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: runcite-gruf-rspec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Shaun McCormick
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-07-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: gruf
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.5'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 2.5.1
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '2.5'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 2.5.1
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.8'
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.8'
89
+ description: RSpec assistance library for gruf, including testing helpers
90
+ email:
91
+ - splittingred@gmail.com
92
+ executables: []
93
+ extensions: []
94
+ extra_rdoc_files: []
95
+ files:
96
+ - CHANGELOG.md
97
+ - CODE_OF_CONDUCT.md
98
+ - README.md
99
+ - gruf-rspec.gemspec
100
+ - lib/gruf/rspec.rb
101
+ - lib/gruf/rspec/authentication_hydrators/base.rb
102
+ - lib/gruf/rspec/authentication_hydrators/basic.rb
103
+ - lib/gruf/rspec/configuration.rb
104
+ - lib/gruf/rspec/error_matcher.rb
105
+ - lib/gruf/rspec/helpers.rb
106
+ - lib/gruf/rspec/metadata_factory.rb
107
+ - lib/gruf/rspec/version.rb
108
+ homepage: https://github.com/runciteassociates/gruf-rspec
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubygems_version: 3.0.4
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: RSpec assistance library for gruf
131
+ test_files: []