mock_server 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/mock_server/playback.rb +84 -82
- data/lib/mock_server/record.rb +40 -44
- data/lib/mock_server/spec/helpers.rb +264 -252
- data/lib/mock_server/state.rb +22 -25
- data/lib/mock_server/store/global.rb +12 -16
- data/lib/mock_server/utils.rb +55 -54
- metadata +1 -1
data/lib/mock_server/playback.rb
CHANGED
@@ -8,114 +8,116 @@ unless defined? MockServer::Store
|
|
8
8
|
require 'mock_server/store/global'
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
include MockServer::Store
|
15
|
-
|
16
|
-
def initialize(app, opt = {})
|
17
|
-
@app = app
|
18
|
-
@options = mock_server_options_merge(opt)
|
19
|
-
end
|
20
|
-
|
21
|
-
def call(env)
|
22
|
-
@options = self.mock_server_options_read
|
23
|
-
|
24
|
-
verbose(env) if @options[:verbose]
|
25
|
-
return @app.call(env) unless @options[:routes] and
|
26
|
-
lazy_match @options[:routes], env["PATH_INFO"]
|
11
|
+
class MockServer::Playback
|
12
|
+
include MockServer::Utils
|
13
|
+
include MockServer::Store
|
27
14
|
|
28
|
-
|
15
|
+
def initialize(app, opt = {})
|
16
|
+
@app = app
|
17
|
+
@options = mock_server_options_merge(opt)
|
18
|
+
end
|
29
19
|
|
30
|
-
|
20
|
+
def call(env)
|
21
|
+
@options = self.mock_server_options_read
|
31
22
|
|
32
|
-
|
23
|
+
verbose(env) if @options[:verbose]
|
24
|
+
return @app.call(env) unless matchable_request?(env)
|
33
25
|
|
34
|
-
|
26
|
+
@request = Rack::Request.new(env)
|
27
|
+
@options[:requests_stack] << @request.path
|
28
|
+
@data = load_data
|
35
29
|
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
response = build_response
|
31
|
+
self.mock_server_options_write(@options)
|
32
|
+
response
|
33
|
+
end
|
39
34
|
|
40
|
-
|
41
|
-
[response[:status], response[:headers], [response[:body]]]
|
42
|
-
else
|
43
|
-
error = { @request.path => "Couldn't match #{@request.request_method} #{@request.path}" }
|
44
|
-
@options[:errors_stack] << error
|
45
|
-
[404, {}, ['RECORD NOT FOUND!']]
|
46
|
-
end
|
35
|
+
private
|
47
36
|
|
48
|
-
|
49
|
-
|
37
|
+
def build_response
|
38
|
+
if record = match_request
|
39
|
+
return_record(record)
|
40
|
+
else
|
41
|
+
return_error
|
50
42
|
end
|
43
|
+
end
|
51
44
|
|
52
|
-
|
45
|
+
def return_record(record)
|
46
|
+
@options[:success_stack] << @request.path
|
47
|
+
@options[:matcher_exceptions].clear
|
48
|
+
response = record[:response]
|
49
|
+
[response[:status], response[:headers], [response[:body]]]
|
50
|
+
end
|
53
51
|
|
54
|
-
|
55
|
-
|
52
|
+
def return_error
|
53
|
+
error = { @request.path => "Couldn't match #{@request.request_method} #{@request.path}" }
|
54
|
+
@options[:errors_stack] << error
|
55
|
+
[404, {}, ['RECORD NOT FOUND!']]
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
def match_request
|
59
|
+
request = Hashie::Mash.new hashified_request
|
59
60
|
|
60
|
-
|
61
|
+
# Filter out data records by path and method
|
62
|
+
records = filter_records(request)
|
61
63
|
|
62
|
-
|
63
|
-
matchers.detect { |matcher|
|
64
|
-
# Match the request with a record by validating against the matcher if any.
|
65
|
-
data = @data.detect { |entry|
|
66
|
-
recorded_request = Hashie::Mash.new entry[:request]
|
67
|
-
recorded_response = entry[:response].dup
|
64
|
+
matchers = filter_matchers(request)
|
68
65
|
|
69
|
-
|
70
|
-
|
66
|
+
record = false
|
67
|
+
matchers.detect { |matcher|
|
68
|
+
# Match the request with a record by validating against the matcher if any.
|
69
|
+
record = records.detect { |entry|
|
70
|
+
recorded_request = Hashie::Mash.new entry[:request]
|
71
|
+
recorded_response = entry[:response].dup
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
}
|
75
|
-
data
|
76
|
-
end
|
73
|
+
recorded_response[:body] = JSON.parse(recorded_response[:body]) rescue recorded_response[:body]
|
74
|
+
recorded_response = Hashie::Mash.new recorded_response
|
77
75
|
|
78
|
-
|
79
|
-
@options[:matchers].select { |match|
|
80
|
-
request[:method].to_s.upcase == match[:method].to_s.upcase and request[:path] == match[:path]
|
76
|
+
test_request_and_matcher(matcher, request, recorded_request, recorded_response)
|
81
77
|
}
|
82
|
-
|
78
|
+
}
|
79
|
+
record
|
80
|
+
end
|
83
81
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
82
|
+
def filter_matchers(request)
|
83
|
+
@options[:matchers].select { |match|
|
84
|
+
request[:method].to_s.upcase == match[:method].to_s.upcase and request[:path] == match[:path]
|
85
|
+
}
|
86
|
+
end
|
89
87
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
store_matcher_exception(matcher_err)
|
96
|
-
false
|
97
|
-
end
|
98
|
-
end
|
88
|
+
def filter_records(request)
|
89
|
+
@data.select { |record|
|
90
|
+
record[:request][:path] == request[:path] and record[:request][:method] == request[:method]
|
91
|
+
}
|
92
|
+
end
|
99
93
|
|
100
|
-
|
101
|
-
|
94
|
+
def test_request_and_matcher(matcher, request, recorded_request, recorded_response)
|
95
|
+
return true if matcher[:matcher].nil?
|
96
|
+
begin
|
97
|
+
matcher[:matcher].call(request, recorded_request, recorded_response) == true
|
98
|
+
rescue => matcher_err
|
99
|
+
store_matcher_exception(matcher_err)
|
100
|
+
false
|
102
101
|
end
|
102
|
+
end
|
103
103
|
|
104
|
-
|
105
|
-
|
104
|
+
def store_matcher_exception(exception)
|
105
|
+
@options[:matcher_exceptions] << exception
|
106
|
+
end
|
106
107
|
|
107
|
-
|
108
|
+
def load_data
|
109
|
+
FileUtils.mkdir_p(@options[:path]) unless File.exists? @options[:path]
|
108
110
|
|
109
|
-
|
110
|
-
file_path = File.join( @options[:path], filename + '.yml' )
|
111
|
-
content = File.open(file_path).read
|
112
|
-
compiled = ERB.new(content).result
|
113
|
-
parsed = YAML.load(compiled)
|
114
|
-
data += parsed
|
115
|
-
end
|
111
|
+
data = []
|
116
112
|
|
117
|
-
|
113
|
+
@options[:record_filenames].map do |filename|
|
114
|
+
file_path = File.join( @options[:path], filename + '.yml' )
|
115
|
+
content = File.open(file_path).read
|
116
|
+
compiled = ERB.new(content).result
|
117
|
+
parsed = YAML.load(compiled)
|
118
|
+
data += parsed
|
118
119
|
end
|
119
120
|
|
121
|
+
data
|
120
122
|
end
|
121
123
|
end
|
data/lib/mock_server/record.rb
CHANGED
@@ -5,63 +5,59 @@ unless defined? MockServer::Store
|
|
5
5
|
require 'mock_server/store/global'
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
include MockServer::Store
|
8
|
+
class MockServer::Record
|
9
|
+
include MockServer::Utils
|
10
|
+
include MockServer::Store
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
def initialize(app, opt = {})
|
13
|
+
@app = app
|
14
|
+
@options = mock_server_options_merge(opt)
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
17
|
+
def call(env)
|
18
|
+
@options = self.mock_server_options_read
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
lazy_match @options[:routes], env["PATH_INFO"]
|
20
|
+
verbose(env) if @options[:verbose]
|
21
|
+
return @app.call(env) unless matchable_request?(env)
|
24
22
|
|
25
|
-
|
26
|
-
|
23
|
+
@request = Rack::Request.new(env)
|
24
|
+
@data = load_data
|
27
25
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
26
|
+
@app.call(env).tap do |status, header, response|
|
27
|
+
record_response(status, header, response)
|
28
|
+
self.mock_server_options_write(@options)
|
29
|
+
response
|
33
30
|
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def record_response(status, header, response)
|
38
|
-
request = hashified_request
|
31
|
+
end
|
39
32
|
|
40
|
-
|
41
|
-
save_data(@data)
|
42
|
-
end
|
33
|
+
private
|
43
34
|
|
44
|
-
|
45
|
-
|
46
|
-
end
|
35
|
+
def record_response(status, header, response)
|
36
|
+
request = hashified_request
|
47
37
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
38
|
+
@data << { :request => request, :response => hashify_response(status, header, response) }
|
39
|
+
save_data(@data)
|
40
|
+
end
|
41
|
+
|
42
|
+
def records_path
|
43
|
+
File.join( @options[:path], @options[:filename] + '.yml' )
|
44
|
+
end
|
45
|
+
|
46
|
+
def save_data(data)
|
47
|
+
File.open(records_path, 'w') do |f|
|
48
|
+
YAML.dump(data, f)
|
52
49
|
end
|
50
|
+
end
|
53
51
|
|
54
|
-
|
55
|
-
|
52
|
+
def load_data
|
53
|
+
FileUtils.mkdir_p(@options[:path]) unless File.exists? @options[:path]
|
56
54
|
|
57
|
-
|
55
|
+
data = YAML.load_file(records_path) rescue []
|
58
56
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
57
|
+
if data.is_a? Array
|
58
|
+
data
|
59
|
+
else
|
60
|
+
[]
|
64
61
|
end
|
65
|
-
|
66
62
|
end
|
67
63
|
end
|
@@ -2,288 +2,300 @@ unless defined? MockServer::Store
|
|
2
2
|
require 'mock_server/store/global'
|
3
3
|
end
|
4
4
|
|
5
|
-
module MockServer
|
6
|
-
module
|
7
|
-
|
8
|
-
include MockServer::Store
|
5
|
+
module MockServer::Spec
|
6
|
+
module Helpers
|
7
|
+
include MockServer::Store
|
9
8
|
|
9
|
+
# Public: Inspect mock server options
|
10
|
+
#
|
11
|
+
# Returns a String.
|
12
|
+
def mock_server_inspect
|
13
|
+
self.mock_server_options_read.inspect
|
14
|
+
end
|
10
15
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
# Public: Overwrite or initialize the list of fixtures
|
17
|
+
#
|
18
|
+
# *arguments - Filename...
|
19
|
+
#
|
20
|
+
# Examples
|
21
|
+
#
|
22
|
+
# mock_server_use_record(:users, :comments)
|
23
|
+
#
|
24
|
+
def mock_server_use_record(*arguments)
|
25
|
+
mock_server_options_set(:record_filenames, arguments)
|
26
|
+
end
|
17
27
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
# Public: Add fixtures to the list of fixtures
|
29
|
+
#
|
30
|
+
# *arguments - Filename...
|
31
|
+
#
|
32
|
+
# Examples
|
33
|
+
#
|
34
|
+
# mock_server_add_record(:users, :comments)
|
35
|
+
#
|
36
|
+
def mock_server_add_record(*arguments)
|
37
|
+
config = (mock_server_options_fetch(:record_filenames, []) + arguments)
|
38
|
+
mock_server_options_set(:record_filenames, config)
|
39
|
+
end
|
29
40
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
41
|
+
# Public: Set the path of fixtures files
|
42
|
+
#
|
43
|
+
# path - Sting of the fixtures path
|
44
|
+
#
|
45
|
+
# Examples
|
46
|
+
#
|
47
|
+
# mock_server_set_fixture_path('fixtures/records/')
|
48
|
+
#
|
49
|
+
def mock_server_set_fixture_path(path)
|
50
|
+
mock_server_options_set(:path, path)
|
51
|
+
end
|
42
52
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
53
|
+
# Public: Enabled MockServer on a given routes.
|
54
|
+
# Accept unix-directory like */** catch all.
|
55
|
+
#
|
56
|
+
# *arguments - Sting of the fixtures path
|
57
|
+
#
|
58
|
+
# Examples
|
59
|
+
#
|
60
|
+
# mock_server_enable_routes('/api/2/**', '/api/verify')
|
61
|
+
#
|
62
|
+
def mock_server_enable_routes(*paths)
|
63
|
+
routes = mock_server_options_fetch(:routes, []) + paths
|
64
|
+
mock_server_options_set(:routes, routes)
|
65
|
+
end
|
54
66
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
67
|
+
# Public: Disable MockServer on a given routes.
|
68
|
+
#
|
69
|
+
# *paths - Sting of the fixtures path
|
70
|
+
#
|
71
|
+
# Examples
|
72
|
+
#
|
73
|
+
# mock_server_disable_path('/api/2/**', '/api/verify')
|
74
|
+
#
|
75
|
+
def mock_server_disable_path(*paths)
|
76
|
+
routes = mock_server_options_fetch(:routes, []) - paths
|
77
|
+
mock_server_options_set(:routes, routes.flatten)
|
78
|
+
end
|
68
79
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
mock_server_options_set(:routes, routes.flatten)
|
80
|
-
end
|
80
|
+
# Public: Disable all routes being server by MockServer
|
81
|
+
#
|
82
|
+
#
|
83
|
+
# Examples
|
84
|
+
#
|
85
|
+
# mock_server_disable_all_routes!
|
86
|
+
#
|
87
|
+
def mock_server_disable_all_routes!
|
88
|
+
mock_server_options_set(:routes, [])
|
89
|
+
end
|
81
90
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
91
|
+
# Public: Register a matcher on a GET request for a given route.
|
92
|
+
#
|
93
|
+
# path - Relative HTTP path to match
|
94
|
+
# &block - Optional block for complex matching on the request
|
95
|
+
#
|
96
|
+
# Examples
|
97
|
+
#
|
98
|
+
# mock_server_get('/api/2/account')
|
99
|
+
#
|
100
|
+
# mock_server_get('/api/2/account') { |request, recorded_request| request.body == recorded_request.body }
|
101
|
+
#
|
102
|
+
def mock_server_get(path, &block)
|
103
|
+
mock_server_request :get, path, block
|
104
|
+
end
|
92
105
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
106
|
+
# Public: Register a matcher on a POST request for a given route.
|
107
|
+
#
|
108
|
+
# path - Relative HTTP path to match
|
109
|
+
# &block - Optional block for complex matching on the request
|
110
|
+
#
|
111
|
+
# Examples
|
112
|
+
#
|
113
|
+
# mock_server_post('/api/2/account')
|
114
|
+
#
|
115
|
+
# mock_server_post('/api/2/account') { |request, recorded_request| request.body == recorded_request.body }
|
116
|
+
#
|
117
|
+
def mock_server_post(path, &block)
|
118
|
+
mock_server_request :post, path, block
|
119
|
+
end
|
107
120
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
121
|
+
# Public: Register a matcher on a PUT request for a given route.
|
122
|
+
#
|
123
|
+
# path - Relative HTTP path to match
|
124
|
+
# &block - Optional block for complex matching on the request
|
125
|
+
#
|
126
|
+
# Examples
|
127
|
+
#
|
128
|
+
# mock_server_put('/api/2/account')
|
129
|
+
#
|
130
|
+
# mock_server_put('/api/2/account') { |request, recorded_request| request.body == recorded_request.body }
|
131
|
+
#
|
132
|
+
def mock_server_put(path, &block)
|
133
|
+
mock_server_request :put, path, block
|
134
|
+
end
|
122
135
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
136
|
+
# Public: Register a matcher on a PATCH request for a given route.
|
137
|
+
#
|
138
|
+
# path - Relative HTTP path to match
|
139
|
+
# &block - Optional block for complex matching on the request
|
140
|
+
#
|
141
|
+
# Examples
|
142
|
+
#
|
143
|
+
# mock_server_patch('/api/2/account')
|
144
|
+
#
|
145
|
+
# mock_server_patch('/api/2/account') { |request, recorded_request| request.body == recorded_request.body }
|
146
|
+
#
|
147
|
+
def mock_server_patch(path, &block)
|
148
|
+
mock_server_request :patch, path, block
|
149
|
+
end
|
137
150
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
151
|
+
# Public: Register a matcher on a DELETE request for a given route.
|
152
|
+
#
|
153
|
+
# path - Relative HTTP path to match
|
154
|
+
# &block - Optional block for complex matching on the request
|
155
|
+
#
|
156
|
+
# Examples
|
157
|
+
#
|
158
|
+
# mock_server_delete('/api/2/account')
|
159
|
+
#
|
160
|
+
# mock_server_delete('/api/2/account') { |request, recorded_request| request.body == recorded_request.body }
|
161
|
+
#
|
162
|
+
def mock_server_delete(path, &block)
|
163
|
+
mock_server_request :delete, path, block
|
164
|
+
end
|
152
165
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
166
|
+
# Public: Clear all the matchers
|
167
|
+
#
|
168
|
+
def mock_server_clear_matchers!
|
169
|
+
mock_server_options_set(:matchers, [])
|
170
|
+
end
|
158
171
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
172
|
+
# Public: Retrive the MockServer request stack.
|
173
|
+
#
|
174
|
+
# Return array of request path.
|
175
|
+
def mock_server_requests_stack
|
176
|
+
mock_server_options_fetch(:requests_stack, [])
|
177
|
+
end
|
165
178
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
179
|
+
# Public: Clear the MockServer request stack.
|
180
|
+
def mock_server_requests_stack_clear!
|
181
|
+
mock_server_options_set(:requests_stack, [])
|
182
|
+
end
|
170
183
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
184
|
+
# Public: Retrive the MockServer request stack.
|
185
|
+
#
|
186
|
+
# Return array of request path.
|
187
|
+
def mock_server_errors_stack
|
188
|
+
mock_server_options_fetch(:errors_stack, [])
|
189
|
+
end
|
177
190
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
191
|
+
# Public: Retrive the MockServer errors request stack.
|
192
|
+
# i.e.: path being register for being serve by MockServer, but
|
193
|
+
# no suitable matcher was found to serve the request will be
|
194
|
+
# added to the error stack
|
195
|
+
#
|
196
|
+
# Return array of errors.
|
197
|
+
def mock_server_errors_stack_clear!
|
198
|
+
mock_server_options_set(:errors_stack, [])
|
199
|
+
end
|
187
200
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
201
|
+
# Public: Retrive the MockServer successful request stack.
|
202
|
+
#
|
203
|
+
# Return array of successful response stack.
|
204
|
+
def mock_server_success_stack
|
205
|
+
mock_server_options_fetch(:success_stack, [])
|
206
|
+
end
|
194
207
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
208
|
+
# Public: Clear the MockServer successful request stack.
|
209
|
+
def mock_server_success_stack_clear!
|
210
|
+
mock_server_options_set(:success_stack, [])
|
211
|
+
end
|
199
212
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
+
# Public: Clear the MockServer response stack.
|
214
|
+
#
|
215
|
+
# alias:
|
216
|
+
#
|
217
|
+
# mock_server_requests_stack_clear!
|
218
|
+
# mock_server_success_stack_clear!
|
219
|
+
# mock_server_errors_stack_clear!
|
220
|
+
#
|
221
|
+
def mock_server_response_stack_clear!
|
222
|
+
mock_server_requests_stack_clear!
|
223
|
+
mock_server_success_stack_clear!
|
224
|
+
mock_server_errors_stack_clear!
|
225
|
+
end
|
213
226
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
+
# Public: Clear the MockServer state.
|
228
|
+
#
|
229
|
+
# alias:
|
230
|
+
#
|
231
|
+
# mock_server_response_stack_clear!
|
232
|
+
# mock_server_clear_matchers!
|
233
|
+
# mock_server_disable_all_routes!
|
234
|
+
#
|
235
|
+
def mock_server_reset!
|
236
|
+
mock_server_response_stack_clear!
|
237
|
+
mock_server_clear_matchers!
|
238
|
+
mock_server_disable_all_routes!
|
239
|
+
end
|
227
240
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
end
|
241
|
+
# Public: Utility helper to reraise errors catch inside the matchers block
|
242
|
+
#
|
243
|
+
def mock_server_reraise_matcher_exceptions
|
244
|
+
mock_server_options_fetch(:matcher_exceptions, []).each do |exception|
|
245
|
+
raise exception
|
234
246
|
end
|
247
|
+
end
|
235
248
|
|
236
|
-
|
249
|
+
protected
|
237
250
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
# Internal: Insert a matcher hash into the matchers array of the MockServer storage class.
|
255
|
-
#
|
256
|
-
def add_mock_server_matcher(matcher)
|
257
|
-
options = self.mock_server_options_read
|
258
|
-
options[:matchers].unshift(matcher)
|
259
|
-
mock_server_options_write(options)
|
260
|
-
end
|
251
|
+
# Internal: Register a matcher on a given route for playback
|
252
|
+
#
|
253
|
+
# method - HTTP verb to register
|
254
|
+
# path - Relative HTTP path to match
|
255
|
+
# matcher - Optional proc for complex matching on the request
|
256
|
+
#
|
257
|
+
# Examples
|
258
|
+
#
|
259
|
+
# mock_server_request(:get, '/api/2/account')
|
260
|
+
#
|
261
|
+
# mock_server_request(:get, '/api/2/account', lambda {|request, recorded_request| request.body == recorded_request.body } )
|
262
|
+
#
|
263
|
+
def mock_server_request(method, path, matcher)
|
264
|
+
add_mock_server_matcher({ :method => method, :path => path, :matcher => matcher })
|
265
|
+
end
|
261
266
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
end
|
270
|
-
end
|
267
|
+
# Internal: Insert a matcher hash into the matchers array of the MockServer storage class.
|
268
|
+
#
|
269
|
+
def add_mock_server_matcher(matcher)
|
270
|
+
options = self.mock_server_options_read
|
271
|
+
options[:matchers].unshift(matcher)
|
272
|
+
mock_server_options_write(options)
|
273
|
+
end
|
271
274
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
275
|
+
# Internal: Fetch key from the storage class
|
276
|
+
#
|
277
|
+
def mock_server_options_fetch(key, value)
|
278
|
+
if self.mock_server_options_read[key]
|
279
|
+
mock_server_options_get(key)
|
280
|
+
else
|
281
|
+
mock_server_options_set(key, value)
|
278
282
|
end
|
283
|
+
end
|
279
284
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
285
|
+
# Internal: Setter for the storage class
|
286
|
+
#
|
287
|
+
def mock_server_options_set(key, value)
|
288
|
+
hash = self.mock_server_options_read
|
289
|
+
hash[key] = value
|
290
|
+
self.mock_server_options_write(hash)
|
291
|
+
end
|
286
292
|
|
293
|
+
# Internal: Getter for the storage class
|
294
|
+
#
|
295
|
+
def mock_server_options_get(key)
|
296
|
+
hash = self.mock_server_options_read
|
297
|
+
hash[key]
|
287
298
|
end
|
299
|
+
|
288
300
|
end
|
289
301
|
end
|
data/lib/mock_server/state.rb
CHANGED
@@ -1,33 +1,30 @@
|
|
1
1
|
require 'hashie'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
property :matcher_exceptions, :default => []
|
3
|
+
class MockServer::State < Hashie::Dash
|
4
|
+
property :path, :default => 'fixtures/records'
|
5
|
+
property :filename, :default => 'record'
|
6
|
+
property :routes, :default => []
|
7
|
+
property :record_filenames, :default => []
|
8
|
+
property :matchers, :default => []
|
9
|
+
property :verbose, :default => false
|
10
|
+
property :requests_stack, :default => []
|
11
|
+
property :success_stack, :default => []
|
12
|
+
property :errors_stack, :default => []
|
13
|
+
property :requests_stack, :default => []
|
14
|
+
property :matcher_exceptions, :default => []
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
new_hash
|
16
|
+
def merge(hash)
|
17
|
+
new_hash = self
|
18
|
+
hash.each do |k,v|
|
19
|
+
new_hash[k] = v
|
23
20
|
end
|
21
|
+
new_hash
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
self
|
24
|
+
def merge!(hash)
|
25
|
+
hash.each do |k,v|
|
26
|
+
self[k] = v
|
30
27
|
end
|
31
|
-
|
28
|
+
self
|
32
29
|
end
|
33
30
|
end
|
@@ -1,22 +1,18 @@
|
|
1
1
|
require 'hashie'
|
2
2
|
|
3
|
-
module MockServer
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
$mock_server_options.merge!(opt)
|
9
|
-
end
|
10
|
-
|
11
|
-
def mock_server_options_read
|
12
|
-
$mock_server_options ||= MockServer::State.new
|
13
|
-
$mock_server_options
|
14
|
-
end
|
3
|
+
module MockServer::Store
|
4
|
+
def mock_server_options_merge(opt = {})
|
5
|
+
$mock_server_options ||= MockServer::State.new(opt)
|
6
|
+
$mock_server_options.merge!(opt)
|
7
|
+
end
|
15
8
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
9
|
+
def mock_server_options_read
|
10
|
+
$mock_server_options ||= MockServer::State.new
|
11
|
+
$mock_server_options
|
12
|
+
end
|
20
13
|
|
14
|
+
def mock_server_options_write(value)
|
15
|
+
$mock_server_options ||= MockServer::State.new
|
16
|
+
$mock_server_options = value
|
21
17
|
end
|
22
18
|
end
|
data/lib/mock_server/utils.rb
CHANGED
@@ -1,59 +1,60 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'json'
|
3
3
|
|
4
|
-
module MockServer
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
4
|
+
module MockServer::Utils
|
5
|
+
private
|
6
|
+
|
7
|
+
def verbose(env)
|
8
|
+
interception = lazy_match(@options[:routes], env["PATH_INFO"]) ? "intercepted!" : "NOT intercepted."
|
9
|
+
puts %([MockServer] #{env["PATH_INFO"]} was #{interception}"\n)
|
10
|
+
end
|
11
|
+
|
12
|
+
def matchable_request?(env)
|
13
|
+
@options[:routes] and lazy_match @options[:routes], env["PATH_INFO"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def lazy_match(strings, path)
|
17
|
+
regexps = strings.map { |str|
|
18
|
+
escaped = Regexp.escape(str)
|
19
|
+
escaped.gsub!('\\*\\*', '[\w|.|\-|\/]+')
|
20
|
+
escaped.gsub!('\\*', '[\w|.|\-]+')
|
21
|
+
Regexp.new("^#{escaped}$")
|
22
|
+
}
|
23
|
+
|
24
|
+
regexps.any? { |regex| regex.match(path) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def hashified_request
|
28
|
+
#rewind to ensure we read from the start
|
29
|
+
@request.body.rewind
|
30
|
+
|
31
|
+
#read body
|
32
|
+
body = @request.body.read
|
33
|
+
|
34
|
+
#rewind in case upstream expects it rewound
|
35
|
+
@request.body.rewind
|
36
|
+
|
37
|
+
json = JSON.parse(body) rescue body
|
38
|
+
|
39
|
+
{
|
40
|
+
:method => @request.request_method,
|
41
|
+
:path => @request.path,
|
42
|
+
:query => @request.query_string,
|
43
|
+
:body => json
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def hashify_response(status, header, response)
|
48
|
+
{
|
49
|
+
:method => @request.request_method,
|
50
|
+
:path => @request.path,
|
51
|
+
:status => status,
|
52
|
+
:headers => header,
|
53
|
+
:body => if response.respond_to? :body
|
54
|
+
response.body
|
55
|
+
else
|
56
|
+
response.join
|
57
|
+
end
|
58
|
+
}
|
58
59
|
end
|
59
60
|
end
|