evil-client 0.3.3 → 1.0.0
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/.codeclimate.yml +0 -11
- data/.gitignore +1 -0
- data/.rspec +0 -1
- data/.rubocop.yml +22 -19
- data/.travis.yml +1 -0
- data/CHANGELOG.md +251 -6
- data/LICENSE.txt +3 -1
- data/README.md +47 -81
- data/docs/helpers/body.md +93 -0
- data/docs/helpers/connection.md +19 -0
- data/docs/helpers/headers.md +72 -0
- data/docs/helpers/http_method.md +39 -0
- data/docs/helpers/let.md +14 -0
- data/docs/helpers/logger.md +24 -0
- data/docs/helpers/middleware.md +56 -0
- data/docs/helpers/operation.md +103 -0
- data/docs/helpers/option.md +50 -0
- data/docs/helpers/path.md +37 -0
- data/docs/helpers/query.md +59 -0
- data/docs/helpers/response.md +40 -0
- data/docs/helpers/scope.md +121 -0
- data/docs/helpers/security.md +102 -0
- data/docs/helpers/validate.md +68 -0
- data/docs/index.md +70 -78
- data/docs/license.md +5 -1
- data/docs/rspec.md +96 -0
- data/evil-client.gemspec +10 -8
- data/lib/evil/client.rb +126 -72
- data/lib/evil/client/builder.rb +47 -0
- data/lib/evil/client/builder/operation.rb +40 -0
- data/lib/evil/client/builder/scope.rb +31 -0
- data/lib/evil/client/chaining.rb +17 -0
- data/lib/evil/client/connection.rb +60 -20
- data/lib/evil/client/container.rb +66 -0
- data/lib/evil/client/container/operation.rb +23 -0
- data/lib/evil/client/container/scope.rb +28 -0
- data/lib/evil/client/exceptions/definition_error.rb +15 -0
- data/lib/evil/client/exceptions/name_error.rb +32 -0
- data/lib/evil/client/exceptions/response_error.rb +42 -0
- data/lib/evil/client/exceptions/type_error.rb +29 -0
- data/lib/evil/client/exceptions/validation_error.rb +27 -0
- data/lib/evil/client/formatter.rb +49 -0
- data/lib/evil/client/formatter/form.rb +45 -0
- data/lib/evil/client/formatter/multipart.rb +33 -0
- data/lib/evil/client/formatter/part.rb +66 -0
- data/lib/evil/client/formatter/text.rb +21 -0
- data/lib/evil/client/resolver.rb +84 -0
- data/lib/evil/client/resolver/body.rb +22 -0
- data/lib/evil/client/resolver/format.rb +30 -0
- data/lib/evil/client/resolver/headers.rb +46 -0
- data/lib/evil/client/resolver/http_method.rb +34 -0
- data/lib/evil/client/resolver/middleware.rb +36 -0
- data/lib/evil/client/resolver/query.rb +39 -0
- data/lib/evil/client/resolver/request.rb +96 -0
- data/lib/evil/client/resolver/response.rb +26 -0
- data/lib/evil/client/resolver/security.rb +113 -0
- data/lib/evil/client/resolver/uri.rb +35 -0
- data/lib/evil/client/rspec.rb +127 -0
- data/lib/evil/client/schema.rb +105 -0
- data/lib/evil/client/schema/operation.rb +177 -0
- data/lib/evil/client/schema/scope.rb +73 -0
- data/lib/evil/client/settings.rb +172 -0
- data/lib/evil/client/settings/validator.rb +64 -0
- data/mkdocs.yml +21 -15
- data/spec/features/custom_connection_spec.rb +17 -0
- data/spec/features/operation/middleware_spec.rb +50 -0
- data/spec/features/operation/options_spec.rb +71 -0
- data/spec/features/operation/request_spec.rb +94 -0
- data/spec/features/operation/response_spec.rb +48 -0
- data/spec/features/scope/options_spec.rb +52 -0
- data/spec/fixtures/locales/en.yml +16 -0
- data/spec/fixtures/test_client.rb +76 -0
- data/spec/spec_helper.rb +18 -6
- data/spec/support/fixtures_helper.rb +7 -0
- data/spec/unit/builder/operation_spec.rb +90 -0
- data/spec/unit/builder/scope_spec.rb +84 -0
- data/spec/unit/client_spec.rb +137 -0
- data/spec/unit/connection_spec.rb +78 -0
- data/spec/unit/container/operation_spec.rb +81 -0
- data/spec/unit/container/scope_spec.rb +61 -0
- data/spec/unit/container_spec.rb +107 -0
- data/spec/unit/exceptions/definition_error_spec.rb +15 -0
- data/spec/unit/exceptions/name_error_spec.rb +77 -0
- data/spec/unit/exceptions/response_error_spec.rb +22 -0
- data/spec/unit/exceptions/type_error_spec.rb +71 -0
- data/spec/unit/exceptions/validation_error_spec.rb +13 -0
- data/spec/unit/formatter/form_spec.rb +27 -0
- data/spec/unit/formatter/multipart_spec.rb +23 -0
- data/spec/unit/formatter/part_spec.rb +49 -0
- data/spec/unit/formatter/text_spec.rb +37 -0
- data/spec/unit/formatter_spec.rb +46 -0
- data/spec/unit/resolver/body_spec.rb +65 -0
- data/spec/unit/resolver/format_spec.rb +66 -0
- data/spec/unit/resolver/headers_spec.rb +93 -0
- data/spec/unit/resolver/http_method_spec.rb +67 -0
- data/spec/unit/resolver/middleware_spec.rb +83 -0
- data/spec/unit/resolver/query_spec.rb +85 -0
- data/spec/unit/resolver/request_spec.rb +121 -0
- data/spec/unit/resolver/response_spec.rb +64 -0
- data/spec/unit/resolver/security_spec.rb +156 -0
- data/spec/unit/resolver/uri_spec.rb +117 -0
- data/spec/unit/rspec_spec.rb +342 -0
- data/spec/unit/schema/operation_spec.rb +309 -0
- data/spec/unit/schema/scope_spec.rb +110 -0
- data/spec/unit/schema_spec.rb +157 -0
- data/spec/unit/settings/validator_spec.rb +128 -0
- data/spec/unit/settings_spec.rb +248 -0
- metadata +192 -135
- data/docs/base_url.md +0 -38
- data/docs/documentation.md +0 -9
- data/docs/headers.md +0 -59
- data/docs/http_method.md +0 -31
- data/docs/model.md +0 -173
- data/docs/operation.md +0 -0
- data/docs/overview.md +0 -0
- data/docs/path.md +0 -48
- data/docs/query.md +0 -99
- data/docs/responses.md +0 -66
- data/docs/security.md +0 -102
- data/docs/settings.md +0 -32
- data/lib/evil/client/connection/net_http.rb +0 -57
- data/lib/evil/client/dsl.rb +0 -127
- data/lib/evil/client/dsl/base.rb +0 -26
- data/lib/evil/client/dsl/files.rb +0 -37
- data/lib/evil/client/dsl/headers.rb +0 -16
- data/lib/evil/client/dsl/http_method.rb +0 -24
- data/lib/evil/client/dsl/operation.rb +0 -91
- data/lib/evil/client/dsl/operations.rb +0 -41
- data/lib/evil/client/dsl/path.rb +0 -25
- data/lib/evil/client/dsl/query.rb +0 -16
- data/lib/evil/client/dsl/response.rb +0 -61
- data/lib/evil/client/dsl/responses.rb +0 -29
- data/lib/evil/client/dsl/scope.rb +0 -27
- data/lib/evil/client/dsl/security.rb +0 -57
- data/lib/evil/client/dsl/verifier.rb +0 -35
- data/lib/evil/client/middleware.rb +0 -81
- data/lib/evil/client/middleware/base.rb +0 -11
- data/lib/evil/client/middleware/merge_security.rb +0 -20
- data/lib/evil/client/middleware/normalize_headers.rb +0 -17
- data/lib/evil/client/middleware/stringify_form.rb +0 -40
- data/lib/evil/client/middleware/stringify_json.rb +0 -19
- data/lib/evil/client/middleware/stringify_multipart.rb +0 -36
- data/lib/evil/client/middleware/stringify_multipart/part.rb +0 -36
- data/lib/evil/client/middleware/stringify_query.rb +0 -35
- data/lib/evil/client/operation.rb +0 -34
- data/lib/evil/client/operation/request.rb +0 -26
- data/lib/evil/client/operation/response.rb +0 -39
- data/lib/evil/client/operation/response_error.rb +0 -13
- data/lib/evil/client/operation/unexpected_response_error.rb +0 -19
- data/spec/features/instantiation_spec.rb +0 -68
- data/spec/features/middleware_spec.rb +0 -79
- data/spec/features/operation_with_documentation_spec.rb +0 -41
- data/spec/features/operation_with_files_spec.rb +0 -40
- data/spec/features/operation_with_form_body_spec.rb +0 -158
- data/spec/features/operation_with_headers_spec.rb +0 -99
- data/spec/features/operation_with_http_method_spec.rb +0 -45
- data/spec/features/operation_with_json_body_spec.rb +0 -156
- data/spec/features/operation_with_nested_responses_spec.rb +0 -95
- data/spec/features/operation_with_path_spec.rb +0 -47
- data/spec/features/operation_with_query_spec.rb +0 -84
- data/spec/features/operation_with_security_spec.rb +0 -228
- data/spec/features/scoping_spec.rb +0 -48
- data/spec/support/test_client.rb +0 -15
- data/spec/unit/evil/client/connection/net_http_spec.rb +0 -38
- data/spec/unit/evil/client/dsl/files_spec.rb +0 -37
- data/spec/unit/evil/client/dsl/operation_spec.rb +0 -374
- data/spec/unit/evil/client/dsl/operations_spec.rb +0 -29
- data/spec/unit/evil/client/dsl/scope_spec.rb +0 -32
- data/spec/unit/evil/client/dsl/security_spec.rb +0 -135
- data/spec/unit/evil/client/middleware/merge_security_spec.rb +0 -32
- data/spec/unit/evil/client/middleware/normalize_headers_spec.rb +0 -17
- data/spec/unit/evil/client/middleware/stringify_form_spec.rb +0 -63
- data/spec/unit/evil/client/middleware/stringify_json_spec.rb +0 -61
- data/spec/unit/evil/client/middleware/stringify_multipart/part_spec.rb +0 -59
- data/spec/unit/evil/client/middleware/stringify_multipart_spec.rb +0 -62
- data/spec/unit/evil/client/middleware/stringify_query_spec.rb +0 -40
- data/spec/unit/evil/client/middleware_spec.rb +0 -46
- data/spec/unit/evil/client/operation/request_spec.rb +0 -49
- data/spec/unit/evil/client/operation/response_spec.rb +0 -63
@@ -0,0 +1,73 @@
|
|
1
|
+
require_relative "operation"
|
2
|
+
|
3
|
+
class Evil::Client
|
4
|
+
#
|
5
|
+
# Mutable container of definitions for sub-scopes and operations
|
6
|
+
# with DSL to configure those definitions.
|
7
|
+
#
|
8
|
+
class Schema::Scope < Schema::Operation
|
9
|
+
# Tells that this is a schema for a scope (not the final operation)
|
10
|
+
#
|
11
|
+
# @return [false]
|
12
|
+
#
|
13
|
+
def leaf?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
# The collection of named sub-scope schemas
|
18
|
+
#
|
19
|
+
# Every sub-scope schema refers to the current one as a [#parent]
|
20
|
+
#
|
21
|
+
# @return [Hash<Symbol, Class>]
|
22
|
+
#
|
23
|
+
def scopes
|
24
|
+
@__children__.reject { |_, child| child.leaf? }
|
25
|
+
end
|
26
|
+
|
27
|
+
# The collection of named operation schemas
|
28
|
+
#
|
29
|
+
# @return [Hash<[Symbol, nil], Class>]
|
30
|
+
#
|
31
|
+
def operations
|
32
|
+
@__children__.select { |_, child| child.leaf? }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Creates or updates sub-scope definition
|
36
|
+
#
|
37
|
+
# @param [#to_sym] name The unique name of subscope inside current scope
|
38
|
+
# @param [Proc] block The block containing definition for the subscope
|
39
|
+
# @return [self]
|
40
|
+
#
|
41
|
+
def scope(name, &block)
|
42
|
+
key = NameError.check!(name, RESERVED)
|
43
|
+
TypeError.check! self, key, :scope
|
44
|
+
@__children__[key] ||= self.class.new(self, key)
|
45
|
+
@__children__[key].instance_exec(&block)
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
# Creates or updates operation definition
|
50
|
+
#
|
51
|
+
# @param [#to_sym] name The unique name of operation inside the scope
|
52
|
+
# @param [Proc] block The block containing definition for the operation
|
53
|
+
# @return [self]
|
54
|
+
#
|
55
|
+
def operation(name, &block)
|
56
|
+
key = NameError.check!(name, RESERVED)
|
57
|
+
TypeError.check! self, key, :operation
|
58
|
+
@__children__[key] ||= self.class.superclass.new(self, key)
|
59
|
+
@__children__[key].instance_exec(&block)
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def initialize(*)
|
66
|
+
super
|
67
|
+
@__children__ = {}
|
68
|
+
end
|
69
|
+
|
70
|
+
RESERVED = \
|
71
|
+
%i[operations scopes scope options schema settings inspect logger].freeze
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
class Evil::Client
|
2
|
+
#
|
3
|
+
# Container for settings assigned to some operation or scope.
|
4
|
+
#
|
5
|
+
class Settings
|
6
|
+
require_relative "settings/validator"
|
7
|
+
|
8
|
+
extend Dry::Initializer
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# The schema klass settings belongs to
|
12
|
+
#
|
13
|
+
# @return [Class]
|
14
|
+
#
|
15
|
+
attr_reader :schema
|
16
|
+
|
17
|
+
# Only options can be defined for the settings container
|
18
|
+
# @private
|
19
|
+
def param(*args)
|
20
|
+
option(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Creates or updates the settings' initializer
|
24
|
+
#
|
25
|
+
# @see [http://dry-rb.org/gems/dry-initializer]
|
26
|
+
#
|
27
|
+
# @param [#to_sym] key Symbolic name of the option
|
28
|
+
# @param [#call] type Type coercer for the option
|
29
|
+
# @option opts [#call] :type Another way to assign type coercer
|
30
|
+
# @option opts [#call] :default Proc containing default value
|
31
|
+
# @option opts [Boolean] :optional Whether it can be missed
|
32
|
+
# @option opts [#to_sym] :as The name of settings variable
|
33
|
+
# @option opts [false, :private, :protected] :reader Reader method type
|
34
|
+
# @return [self]
|
35
|
+
#
|
36
|
+
def option(key, type = nil, as: key.to_sym, **opts)
|
37
|
+
NameError.check!(as, RESERVED)
|
38
|
+
super
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
# Creates or reloads memoized attribute
|
43
|
+
#
|
44
|
+
# @param [#to_sym] key The name of the attribute
|
45
|
+
# @param [Proc] block The body of new attribute
|
46
|
+
# @return [self]
|
47
|
+
#
|
48
|
+
def let(key, &block)
|
49
|
+
NameError.check!(key, RESERVED)
|
50
|
+
define_method(key) do
|
51
|
+
instance_variable_get(:"@#{key}") ||
|
52
|
+
instance_variable_set(:"@#{key}", instance_exec(&block))
|
53
|
+
end
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
# Define validator for the attribute
|
58
|
+
#
|
59
|
+
# @param [#to_sym] key The name of the attribute
|
60
|
+
# @param [Proc] block The body of new attribute
|
61
|
+
# @return [self]
|
62
|
+
#
|
63
|
+
def validate(key, &block)
|
64
|
+
validators[key] = Validator.new(@schema, key, &block)
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
# Collection of validators to check initialized settings
|
69
|
+
#
|
70
|
+
# @return [Hash<Symbol, Evil::Client::Validator>]
|
71
|
+
#
|
72
|
+
def validators
|
73
|
+
@validators ||= {}
|
74
|
+
end
|
75
|
+
|
76
|
+
# Human-friendly representation of settings class
|
77
|
+
#
|
78
|
+
# @return [String]
|
79
|
+
#
|
80
|
+
def name
|
81
|
+
super || @schema.to_s
|
82
|
+
end
|
83
|
+
alias_method :to_s, :name
|
84
|
+
alias_method :to_str, :name
|
85
|
+
alias_method :inspect, :name
|
86
|
+
|
87
|
+
# Builds settings with options
|
88
|
+
#
|
89
|
+
# @param [Logger, nil] logger
|
90
|
+
# @param [Hash<#to_sym, Object>, nil] opts
|
91
|
+
# @return [Evil::Client::Settings]
|
92
|
+
#
|
93
|
+
def new(logger, opts = {})
|
94
|
+
logger&.debug(self) { "initializing with options #{opts}..." }
|
95
|
+
opts = Hash(opts).each_with_object({}) { |(k, v), o| o[k.to_sym] = v }
|
96
|
+
super logger, opts
|
97
|
+
rescue => error
|
98
|
+
raise ValidationError, error.message
|
99
|
+
end
|
100
|
+
|
101
|
+
# @private
|
102
|
+
RESERVED = \
|
103
|
+
%i[options datetime scope logger basic_auth key_auth token_auth].freeze
|
104
|
+
end
|
105
|
+
|
106
|
+
# The processed hash of options contained by the instance of settings
|
107
|
+
#
|
108
|
+
# @return [Hash<Symbol, Object>]
|
109
|
+
#
|
110
|
+
def options
|
111
|
+
@__options__
|
112
|
+
end
|
113
|
+
|
114
|
+
# @!attribute logger
|
115
|
+
# @return [Logger, nil] The logger attached to current settings
|
116
|
+
attr_accessor :logger
|
117
|
+
|
118
|
+
# DSL helper to format datetimes following RFC7231/RFC2822
|
119
|
+
#
|
120
|
+
# @see https://tools.ietf.org/html/rfc7231#section-7.1.1.1
|
121
|
+
#
|
122
|
+
# @param [Date, String, nil] value Value to be formatted
|
123
|
+
# @return [String, nil]
|
124
|
+
#
|
125
|
+
def datetime(value)
|
126
|
+
return unless value
|
127
|
+
|
128
|
+
value = DateTime.parse(value) if value.is_a? String
|
129
|
+
value = value.to_datetime if value.respond_to? :to_datetime
|
130
|
+
raise "Cannot convert #{value} to DateTime" unless value.is_a?(DateTime)
|
131
|
+
|
132
|
+
value.rfc2822
|
133
|
+
end
|
134
|
+
|
135
|
+
# Human-readable representation of settings instance
|
136
|
+
#
|
137
|
+
# @return [String]
|
138
|
+
#
|
139
|
+
def inspect
|
140
|
+
number = super.match(/\>\:([^ ]+) /)[1]
|
141
|
+
params = options.map { |k, v| "@#{k}=#{v}" }.join(", ")
|
142
|
+
number ? "#<#{self.class}:#{number} #{params}>" : super
|
143
|
+
end
|
144
|
+
alias_method :to_str, :inspect
|
145
|
+
alias_method :to_s, :inspect
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def initialize(logger, **options)
|
150
|
+
@logger = logger
|
151
|
+
super(options)
|
152
|
+
|
153
|
+
logger&.debug(self) { "initialized" }
|
154
|
+
__validate__!
|
155
|
+
end
|
156
|
+
|
157
|
+
def __validate__!
|
158
|
+
__validators__.reverse.each { |validator| validator.call(self) }
|
159
|
+
end
|
160
|
+
|
161
|
+
def __validators__
|
162
|
+
klass = self.class
|
163
|
+
[].tap do |list|
|
164
|
+
loop do
|
165
|
+
list.concat klass.validators.values
|
166
|
+
klass = klass.superclass
|
167
|
+
break if klass == Evil::Client::Settings
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class Evil::Client
|
2
|
+
#
|
3
|
+
# Validator to be called in context of initialized settings
|
4
|
+
#
|
5
|
+
class Settings::Validator
|
6
|
+
# Performs validation of initialized settings
|
7
|
+
#
|
8
|
+
# @param [Evil::Client::Settings]
|
9
|
+
# @return true
|
10
|
+
# @raise [Evil::Client::ValidationError] when a validation fails
|
11
|
+
#
|
12
|
+
def call(settings)
|
13
|
+
if validate!(settings, @block)
|
14
|
+
settings&.logger&.debug(self) { "passed for #{settings}" }
|
15
|
+
true
|
16
|
+
else
|
17
|
+
settings&.logger&.error(self) { "failed for #{settings}" }
|
18
|
+
raise ValidationError.new(@key, @schema, settings.options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Human-friendly representation of current validator
|
23
|
+
#
|
24
|
+
# @return [String]
|
25
|
+
#
|
26
|
+
def to_s
|
27
|
+
"#{@schema}.validator[:#{@key}]"
|
28
|
+
end
|
29
|
+
alias_method :to_str, :to_s
|
30
|
+
alias_method :inspect, :to_s
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def initialize(schema, key, &block)
|
35
|
+
check_key! key
|
36
|
+
check_block! block
|
37
|
+
|
38
|
+
@schema = schema
|
39
|
+
@key = key.to_sym
|
40
|
+
@block = block
|
41
|
+
end
|
42
|
+
|
43
|
+
def check_key!(key)
|
44
|
+
message = if !key.respond_to? :to_sym
|
45
|
+
"Validator should have a symbolic name"
|
46
|
+
elsif key.empty?
|
47
|
+
"Validator name should not be empty"
|
48
|
+
end
|
49
|
+
|
50
|
+
raise ArgumentError.new(message) if message
|
51
|
+
end
|
52
|
+
|
53
|
+
def check_block!(block)
|
54
|
+
raise ArgumentError, "You should set block for validation" unless block
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate!(settings, block)
|
58
|
+
settings.instance_eval(&block) && true
|
59
|
+
rescue => error
|
60
|
+
settings&.logger&.error(self) { "broken for #{settings} with #{error}" }
|
61
|
+
raise
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/mkdocs.yml
CHANGED
@@ -1,21 +1,27 @@
|
|
1
|
+
# The structure of documentation at readthedocs.com
|
1
2
|
---
|
2
3
|
site_name: Evil::Client
|
3
|
-
site_description: Human-friendly DSL for building HTTP(s) clients
|
4
|
+
site_description: Human-friendly DSL for building HTTP(s) clients to remote API
|
4
5
|
repo_url: https://github.com/nepalez/evil-client
|
5
6
|
site_author: Andrew Kozin
|
6
7
|
theme: readthedocs
|
7
8
|
pages:
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
9
|
+
Synopsis: index.md
|
10
|
+
Helpers:
|
11
|
+
scope: helpers/scope.md
|
12
|
+
operation: helpers/operation.md
|
13
|
+
option: helpers/option.md
|
14
|
+
let: helpers/let.md
|
15
|
+
validate: helpers/validate.md
|
16
|
+
path: helpers/path.md
|
17
|
+
http_method: helpers/http_method.md
|
18
|
+
security: helpers/security.md
|
19
|
+
headers: helpers/headers.md
|
20
|
+
query: helpers/query.md
|
21
|
+
'body and format': helpers/body.md
|
22
|
+
response: helpers/response.md
|
23
|
+
middleware: helpers/middleware.md
|
24
|
+
connection: helpers/connection.md
|
25
|
+
logger: helpers/logger.md
|
26
|
+
'RSpec matcher': rspec.md
|
27
|
+
License: license.md
|
@@ -0,0 +1,17 @@
|
|
1
|
+
RSpec.describe "custom connection" do
|
2
|
+
let(:conn) { double call: response }
|
3
|
+
let(:response) { [200, { "Foo" => "Bar" }, ["Hello!"]] }
|
4
|
+
let(:params) { { subdomain: "europe", user: "andy", token: "foo" } }
|
5
|
+
let(:users) { Test::Client.new(params).crm(version: 4).users }
|
6
|
+
|
7
|
+
before do
|
8
|
+
load "spec/fixtures/test_client.rb"
|
9
|
+
Test::Client.connection = conn
|
10
|
+
end
|
11
|
+
|
12
|
+
subject { users.fetch id: 2 }
|
13
|
+
|
14
|
+
it "uses new connection" do
|
15
|
+
expect(subject).to eq response
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
RSpec.describe "operation request" do
|
2
|
+
before do
|
3
|
+
# Adds header tag to request/response
|
4
|
+
class Test::Middleware
|
5
|
+
extend Dry::Initializer
|
6
|
+
param :app
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
env["HTTP_Variables"].update tags
|
10
|
+
status, headers, body = app.call(env)
|
11
|
+
[status, headers.merge(tags), body]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Foo < Test::Middleware
|
16
|
+
def tags; { "Tag" => "Foo" }; end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Bar < Test::Middleware
|
20
|
+
def tags; { "Tag" => "Bar" }; end
|
21
|
+
end
|
22
|
+
|
23
|
+
load "spec/fixtures/test_client.rb"
|
24
|
+
class Test::Client < Evil::Client
|
25
|
+
middleware { Foo }
|
26
|
+
|
27
|
+
scope :crm do
|
28
|
+
middleware { Bar }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
stub_request(:any, //).to_return(status: 200, body: [], headers: {})
|
33
|
+
end
|
34
|
+
|
35
|
+
subject do
|
36
|
+
Test::Client.new(subdomain: "europe", user: "andy", password: "foo")
|
37
|
+
.crm(version: 4)
|
38
|
+
.users
|
39
|
+
.fetch(id: 1)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "applies middleware in a proper order" do
|
43
|
+
expected_request = \
|
44
|
+
a_request(:get, "https://europe.example.com/crm/v4/users/1")
|
45
|
+
.with headers: { "Tag" => "Bar" }
|
46
|
+
|
47
|
+
expect(subject).to eq [200, { "Tag" => "Foo" }, []]
|
48
|
+
expect(expected_request).to have_been_made
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
RSpec.describe "operation options" do
|
2
|
+
before { load "spec/fixtures/test_client.rb" }
|
3
|
+
|
4
|
+
let(:params) { { subdomain: "europe", user: "andy", token: "foo", foo: 0 } }
|
5
|
+
let(:users) { Test::Client.new(params).crm(version: 4).users }
|
6
|
+
|
7
|
+
shared_examples :valid_client do |details = "properly"|
|
8
|
+
it "[assigns operation options #{details}]" do
|
9
|
+
expect(subject.options).to eq options
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it_behaves_like :valid_client, "with defined options" do
|
14
|
+
subject { users.operations[:fetch].new(id: 9, baz: :QUX) }
|
15
|
+
let(:options) do
|
16
|
+
{ subdomain: "europe", user: "andy", token: "foo", version: 4, id: 9 }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it_behaves_like :valid_client, "with reloaded scope options" do
|
21
|
+
subject { users.operations[:fetch].new(id: 9, version: 8) }
|
22
|
+
let(:options) do
|
23
|
+
{ subdomain: "europe", user: "andy", token: "foo", version: 8, id: 9 }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it_behaves_like :valid_client, "with reloaded root options" do
|
28
|
+
subject { users.operations[:fetch].new(id: 9, user: "leo") }
|
29
|
+
let(:options) do
|
30
|
+
{ subdomain: "europe", user: "leo", token: "foo", version: 4, id: 9 }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it_behaves_like :valid_client, "with operation-specific options" do
|
35
|
+
subject { users.operations[:create].new(name: "Joe", language: "en") }
|
36
|
+
let(:options) do
|
37
|
+
{
|
38
|
+
subdomain: "europe",
|
39
|
+
user: "andy",
|
40
|
+
token: "foo",
|
41
|
+
version: 4,
|
42
|
+
name: "Joe",
|
43
|
+
language: "en"
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when required options missed" do
|
49
|
+
subject { users.operations[:create].new(language: "it") }
|
50
|
+
|
51
|
+
it "raises Evil::Client::ValidationError" do
|
52
|
+
expect { subject }.to raise_error Evil::Client::ValidationError, /name/
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when operation validation failed" do
|
57
|
+
subject { users.operations[:filter].new }
|
58
|
+
|
59
|
+
it "raises Evil::Client::ValidationError" do
|
60
|
+
expect { subject }.to raise_error Evil::Client::ValidationError, /id/
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when scope validation failed" do
|
65
|
+
subject { users.operations[:fetch].new id: 8, token: nil }
|
66
|
+
|
67
|
+
it "raises Evil::Client::ValidationError" do
|
68
|
+
expect { subject }.to raise_error Evil::Client::ValidationError, /token/
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|