mock_server 0.4.2 → 0.4.3
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 +87 -85
- data/lib/mock_server/record.rb +40 -38
- data/lib/mock_server/spec/helpers.rb +2 -2
- data/lib/mock_server/state.rb +24 -22
- data/lib/mock_server/store/global.rb +14 -12
- data/lib/mock_server/utils.rb +57 -55
- metadata +1 -1
data/lib/mock_server/playback.rb
CHANGED
@@ -8,116 +8,118 @@ unless defined? MockServer::Store
|
|
8
8
|
require 'mock_server/store/global'
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
module MockServer
|
12
|
+
class Playback
|
13
|
+
include MockServer::Utils
|
14
|
+
include MockServer::Store
|
15
|
+
|
16
|
+
def initialize(app, opt = {})
|
17
|
+
@app = app
|
18
|
+
@options = mock_server_options_merge(opt)
|
19
|
+
end
|
14
20
|
|
15
|
-
|
16
|
-
|
17
|
-
@options = mock_server_options_merge(opt)
|
18
|
-
end
|
21
|
+
def call(env)
|
22
|
+
@options = self.mock_server_options_read
|
19
23
|
|
20
|
-
|
21
|
-
|
24
|
+
verbose(env) if @options[:verbose]
|
25
|
+
return @app.call(env) unless matchable_request?(env)
|
22
26
|
|
23
|
-
|
24
|
-
|
27
|
+
@request = Rack::Request.new(env)
|
28
|
+
@options[:requests_stack] << @request.path
|
29
|
+
@data = load_data
|
25
30
|
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
response = build_response
|
32
|
+
self.mock_server_options_write(@options)
|
33
|
+
response
|
34
|
+
end
|
29
35
|
|
30
|
-
|
31
|
-
self.mock_server_options_write(@options)
|
32
|
-
response
|
33
|
-
end
|
36
|
+
private
|
34
37
|
|
35
|
-
|
38
|
+
def build_response
|
39
|
+
if record = match_request
|
40
|
+
return_record(record)
|
41
|
+
else
|
42
|
+
return_error
|
43
|
+
end
|
44
|
+
end
|
36
45
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
46
|
+
def return_record(record)
|
47
|
+
@options[:success_stack] << @request.path
|
48
|
+
@options[:matcher_exceptions].clear
|
49
|
+
response = record[:response]
|
50
|
+
[response[:status], response[:headers], [response[:body]]]
|
42
51
|
end
|
43
|
-
end
|
44
52
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
53
|
+
def return_error
|
54
|
+
error = { @request.path => "Couldn't match #{@request.request_method} #{@request.path}" }
|
55
|
+
@options[:errors_stack] << error
|
56
|
+
[404, {}, ['RECORD NOT FOUND!']]
|
57
|
+
end
|
51
58
|
|
52
|
-
|
53
|
-
|
54
|
-
@options[:errors_stack] << error
|
55
|
-
[404, {}, ['RECORD NOT FOUND!']]
|
56
|
-
end
|
59
|
+
def match_request
|
60
|
+
request = Hashie::Mash.new hashified_request
|
57
61
|
|
58
|
-
|
59
|
-
|
62
|
+
# Filter out data records by path and method
|
63
|
+
records = filter_records(request)
|
60
64
|
|
61
|
-
|
62
|
-
records = filter_records(request)
|
65
|
+
matchers = filter_matchers(request)
|
63
66
|
|
64
|
-
|
67
|
+
record = false
|
68
|
+
matchers.detect { |matcher|
|
69
|
+
# Match the request with a record by validating against the matcher if any.
|
70
|
+
record = records.detect { |entry|
|
71
|
+
recorded_request = Hashie::Mash.new entry[:request]
|
72
|
+
recorded_response = entry[:response].dup
|
65
73
|
|
66
|
-
|
67
|
-
|
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
|
74
|
+
recorded_response[:body] = JSON.parse(recorded_response[:body]) rescue recorded_response[:body]
|
75
|
+
recorded_response = Hashie::Mash.new recorded_response
|
72
76
|
|
73
|
-
|
74
|
-
|
77
|
+
test_request_and_matcher(matcher, request, recorded_request, recorded_response)
|
78
|
+
}
|
79
|
+
}
|
80
|
+
record
|
81
|
+
end
|
75
82
|
|
76
|
-
|
83
|
+
def filter_matchers(request)
|
84
|
+
@options[:matchers].select { |match|
|
85
|
+
request[:method].to_s.upcase == match[:method].to_s.upcase and request[:path] == match[:path]
|
77
86
|
}
|
78
|
-
|
79
|
-
record
|
80
|
-
end
|
87
|
+
end
|
81
88
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
89
|
+
def filter_records(request)
|
90
|
+
@data.select { |record|
|
91
|
+
record[:request][:path] == request[:path] and record[:request][:method] == request[:method]
|
92
|
+
}
|
93
|
+
end
|
87
94
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
95
|
+
def test_request_and_matcher(matcher, request, recorded_request, recorded_response)
|
96
|
+
return true if matcher[:matcher].nil?
|
97
|
+
begin
|
98
|
+
matcher[:matcher].call(request, recorded_request, recorded_response) == true
|
99
|
+
rescue => matcher_err
|
100
|
+
store_matcher_exception(matcher_err)
|
101
|
+
false
|
102
|
+
end
|
103
|
+
end
|
93
104
|
|
94
|
-
|
95
|
-
|
96
|
-
begin
|
97
|
-
matcher[:matcher].call(request, recorded_request, recorded_response) == true
|
98
|
-
rescue => matcher_err
|
99
|
-
store_matcher_exception(matcher_err)
|
100
|
-
false
|
105
|
+
def store_matcher_exception(exception)
|
106
|
+
@options[:matcher_exceptions] << exception
|
101
107
|
end
|
102
|
-
end
|
103
108
|
|
104
|
-
|
105
|
-
|
106
|
-
end
|
109
|
+
def load_data
|
110
|
+
FileUtils.mkdir_p(@options[:path]) unless File.exists? @options[:path]
|
107
111
|
|
108
|
-
|
109
|
-
FileUtils.mkdir_p(@options[:path]) unless File.exists? @options[:path]
|
112
|
+
data = []
|
110
113
|
|
111
|
-
|
114
|
+
@options[:record_filenames].map do |filename|
|
115
|
+
file_path = File.join( @options[:path], filename + '.yml' )
|
116
|
+
content = File.open(file_path).read
|
117
|
+
compiled = ERB.new(content).result
|
118
|
+
parsed = YAML.load(compiled)
|
119
|
+
data += parsed
|
120
|
+
end
|
112
121
|
|
113
|
-
|
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
|
122
|
+
data
|
119
123
|
end
|
120
|
-
|
121
|
-
data
|
122
124
|
end
|
123
125
|
end
|
data/lib/mock_server/record.rb
CHANGED
@@ -5,59 +5,61 @@ unless defined? MockServer::Store
|
|
5
5
|
require 'mock_server/store/global'
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
module MockServer
|
9
|
+
class Record
|
10
|
+
include MockServer::Utils
|
11
|
+
include MockServer::Store
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
def initialize(app, opt = {})
|
14
|
+
@app = app
|
15
|
+
@options = mock_server_options_merge(opt)
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
def call(env)
|
19
|
+
@options = self.mock_server_options_read
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
verbose(env) if @options[:verbose]
|
22
|
+
return @app.call(env) unless matchable_request?(env)
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
@request = Rack::Request.new(env)
|
25
|
+
@data = load_data
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
@app.call(env).tap do |status, header, response|
|
28
|
+
record_response(status, header, response)
|
29
|
+
self.mock_server_options_write(@options)
|
30
|
+
response
|
31
|
+
end
|
30
32
|
end
|
31
|
-
end
|
32
33
|
|
33
|
-
|
34
|
+
private
|
34
35
|
|
35
|
-
|
36
|
-
|
36
|
+
def record_response(status, header, response)
|
37
|
+
request = hashified_request
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
@data << { :request => request, :response => hashify_response(status, header, response) }
|
40
|
+
save_data(@data)
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
def records_path
|
44
|
+
File.join( @options[:path], @options[:filename] + '.yml' )
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
def save_data(data)
|
48
|
+
File.open(records_path, 'w') do |f|
|
49
|
+
YAML.dump(data, f)
|
50
|
+
end
|
49
51
|
end
|
50
|
-
end
|
51
52
|
|
52
|
-
|
53
|
-
|
53
|
+
def load_data
|
54
|
+
FileUtils.mkdir_p(@options[:path]) unless File.exists? @options[:path]
|
54
55
|
|
55
|
-
|
56
|
+
data = YAML.load_file(records_path) rescue []
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
if data.is_a? Array
|
59
|
+
data
|
60
|
+
else
|
61
|
+
[]
|
62
|
+
end
|
61
63
|
end
|
62
64
|
end
|
63
65
|
end
|
@@ -2,7 +2,7 @@ unless defined? MockServer::Store
|
|
2
2
|
require 'mock_server/store/global'
|
3
3
|
end
|
4
4
|
|
5
|
-
module MockServer
|
5
|
+
module MockServer; module Spec
|
6
6
|
module Helpers
|
7
7
|
include MockServer::Store
|
8
8
|
|
@@ -298,4 +298,4 @@ module MockServer::Spec
|
|
298
298
|
end
|
299
299
|
|
300
300
|
end
|
301
|
-
end
|
301
|
+
end; end
|
data/lib/mock_server/state.rb
CHANGED
@@ -1,30 +1,32 @@
|
|
1
1
|
require 'hashie'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
module MockServer
|
4
|
+
class State < Hashie::Dash
|
5
|
+
property :path, :default => 'fixtures/records'
|
6
|
+
property :filename, :default => 'record'
|
7
|
+
property :routes, :default => []
|
8
|
+
property :record_filenames, :default => []
|
9
|
+
property :matchers, :default => []
|
10
|
+
property :verbose, :default => false
|
11
|
+
property :requests_stack, :default => []
|
12
|
+
property :success_stack, :default => []
|
13
|
+
property :errors_stack, :default => []
|
14
|
+
property :requests_stack, :default => []
|
15
|
+
property :matcher_exceptions, :default => []
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
def merge(hash)
|
18
|
+
new_hash = self
|
19
|
+
hash.each do |k,v|
|
20
|
+
new_hash[k] = v
|
21
|
+
end
|
22
|
+
new_hash
|
20
23
|
end
|
21
|
-
new_hash
|
22
|
-
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
def merge!(hash)
|
26
|
+
hash.each do |k,v|
|
27
|
+
self[k] = v
|
28
|
+
end
|
29
|
+
self
|
27
30
|
end
|
28
|
-
self
|
29
31
|
end
|
30
32
|
end
|
@@ -1,18 +1,20 @@
|
|
1
1
|
require 'hashie'
|
2
2
|
|
3
|
-
module MockServer
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module MockServer
|
4
|
+
module Store
|
5
|
+
def mock_server_options_merge(opt = {})
|
6
|
+
$mock_server_options ||= MockServer::State.new(opt)
|
7
|
+
$mock_server_options.merge!(opt)
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
def mock_server_options_read
|
11
|
+
$mock_server_options ||= MockServer::State.new
|
12
|
+
$mock_server_options
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
def mock_server_options_write(value)
|
16
|
+
$mock_server_options ||= MockServer::State.new
|
17
|
+
$mock_server_options = value
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
data/lib/mock_server/utils.rb
CHANGED
@@ -1,60 +1,62 @@
|
|
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
|
-
response.body
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
4
|
+
module MockServer
|
5
|
+
module Utils
|
6
|
+
private
|
7
|
+
|
8
|
+
def verbose(env)
|
9
|
+
interception = lazy_match(@options[:routes], env["PATH_INFO"]) ? "intercepted!" : "NOT intercepted."
|
10
|
+
puts %([MockServer] #{env["PATH_INFO"]} was #{interception}"\n)
|
11
|
+
end
|
12
|
+
|
13
|
+
def matchable_request?(env)
|
14
|
+
@options[:routes] and lazy_match @options[:routes], env["PATH_INFO"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def lazy_match(strings, path)
|
18
|
+
regexps = strings.map { |str|
|
19
|
+
escaped = Regexp.escape(str)
|
20
|
+
escaped.gsub!('\\*\\*', '[\w|.|\-|\/]+')
|
21
|
+
escaped.gsub!('\\*', '[\w|.|\-]+')
|
22
|
+
Regexp.new("^#{escaped}$")
|
23
|
+
}
|
24
|
+
|
25
|
+
regexps.any? { |regex| regex.match(path) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def hashified_request
|
29
|
+
#rewind to ensure we read from the start
|
30
|
+
@request.body.rewind
|
31
|
+
|
32
|
+
#read body
|
33
|
+
body = @request.body.read
|
34
|
+
|
35
|
+
#rewind in case upstream expects it rewound
|
36
|
+
@request.body.rewind
|
37
|
+
|
38
|
+
json = JSON.parse(body) rescue body
|
39
|
+
|
40
|
+
{
|
41
|
+
:method => @request.request_method,
|
42
|
+
:path => @request.path,
|
43
|
+
:query => @request.query_string,
|
44
|
+
:body => json
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def hashify_response(status, header, response)
|
49
|
+
{
|
50
|
+
:method => @request.request_method,
|
51
|
+
:path => @request.path,
|
52
|
+
:status => status,
|
53
|
+
:headers => header,
|
54
|
+
:body => if response.respond_to? :body
|
55
|
+
response.body
|
56
|
+
else
|
57
|
+
response.join
|
58
|
+
end
|
59
|
+
}
|
60
|
+
end
|
59
61
|
end
|
60
62
|
end
|