mirage-on-thin 3.0.8

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.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/.simplecov +6 -0
  5. data/.travis.yml +3 -0
  6. data/Gemfile +29 -0
  7. data/Gemfile.lock +151 -0
  8. data/HISTORY +22 -0
  9. data/README.md +156 -0
  10. data/Rakefile +10 -0
  11. data/VERSION +1 -0
  12. data/bin/mirage +14 -0
  13. data/features/.nav +29 -0
  14. data/features/client/clear.feature +78 -0
  15. data/features/client/configure.feature +72 -0
  16. data/features/client/model.feature +95 -0
  17. data/features/client/preview_responses.feature +33 -0
  18. data/features/client/prime.feature +32 -0
  19. data/features/client/put.feature +111 -0
  20. data/features/client/readme.md +3 -0
  21. data/features/client/requests.feature +20 -0
  22. data/features/client/running.feature +51 -0
  23. data/features/client/save_and_revert.feature +39 -0
  24. data/features/client/start.feature +46 -0
  25. data/features/client/stop.feature +53 -0
  26. data/features/commandline_interface/help.feature +17 -0
  27. data/features/commandline_interface/readme.md +1 -0
  28. data/features/commandline_interface/start.feature +18 -0
  29. data/features/commandline_interface/stop.feature +42 -0
  30. data/features/logging.feature +6 -0
  31. data/features/prime.feature +35 -0
  32. data/features/readme.md +7 -0
  33. data/features/requests/delete.feature +48 -0
  34. data/features/requests/get.feature +36 -0
  35. data/features/save_and_revert.feature +35 -0
  36. data/features/step_definitions/my_steps.rb +98 -0
  37. data/features/step_definitions/observation_steps.rb +103 -0
  38. data/features/support/command_line.rb +33 -0
  39. data/features/support/env.rb +22 -0
  40. data/features/support/hooks.rb +26 -0
  41. data/features/support/mirage.rb +12 -0
  42. data/features/support/web.rb +20 -0
  43. data/features/templates/delete.feature +45 -0
  44. data/features/templates/get.feature +54 -0
  45. data/features/templates/path_wildcards.feature +10 -0
  46. data/features/templates/preview.feature +18 -0
  47. data/features/templates/put.feature +77 -0
  48. data/features/templates/put_with_substitutions.feature +22 -0
  49. data/features/templates/readme.md +4 -0
  50. data/features/templates/required_content.feature +113 -0
  51. data/features/web_user_interface.feature +44 -0
  52. data/full_build.sh +100 -0
  53. data/lib/mirage/client.rb +10 -0
  54. data/lib/mirage/client/cli_bridge.rb +30 -0
  55. data/lib/mirage/client/client.rb +73 -0
  56. data/lib/mirage/client/error.rb +22 -0
  57. data/lib/mirage/client/helpers/method_builder.rb +19 -0
  58. data/lib/mirage/client/request.rb +26 -0
  59. data/lib/mirage/client/requests.rb +13 -0
  60. data/lib/mirage/client/runner.rb +103 -0
  61. data/lib/mirage/client/template.rb +56 -0
  62. data/lib/mirage/client/template/configuration.rb +44 -0
  63. data/lib/mirage/client/template/model.rb +48 -0
  64. data/lib/mirage/client/template/model/common_methods.rb +24 -0
  65. data/lib/mirage/client/template/model/instance_methods.rb +95 -0
  66. data/lib/mirage/client/templates.rb +50 -0
  67. data/mirage-on-thin.gemspec +175 -0
  68. data/mirage_server.rb +35 -0
  69. data/server/app.rb +4 -0
  70. data/server/binary_data_checker.rb +15 -0
  71. data/server/extensions/hash.rb +10 -0
  72. data/server/extensions/object.rb +5 -0
  73. data/server/helpers.rb +3 -0
  74. data/server/helpers/http_headers.rb +31 -0
  75. data/server/helpers/template_requirements.rb +33 -0
  76. data/server/mock_response.rb +242 -0
  77. data/server/server.rb +184 -0
  78. data/spec/client/cli_bridge_spec.rb +63 -0
  79. data/spec/client/client_spec.rb +179 -0
  80. data/spec/client/helpers/method_builder_spec.rb +40 -0
  81. data/spec/client/request_spec.rb +39 -0
  82. data/spec/client/requests_spec.rb +9 -0
  83. data/spec/client/runner_spec.rb +138 -0
  84. data/spec/client/template/configuration_spec.rb +32 -0
  85. data/spec/client/template/model/common_methods_spec.rb +25 -0
  86. data/spec/client/template/model/instance_methods_spec.rb +169 -0
  87. data/spec/client/template/model_spec.rb +119 -0
  88. data/spec/client/template_spec.rb +146 -0
  89. data/spec/client/templates_spec.rb +197 -0
  90. data/spec/resources/binary.file +0 -0
  91. data/spec/server/binary_data_checker_spec.rb +21 -0
  92. data/spec/server/helpers/http_headers_spec.rb +20 -0
  93. data/spec/server/helpers/template_requirements_spec.rb +34 -0
  94. data/spec/server/mock_response_spec.rb +577 -0
  95. data/spec/server/server_spec.rb +156 -0
  96. data/spec/spec_helper.rb +85 -0
  97. data/tasks/application.rake +7 -0
  98. data/tasks/packaging.rake +28 -0
  99. data/tasks/tests.rake +25 -0
  100. data/views/index.haml +16 -0
  101. data/views/response.haml +46 -0
  102. metadata +337 -0
