mock_server 0.4.1 → 0.4.2
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/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
|