holoserve 0.2.1 → 0.3.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.
- data/README.rdoc +85 -56
- data/bin/holoserve +5 -2
- data/lib/holoserve/fixture/importer.rb +44 -0
- data/lib/holoserve/fixture.rb +6 -0
- data/lib/holoserve/interface/control.rb +84 -33
- data/lib/holoserve/interface/fake.rb +8 -15
- data/lib/holoserve/pair/finder.rb +10 -5
- data/lib/holoserve/request/matcher.rb +4 -3
- data/lib/holoserve/response/combiner.rb +34 -0
- data/lib/holoserve/response.rb +1 -0
- data/lib/holoserve/runner.rb +19 -10
- data/lib/holoserve/tool/data_path.rb +56 -0
- data/lib/holoserve/tool/uploader.rb +9 -5
- data/lib/holoserve/tool.rb +1 -0
- data/lib/holoserve.rb +8 -16
- data/spec/lib/holoserve/fixture/importer_spec.rb +79 -0
- data/spec/lib/holoserve/tool/data_path_spec.rb +75 -0
- metadata +27 -22
- data/lib/holoserve/bucket.rb +0 -10
- data/lib/holoserve/configuration.rb +0 -50
- data/lib/holoserve/history.rb +0 -14
data/README.rdoc
CHANGED
|
@@ -6,14 +6,18 @@ run faster and be independent from other API and network problems.
|
|
|
6
6
|
|
|
7
7
|
== Concept
|
|
8
8
|
|
|
9
|
-
HoloServe runs a rack application server, that matches any incoming request to a list of request profiles
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
The
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
HoloServe runs a rack application server, that matches any incoming request to a list of request profiles. These
|
|
10
|
+
profiles are defined in set of request/response-pairs. If a match is found, the defined static response is returned. The
|
|
11
|
+
other half of the matched profile contains a set of responses. One for each situation the faked API can be possibily in.
|
|
12
|
+
The response for the currently set situation will be merged with a default response and returned. The name of the
|
|
13
|
+
matched request/response pair is saved in a request history. If no match is found, a 404 is returned and the request
|
|
14
|
+
data is stored in the bucket for unhandeled requests. These informations can be used to extend the server layout with
|
|
15
|
+
missing request handlers.
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
To avoid too much duplication in the definition of the request/response-pairs, it is possible upload some fixture data
|
|
18
|
+
that is shared between all pair definitions. The pair can than refer to these fixtures.
|
|
19
|
+
|
|
20
|
+
The pairs, fixtures, situation, history and bucket can be accessed via control routes, which are described below.
|
|
17
21
|
|
|
18
22
|
== Installation
|
|
19
23
|
|
|
@@ -27,48 +31,58 @@ To start up an empty Holoserve instance, type...
|
|
|
27
31
|
|
|
28
32
|
holoserve
|
|
29
33
|
|
|
30
|
-
To load
|
|
34
|
+
To load the server with a couple of pairs, fixtures and define a situation during start up, use these parameters.
|
|
31
35
|
|
|
32
|
-
holoserve -
|
|
36
|
+
holoserve -d path/to/pairs/*.yaml -f path/to/fixtures/*.yaml -s backend_without_users
|
|
33
37
|
|
|
34
|
-
Notice, that the
|
|
38
|
+
Notice, that the files must have either the <tt>.yaml</tt> or the <tt>.json</tt> extension.
|
|
35
39
|
|
|
36
40
|
== Control routes
|
|
37
41
|
|
|
38
42
|
If you're using Ruby, you can control Holoserve via the
|
|
39
43
|
{Holoserve Connector}[https://github.com/skrill/holoserve-connector] gem.
|
|
40
44
|
|
|
41
|
-
=== POST /_control/
|
|
45
|
+
=== POST /_control/pairs
|
|
42
46
|
|
|
43
|
-
It should receive a parameter named <tt>file</tt> that contains a file with
|
|
44
|
-
should fit the specified format. The format can be <tt>yaml</tt> or <tt>json</tt>. See
|
|
45
|
-
{
|
|
47
|
+
Adds a pair definition to Holoserve. It should receive a parameter named <tt>file</tt> that contains a file with exactly
|
|
48
|
+
one pair. The format of the file should fit the specified format. The format can be <tt>yaml</tt> or <tt>json</tt>. See
|
|
49
|
+
{Pair file format}[rdoc-label:Pair-file-format] below. The basename of the transmitted file will be taken as the pair
|
|
50
|
+
id.
|
|
46
51
|
|
|
47
|
-
=== GET /_control/
|
|
52
|
+
=== GET /_control/pairs/:id.:format
|
|
48
53
|
|
|
49
|
-
Returns the
|
|
54
|
+
Returns the pair definition in the requested format.
|
|
50
55
|
|
|
51
|
-
=== DELETE /_control/
|
|
56
|
+
=== DELETE /_control/pairs
|
|
52
57
|
|
|
53
|
-
Removes
|
|
58
|
+
Removes all pairs.
|
|
54
59
|
|
|
55
|
-
===
|
|
60
|
+
=== POST /_control/fixtures
|
|
56
61
|
|
|
57
|
-
|
|
62
|
+
Adds fixture data to Holoserve. The request is similar to <tt>POST /_control/pairs</tt>. The upload file can contain any
|
|
63
|
+
yaml or json formatted data. The basename of the file will be taken as the fixture id.
|
|
58
64
|
|
|
59
|
-
=== GET /_control/
|
|
65
|
+
=== GET /_control/fixtures/:id
|
|
60
66
|
|
|
61
|
-
Returns the
|
|
67
|
+
Returns the requested fixture.
|
|
68
|
+
|
|
69
|
+
=== DELETE /_control/fixtures
|
|
70
|
+
|
|
71
|
+
Removes all fixtures.
|
|
62
72
|
|
|
63
|
-
===
|
|
73
|
+
=== PUT /_control/situation
|
|
64
74
|
|
|
65
|
-
|
|
75
|
+
Sets the current situation with the transmitted <tt>name</tt> parameter.
|
|
76
|
+
|
|
77
|
+
=== GET /_control/situation
|
|
78
|
+
|
|
79
|
+
Returns the name of the current situation.
|
|
66
80
|
|
|
67
81
|
==== Response example
|
|
68
82
|
|
|
69
83
|
backend_without_users
|
|
70
84
|
|
|
71
|
-
=== GET /_control/bucket
|
|
85
|
+
=== GET /_control/bucket
|
|
72
86
|
|
|
73
87
|
Returns a list of all requests that has been received, but couldn't be handled.
|
|
74
88
|
|
|
@@ -110,50 +124,65 @@ Returns a list of all names of pairs that has been triggered.
|
|
|
110
124
|
|
|
111
125
|
Removes all entries from the history.
|
|
112
126
|
|
|
113
|
-
==
|
|
127
|
+
== Pair file format
|
|
114
128
|
|
|
115
|
-
The
|
|
129
|
+
The request/response pair file should have the following format.
|
|
116
130
|
|
|
117
|
-
-
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
- request:
|
|
132
|
+
imports:
|
|
133
|
+
- path: "test_fixture.users.0"
|
|
134
|
+
as: "parameters"
|
|
135
|
+
only: [ "username", "password" ]
|
|
120
136
|
method: "POST"
|
|
121
|
-
path: "/
|
|
137
|
+
path: "/session"
|
|
122
138
|
headers:
|
|
123
139
|
HTTP_USER_AGENT: "Ruby"
|
|
124
|
-
HTTP_AUTHORIZATION: "OAuth oauth_token=12345"
|
|
125
|
-
body:
|
|
126
|
-
"test=value"
|
|
127
|
-
parameters:
|
|
128
|
-
test: "value"
|
|
129
140
|
oauth:
|
|
130
141
|
oauth_token: "12345"
|
|
131
142
|
responses:
|
|
132
143
|
default:
|
|
133
144
|
status: 200
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
"
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
user_exists:
|
|
146
|
+
imports:
|
|
147
|
+
- path: "test_fixture.users.0"
|
|
148
|
+
as: "json.user"
|
|
149
|
+
user_is_missing:
|
|
150
|
+
json:
|
|
151
|
+
message: "user not found"
|
|
152
|
+
- request:
|
|
153
|
+
imports:
|
|
154
|
+
- path: "test_fixture.users.0"
|
|
155
|
+
as: "parameters"
|
|
156
|
+
only: "username"
|
|
157
|
+
method: "POST"
|
|
158
|
+
path: "/session"
|
|
159
|
+
headers:
|
|
160
|
+
HTTP_USER_AGENT: "Ruby"
|
|
161
|
+
parameters:
|
|
162
|
+
password: "invalid"
|
|
163
|
+
oauth:
|
|
164
|
+
oauth_token: "12345"
|
|
141
165
|
responses:
|
|
142
|
-
|
|
166
|
+
user_exists:
|
|
167
|
+
status: 401
|
|
168
|
+
json:
|
|
169
|
+
message: "invalid password"
|
|
170
|
+
user_is_missing:
|
|
143
171
|
status: 200
|
|
144
|
-
|
|
145
|
-
"
|
|
172
|
+
json:
|
|
173
|
+
message: "user not found"
|
|
146
174
|
|
|
147
|
-
|
|
148
|
-
<tt>test_received</tt> and would match a <tt>POST</tt> request to the path <tt>/test</tt>.
|
|
175
|
+
The fixture data where this example pair definition relies on, could look like to following.
|
|
149
176
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
177
|
+
users:
|
|
178
|
+
- email: "one@test.com"
|
|
179
|
+
username: "one"
|
|
180
|
+
password: "valid"
|
|
153
181
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
182
|
+
This example defines two request/response pairs and two situations. The two pairs differs only the parameters that they
|
|
183
|
+
match against. The first one handles the case in which the parameters <tt>username=one</tt> and <tt>password=valid</tt>
|
|
184
|
+
are posted and the second one reacts on the transmission of <tt>username=one</tt> and <tt>password=invalid</tt>.
|
|
157
185
|
|
|
158
|
-
|
|
159
|
-
|
|
186
|
+
If the situation is set to <tt>user_exists</tt>, the first situation would return the complete user object encoded as
|
|
187
|
+
json, while the second one would reply the message "invalid password". In the situation "user_is_missing", both requests
|
|
188
|
+
would be replied with the message "user not found".
|
data/bin/holoserve
CHANGED
|
@@ -14,8 +14,11 @@ OptionParser.new do |parser|
|
|
|
14
14
|
parser.on("-p", "--port PORT", Integer, "The port holoserve should listen to.") do |value|
|
|
15
15
|
options[:port] = value
|
|
16
16
|
end
|
|
17
|
-
parser.on("-
|
|
18
|
-
options[:
|
|
17
|
+
parser.on("-f", "--fixture-files PATTERN", "Load the specified fixture files on startup.") do |value|
|
|
18
|
+
options[:fixture_file_pattern] = value
|
|
19
|
+
end
|
|
20
|
+
parser.on("-d", "--pair-files PATTERN", "Load the specified pair files on startup.") do |value|
|
|
21
|
+
options[:pair_file_pattern] = value
|
|
19
22
|
end
|
|
20
23
|
parser.on("-s", "--situation SITUATION", "Sets the situation.") do |value|
|
|
21
24
|
options[:situation] = value
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
|
|
2
|
+
class Holoserve::Fixture::Importer
|
|
3
|
+
|
|
4
|
+
attr_accessor :fixtures
|
|
5
|
+
|
|
6
|
+
def initialize(hash, fixtures)
|
|
7
|
+
@fixtures = fixtures
|
|
8
|
+
self.hash = hash
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def hash=(value)
|
|
12
|
+
@imports = value.respond_to?(:delete) && value.delete(:imports) || [ ]
|
|
13
|
+
@hash = value
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def hash
|
|
17
|
+
import
|
|
18
|
+
merge
|
|
19
|
+
@result
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def import
|
|
25
|
+
@imports.each do |import|
|
|
26
|
+
path = import[:path]
|
|
27
|
+
as = import[:as] || path
|
|
28
|
+
only = import[:only]
|
|
29
|
+
|
|
30
|
+
value = Holoserve::Tool::DataPath.new(path, @fixtures).fetch
|
|
31
|
+
|
|
32
|
+
value.delete_if do |key, v|
|
|
33
|
+
![ only ].flatten.compact.include?(key.to_s)
|
|
34
|
+
end if only.respond_to?(:include?) && value.respond_to?(:delete_if)
|
|
35
|
+
|
|
36
|
+
@result = Holoserve::Tool::DataPath.new(as, @result || { }).store value
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def merge
|
|
41
|
+
@result = Holoserve::Tool::Merger.new(@result, @hash).result if @hash
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
@@ -7,60 +7,67 @@ class Holoserve::Interface::Control < Sinatra::Base
|
|
|
7
7
|
mime_type :yaml, "application/x-yaml"
|
|
8
8
|
mime_type :json, "application/json"
|
|
9
9
|
|
|
10
|
-
post "/_control/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
error 400, error.inspect
|
|
10
|
+
post "/_control/pairs" do
|
|
11
|
+
load_file_into(pairs) ?
|
|
12
|
+
acknowledgement :
|
|
13
|
+
bad_request
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
get "/_control/pairs/:id.:format" do |id, format|
|
|
17
|
+
pair = pairs[id.to_sym]
|
|
18
|
+
if pair
|
|
19
|
+
respond_formatted pair, format
|
|
20
|
+
else
|
|
21
|
+
not_found
|
|
23
22
|
end
|
|
24
23
|
end
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
delete "/_control/pairs" do
|
|
26
|
+
pairs.clear
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
post "/_control/fixtures" do
|
|
30
|
+
load_file_into(fixtures) ?
|
|
31
|
+
acknowledgement :
|
|
32
|
+
bad_request
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
get "/_control/fixtures/:id.:format" do |id, format|
|
|
36
|
+
fixture = fixtures[id.to_sym]
|
|
37
|
+
if fixture
|
|
38
|
+
respond_formatted fixture, format
|
|
31
39
|
else
|
|
32
|
-
|
|
40
|
+
not_found
|
|
33
41
|
end
|
|
34
42
|
end
|
|
35
43
|
|
|
36
|
-
delete "/_control/
|
|
37
|
-
|
|
38
|
-
respond_json_acknowledgement
|
|
44
|
+
delete "/_control/fixtures" do
|
|
45
|
+
fixtures.clear
|
|
39
46
|
end
|
|
40
47
|
|
|
41
|
-
put "/_control/situation
|
|
42
|
-
configuration
|
|
48
|
+
put "/_control/situation" do
|
|
49
|
+
configuration[:situation] = params[:name]
|
|
43
50
|
respond_json_acknowledgement
|
|
44
51
|
end
|
|
45
52
|
|
|
46
53
|
get "/_control/situation" do
|
|
47
|
-
configuration
|
|
54
|
+
respond_json :name => configuration[:situation]
|
|
48
55
|
end
|
|
49
56
|
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
get "/_control/bucket" do
|
|
58
|
+
respond_json bucket
|
|
52
59
|
end
|
|
53
60
|
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
delete "/_control/bucket" do
|
|
62
|
+
bucket.clear
|
|
56
63
|
end
|
|
57
64
|
|
|
58
65
|
get "/_control/history" do
|
|
59
|
-
respond_json history
|
|
66
|
+
respond_json history
|
|
60
67
|
end
|
|
61
68
|
|
|
62
69
|
delete "/_control/history" do
|
|
63
|
-
history.clear
|
|
70
|
+
history.clear
|
|
64
71
|
respond_json_acknowledgement
|
|
65
72
|
end
|
|
66
73
|
|
|
@@ -70,6 +77,16 @@ class Holoserve::Interface::Control < Sinatra::Base
|
|
|
70
77
|
respond_json :ok => true
|
|
71
78
|
end
|
|
72
79
|
|
|
80
|
+
def respond_formatted(data, format)
|
|
81
|
+
if format == "yaml"
|
|
82
|
+
respond_yaml data
|
|
83
|
+
elsif format == "json"
|
|
84
|
+
respond_json data
|
|
85
|
+
else
|
|
86
|
+
bad_request
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
73
90
|
def respond_json(object)
|
|
74
91
|
content_type :json
|
|
75
92
|
JSON.dump object
|
|
@@ -80,16 +97,50 @@ class Holoserve::Interface::Control < Sinatra::Base
|
|
|
80
97
|
object.to_yaml
|
|
81
98
|
end
|
|
82
99
|
|
|
100
|
+
def acknowledgement
|
|
101
|
+
[ 200, { }, [ "" ] ]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def bad_request
|
|
105
|
+
[ 400, { }, [ "bad request" ] ]
|
|
106
|
+
end
|
|
107
|
+
|
|
83
108
|
def not_acceptable
|
|
84
109
|
[ 406, { }, [ "format not acceptable" ] ]
|
|
85
110
|
end
|
|
86
111
|
|
|
112
|
+
def load_file_into(hash)
|
|
113
|
+
data = load_file params["file"][:tempfile]
|
|
114
|
+
return false unless data
|
|
115
|
+
id = File.basename params["file"][:filename], ".*"
|
|
116
|
+
hash[id.to_sym] = Holoserve::Tool::Hash::KeySymbolizer.new(data).hash
|
|
117
|
+
true
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def load_file(filename)
|
|
121
|
+
YAML::load_file filename
|
|
122
|
+
rescue Psych::SyntaxError
|
|
123
|
+
begin
|
|
124
|
+
JSON.parse File.read(filename)
|
|
125
|
+
rescue JSON::ParserError
|
|
126
|
+
nil
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def pairs
|
|
131
|
+
configuration[:pairs]
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def fixtures
|
|
135
|
+
configuration[:fixtures]
|
|
136
|
+
end
|
|
137
|
+
|
|
87
138
|
def bucket
|
|
88
|
-
|
|
139
|
+
configuration[:bucket]
|
|
89
140
|
end
|
|
90
141
|
|
|
91
142
|
def history
|
|
92
|
-
|
|
143
|
+
configuration[:history]
|
|
93
144
|
end
|
|
94
145
|
|
|
95
146
|
def configuration
|
|
@@ -7,10 +7,10 @@ class Holoserve::Interface::Fake
|
|
|
7
7
|
pair = Holoserve::Pair::Finder.new(configuration, request).pair
|
|
8
8
|
if pair
|
|
9
9
|
if name = pair[:name]
|
|
10
|
-
history
|
|
10
|
+
history << name
|
|
11
11
|
logger.info "received handled request with name '#{name}'"
|
|
12
12
|
end
|
|
13
|
-
response =
|
|
13
|
+
response = Holoserve::Response::Combiner.new(pair[:responses], configuration).response
|
|
14
14
|
if response.empty?
|
|
15
15
|
logger.warn "received request #{pair[:name]} with undefined response"
|
|
16
16
|
not_found
|
|
@@ -18,7 +18,7 @@ class Holoserve::Interface::Fake
|
|
|
18
18
|
Holoserve::Response::Composer.new(response).response_array
|
|
19
19
|
end
|
|
20
20
|
else
|
|
21
|
-
bucket
|
|
21
|
+
bucket << request
|
|
22
22
|
logger.error "received unhandled request\n" + request.pretty_inspect
|
|
23
23
|
not_found
|
|
24
24
|
end
|
|
@@ -26,31 +26,24 @@ class Holoserve::Interface::Fake
|
|
|
26
26
|
|
|
27
27
|
private
|
|
28
28
|
|
|
29
|
-
def compose_response(pair)
|
|
30
|
-
responses = pair[:responses]
|
|
31
|
-
response_default = responses[:default] || { }
|
|
32
|
-
response_situation = (configuration.situation && responses[configuration.situation.to_sym]) || { }
|
|
33
|
-
Holoserve::Tool::Merger.new(response_default, response_situation).result
|
|
34
|
-
end
|
|
35
|
-
|
|
36
29
|
def not_found
|
|
37
30
|
[ 404, { "Content-Type" => "text/plain" }, [ "no response found for this request" ] ]
|
|
38
31
|
end
|
|
39
32
|
|
|
40
33
|
def logger
|
|
41
|
-
|
|
34
|
+
Holoserve.instance.logger
|
|
42
35
|
end
|
|
43
36
|
|
|
44
|
-
def
|
|
45
|
-
configuration
|
|
37
|
+
def pairs
|
|
38
|
+
configuration[:pairs]
|
|
46
39
|
end
|
|
47
40
|
|
|
48
41
|
def bucket
|
|
49
|
-
|
|
42
|
+
configuration[:bucket]
|
|
50
43
|
end
|
|
51
44
|
|
|
52
45
|
def history
|
|
53
|
-
|
|
46
|
+
configuration[:history]
|
|
54
47
|
end
|
|
55
48
|
|
|
56
49
|
def configuration
|
|
@@ -6,16 +6,21 @@ class Holoserve::Pair::Finder
|
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def pair
|
|
9
|
-
return nil unless
|
|
10
|
-
|
|
11
|
-
Holoserve::Request::Matcher.new(@request, pair[:request]).match?
|
|
9
|
+
return nil unless pairs
|
|
10
|
+
pairs.each do |name, pair|
|
|
11
|
+
return pair.merge(:name => name) if Holoserve::Request::Matcher.new(@request, pair[:request], fixtures).match?
|
|
12
12
|
end
|
|
13
|
+
nil
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
private
|
|
16
17
|
|
|
17
|
-
def
|
|
18
|
-
@configuration
|
|
18
|
+
def pairs
|
|
19
|
+
@configuration[:pairs]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def fixtures
|
|
23
|
+
@configuration[:fixtures]
|
|
19
24
|
end
|
|
20
25
|
|
|
21
26
|
end
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
class Holoserve::Request::Matcher
|
|
3
3
|
|
|
4
|
-
def initialize(request, request_subset)
|
|
5
|
-
@request
|
|
4
|
+
def initialize(request, request_subset, fixtures)
|
|
5
|
+
@request = request
|
|
6
|
+
@request_subset = Holoserve::Fixture::Importer.new(request_subset, fixtures).hash
|
|
6
7
|
end
|
|
7
8
|
|
|
8
9
|
def match?
|
|
@@ -15,7 +16,7 @@ class Holoserve::Request::Matcher
|
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
private
|
|
18
|
-
|
|
19
|
+
|
|
19
20
|
def match_method?
|
|
20
21
|
@request_subset[:method] ?
|
|
21
22
|
@request[:method] == @request_subset[:method] :
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
class Holoserve::Response::Combiner
|
|
3
|
+
|
|
4
|
+
def initialize(responses, configuration)
|
|
5
|
+
@responses, @configuration = responses, configuration
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def response
|
|
9
|
+
Holoserve::Tool::Merger.new(default_response, situation_response).result
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def default_response
|
|
15
|
+
@responses[:default] ?
|
|
16
|
+
Holoserve::Fixture::Importer.new(@responses[:default], fixtures).hash :
|
|
17
|
+
{ }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def situation_response
|
|
21
|
+
situation && @responses[situation.to_sym] ?
|
|
22
|
+
Holoserve::Fixture::Importer.new(@responses[situation.to_sym], fixtures).hash :
|
|
23
|
+
{ }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def fixtures
|
|
27
|
+
@configuration[:fixtures]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def situation
|
|
31
|
+
@configuration[:situation]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
data/lib/holoserve/response.rb
CHANGED
data/lib/holoserve/runner.rb
CHANGED
|
@@ -7,7 +7,8 @@ class Holoserve::Runner
|
|
|
7
7
|
|
|
8
8
|
def initialize(options = { })
|
|
9
9
|
@port = options[:port] || 4250
|
|
10
|
-
@
|
|
10
|
+
@fixture_file_pattern = options[:fixture_file_pattern]
|
|
11
|
+
@pair_file_pattern = options[:pair_file_pattern]
|
|
11
12
|
@situation = options[:situation]
|
|
12
13
|
|
|
13
14
|
@rackup_options = Unicorn::Configurator::RACKUP
|
|
@@ -20,7 +21,8 @@ class Holoserve::Runner
|
|
|
20
21
|
|
|
21
22
|
def start
|
|
22
23
|
@unicorn.start
|
|
23
|
-
|
|
24
|
+
upload_fixtures if @fixture_file_pattern
|
|
25
|
+
upload_pairs if @pair_file_pattern
|
|
24
26
|
set_situation if @situation
|
|
25
27
|
end
|
|
26
28
|
|
|
@@ -42,15 +44,22 @@ class Holoserve::Runner
|
|
|
42
44
|
|
|
43
45
|
private
|
|
44
46
|
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
+
def upload_fixtures
|
|
48
|
+
Dir[ @fixture_file_pattern ].each do |filename|
|
|
49
|
+
upload_file "http://localhost:#{port}/_control/fixtures", filename
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def upload_pairs
|
|
54
|
+
Dir[ @pair_file_pattern ].each do |filename|
|
|
55
|
+
upload_file "http://localhost:#{port}/_control/pairs", filename
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def upload_file(url, filename)
|
|
60
|
+
format = File.extname(filename).sub(/^\./, "")
|
|
47
61
|
raise ArgumentError, "file extension indicates wrong format '#{format}' (choose yaml or json)" unless [ "yaml", "json" ].include?(format)
|
|
48
|
-
Holoserve::Tool::Uploader.new(
|
|
49
|
-
@layout_filename,
|
|
50
|
-
:post,
|
|
51
|
-
"http://localhost:#{port}/_control/layout.#{format}",
|
|
52
|
-
:expected_status_code => 200
|
|
53
|
-
).upload
|
|
62
|
+
Holoserve::Tool::Uploader.new(filename, :post, url, :expected_status_code => 200).upload
|
|
54
63
|
nil
|
|
55
64
|
end
|
|
56
65
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
class Holoserve::Tool::DataPath
|
|
3
|
+
|
|
4
|
+
PATH_SEPARATOR = ".".freeze unless defined?(PATH_SEPARATOR)
|
|
5
|
+
|
|
6
|
+
attr_accessor :path
|
|
7
|
+
attr_accessor :data
|
|
8
|
+
|
|
9
|
+
def initialize(path, data)
|
|
10
|
+
@path, @data = path, data
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def fetch
|
|
14
|
+
path = @path ? @path.split(PATH_SEPARATOR) : [ ]
|
|
15
|
+
return @data if path.empty?
|
|
16
|
+
|
|
17
|
+
selected = @data
|
|
18
|
+
key = parse_key path.shift
|
|
19
|
+
|
|
20
|
+
while path.length > 0
|
|
21
|
+
return nil unless selected.respond_to?(:[])
|
|
22
|
+
selected = selected[key]
|
|
23
|
+
|
|
24
|
+
key = parse_key path.shift
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
return nil unless selected.respond_to?(:[])
|
|
28
|
+
selected[key]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def store(value)
|
|
32
|
+
path = @path ? @path.split(PATH_SEPARATOR) : [ ]
|
|
33
|
+
return value if path.empty?
|
|
34
|
+
|
|
35
|
+
selected = @data
|
|
36
|
+
key = parse_key path.shift
|
|
37
|
+
|
|
38
|
+
while path.length > 0
|
|
39
|
+
break unless selected.respond_to?(:[])
|
|
40
|
+
|
|
41
|
+
selected[key] ||= { }
|
|
42
|
+
selected = selected[key]
|
|
43
|
+
key = parse_key path.shift
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
selected[key] = value
|
|
47
|
+
@data
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def parse_key(key)
|
|
53
|
+
key =~ /^\d+$/ ? key.to_i : key.to_sym
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
@@ -7,10 +7,7 @@ class Holoserve::Tool::Uploader
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def upload
|
|
10
|
-
|
|
11
|
-
options[:headers] = (@options[:headers] || { }).merge(headers)
|
|
12
|
-
options[:body] = body
|
|
13
|
-
Transport::HTTP.request @http_method, @url, options
|
|
10
|
+
Transport::HTTP.request @http_method, @url, @options.merge(:headers => headers, :body => body)
|
|
14
11
|
end
|
|
15
12
|
|
|
16
13
|
private
|
|
@@ -22,13 +19,20 @@ class Holoserve::Tool::Uploader
|
|
|
22
19
|
def body
|
|
23
20
|
"--#{boundary}\r\n" +
|
|
24
21
|
"Content-Disposition: form-data; name=\"file\"; filename=\"#{File.basename(@filename)}\"\r\n" +
|
|
25
|
-
"Content-Type:
|
|
22
|
+
"Content-Type: #{content_type}\r\n" +
|
|
26
23
|
"\r\n" +
|
|
27
24
|
File.read(@filename) +
|
|
28
25
|
"\r\n" +
|
|
29
26
|
"--#{boundary}--\r\n"
|
|
30
27
|
end
|
|
31
28
|
|
|
29
|
+
def content_type
|
|
30
|
+
{
|
|
31
|
+
"yaml" => "application/x-yaml",
|
|
32
|
+
"json" => "application/json"
|
|
33
|
+
}[ File.extname(@filename) ] || "text/plain"
|
|
34
|
+
end
|
|
35
|
+
|
|
32
36
|
def boundary
|
|
33
37
|
"xxx12345xxx"
|
|
34
38
|
end
|
data/lib/holoserve/tool.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
module Holoserve::Tool
|
|
3
3
|
|
|
4
|
+
autoload :DataPath, File.join(File.dirname(__FILE__), "tool", "data_path")
|
|
4
5
|
autoload :Hash, File.join(File.dirname(__FILE__), "tool", "hash")
|
|
5
6
|
autoload :Merger, File.join(File.dirname(__FILE__), "tool", "merger")
|
|
6
7
|
autoload :Uploader, File.join(File.dirname(__FILE__), "tool", "uploader")
|
data/lib/holoserve.rb
CHANGED
|
@@ -3,9 +3,7 @@ require 'logger'
|
|
|
3
3
|
|
|
4
4
|
class Holoserve
|
|
5
5
|
|
|
6
|
-
autoload :
|
|
7
|
-
autoload :Configuration, File.join(File.dirname(__FILE__), "holoserve", "configuration")
|
|
8
|
-
autoload :History, File.join(File.dirname(__FILE__), "holoserve", "history")
|
|
6
|
+
autoload :Fixture, File.join(File.dirname(__FILE__), "holoserve", "fixture")
|
|
9
7
|
autoload :Interface, File.join(File.dirname(__FILE__), "holoserve", "interface")
|
|
10
8
|
autoload :Pair, File.join(File.dirname(__FILE__), "holoserve", "pair")
|
|
11
9
|
autoload :Request, File.join(File.dirname(__FILE__), "holoserve", "request")
|
|
@@ -15,15 +13,11 @@ class Holoserve
|
|
|
15
13
|
|
|
16
14
|
attr_reader :logger
|
|
17
15
|
attr_reader :configuration
|
|
18
|
-
attr_reader :bucket
|
|
19
|
-
attr_reader :history
|
|
20
16
|
attr_reader :rack
|
|
21
17
|
|
|
22
18
|
def initialize
|
|
23
19
|
initialize_logger
|
|
24
20
|
initialize_configuration
|
|
25
|
-
initialize_bucket
|
|
26
|
-
initialize_history
|
|
27
21
|
initialize_rack
|
|
28
22
|
end
|
|
29
23
|
|
|
@@ -34,15 +28,13 @@ class Holoserve
|
|
|
34
28
|
end
|
|
35
29
|
|
|
36
30
|
def initialize_configuration
|
|
37
|
-
@configuration =
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def initialize_history
|
|
45
|
-
@history = History.new
|
|
31
|
+
@configuration = {
|
|
32
|
+
:pairs => { },
|
|
33
|
+
:fixtures => { },
|
|
34
|
+
:situation => nil,
|
|
35
|
+
:bucket => [ ],
|
|
36
|
+
:history => [ ]
|
|
37
|
+
}
|
|
46
38
|
end
|
|
47
39
|
|
|
48
40
|
def initialize_rack
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "helper"))
|
|
2
|
+
|
|
3
|
+
describe Holoserve::Fixture::Importer do
|
|
4
|
+
|
|
5
|
+
let(:fixtures) { { :test => { :nested => "value", :second => "value" }, :another => "value" } }
|
|
6
|
+
|
|
7
|
+
subject { described_class.new nil, fixtures }
|
|
8
|
+
|
|
9
|
+
describe "hash" do
|
|
10
|
+
|
|
11
|
+
it "should return the original hash if there is no imports section" do
|
|
12
|
+
subject.hash = {
|
|
13
|
+
:test => "value"
|
|
14
|
+
}
|
|
15
|
+
subject.hash.should == { :test => "value" }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should return a hash with imported fixtures" do
|
|
19
|
+
subject.hash = {
|
|
20
|
+
:imports => [
|
|
21
|
+
{ :path => "test.nested" }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
subject.hash.should == { :test => { :nested => "value" } }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should return a hash with imported fixtures at a target path" do
|
|
28
|
+
subject.hash = {
|
|
29
|
+
:imports => [
|
|
30
|
+
{ :path => "test.nested", :as => "test" }
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
subject.hash.should == { :test => "value" }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should return a hash with imported and filtered fixtures" do
|
|
37
|
+
subject.hash = {
|
|
38
|
+
:imports => [
|
|
39
|
+
{ :path => "test", :as => "test", :only => [ "second" ] }
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
subject.hash.should == { :test => { :second => "value" } }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should return a hash where all the imports are imported" do
|
|
46
|
+
subject.hash = {
|
|
47
|
+
:imports => [
|
|
48
|
+
{ :path => "test.nested", :as => "test" },
|
|
49
|
+
{ :path => "another", :as => "another.test" }
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
subject.hash.should == { :test => "value", :another => { :test => "value" } }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should return a hash where the data is merged with the imports" do
|
|
56
|
+
subject.hash = {
|
|
57
|
+
:imports => [
|
|
58
|
+
{ :path => "test.nested", :as => "test" }
|
|
59
|
+
],
|
|
60
|
+
:another => "value"
|
|
61
|
+
}
|
|
62
|
+
subject.hash.should == { :test => "value", :another => "value" }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should return a hash where the data is deep merged with the imports" do
|
|
66
|
+
subject.hash = {
|
|
67
|
+
:imports => [
|
|
68
|
+
{ :path => "test.nested", :as => "test.nested" }
|
|
69
|
+
],
|
|
70
|
+
:test => {
|
|
71
|
+
:another => "value"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
subject.hash.should == { :test => { :nested => "value", :another => "value" } }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "helper"))
|
|
2
|
+
|
|
3
|
+
describe Holoserve::Tool::DataPath do
|
|
4
|
+
|
|
5
|
+
subject { described_class.new nil, nil }
|
|
6
|
+
|
|
7
|
+
describe "fetch" do
|
|
8
|
+
|
|
9
|
+
it "should return the given data if no path is specified" do
|
|
10
|
+
subject.path = nil
|
|
11
|
+
subject.data = { :test => "value" }
|
|
12
|
+
subject.fetch.should == { :test => "value" }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should return the value specified by the given path" do
|
|
16
|
+
subject.path = "test"
|
|
17
|
+
subject.data = { :test => "value" }
|
|
18
|
+
subject.fetch.should == "value"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should return the nested value specified by the given path" do
|
|
22
|
+
subject.path = "test.nested"
|
|
23
|
+
subject.data = { :test => { :nested => "value" } }
|
|
24
|
+
subject.fetch.should == "value"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should return nil if the path points to nowhere" do
|
|
28
|
+
subject.path = "test.nested"
|
|
29
|
+
subject.data = { :test => true }
|
|
30
|
+
subject.fetch.should be_nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should return nil if the last path element doesn't exists'" do
|
|
34
|
+
subject.path = "test.nested"
|
|
35
|
+
subject.data = { :test => { :another => "value" } }
|
|
36
|
+
subject.fetch.should be_nil
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should return in an array nested value specified by the given path" do
|
|
40
|
+
subject.path = "test.1.nested"
|
|
41
|
+
subject.data = { :test => [ { }, { :nested => "value" } ] }
|
|
42
|
+
subject.fetch.should == "value"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe "store" do
|
|
48
|
+
|
|
49
|
+
it "should return the given value if no path is specified" do
|
|
50
|
+
subject.path = nil
|
|
51
|
+
subject.data = { :test => "value" }
|
|
52
|
+
subject.store("value").should == "value"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should store the given value at the specified path" do
|
|
56
|
+
subject.path = "another"
|
|
57
|
+
subject.data = { :test => "value" }
|
|
58
|
+
subject.store("value").should == { :test => "value", :another => "value" }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "should store the given value in a nested hash" do
|
|
62
|
+
subject.path = "test.another"
|
|
63
|
+
subject.data = { :test => { :nested => "value" } }
|
|
64
|
+
subject.store("value").should == { :test => { :nested => "value", :another => "value" } }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should store the given value at the specified path and create it if missing" do
|
|
68
|
+
subject.path = "another.test"
|
|
69
|
+
subject.data = { :test => "value" }
|
|
70
|
+
subject.store("value").should == { :test => "value", :another => { :test => "value" } }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: holoserve
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,11 +9,11 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2012-02-
|
|
12
|
+
date: 2012-02-09 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rack
|
|
16
|
-
requirement: &
|
|
16
|
+
requirement: &70132546243580 !ruby/object:Gem::Requirement
|
|
17
17
|
none: false
|
|
18
18
|
requirements:
|
|
19
19
|
- - ! '>='
|
|
@@ -21,10 +21,10 @@ dependencies:
|
|
|
21
21
|
version: '0'
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
|
-
version_requirements: *
|
|
24
|
+
version_requirements: *70132546243580
|
|
25
25
|
- !ruby/object:Gem::Dependency
|
|
26
26
|
name: sinatra
|
|
27
|
-
requirement: &
|
|
27
|
+
requirement: &70132546257040 !ruby/object:Gem::Requirement
|
|
28
28
|
none: false
|
|
29
29
|
requirements:
|
|
30
30
|
- - ! '>='
|
|
@@ -32,10 +32,10 @@ dependencies:
|
|
|
32
32
|
version: '0'
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
|
-
version_requirements: *
|
|
35
|
+
version_requirements: *70132546257040
|
|
36
36
|
- !ruby/object:Gem::Dependency
|
|
37
37
|
name: unicorn
|
|
38
|
-
requirement: &
|
|
38
|
+
requirement: &70132546255800 !ruby/object:Gem::Requirement
|
|
39
39
|
none: false
|
|
40
40
|
requirements:
|
|
41
41
|
- - ! '>='
|
|
@@ -43,10 +43,10 @@ dependencies:
|
|
|
43
43
|
version: '0'
|
|
44
44
|
type: :runtime
|
|
45
45
|
prerelease: false
|
|
46
|
-
version_requirements: *
|
|
46
|
+
version_requirements: *70132546255800
|
|
47
47
|
- !ruby/object:Gem::Dependency
|
|
48
48
|
name: transport
|
|
49
|
-
requirement: &
|
|
49
|
+
requirement: &70132546254300 !ruby/object:Gem::Requirement
|
|
50
50
|
none: false
|
|
51
51
|
requirements:
|
|
52
52
|
- - ! '>='
|
|
@@ -54,10 +54,10 @@ dependencies:
|
|
|
54
54
|
version: '0'
|
|
55
55
|
type: :runtime
|
|
56
56
|
prerelease: false
|
|
57
|
-
version_requirements: *
|
|
57
|
+
version_requirements: *70132546254300
|
|
58
58
|
- !ruby/object:Gem::Dependency
|
|
59
59
|
name: cucumber
|
|
60
|
-
requirement: &
|
|
60
|
+
requirement: &70132546252800 !ruby/object:Gem::Requirement
|
|
61
61
|
none: false
|
|
62
62
|
requirements:
|
|
63
63
|
- - ! '>='
|
|
@@ -65,10 +65,10 @@ dependencies:
|
|
|
65
65
|
version: '0'
|
|
66
66
|
type: :development
|
|
67
67
|
prerelease: false
|
|
68
|
-
version_requirements: *
|
|
68
|
+
version_requirements: *70132546252800
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: rspec
|
|
71
|
-
requirement: &
|
|
71
|
+
requirement: &70132546265600 !ruby/object:Gem::Requirement
|
|
72
72
|
none: false
|
|
73
73
|
requirements:
|
|
74
74
|
- - ! '>='
|
|
@@ -76,10 +76,10 @@ dependencies:
|
|
|
76
76
|
version: '0'
|
|
77
77
|
type: :development
|
|
78
78
|
prerelease: false
|
|
79
|
-
version_requirements: *
|
|
79
|
+
version_requirements: *70132546265600
|
|
80
80
|
- !ruby/object:Gem::Dependency
|
|
81
81
|
name: transport
|
|
82
|
-
requirement: &
|
|
82
|
+
requirement: &70132546264780 !ruby/object:Gem::Requirement
|
|
83
83
|
none: false
|
|
84
84
|
requirements:
|
|
85
85
|
- - ! '>='
|
|
@@ -87,10 +87,10 @@ dependencies:
|
|
|
87
87
|
version: '0'
|
|
88
88
|
type: :development
|
|
89
89
|
prerelease: false
|
|
90
|
-
version_requirements: *
|
|
90
|
+
version_requirements: *70132546264780
|
|
91
91
|
- !ruby/object:Gem::Dependency
|
|
92
92
|
name: oauth
|
|
93
|
-
requirement: &
|
|
93
|
+
requirement: &70132546263580 !ruby/object:Gem::Requirement
|
|
94
94
|
none: false
|
|
95
95
|
requirements:
|
|
96
96
|
- - ! '>='
|
|
@@ -98,7 +98,7 @@ dependencies:
|
|
|
98
98
|
version: '0'
|
|
99
99
|
type: :development
|
|
100
100
|
prerelease: false
|
|
101
|
-
version_requirements: *
|
|
101
|
+
version_requirements: *70132546263580
|
|
102
102
|
description: This tool can be used to fake webservice APIs for testing proposals.
|
|
103
103
|
email: philipp.bruell@skrill.com
|
|
104
104
|
executables:
|
|
@@ -111,9 +111,8 @@ files:
|
|
|
111
111
|
- LICENSE
|
|
112
112
|
- Rakefile
|
|
113
113
|
- bin/holoserve
|
|
114
|
-
- lib/holoserve/
|
|
115
|
-
- lib/holoserve/
|
|
116
|
-
- lib/holoserve/history.rb
|
|
114
|
+
- lib/holoserve/fixture/importer.rb
|
|
115
|
+
- lib/holoserve/fixture.rb
|
|
117
116
|
- lib/holoserve/interface/control.rb
|
|
118
117
|
- lib/holoserve/interface/fake.rb
|
|
119
118
|
- lib/holoserve/interface.rb
|
|
@@ -122,9 +121,11 @@ files:
|
|
|
122
121
|
- lib/holoserve/request/decomposer.rb
|
|
123
122
|
- lib/holoserve/request/matcher.rb
|
|
124
123
|
- lib/holoserve/request.rb
|
|
124
|
+
- lib/holoserve/response/combiner.rb
|
|
125
125
|
- lib/holoserve/response/composer.rb
|
|
126
126
|
- lib/holoserve/response.rb
|
|
127
127
|
- lib/holoserve/runner.rb
|
|
128
|
+
- lib/holoserve/tool/data_path.rb
|
|
128
129
|
- lib/holoserve/tool/hash/key_symbolizer.rb
|
|
129
130
|
- lib/holoserve/tool/hash.rb
|
|
130
131
|
- lib/holoserve/tool/merger.rb
|
|
@@ -132,6 +133,8 @@ files:
|
|
|
132
133
|
- lib/holoserve/tool.rb
|
|
133
134
|
- lib/holoserve.rb
|
|
134
135
|
- spec/helper.rb
|
|
136
|
+
- spec/lib/holoserve/fixture/importer_spec.rb
|
|
137
|
+
- spec/lib/holoserve/tool/data_path_spec.rb
|
|
135
138
|
- spec/lib/holoserve/tool/merger_spec.rb
|
|
136
139
|
homepage: http://github.com/skrill/holoserve
|
|
137
140
|
licenses: []
|
|
@@ -147,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
147
150
|
version: '0'
|
|
148
151
|
segments:
|
|
149
152
|
- 0
|
|
150
|
-
hash:
|
|
153
|
+
hash: 4596962680025174660
|
|
151
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
155
|
none: false
|
|
153
156
|
requirements:
|
|
@@ -161,4 +164,6 @@ signing_key:
|
|
|
161
164
|
specification_version: 3
|
|
162
165
|
summary: Tool to fake HTTP APIs.
|
|
163
166
|
test_files:
|
|
167
|
+
- spec/lib/holoserve/fixture/importer_spec.rb
|
|
168
|
+
- spec/lib/holoserve/tool/data_path_spec.rb
|
|
164
169
|
- spec/lib/holoserve/tool/merger_spec.rb
|
data/lib/holoserve/bucket.rb
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
require 'yaml'
|
|
2
|
-
|
|
3
|
-
class Holoserve::Configuration
|
|
4
|
-
|
|
5
|
-
class InvalidFormatError < StandardError; end
|
|
6
|
-
|
|
7
|
-
attr_reader :logger
|
|
8
|
-
|
|
9
|
-
attr_reader :layout
|
|
10
|
-
attr_reader :situation
|
|
11
|
-
|
|
12
|
-
def initialize(logger)
|
|
13
|
-
@logger = logger
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def layout=(hash_or_array)
|
|
17
|
-
@layout = Holoserve::Tool::Hash::KeySymbolizer.new(hash_or_array).hash
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def clear_layout!
|
|
21
|
-
self.layout = nil
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def situation=(value)
|
|
25
|
-
@situation = value.to_sym
|
|
26
|
-
logger.info "made '#{value}' the current situation"
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def clear_situation!
|
|
30
|
-
@situation = nil
|
|
31
|
-
logger.info "cleared the current situation"
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def load_layout_from_yaml_file(file)
|
|
35
|
-
self.layout = YAML::load_file file
|
|
36
|
-
logger.info "loaded layouts from yaml file #{file.path}"
|
|
37
|
-
rescue Psych::SyntaxError => error
|
|
38
|
-
self.clear_layout!
|
|
39
|
-
raise InvalidFormatError, error.to_s
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def load_layout_from_json_file(file)
|
|
43
|
-
self.layout = JSON.parse File.read(file)
|
|
44
|
-
logger.info "loaded layouts from json file #{file.path}"
|
|
45
|
-
rescue JSON::ParserError => error
|
|
46
|
-
self.clear_layout!
|
|
47
|
-
raise InvalidFormatError, error.to_s
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
end
|