@@ -0,0 +1,50 @@
1
+ module Mirage
2
+ class Templates
3
+ include HTTParty
4
+
5
+ def initialize base_url
6
+ @url = "#{base_url}/templates"
7
+ @requests = Requests.new(base_url)
8
+ @default_config = Template::Configuration.new
9
+ end
10
+
11
+ def default_config &block
12
+ return @default_config unless block_given?
13
+ calling_instance = eval "self", block.binding
14
+ @default_config.caller_binding = calling_instance
15
+ @default_config.instance_eval &block
16
+ @default_config.caller_binding = nil
17
+ end
18
+
19
+ def delete_all
20
+ self.class.delete(@url)
21
+ @requests.delete_all
22
+ end
23
+
24
+ def put *args, &block
25
+ if args.first.class.is_a?(Template::Model)
26
+ template = args.first
27
+ template = template.clone
28
+ template.endpoint "#{@url}/#{template.endpoint}"
29
+ else
30
+
31
+ endpoint, template = args
32
+ if template.class.is_a?(Template::Model)
33
+ template = template.clone
34
+ template.endpoint "#{@url}/#{endpoint}"
35
+ else
36
+ template = Mirage::Template.new("#{@url}/#{endpoint}", template, @default_config)
37
+ end
38
+
39
+ end
40
+
41
+ if block
42
+ calling_instance = eval "self", block.binding
43
+ template.caller_binding = calling_instance
44
+ template.instance_exec(template, &block)
45
+ template.caller_binding = nil
46
+ end
47
+ template.create
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,175 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "mirage-on-thin"
8
+ s.version = "3.0.8"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Leon Davis"]
12
+ s.date = "2014-11-18"
13
+ s.description = "Mirage aids testing of your applications by hosting mock responses so that your applications do not have to talk to real endpoints. Its accessible via HTTP and has a RESTful interface."
14
+ s.executables = ["mirage"]
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".ruby-gemset",
20
+ ".ruby-version",
21
+ ".simplecov",
22
+ ".travis.yml",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "HISTORY",
26
+ "README.md",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "bin/mirage",
30
+ "features/.nav",
31
+ "features/client/clear.feature",
32
+ "features/client/configure.feature",
33
+ "features/client/model.feature",
34
+ "features/client/preview_responses.feature",
35
+ "features/client/prime.feature",
36
+ "features/client/put.feature",
37
+ "features/client/readme.md",
38
+ "features/client/requests.feature",
39
+ "features/client/running.feature",
40
+ "features/client/save_and_revert.feature",
41
+ "features/client/start.feature",
42
+ "features/client/stop.feature",
43
+ "features/commandline_interface/help.feature",
44
+ "features/commandline_interface/readme.md",
45
+ "features/commandline_interface/start.feature",
46
+ "features/commandline_interface/stop.feature",
47
+ "features/logging.feature",
48
+ "features/prime.feature",
49
+ "features/readme.md",
50
+ "features/requests/delete.feature",
51
+ "features/requests/get.feature",
52
+ "features/save_and_revert.feature",
53
+ "features/step_definitions/my_steps.rb",
54
+ "features/step_definitions/observation_steps.rb",
55
+ "features/support/command_line.rb",
56
+ "features/support/env.rb",
57
+ "features/support/hooks.rb",
58
+ "features/support/mirage.rb",
59
+ "features/support/web.rb",
60
+ "features/templates/delete.feature",
61
+ "features/templates/get.feature",
62
+ "features/templates/path_wildcards.feature",
63
+ "features/templates/preview.feature",
64
+ "features/templates/put.feature",
65
+ "features/templates/put_with_substitutions.feature",
66
+ "features/templates/readme.md",
67
+ "features/templates/required_content.feature",
68
+ "features/web_user_interface.feature",
69
+ "full_build.sh",
70
+ "lib/mirage/client.rb",
71
+ "lib/mirage/client/cli_bridge.rb",
72
+ "lib/mirage/client/client.rb",
73
+ "lib/mirage/client/error.rb",
74
+ "lib/mirage/client/helpers/method_builder.rb",
75
+ "lib/mirage/client/request.rb",
76
+ "lib/mirage/client/requests.rb",
77
+ "lib/mirage/client/runner.rb",
78
+ "lib/mirage/client/template.rb",
79
+ "lib/mirage/client/template/configuration.rb",
80
+ "lib/mirage/client/template/model.rb",
81
+ "lib/mirage/client/template/model/common_methods.rb",
82
+ "lib/mirage/client/template/model/instance_methods.rb",
83
+ "lib/mirage/client/templates.rb",
84
+ "mirage-on-thin.gemspec",
85
+ "mirage_server.rb",
86
+ "server/app.rb",
87
+ "server/binary_data_checker.rb",
88
+ "server/extensions/hash.rb",
89
+ "server/extensions/object.rb",
90
+ "server/helpers.rb",
91
+ "server/helpers/http_headers.rb",
92
+ "server/helpers/template_requirements.rb",
93
+ "server/mock_response.rb",
94
+ "server/server.rb",
95
+ "spec/client/cli_bridge_spec.rb",
96
+ "spec/client/client_spec.rb",
97
+ "spec/client/helpers/method_builder_spec.rb",
98
+ "spec/client/request_spec.rb",
99
+ "spec/client/requests_spec.rb",
100
+ "spec/client/runner_spec.rb",
101
+ "spec/client/template/configuration_spec.rb",
102
+ "spec/client/template/model/common_methods_spec.rb",
103
+ "spec/client/template/model/instance_methods_spec.rb",
104
+ "spec/client/template/model_spec.rb",
105
+ "spec/client/template_spec.rb",
106
+ "spec/client/templates_spec.rb",
107
+ "spec/resources/binary.file",
108
+ "spec/server/binary_data_checker_spec.rb",
109
+ "spec/server/helpers/http_headers_spec.rb",
110
+ "spec/server/helpers/template_requirements_spec.rb",
111
+ "spec/server/mock_response_spec.rb",
112
+ "spec/server/server_spec.rb",
113
+ "spec/spec_helper.rb",
114
+ "tasks/application.rake",
115
+ "tasks/packaging.rake",
116
+ "tasks/tests.rake",
117
+ "views/index.haml",
118
+ "views/response.haml"
119
+ ]
120
+ s.homepage = "https://github.com/lashd/mirage"
121
+ s.licenses = ["MIT"]
122
+ s.post_install_message = "\n===============================================================================\nMirage v3:\n\nMirage has just gone up a major version from 2 to 3. If your project uses\na previous version take a look at https://github.com/lashd/mirage to see\nwhat's changed\n===============================================================================\n"
123
+ s.require_paths = ["lib"]
124
+ s.rubygems_version = "2.0.14"
125
+ s.summary = "Mirage is a easy mock server for testing your applications"
126
+
127
+ if s.respond_to? :specification_version then
128
+ s.specification_version = 4
129
+
130
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
131
+ s.add_runtime_dependency(%q<sinatra>, [">= 0"])
132
+ s.add_runtime_dependency(%q<thin>, [">= 0"])
133
+ s.add_runtime_dependency(%q<childprocess>, [">= 0"])
134
+ s.add_runtime_dependency(%q<waitforit>, [">= 0"])
135
+ s.add_runtime_dependency(%q<thor>, [">= 0"])
136
+ s.add_runtime_dependency(%q<ptools>, [">= 0"])
137
+ s.add_runtime_dependency(%q<httparty>, [">= 0"])
138
+ s.add_runtime_dependency(%q<haml>, [">= 0"])
139
+ s.add_runtime_dependency(%q<hashie>, [">= 0"])
140
+ s.add_development_dependency(%q<rake>, [">= 0"])
141
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
142
+ s.add_development_dependency(%q<sinatra-contrib>, [">= 0"])
143
+ s.add_development_dependency(%q<jruby-openssl>, [">= 0"])
144
+ else
145
+ s.add_dependency(%q<sinatra>, [">= 0"])
146
+ s.add_dependency(%q<thin>, [">= 0"])
147
+ s.add_dependency(%q<childprocess>, [">= 0"])
148
+ s.add_dependency(%q<waitforit>, [">= 0"])
149
+ s.add_dependency(%q<thor>, [">= 0"])
150
+ s.add_dependency(%q<ptools>, [">= 0"])
151
+ s.add_dependency(%q<httparty>, [">= 0"])
152
+ s.add_dependency(%q<haml>, [">= 0"])
153
+ s.add_dependency(%q<hashie>, [">= 0"])
154
+ s.add_dependency(%q<rake>, [">= 0"])
155
+ s.add_dependency(%q<jeweler>, [">= 0"])
156
+ s.add_dependency(%q<sinatra-contrib>, [">= 0"])
157
+ s.add_dependency(%q<jruby-openssl>, [">= 0"])
158
+ end
159
+ else
160
+ s.add_dependency(%q<sinatra>, [">= 0"])
161
+ s.add_dependency(%q<thin>, [">= 0"])
162
+ s.add_dependency(%q<childprocess>, [">= 0"])
163
+ s.add_dependency(%q<waitforit>, [">= 0"])
164
+ s.add_dependency(%q<thor>, [">= 0"])
165
+ s.add_dependency(%q<ptools>, [">= 0"])
166
+ s.add_dependency(%q<httparty>, [">= 0"])
167
+ s.add_dependency(%q<haml>, [">= 0"])
168
+ s.add_dependency(%q<hashie>, [">= 0"])
169
+ s.add_dependency(%q<rake>, [">= 0"])
170
+ s.add_dependency(%q<jeweler>, [">= 0"])
171
+ s.add_dependency(%q<sinatra-contrib>, [">= 0"])
172
+ s.add_dependency(%q<jruby-openssl>, [">= 0"])
173
+ end
174
+ end
175
+
data/mirage_server.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ ROOT_DIR = File.dirname(__FILE__)
3
+ $LOAD_PATH.unshift("#{ROOT_DIR}/lib")
4
+ $LOAD_PATH.unshift("#{ROOT_DIR}/server")
5
+
6
+ require 'sinatra/base'
7
+ require 'extensions/object'
8
+ require 'app'
9
+ require 'extensions/hash'
10
+ require 'mirage/client'
11
+
12
+ module Mirage
13
+ class Server < Sinatra::Base
14
+ configure do
15
+ options = Hash[*ARGV]
16
+ set :defaults, options["defaults"]
17
+ set :port, options["port"]
18
+ $0="Mirage Server port #{settings.port}"
19
+ set :show_exceptions, false
20
+ set :logging, true
21
+ set :dump_errors, true
22
+ set :server, 'thin'
23
+ set :views, "#{ROOT_DIR}/views"
24
+ set :bind, '0.0.0.0'
25
+
26
+ log_file = File.open('mirage.log', 'a')
27
+ log_file.sync=true
28
+ use Rack::CommonLogger, log_file
29
+ enable :logging
30
+ end
31
+ end
32
+ end
33
+
34
+
35
+ Mirage::Server.run! :server => 'thin'
data/server/app.rb ADDED
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ require 'sinatra'
3
+ require 'mock_response'
4
+ require 'server'
@@ -0,0 +1,15 @@
1
+ require 'ptools'
2
+ module Mirage
3
+ module BinaryDataChecker
4
+ class << self
5
+ def contains_binary_data? string
6
+ tmpfile = Tempfile.new("binary_check")
7
+ tmpfile.write(string)
8
+ tmpfile.close
9
+ binary = File.binary?(tmpfile.path)
10
+ FileUtils.rm(tmpfile.path)
11
+ binary
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ class Hash
2
+ alias_method :backup, :[]
3
+
4
+ def [] desired_key
5
+ result = backup(desired_key)
6
+ return result unless result.nil?
7
+ key, value = find{|key, value| key.is_a?(Regexp) && desired_key.is_a?(String) && key.match(desired_key) }
8
+ value
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ class Object
2
+ def deep_clone
3
+ Marshal.load(Marshal.dump(self))
4
+ end
5
+ end
data/server/helpers.rb ADDED
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ require 'helpers/template_requirements'
3
+ require 'helpers/http_headers'
@@ -0,0 +1,31 @@
1
+ require 'rack/utils'
2
+ require 'sinatra/base'
3
+ module Mirage
4
+ class Server < Sinatra::Base
5
+ module Helpers
6
+ module HttpHeaders
7
+ HTTP_HEADER_FILTER_EXCEPTIONS = %w(CONTENT_TYPE CONTENT_LENGTH)
8
+ def extract_http_headers(env)
9
+ headers = env.reject do |k, v|
10
+ !HTTP_HEADER_FILTER_EXCEPTIONS.include?(k.to_s.upcase) && (!(/^HTTP_[A-Z_]+$/ === k) || v.nil?)
11
+ end.map do |k, v|
12
+ [reconstruct_header_name(k), v]
13
+ end.inject(Rack::Utils::HeaderHash.new) do |hash, k_v|
14
+ k, v = k_v
15
+ hash[k] = v
16
+ hash
17
+ end
18
+
19
+ x_forwarded_for = (headers["X-Forwarded-For"].to_s.split(/, +/) << env["REMOTE_ADDR"]).join(", ")
20
+
21
+ headers.merge!("X-Forwarded-For" => x_forwarded_for)
22
+ end
23
+
24
+ def reconstruct_header_name(name)
25
+ name.sub(/^HTTP_/, "").gsub("_", "-")
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,33 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ require 'tempfile'
3
+ require 'ptools'
4
+ require 'sinatra/base'
5
+ require 'helpers/http_headers'
6
+
7
+ module Mirage
8
+ class Server < Sinatra::Base
9
+ module Helpers
10
+ module TemplateRequirements
11
+ def convert_raw_required_params raw_requirements
12
+ raw_requirements.collect { |requirement| requirement.split(":") }.inject({}) do |hash, pair|
13
+ parameter, value = pair.collect { |string| string.strip }
14
+ value = convert_value(value)
15
+ hash[parameter] =value; hash
16
+ end
17
+ end
18
+
19
+ def convert_raw_required_body_content_requirements raw_requirements
20
+ raw_requirements.collect do |string|
21
+ string.start_with?("%r{") && string.end_with?("}") ? eval(string) : string
22
+ end
23
+ end
24
+
25
+
26
+ private
27
+ def convert_value(value)
28
+ value.start_with?("%r{") && value.end_with?("}") ? eval(value) : value
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,242 @@
1
+ require 'binary_data_checker'
2
+
3
+ require 'hashie/mash'
4
+ module Mirage
5
+ class ServerResponseNotFound < Exception
6
+
7
+ end
8
+
9
+ class MalformedResponse < Exception
10
+
11
+ end
12
+
13
+ class MockResponse
14
+ class << self
15
+
16
+ def find_by_id(id)
17
+ all.find { |response| response.response_id == id } || raise(ServerResponseNotFound)
18
+ end
19
+
20
+ def delete(id)
21
+ responses.values.each do |set|
22
+ set.values.each { |responses| responses.delete_if { |response| response.response_id == id } }
23
+ end
24
+ end
25
+
26
+ def delete_all
27
+ responses.clear
28
+ @next_id = 0
29
+ end
30
+
31
+ #TODO - this is flakey, make a proper copy
32
+ def backup
33
+ snapshot.clear and snapshot.replace(responses.deep_clone)
34
+ end
35
+
36
+ def revert
37
+ delete_all and responses.replace(snapshot.deep_clone)
38
+ end
39
+
40
+ def all
41
+ responses.values.collect do |response_set|
42
+ response_set.values
43
+ end.flatten
44
+ end
45
+
46
+ def find_default(options)
47
+ options[:http_method].upcase!
48
+ http_method = options[:http_method]
49
+ default_responses = subdomains(options[:endpoint]).collect do |domain|
50
+ if (responses_for_domain = responses[domain])
51
+ responses_for_domain[http_method].find_all { |response| response.default? } if responses_for_domain[http_method]
52
+ end
53
+ end.flatten.compact
54
+
55
+ default_responses.find { |response| match?(options, response) } || raise(ServerResponseNotFound)
56
+ end
57
+
58
+ def subdomains(name)
59
+ domains=[]
60
+ name.split("/").each do |part|
61
+ domains << (domains.last ? "#{domains.last}/#{part}" : part)
62
+ end
63
+ domains.reverse
64
+ end
65
+
66
+ def find(options)
67
+ options[:response_set] = responses[options[:endpoint]]
68
+ find_in_response_set(options) || raise(ServerResponseNotFound)
69
+ end
70
+
71
+ def add(new_response)
72
+ response_set = responses_for_endpoint(new_response)
73
+ method_specific_responses = response_set[new_response.request_spec['http_method'].upcase]||=[]
74
+ duplicate_response_location = method_specific_responses.index { |response| response.request_spec == new_response.request_spec }
75
+ old_response = method_specific_responses.delete_at(duplicate_response_location) if duplicate_response_location
76
+ if old_response
77
+ new_response.response_id = old_response.response_id
78
+ else
79
+ new_response.response_id = next_id
80
+ end
81
+ method_specific_responses<<new_response
82
+ end
83
+
84
+ private
85
+ def find_in_response_set(options)
86
+ response_set = options.delete(:response_set)
87
+ return unless response_set
88
+
89
+ responses_for_http_method = response_set[options[:http_method].upcase] || []
90
+
91
+ responses = responses_for_http_method.find_all do |stored_response|
92
+ match?(options, stored_response)
93
+ end
94
+
95
+ responses.sort { |a, b| b.score <=> a.score }.first
96
+
97
+ end
98
+
99
+ def match?(options, stored_response)
100
+ parameters = options[:params]
101
+ headers = Hash[options[:headers].collect { |key, value| [key.downcase, value] }]
102
+
103
+ request_spec = stored_response.request_spec
104
+
105
+ match = true
106
+
107
+ {request_spec['parameters'] => parameters,
108
+ request_spec['headers'] => headers}.each do |spec, actual|
109
+ spec.each do |key, value|
110
+ value = interpret_value(value)
111
+ if value.is_a? Regexp
112
+ match = false unless value.match(actual[key])
113
+ else
114
+ match = false unless value == actual[key]
115
+ end
116
+ end
117
+ end
118
+
119
+ request_spec['body_content'].each do |value|
120
+ value = interpret_value(value)
121
+ if value.is_a? Regexp
122
+ match = false unless options[:body] =~ value
123
+ else
124
+ match = false unless options[:body].include?(value)
125
+ end
126
+ end
127
+
128
+ match
129
+ end
130
+
131
+ def interpret_value(value)
132
+ value.start_with?("%r{") && value.end_with?("}") ? eval(value) : value
133
+ end
134
+
135
+ def responses_for_endpoint(response)
136
+ name = response.name
137
+ name = %r{#{name.gsub('*', '.*')}} if name =~ /\*/
138
+ responses[name]||={}
139
+ end
140
+
141
+ def responses
142
+ @responses ||={}
143
+ end
144
+
145
+ def snapshot
146
+ @snapshot ||={}
147
+ end
148
+
149
+ def next_id
150
+ @next_id||= 0
151
+ @next_id+=1
152
+ end
153
+ end
154
+
155
+ attr_reader :name, :request_spec, :response_spec
156
+ attr_accessor :response_id, :requests_url
157
+
158
+ def initialize name, spec={}
159
+
160
+ request_defaults = JSON.parse({:parameters => {},
161
+ :body_content => [],
162
+ :http_method => 'get',
163
+ :headers => {}}.to_json)
164
+ response_defaults = JSON.parse({:default => false,
165
+ :body => Base64.encode64(''),
166
+ :delay => 0,
167
+ :content_type => "text/plain",
168
+ :status => 200}.to_json)
169
+
170
+ @name = name
171
+ @spec = spec
172
+
173
+ @request_spec = Hashie::Mash.new request_defaults.merge(spec['request']||{})
174
+ @response_spec = Hashie::Mash.new response_defaults.merge(spec['response']||{})
175
+
176
+ @request_spec['headers'] = Hash[@request_spec['headers'].collect { |key, value| [key.downcase, value.to_s] }]
177
+ @request_spec['parameters'] = Hash[@request_spec['parameters'].collect { |key, value| [key, value.to_s] }]
178
+ @request_spec['body_content'] = @request_spec['body_content'].collect { |value| value.to_s }
179
+ @binary = BinaryDataChecker.contains_binary_data? @response_spec['body']
180
+
181
+ MockResponse.add self
182
+ end
183
+
184
+ def headers
185
+ @response_spec['headers']
186
+ end
187
+
188
+ def default?
189
+ @response_spec["default"]
190
+ end
191
+
192
+ def score
193
+ [@request_spec['headers'].values, @request_spec['parameters'].values, @request_spec['body_content']].inject(0) do |score, matchers|
194
+ matchers.inject(score) { |matcher_score, value| interpret_value(value).is_a?(Regexp) ? matcher_score+=1 : matcher_score+=2 }
195
+ end
196
+ end
197
+
198
+ def value(request_body='', request_parameters={}, query_string='')
199
+ body = Base64.decode64(response_spec['body'])
200
+ return body if @binary
201
+
202
+ value = body.dup
203
+ value.scan(/\$\{([^\}]*)\}/).flatten.each do |pattern|
204
+
205
+ if (parameter_match = request_parameters[pattern])
206
+ value = value.gsub("${#{pattern}}", parameter_match)
207
+ end
208
+
209
+ [request_body, query_string].each do |string|
210
+ if (string_match = find_match(string, pattern))
211
+ value = value.gsub("${#{pattern}}", string_match)
212
+ end
213
+ end
214
+
215
+ end
216
+ value
217
+ end
218
+
219
+ def == response
220
+ response.is_a?(MockResponse) && @name == response.send(:eval, "@name") && @request_spec == response.send(:eval, "@request_spec") && @response_spec == response.send(:eval, "@response_spec")
221
+ end
222
+
223
+ def raw
224
+ {:id => response_id, :endpoint => @name, :requests_url => requests_url, :response => @response_spec, :request => @request_spec}.to_json
225
+ end
226
+
227
+ def binary?
228
+ @binary
229
+ end
230
+
231
+ private
232
+ def find_match(string, regex)
233
+ string.scan(/#{regex}/).flatten.first
234
+ end
235
+
236
+ def interpret_value(value)
237
+ value.start_with?("%r{") && value.end_with?("}") ? eval(value) : value
238
+ end
239
+
240
+
241
+ end
242
+ end