holoserve 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +55 -45
- data/Rakefile +1 -1
- data/lib/holoserve/interface/control/index.rb +42 -0
- data/lib/holoserve/interface/control.rb +5 -0
- data/lib/holoserve/interface/event.rb +38 -0
- data/lib/holoserve/interface/fake.rb +33 -18
- data/lib/holoserve/interface.rb +16 -0
- data/lib/holoserve/pair/finder.rb +23 -1
- data/lib/holoserve/pair/loader.rb +30 -13
- data/lib/holoserve/pair/validator.rb +47 -0
- data/lib/holoserve/pair.rb +1 -0
- data/lib/holoserve/request/selector.rb +21 -0
- data/lib/holoserve/request.rb +1 -1
- data/lib/holoserve/response/combiner.rb +1 -1
- data/lib/holoserve/response/selector.rb +6 -13
- data/lib/holoserve/tool/hash/matcher.rb +53 -0
- data/lib/holoserve/tool/hash.rb +1 -0
- data/spec/lib/holoserve/pair/validator_spec.rb +52 -0
- data/spec/lib/holoserve/request/selector_spec.rb +69 -0
- data/spec/lib/holoserve/tool/hash/matcher_spec.rb +136 -0
- metadata +73 -18
- data/lib/holoserve/request/matcher.rb +0 -74
data/README.rdoc
CHANGED
@@ -98,11 +98,11 @@ Returns a list of all requests that has been received, but couldn't be handled.
|
|
98
98
|
|
99
99
|
=== GET /_control/history
|
100
100
|
|
101
|
-
Returns a list of
|
101
|
+
Returns a list of hashes, which include the names/id of pairs that has been triggered, with a request variant and a list of response variants.
|
102
102
|
|
103
103
|
==== Response example
|
104
104
|
|
105
|
-
[
|
105
|
+
[{"id":"test_request","request_variant":"default","response_variants":["default","alternative"]}]
|
106
106
|
|
107
107
|
=== DELETE /_control/history
|
108
108
|
|
@@ -112,9 +112,10 @@ Removes all entries from the history.
|
|
112
112
|
|
113
113
|
The request/response pair file should have the following format.
|
114
114
|
|
115
|
-
|
115
|
+
requests:
|
116
|
+
default:
|
116
117
|
imports:
|
117
|
-
- path: "
|
118
|
+
- path: "test_fixtures.users.0"
|
118
119
|
as: "parameters"
|
119
120
|
only: [ "username", "password" ]
|
120
121
|
method: "POST"
|
@@ -123,55 +124,64 @@ The request/response pair file should have the following format.
|
|
123
124
|
HTTP_USER_AGENT: "Ruby"
|
124
125
|
oauth:
|
125
126
|
oauth_token: "12345"
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
- path: "test_fixture.users.0"
|
132
|
-
as: "json.user"
|
133
|
-
transitions:
|
134
|
-
session_one: "existing"
|
135
|
-
"user_one == :missing":
|
136
|
-
json:
|
137
|
-
message: "user not found"
|
138
|
-
- request:
|
127
|
+
responses:
|
128
|
+
default:
|
129
|
+
status: 200
|
130
|
+
found:
|
131
|
+
condition: "username == :existing"
|
139
132
|
imports:
|
140
|
-
- path: "
|
141
|
-
as: "
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
oauth_token: "12345"
|
151
|
-
responses:
|
152
|
-
"user_one == :existing":
|
153
|
-
status: 401
|
154
|
-
json:
|
155
|
-
message: "invalid password"
|
156
|
-
"user_one == :missing":
|
157
|
-
status: 200
|
158
|
-
json:
|
159
|
-
message: "user not found"
|
160
|
-
|
161
|
-
The fixture data where this example pair definition relies on, could look like to following.
|
133
|
+
- path: "test_fixtures.users.0"
|
134
|
+
as: "json.user"
|
135
|
+
transitions:
|
136
|
+
session_one: "existing"
|
137
|
+
not_found:
|
138
|
+
condition: "username == :missing"
|
139
|
+
json:
|
140
|
+
message: "user not found"
|
141
|
+
|
142
|
+
The fixture data where this example pair definition relies on, could look like the following.
|
162
143
|
|
163
144
|
users:
|
164
145
|
- email: "one@test.com"
|
165
146
|
username: "one"
|
166
147
|
password: "valid"
|
167
148
|
|
168
|
-
This example defines
|
169
|
-
|
170
|
-
are posted and the second one reacts on the transmission of <tt>username=one</tt> and <tt>password=invalid</tt>.
|
149
|
+
This example defines a request/response pair situation. It uses <tt>username=one</tt> and <tt>password=valid</tt>
|
150
|
+
as parameters.
|
171
151
|
|
172
|
-
If the state includes <tt>user_one == :existing</tt>, the
|
173
|
-
as json
|
174
|
-
<tt>user_one == :missing</tt>, both requests would be replied with the message "user not found".
|
152
|
+
If the state includes <tt>condition: "user_one == :existing"</tt>, the response would return the complete user object encoded
|
153
|
+
as json. If the state includes <tt>user_one == :missing</tt>, the request would be replied with the message "user not found".
|
175
154
|
|
176
155
|
The <tt>transitions</tt> part of the response allows you set the successor state. If a response is selected, the
|
177
156
|
corresponding transitions will be evaluated.
|
157
|
+
|
158
|
+
|
159
|
+
requests:
|
160
|
+
default:
|
161
|
+
imports:
|
162
|
+
- path: "test_fixtures.users.0.email"
|
163
|
+
as: "parameters"
|
164
|
+
method: "POST"
|
165
|
+
path: "/valid_email"
|
166
|
+
responses:
|
167
|
+
default:
|
168
|
+
status: 200
|
169
|
+
found:
|
170
|
+
condition: "email == :existing"
|
171
|
+
imports:
|
172
|
+
- path: "test_fixtures.users.0.username"
|
173
|
+
as: "json.user.username"
|
174
|
+
transitions:
|
175
|
+
session_one: "existing"
|
176
|
+
not_found:
|
177
|
+
condition: "email == :missing"
|
178
|
+
json:
|
179
|
+
message: "email address not found"
|
180
|
+
|
181
|
+
This example relies on the same fixture file used above.
|
182
|
+
|
183
|
+
This time it uses <tt>email=one@test.com</tt> as a parameter.
|
184
|
+
If the state includes <tt>condition: "email == :existing"</tt>, the response would return a username of the email address
|
185
|
+
owner as json.
|
186
|
+
|
187
|
+
If the state includes <tt>email == :missing</tt>, the response would be a message "email address not found" in json.
|
data/Rakefile
CHANGED
@@ -5,4 +5,4 @@ load File.join(File.dirname(__FILE__), "tasks", "features.rake")
|
|
5
5
|
load File.join(File.dirname(__FILE__), "tasks", "gem.rake")
|
6
6
|
load File.join(File.dirname(__FILE__), "tasks", "goliath.rake")
|
7
7
|
load File.join(File.dirname(__FILE__), "tasks", "rdoc.rake")
|
8
|
-
load File.join(File.dirname(__FILE__), "tasks", "spec.rake")
|
8
|
+
load File.join(File.dirname(__FILE__), "tasks", "spec.rake")
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'goliath/api'
|
2
|
+
require 'goliath/rack/templates'
|
3
|
+
require 'slim'
|
4
|
+
require 'sass'
|
5
|
+
require 'coffee_script'
|
6
|
+
|
7
|
+
module Holoserve::Interface::Control::Index
|
8
|
+
|
9
|
+
class Fetch < Goliath::API
|
10
|
+
include Goliath::Rack::Templates
|
11
|
+
include Holoserve::Interface::Control::Helper
|
12
|
+
|
13
|
+
def response(environment)
|
14
|
+
case environment["REQUEST_URI"]
|
15
|
+
when "/_control"
|
16
|
+
render_slim :index
|
17
|
+
when "/_control/stylesheets/screen.css"
|
18
|
+
render_scss :screen
|
19
|
+
when "/_control/javascripts/all.js"
|
20
|
+
render_coffee :all
|
21
|
+
else
|
22
|
+
not_found
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def render_slim(template)
|
29
|
+
ok slim(template, :views => File.join(Holoserve::Interface::ROOT, "views")), "text/html"
|
30
|
+
end
|
31
|
+
|
32
|
+
def render_scss(template)
|
33
|
+
ok scss(template, :views => File.join(Holoserve::Interface::ROOT, "stylesheets")), "text/css"
|
34
|
+
end
|
35
|
+
|
36
|
+
def render_coffee(template)
|
37
|
+
ok coffee(template, :views => File.join(Holoserve::Interface::ROOT, "javascripts")), "text/javascript"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -4,6 +4,7 @@ module Holoserve::Interface::Control
|
|
4
4
|
|
5
5
|
autoload :Bucket, File.join(File.dirname(__FILE__), "control", "bucket")
|
6
6
|
autoload :History, File.join(File.dirname(__FILE__), "control", "history")
|
7
|
+
autoload :Index, File.join(File.dirname(__FILE__), "control", "index")
|
7
8
|
autoload :Pair, File.join(File.dirname(__FILE__), "control", "pair")
|
8
9
|
autoload :State, File.join(File.dirname(__FILE__), "control", "state")
|
9
10
|
|
@@ -25,6 +26,10 @@ module Holoserve::Interface::Control
|
|
25
26
|
[ 400, { }, [ "bad request" ] ]
|
26
27
|
end
|
27
28
|
|
29
|
+
def not_found
|
30
|
+
[ 404, { }, [ "not found" ] ]
|
31
|
+
end
|
32
|
+
|
28
33
|
def bucket
|
29
34
|
config[:bucket] ||= [ ]
|
30
35
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class Holoserve::Interface::Event
|
4
|
+
|
5
|
+
def on_open(environment)
|
6
|
+
self.class.handler = environment["handler"]
|
7
|
+
end
|
8
|
+
|
9
|
+
def on_message(environment, message)
|
10
|
+
environment.logger.info "MESSAGE #{message}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_close(environment)
|
14
|
+
environment.logger.info("WS CLOSED")
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_error(environment, error)
|
18
|
+
environment.logger.error error
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.handler=(value)
|
22
|
+
@handler = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.send_pair_event(id)
|
26
|
+
send_message "pair:#{id}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.send_bucket_event(request)
|
30
|
+
send_message "bucket:#{JSON.dump(request)}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.send_message(text)
|
34
|
+
return unless @handler
|
35
|
+
@handler.send_text_frame text
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -3,43 +3,58 @@ require 'pp'
|
|
3
3
|
|
4
4
|
class Holoserve::Interface::Fake < Goliath::API
|
5
5
|
|
6
|
+
class NoResponseError < StandardError
|
7
|
+
|
8
|
+
attr_reader :id
|
9
|
+
attr_reader :request_variant
|
10
|
+
|
11
|
+
def initialize(id, request_variant)
|
12
|
+
@id, @request_variant = id, request_variant
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
6
17
|
use Goliath::Rack::Params
|
7
18
|
|
8
19
|
def response(env)
|
9
20
|
request = Holoserve::Request::Decomposer.new(env, params).hash
|
10
|
-
|
21
|
+
finder = Holoserve::Pair::Finder.new(pairs, request)
|
22
|
+
pair = finder.pair
|
11
23
|
if pair
|
12
|
-
id, responses =
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
24
|
+
id, request_variant, responses = finder.id, finder.variant, pair[:responses]
|
25
|
+
|
26
|
+
selector = Holoserve::Response::Selector.new responses, state.merge(:request_variant => request_variant), logger
|
27
|
+
response_variant = selector.selection
|
28
|
+
|
29
|
+
response = if response_variant == :default
|
30
|
+
responses[:default] || { }
|
31
|
+
elsif response_variant
|
32
|
+
Holoserve::Tool::Merger.new(responses[:default] || { }, responses[response_variant]).result
|
33
|
+
else
|
34
|
+
raise NoResponseError, id, request_variant
|
35
|
+
end
|
36
|
+
Holoserve::State::Updater.new(state, response[:transitions]).perform
|
37
|
+
history << {:id => id, :request_variant => request_variant, :response_variant => response_variant}
|
19
38
|
|
20
|
-
|
39
|
+
Holoserve::Interface::Event.send_pair_event id
|
40
|
+
logger.info "handled request [#{id}] with request variant [#{request_variant}] and response variant [#{response_variant}]"
|
21
41
|
|
22
|
-
response = Holoserve::Response::Combiner.new(default_response, selected_responses).response
|
23
42
|
Holoserve::Response::Composer.new(response).response_array
|
24
43
|
else
|
25
44
|
bucket << request
|
45
|
+
Holoserve::Interface::Event.send_bucket_event request
|
26
46
|
logger.error "received unhandled request\n" + request.pretty_inspect
|
27
47
|
|
28
48
|
not_found
|
29
49
|
end
|
50
|
+
rescue NoResponseError => error
|
51
|
+
logger.warn "could not select any response for request [#{error.id}] with request variant [#{error.request_variant}]"
|
30
52
|
end
|
31
53
|
|
32
54
|
private
|
33
55
|
|
34
|
-
def update_state(default_response, selected_responses)
|
35
|
-
Holoserve::State::Updater.new(state, default_response[:transitions]).perform
|
36
|
-
(selected_responses || [ ]).each do |response|
|
37
|
-
Holoserve::State::Updater.new(state, response[:transitions]).perform
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
56
|
def not_found
|
42
|
-
[ 404, { :"Content-Type" => "text/plain" }, [ "no response found for this request" ] ]
|
57
|
+
[ 404, { :"Content-Type" => "text/plain" }, [ "no response found for this request\n" ] ]
|
43
58
|
end
|
44
59
|
|
45
60
|
def bucket
|
data/lib/holoserve/interface.rb
CHANGED
@@ -3,8 +3,22 @@ require 'goliath/api'
|
|
3
3
|
class Holoserve::Interface < Goliath::API
|
4
4
|
|
5
5
|
autoload :Control, File.join(File.dirname(__FILE__), "interface", "control")
|
6
|
+
autoload :Event, File.join(File.dirname(__FILE__), "interface", "event")
|
6
7
|
autoload :Fake, File.join(File.dirname(__FILE__), "interface", "fake")
|
7
8
|
|
9
|
+
ROOT = File.expand_path(File.join(File.dirname(__FILE__), "..", "..")).freeze unless defined?(ROOT)
|
10
|
+
|
11
|
+
use Rack::Static,
|
12
|
+
:root => File.join(ROOT, "public"),
|
13
|
+
:urls => {
|
14
|
+
"/_control/favicon.ico" => "favicon.ico",
|
15
|
+
"/_control/javascripts/vendor/jquery-1.7.2.min.js" => "javascripts/vendor/jquery-1.7.2.min.js",
|
16
|
+
"/_control/javascripts/vendor/jquery.color.js" => "javascripts/vendor/jquery.color.js",
|
17
|
+
"/_control/javascripts/vendor/bootstrap-transition.js" => "javascripts/vendor/bootstrap-transition.js"
|
18
|
+
}
|
19
|
+
|
20
|
+
map "/_control/event", Event
|
21
|
+
|
8
22
|
get "/_control/bucket", Control::Bucket::Fetch
|
9
23
|
delete "/_control/bucket", Control::Bucket::Delete
|
10
24
|
|
@@ -18,6 +32,8 @@ class Holoserve::Interface < Goliath::API
|
|
18
32
|
get "/_control/state", Control::State::Fetch
|
19
33
|
delete "/_control/state", Control::State::Delete
|
20
34
|
|
35
|
+
get "/_control*", Control::Index::Fetch
|
36
|
+
|
21
37
|
map "/*", Fake
|
22
38
|
|
23
39
|
end
|
@@ -6,9 +6,31 @@ class Holoserve::Pair::Finder
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def pair
|
9
|
+
return @pair unless find_pair.nil?
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def id
|
14
|
+
return @id unless find_pair.nil?
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def variant
|
19
|
+
return @variant unless find_pair.nil?
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def find_pair
|
9
26
|
return nil unless @pairs
|
10
27
|
@pairs.each do |id, pair|
|
11
|
-
|
28
|
+
@variant = Holoserve::Request::Selector.new(@request, pair[:requests]).selection
|
29
|
+
unless @variant.nil?
|
30
|
+
@pair = pair
|
31
|
+
@id = id
|
32
|
+
return ""
|
33
|
+
end
|
12
34
|
end
|
13
35
|
nil
|
14
36
|
end
|
@@ -7,6 +7,9 @@ class Holoserve::Pair::Loader
|
|
7
7
|
@fixtures, @pairs = { }, { }
|
8
8
|
@fixture_file_pattern, @pair_file_pattern = fixture_file_pattern, pair_file_pattern
|
9
9
|
@logger = logger
|
10
|
+
@validator = Holoserve::Pair::Validator.new
|
11
|
+
rescue Holoserve::Pair::Validator::InvalidSchemaError => error
|
12
|
+
@logger.error error.inspect
|
10
13
|
end
|
11
14
|
|
12
15
|
def pairs
|
@@ -21,22 +24,33 @@ class Holoserve::Pair::Loader
|
|
21
24
|
Dir[ @fixture_file_pattern ].each do |filename|
|
22
25
|
id = extract_id filename
|
23
26
|
fixture = load_file filename
|
24
|
-
|
25
|
-
|
27
|
+
if fixture
|
28
|
+
@fixtures[id] = fixture
|
29
|
+
@logger.info "loaded fixture '#{id}'"
|
30
|
+
end
|
26
31
|
end
|
27
32
|
@fixtures.freeze
|
28
33
|
end
|
29
34
|
|
30
35
|
def load_pairs
|
31
36
|
Dir[ @pair_file_pattern ].each do |filename|
|
32
|
-
|
33
|
-
pair = load_file filename
|
34
|
-
@pairs[id] = pair_with_imports pair if pair
|
35
|
-
@logger.info "loaded pair '#{id}'"
|
37
|
+
load_pair filename
|
36
38
|
end
|
37
39
|
@pairs.freeze
|
38
40
|
end
|
39
41
|
|
42
|
+
def load_pair(filename)
|
43
|
+
id = extract_id filename
|
44
|
+
pair = load_file filename
|
45
|
+
if pair
|
46
|
+
@validator.validate(pair)
|
47
|
+
@pairs[id] = pair_with_imports pair
|
48
|
+
@logger.info "loaded pair '#{id}'"
|
49
|
+
end
|
50
|
+
rescue Holoserve::Pair::Validator::InvalidError => error
|
51
|
+
@logger.error error.inspect
|
52
|
+
end
|
53
|
+
|
40
54
|
def extract_id(filename)
|
41
55
|
File.basename filename, ".*"
|
42
56
|
end
|
@@ -52,18 +66,21 @@ class Holoserve::Pair::Loader
|
|
52
66
|
rescue JSON::ParserError
|
53
67
|
nil
|
54
68
|
end
|
55
|
-
|
69
|
+
end
|
56
70
|
Holoserve::Tool::Hash::KeySymbolizer.new(data).hash
|
57
71
|
end
|
58
72
|
|
59
73
|
def pair_with_imports(pair)
|
60
|
-
result = {
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
(pair[:responses] || { }).each do |id, response|
|
65
|
-
result[:responses][id] = Holoserve::Fixture::Importer.new(response, @fixtures).result
|
74
|
+
result = { :requests => { }, :responses => { } }
|
75
|
+
|
76
|
+
pair[:requests].each do |variant, request|
|
77
|
+
result[:requests][variant] = Holoserve::Fixture::Importer.new(request, @fixtures).result
|
66
78
|
end
|
79
|
+
|
80
|
+
pair[:responses].each do |variant, response|
|
81
|
+
result[:responses][variant] = Holoserve::Fixture::Importer.new(response, @fixtures).result
|
82
|
+
end
|
83
|
+
|
67
84
|
result
|
68
85
|
end
|
69
86
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'kwalify'
|
3
|
+
|
4
|
+
class Holoserve::Pair::Validator
|
5
|
+
|
6
|
+
class Error < StandardError
|
7
|
+
|
8
|
+
def initialize(errors)
|
9
|
+
@errors = errors
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"<#{self.class} error count = #{@errors.size}>"
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
"#{self.class}\n " + @errors.join("\n ")
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class InvalidError < Error; end
|
23
|
+
class InvalidSchemaError < Error; end
|
24
|
+
|
25
|
+
attr_accessor :schema_path
|
26
|
+
|
27
|
+
def initialize(schema_path = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "schema", "schema.yaml")))
|
28
|
+
@schema_path = schema_path
|
29
|
+
@meta_validator = Kwalify::MetaValidator.instance
|
30
|
+
load_schema
|
31
|
+
@validator = Kwalify::Validator.new(@schema)
|
32
|
+
end
|
33
|
+
|
34
|
+
def validate(hash)
|
35
|
+
errors = @validator.validate(hash)
|
36
|
+
raise InvalidError, errors if errors && !errors.empty?
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def load_schema
|
42
|
+
@schema = Kwalify::Yaml::load_file(@schema_path)
|
43
|
+
errors = @meta_validator.validate(@schema)
|
44
|
+
raise InvalidSchemaError, errors if errors && !errors.empty?
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/lib/holoserve/pair.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
class Holoserve::Request::Selector
|
3
|
+
|
4
|
+
attr_accessor :request
|
5
|
+
|
6
|
+
def initialize(request, request_subsets)
|
7
|
+
@request, @request_subsets = request, request_subsets
|
8
|
+
end
|
9
|
+
|
10
|
+
def selection
|
11
|
+
if Holoserve::Tool::Hash::Matcher.new(@request, @request_subsets[:default]).match?
|
12
|
+
@request_subsets.each do |variant, subset|
|
13
|
+
next if variant == :default
|
14
|
+
return variant if Holoserve::Tool::Hash::Matcher.new(@request, subset).match?
|
15
|
+
end
|
16
|
+
return :default
|
17
|
+
end
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/holoserve/request.rb
CHANGED
@@ -2,6 +2,6 @@
|
|
2
2
|
module Holoserve::Request
|
3
3
|
|
4
4
|
autoload :Decomposer, File.join(File.dirname(__FILE__), "request", "decomposer")
|
5
|
-
autoload :
|
5
|
+
autoload :Selector, File.join(File.dirname(__FILE__), "request", "selector")
|
6
6
|
|
7
7
|
end
|
@@ -24,26 +24,19 @@ class Holoserve::Response::Selector
|
|
24
24
|
@sandbox = Sandbox.new state, logger
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
@responses
|
29
|
-
|
30
|
-
{ }
|
31
|
-
end
|
32
|
-
|
33
|
-
def selected_responses
|
34
|
-
result = [ ]
|
35
|
-
(@responses || { }).each do |line, response|
|
36
|
-
next if line.to_s == "default"
|
27
|
+
def selection
|
28
|
+
@responses.each do |key, response|
|
29
|
+
next if key.to_sym == :default
|
37
30
|
begin
|
38
31
|
match = @sandbox.instance_eval do
|
39
|
-
eval
|
32
|
+
eval response[:condition]
|
40
33
|
end
|
41
|
-
|
34
|
+
return key.to_sym if match
|
42
35
|
rescue Object => error
|
43
36
|
@logger.error error.inspect
|
44
37
|
end
|
45
38
|
end
|
46
|
-
|
39
|
+
@responses.has_key?(:default) ? :default : nil
|
47
40
|
end
|
48
41
|
|
49
42
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
class Holoserve::Tool::Hash::Matcher
|
3
|
+
|
4
|
+
attr_accessor :hash
|
5
|
+
attr_accessor :subset
|
6
|
+
|
7
|
+
def initialize(hash, subset)
|
8
|
+
@hash, @subset = hash, subset
|
9
|
+
end
|
10
|
+
|
11
|
+
def match?
|
12
|
+
return false if @hash.length < @subset.length
|
13
|
+
@subset.each do |key, value|
|
14
|
+
if @hash.has_key?(key)
|
15
|
+
return false unless match_value?(@hash[key], value)
|
16
|
+
else
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def match_value?(value_one, value_two)
|
26
|
+
if value_one.is_a?(Hash) && value_two.is_a?(Hash)
|
27
|
+
return false unless match_hash?(value_one, value_two)
|
28
|
+
elsif value_one.is_a?(Array) && value_two.is_a?(Array)
|
29
|
+
return false unless match_array?(value_one, value_two)
|
30
|
+
else
|
31
|
+
return false unless value_one == value_two
|
32
|
+
end
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def match_hash?(hash, subset)
|
37
|
+
tmp = Holoserve::Tool::Hash::Matcher.new(hash, subset)
|
38
|
+
return false unless tmp.match?
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
def match_array?(array, subset)
|
43
|
+
return false if array.length < subset.length
|
44
|
+
subset.each_index do |i|
|
45
|
+
if subset[i].is_a?(Hash) && array[i].is_a?(Hash)
|
46
|
+
return false unless match_hash?(array[i], subset[i])
|
47
|
+
elsif subset[i].is_a?(Array) && array[i].is_a?(Array)
|
48
|
+
return false unless match_array?(array[i], subset[i])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
true
|
52
|
+
end
|
53
|
+
end
|
data/lib/holoserve/tool/hash.rb
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "helper"))
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
describe Holoserve::Pair::Validator do
|
5
|
+
|
6
|
+
let(:valid_schema_path) do
|
7
|
+
File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "..", "schema", "schema.yaml"))
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:invalid_schema_path) do
|
11
|
+
File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "..", "features", "pairs", "invalid", "test_invalid_schema.yaml"))
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:valid_hash) do
|
15
|
+
file = YAML::load_file(File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "..", "features", "pairs", "test_evaluation.yaml")))
|
16
|
+
Holoserve::Tool::Hash::KeySymbolizer.new(file).hash
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:invalid_hash) do
|
20
|
+
file = YAML::load_file(File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "..", "features", "pairs", "invalid", "test_invalid_headers.yaml")))
|
21
|
+
Holoserve::Tool::Hash::KeySymbolizer.new(file).hash
|
22
|
+
end
|
23
|
+
|
24
|
+
subject { described_class.new valid_schema_path }
|
25
|
+
|
26
|
+
describe "#initialize" do
|
27
|
+
|
28
|
+
it "should raise an InvalidSchemaError if the schema file is invalid" do
|
29
|
+
lambda do
|
30
|
+
described_class.new invalid_schema_path
|
31
|
+
end.should raise_error(described_class::InvalidSchemaError)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#validate" do
|
37
|
+
|
38
|
+
it "should return true if a valid pair file is provided" do
|
39
|
+
lambda do
|
40
|
+
subject.validate(valid_hash)
|
41
|
+
end.should_not raise_error
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return false if an invalid pair file is provided" do
|
45
|
+
lambda do
|
46
|
+
subject.validate(invalid_hash)
|
47
|
+
end.should raise_error(described_class::InvalidError)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "helper"))
|
2
|
+
|
3
|
+
describe Holoserve::Request::Selector do
|
4
|
+
|
5
|
+
let(:subsets) do
|
6
|
+
{
|
7
|
+
:default => {
|
8
|
+
:method => "GET",
|
9
|
+
:path => "/test"
|
10
|
+
},
|
11
|
+
:test => {
|
12
|
+
:headers => {
|
13
|
+
:HTTP_TEST => "value"
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:variant_matching_request) do
|
20
|
+
{
|
21
|
+
:method => "GET",
|
22
|
+
:path => "/test",
|
23
|
+
:headers => {
|
24
|
+
:HTTP_TEST => "value",
|
25
|
+
:HTTP_HOST => "localhost"
|
26
|
+
}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:invalid_request) do
|
31
|
+
{
|
32
|
+
:method => "POST",
|
33
|
+
:other_test => {
|
34
|
+
:key => "value"
|
35
|
+
}
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:default_matching_request) do
|
40
|
+
{
|
41
|
+
:method => "GET",
|
42
|
+
:path => "/test",
|
43
|
+
:parameters => {
|
44
|
+
:test => "value"
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
subject { described_class.new invalid_request, subsets }
|
50
|
+
|
51
|
+
describe "#selection" do
|
52
|
+
|
53
|
+
it "should return nil if request is not matching default nor any other subset" do
|
54
|
+
subject.selection.should be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return :default if the default subset is matched" do
|
58
|
+
subject.request = default_matching_request
|
59
|
+
subject.selection.should == :default
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return :test if the corresponding subset is matched" do
|
63
|
+
subject.request = variant_matching_request
|
64
|
+
subject.selection.should == :test
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require File.expand_path("../../../../helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Holoserve::Tool::Hash::Matcher do
|
4
|
+
|
5
|
+
let(:hash) do
|
6
|
+
{
|
7
|
+
:test => "value",
|
8
|
+
:nested => {
|
9
|
+
:unspecified => "value",
|
10
|
+
:another => "test value"
|
11
|
+
},
|
12
|
+
:unspecified => "value",
|
13
|
+
:nested_array => [{:hash => "value", :unspecified => "value", :morehash => {:test => "value", :unspecified => "value", :array => [{:test => "value"}]}}]
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:matching_subset) do
|
18
|
+
{
|
19
|
+
:test => "value"
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:matching_subset_with_nested_hash) do
|
24
|
+
{
|
25
|
+
:nested => {
|
26
|
+
:another => "test value"
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:matching_subset_with_nested_array) do
|
32
|
+
{
|
33
|
+
:nested_array => [{:hash => "value"}]
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
let(:matching_subset_with_nested_array_and_nested_hash) do
|
38
|
+
{
|
39
|
+
:nested_array => [{:hash => "value", :morehash => {:test => "value"}}]
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
let(:matching_subset_with_nested_array_and_nested_hash_and_nested_array) do
|
44
|
+
{
|
45
|
+
:nested_array => [{:hash => "value", :morehash => {:test => "value", :array => [{:test => "value"}]}}]
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
let(:mismatching_subset) do
|
50
|
+
{
|
51
|
+
:test => "another value"
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
let(:mismatching_subset_with_nested_hash) do
|
56
|
+
{
|
57
|
+
:nested => {
|
58
|
+
:another => "another value"
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
let(:mismatching_subset_with_nested_array) do
|
64
|
+
{
|
65
|
+
:nested_array => [{:hash => "other value"}]
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
let(:mismatching_subset_with_nested_array_and_nested_hash) do
|
70
|
+
{
|
71
|
+
:nested_array => [{:hash => "value", :morehash => {:test => "other value"}}]
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
let(:mismatching_subset_with_nested_array_and_nested_hash_and_nested_array) do
|
76
|
+
{
|
77
|
+
:nested_array => [{:hash => "value", :morehash => {:test => "value", :array => [{:test => "other value"}]}}]
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
subject { described_class.new hash, matching_subset }
|
82
|
+
|
83
|
+
describe "#match?" do
|
84
|
+
|
85
|
+
it "should return true if a matching subset is provided" do
|
86
|
+
subject.match?.should be_true
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return false if a mismatching subset is provided" do
|
90
|
+
subject.subset = mismatching_subset
|
91
|
+
subject.match?.should be_false
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should return true if a matching subset with nested hash is provided" do
|
95
|
+
subject.subset = matching_subset_with_nested_hash
|
96
|
+
subject.match?.should be_true
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should return false if a mismatching subset with nested hash is provided" do
|
100
|
+
subject.subset = mismatching_subset_with_nested_hash
|
101
|
+
subject.match?.should be_false
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should return true if a matching subset with nested array is provided" do
|
105
|
+
subject.subset = matching_subset_with_nested_array
|
106
|
+
subject.match?.should be_true
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should return false if a mismatching subset with nested array is provided" do
|
110
|
+
subject.subset = mismatching_subset_with_nested_array
|
111
|
+
subject.match?.should be_false
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should return true if a matching subset with nested array and nested hash is provided" do
|
115
|
+
subject.subset = matching_subset_with_nested_array_and_nested_hash
|
116
|
+
subject.match?.should be_true
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should return false if a mismatching subset with nested array and nested hash is provided" do
|
120
|
+
subject.subset = mismatching_subset_with_nested_array_and_nested_hash
|
121
|
+
subject.match?.should be_false
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should return true if a matching subset with nested array and nested hash and nested array is provided" do
|
125
|
+
subject.subset = matching_subset_with_nested_array_and_nested_hash_and_nested_array
|
126
|
+
subject.match?.should be_true
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should return false if a mismatching subset with nested array and nested hash and nested array is provided" do
|
130
|
+
subject.subset = mismatching_subset_with_nested_array_and_nested_hash_and_nested_array
|
131
|
+
subject.match?.should be_false
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
metadata
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: holoserve
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Philipp Brüll
|
9
|
+
- Maximilian Hoffmann
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2012-
|
13
|
+
date: 2012-06-22 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: goliath
|
16
|
-
requirement: &
|
17
|
+
requirement: &70242257528700 !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
20
|
- - ! '>='
|
@@ -21,10 +22,54 @@ dependencies:
|
|
21
22
|
version: '0'
|
22
23
|
type: :runtime
|
23
24
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
+
version_requirements: *70242257528700
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: slim
|
28
|
+
requirement: &70242257527940 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *70242257527940
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: sass
|
39
|
+
requirement: &70242257526740 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *70242257526740
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: coffee-script
|
50
|
+
requirement: &70242257526220 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *70242257526220
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: kwalify
|
61
|
+
requirement: &70242257525580 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
type: :runtime
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *70242257525580
|
25
70
|
- !ruby/object:Gem::Dependency
|
26
71
|
name: rake
|
27
|
-
requirement: &
|
72
|
+
requirement: &70242257523600 !ruby/object:Gem::Requirement
|
28
73
|
none: false
|
29
74
|
requirements:
|
30
75
|
- - ! '>='
|
@@ -32,10 +77,10 @@ dependencies:
|
|
32
77
|
version: '0'
|
33
78
|
type: :development
|
34
79
|
prerelease: false
|
35
|
-
version_requirements: *
|
80
|
+
version_requirements: *70242257523600
|
36
81
|
- !ruby/object:Gem::Dependency
|
37
82
|
name: rdoc
|
38
|
-
requirement: &
|
83
|
+
requirement: &70242257522300 !ruby/object:Gem::Requirement
|
39
84
|
none: false
|
40
85
|
requirements:
|
41
86
|
- - ! '>='
|
@@ -43,10 +88,10 @@ dependencies:
|
|
43
88
|
version: '0'
|
44
89
|
type: :development
|
45
90
|
prerelease: false
|
46
|
-
version_requirements: *
|
91
|
+
version_requirements: *70242257522300
|
47
92
|
- !ruby/object:Gem::Dependency
|
48
93
|
name: cucumber
|
49
|
-
requirement: &
|
94
|
+
requirement: &70242257537280 !ruby/object:Gem::Requirement
|
50
95
|
none: false
|
51
96
|
requirements:
|
52
97
|
- - ! '>='
|
@@ -54,10 +99,10 @@ dependencies:
|
|
54
99
|
version: '0'
|
55
100
|
type: :development
|
56
101
|
prerelease: false
|
57
|
-
version_requirements: *
|
102
|
+
version_requirements: *70242257537280
|
58
103
|
- !ruby/object:Gem::Dependency
|
59
104
|
name: rspec
|
60
|
-
requirement: &
|
105
|
+
requirement: &70242257536160 !ruby/object:Gem::Requirement
|
61
106
|
none: false
|
62
107
|
requirements:
|
63
108
|
- - ! '>='
|
@@ -65,10 +110,10 @@ dependencies:
|
|
65
110
|
version: '0'
|
66
111
|
type: :development
|
67
112
|
prerelease: false
|
68
|
-
version_requirements: *
|
113
|
+
version_requirements: *70242257536160
|
69
114
|
- !ruby/object:Gem::Dependency
|
70
115
|
name: transport
|
71
|
-
requirement: &
|
116
|
+
requirement: &70242257535520 !ruby/object:Gem::Requirement
|
72
117
|
none: false
|
73
118
|
requirements:
|
74
119
|
- - ! '>='
|
@@ -76,10 +121,10 @@ dependencies:
|
|
76
121
|
version: '0'
|
77
122
|
type: :development
|
78
123
|
prerelease: false
|
79
|
-
version_requirements: *
|
124
|
+
version_requirements: *70242257535520
|
80
125
|
- !ruby/object:Gem::Dependency
|
81
126
|
name: oauth
|
82
|
-
requirement: &
|
127
|
+
requirement: &70242257534980 !ruby/object:Gem::Requirement
|
83
128
|
none: false
|
84
129
|
requirements:
|
85
130
|
- - ! '>='
|
@@ -87,7 +132,7 @@ dependencies:
|
|
87
132
|
version: '0'
|
88
133
|
type: :development
|
89
134
|
prerelease: false
|
90
|
-
version_requirements: *
|
135
|
+
version_requirements: *70242257534980
|
91
136
|
description: This tool can be used to fake webservice APIs for testing proposals.
|
92
137
|
email: philipp.bruell@skrill.com
|
93
138
|
executables:
|
@@ -105,16 +150,19 @@ files:
|
|
105
150
|
- lib/holoserve/fixture.rb
|
106
151
|
- lib/holoserve/interface/control/bucket.rb
|
107
152
|
- lib/holoserve/interface/control/history.rb
|
153
|
+
- lib/holoserve/interface/control/index.rb
|
108
154
|
- lib/holoserve/interface/control/pair.rb
|
109
155
|
- lib/holoserve/interface/control/state.rb
|
110
156
|
- lib/holoserve/interface/control.rb
|
157
|
+
- lib/holoserve/interface/event.rb
|
111
158
|
- lib/holoserve/interface/fake.rb
|
112
159
|
- lib/holoserve/interface.rb
|
113
160
|
- lib/holoserve/pair/finder.rb
|
114
161
|
- lib/holoserve/pair/loader.rb
|
162
|
+
- lib/holoserve/pair/validator.rb
|
115
163
|
- lib/holoserve/pair.rb
|
116
164
|
- lib/holoserve/request/decomposer.rb
|
117
|
-
- lib/holoserve/request/
|
165
|
+
- lib/holoserve/request/selector.rb
|
118
166
|
- lib/holoserve/request.rb
|
119
167
|
- lib/holoserve/response/combiner.rb
|
120
168
|
- lib/holoserve/response/composer.rb
|
@@ -124,6 +172,7 @@ files:
|
|
124
172
|
- lib/holoserve/state.rb
|
125
173
|
- lib/holoserve/tool/data_path.rb
|
126
174
|
- lib/holoserve/tool/hash/key_symbolizer.rb
|
175
|
+
- lib/holoserve/tool/hash/matcher.rb
|
127
176
|
- lib/holoserve/tool/hash.rb
|
128
177
|
- lib/holoserve/tool/merger.rb
|
129
178
|
- lib/holoserve/tool/uploader.rb
|
@@ -131,7 +180,10 @@ files:
|
|
131
180
|
- lib/holoserve.rb
|
132
181
|
- spec/helper.rb
|
133
182
|
- spec/lib/holoserve/fixture/importer_spec.rb
|
183
|
+
- spec/lib/holoserve/pair/validator_spec.rb
|
184
|
+
- spec/lib/holoserve/request/selector_spec.rb
|
134
185
|
- spec/lib/holoserve/tool/data_path_spec.rb
|
186
|
+
- spec/lib/holoserve/tool/hash/matcher_spec.rb
|
135
187
|
- spec/lib/holoserve/tool/merger_spec.rb
|
136
188
|
- spec/lib/holoserve_spec.rb
|
137
189
|
homepage: http://github.com/skrill/holoserve
|
@@ -148,7 +200,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
148
200
|
version: '0'
|
149
201
|
segments:
|
150
202
|
- 0
|
151
|
-
hash:
|
203
|
+
hash: 3487198030302980531
|
152
204
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
205
|
none: false
|
154
206
|
requirements:
|
@@ -163,6 +215,9 @@ specification_version: 3
|
|
163
215
|
summary: Tool to fake HTTP APIs.
|
164
216
|
test_files:
|
165
217
|
- spec/lib/holoserve/fixture/importer_spec.rb
|
218
|
+
- spec/lib/holoserve/pair/validator_spec.rb
|
219
|
+
- spec/lib/holoserve/request/selector_spec.rb
|
166
220
|
- spec/lib/holoserve/tool/data_path_spec.rb
|
221
|
+
- spec/lib/holoserve/tool/hash/matcher_spec.rb
|
167
222
|
- spec/lib/holoserve/tool/merger_spec.rb
|
168
223
|
- spec/lib/holoserve_spec.rb
|
@@ -1,74 +0,0 @@
|
|
1
|
-
|
2
|
-
class Holoserve::Request::Matcher
|
3
|
-
|
4
|
-
def initialize(request, request_subset)
|
5
|
-
@request, @request_subset = request, request_subset
|
6
|
-
end
|
7
|
-
|
8
|
-
def match?
|
9
|
-
match_method? &&
|
10
|
-
match_path? &&
|
11
|
-
match_headers? &&
|
12
|
-
match_body? &&
|
13
|
-
match_parameters? &&
|
14
|
-
match_oauth? &&
|
15
|
-
match_json?
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def match_method?
|
21
|
-
@request_subset[:method] ?
|
22
|
-
@request[:method] == @request_subset[:method] :
|
23
|
-
true
|
24
|
-
end
|
25
|
-
|
26
|
-
def match_path?
|
27
|
-
@request_subset[:path] ?
|
28
|
-
@request[:path] == @request_subset[:path] :
|
29
|
-
true
|
30
|
-
end
|
31
|
-
|
32
|
-
def match_headers?
|
33
|
-
match = true
|
34
|
-
(@request_subset[:headers] || { }).each do |key, value|
|
35
|
-
match &&= @request[:headers][key] == value
|
36
|
-
end
|
37
|
-
match
|
38
|
-
end
|
39
|
-
|
40
|
-
def match_body?
|
41
|
-
@request_subset[:body] ?
|
42
|
-
@request[:body] == @request_subset[:body] :
|
43
|
-
true
|
44
|
-
end
|
45
|
-
|
46
|
-
def match_parameters?
|
47
|
-
match = true
|
48
|
-
(@request_subset[:parameters] || { }).each do |key, value|
|
49
|
-
match &&= @request[:parameters].is_a?(Hash) && (@request[:parameters][key] == value)
|
50
|
-
end
|
51
|
-
match
|
52
|
-
end
|
53
|
-
|
54
|
-
def match_oauth?
|
55
|
-
match = true
|
56
|
-
(@request_subset[:oauth] || { }).each do |key, value|
|
57
|
-
match &&= @request[:oauth].is_a?(Hash) && (@request[:oauth][key] == value)
|
58
|
-
end
|
59
|
-
match
|
60
|
-
end
|
61
|
-
|
62
|
-
def match_json?
|
63
|
-
match_hash? :json
|
64
|
-
end
|
65
|
-
|
66
|
-
def match_hash?(hash_key)
|
67
|
-
match = true
|
68
|
-
(@request_subset[hash_key] || { }).each do |key, value|
|
69
|
-
match &&= @request[hash_key].is_a?(Hash) && (@request[hash_key][key] == value)
|
70
|
-
end
|
71
|
-
match
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|