mirage 2.2.3 → 2.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.
Files changed (36) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +11 -2
  3. data/HISTORY +1 -0
  4. data/VERSION +1 -1
  5. data/bin/mirage +6 -8
  6. data/features/client/clear.feature +8 -8
  7. data/features/client/{response.feature → preview_responses.feature} +0 -0
  8. data/features/client/put.feature +9 -1
  9. data/features/client/{request.feature → requests.feature} +0 -0
  10. data/features/client/running.feature +49 -0
  11. data/features/client/{command_line_interface.feature → start.feature} +0 -12
  12. data/features/client/stop.feature +85 -0
  13. data/features/server/commandline_interface/help.feature +16 -0
  14. data/features/server/commandline_interface/start.feature +30 -0
  15. data/features/server/commandline_interface/stop.feature +42 -0
  16. data/features/server/prime.feature +8 -7
  17. data/features/step_definitions/my_steps.rb +20 -16
  18. data/features/support/command_line.rb +22 -0
  19. data/features/support/env.rb +11 -121
  20. data/features/support/hooks.rb +30 -0
  21. data/features/support/mirage.rb +8 -0
  22. data/lib/mirage/client/client.rb +124 -0
  23. data/lib/mirage/client/error.rb +22 -0
  24. data/lib/mirage/client/response.rb +29 -0
  25. data/lib/mirage/client/runner.rb +142 -0
  26. data/lib/mirage/client.rb +4 -206
  27. data/mirage.gemspec +25 -8
  28. data/mirage_server.rb +15 -10
  29. data/rakefile +7 -1
  30. data/spec/running_via_api_spec.rb +147 -0
  31. data/spec/running_via_api_windows_spec.rb +187 -0
  32. data/test.rb +21 -4
  33. metadata +66 -33
  34. data/features/client/mirage_client.feature +0 -36
  35. data/features/server/command_line_iterface.feature +0 -45
  36. data/lib/mirage/cli.rb +0 -69
data/lib/mirage/client.rb CHANGED
@@ -1,208 +1,6 @@
1
1
  $LOAD_PATH.unshift "#{File.dirname(__FILE__)}"
2
- require 'uri'
3
- require 'waitforit'
4
- require 'childprocess'
5
2
  require 'client/web'
6
- require 'cli'
7
- require 'ostruct'
8
- require 'optparse'
9
-
10
- module Mirage
11
-
12
- class << self
13
-
14
- def start args={}
15
- puts "Starting Mirage"
16
- args = convert_to_command_line_argument_array(args) if args.is_a? Hash
17
-
18
- Mirage::CLI.run args
19
- mirage_client = Mirage::Client.new "http://localhost:#{Mirage::CLI.parse_options(args)[:port]}/mirage"
20
- wait_until(:timeout_after => 30.seconds) { mirage_client.running? }
21
-
22
- begin
23
- mirage_client.prime
24
- rescue Mirage::InternalServerException => e
25
- puts "WARN: #{e.message}"
26
- end
27
- mirage_client
28
- end
29
-
30
- def stop
31
- puts "Stopping Mirage"
32
- Mirage::CLI.stop
33
- end
34
-
35
- private
36
- def convert_to_command_line_argument_array(args)
37
- command_line_arguments = {}
38
- args.each do |key, value|
39
- command_line_arguments["--#{key}"] = "#{value}"
40
- end
41
- command_line_arguments.to_a.flatten
42
- end
43
- end
44
-
45
- class MirageError < ::Exception
46
- attr_reader :code
47
-
48
- def initialize message, code
49
- super message
50
- @code = message, code
51
- end
52
- end
53
-
54
- class Response < OpenStruct
55
-
56
- attr_accessor :content_type
57
- attr_reader :value
58
-
59
- def initialize response
60
- @content_type = 'text/plain'
61
- @value = response
62
- super({})
63
- end
64
-
65
- def headers
66
- headers = {}
67
-
68
- @table.each { |header, value| headers["X-mirage-#{header.to_s.gsub('_', '-')}"] = value }
69
- headers['Content-Type']=@content_type
70
- headers['X-mirage-file'] = 'true' if @response.kind_of?(IO)
71
-
72
- headers
73
- end
74
-
75
- end
76
-
77
- class InternalServerException < MirageError;
78
- end
79
-
80
- class ResponseNotFound < MirageError;
81
- end
82
-
83
- class Client
84
- include ::Mirage::Web
85
- attr_reader :url
86
-
87
- # Creates an instance of the MIrage client that can be used to interact with the Mirage Server
88
- #
89
- # Client.new => a client that is configured to connect to Mirage on http://localhost:7001/mirage (the default settings for Mirage)
90
- # Client.new(URL) => a client that is configured to connect to an instance of Mirage running on the specified url.
91
- def initialize url="http://localhost:7001/mirage"
92
- @url = url
93
- end
94
-
95
-
96
- # Set a text or file based response template, to be hosted at a given end point. A block can be specified to configure the template
97
- # Client.set(endpoint, response, &block) => unique id that can be used to call back to the server
98
- #
99
- # Examples:
100
- # Client.put('greeting', 'hello')
101
- #
102
- # Client.put('greeting', 'hello') do |response|
103
- # response.pattern = 'pattern' #regex or string literal applied against the request querystring and body
104
- # response.method = :post #By default templates will respond to get requests
105
- # response.content_type = 'text/html' #defaults text/plain
106
- # response.default = true # defaults to false. setting to true will allow this template to respond to request made to sub resources should it match.
107
- # end
108
- def put endpoint, response_value, &block
109
- response = Response.new response_value
110
-
111
- yield response if block_given?
112
-
113
- build_response(http_put("#{@url}/templates/#{endpoint}", response.value, response.headers))
114
- end
115
-
116
- # Use to look at what a response contains without actually triggering it.
117
- # client.response(response_id) => response held on the server as a String
118
- def response response_id
119
- response = build_response(http_get("#{@url}/templates/#{response_id}"))
120
- case response
121
- when String then
122
- return response
123
- when Mirage::Web::FileResponse then
124
- return response.response.body
125
- end
126
-
127
- end
128
-
129
- # Clear Content from Mirage
130
- #
131
- # If a response id is not valid, a ResponseNotFound exception will be thrown
132
- #
133
- # Examples:
134
- # Client.new.clear # clear all responses and associated requests
135
- # Client.new.clear(response_id) # Clear the response and tracked request for a given response id
136
- # Client.new.clear(:requests) # Clear all tracked request information
137
- # Client.new.clear(:request => response_id) # Clear the tracked request for a given response id
138
- def clear thing=nil
139
-
140
- case thing
141
- when :requests
142
- http_delete("#{@url}/requests")
143
- when Numeric then
144
- http_delete("#{@url}/templates/#{thing}")
145
- when Hash then
146
- puts "deleteing request #{thing[:request]}"
147
- http_delete("#{@url}/requests/#{thing[:request]}") if thing[:request]
148
- else
149
- NilClass
150
- http_delete("#{@url}/templates")
151
- end
152
-
153
- end
154
-
155
-
156
- # Retrieve the last request that triggered a response to be returned. If the request contained content in its body, this is returned. If the
157
- # request did not have any content in its body then what ever was in the request query string is returned instead
158
- #
159
- # Example:
160
- # Client.new.track(response_id) => Tracked request as a String
161
- def request response_id
162
- build_response(http_get("#{@url}/requests/#{response_id}"))
163
- end
164
-
165
- # Save the state of the Mirage server so that it can be reverted back to that exact state at a later time.
166
- def save
167
- http_put("#{@url}/backup", '').code == 200
168
- end
169
-
170
-
171
- # Revert the state of Mirage back to the state that was last saved
172
- # If there is no snapshot to rollback to, nothing happens
173
- def revert
174
- http_put("#{@url}", '').code == 200
175
- end
176
-
177
-
178
- # Check to see if Mirage is up and running
179
- def running?
180
- begin
181
- http_get(@url) and return true
182
- rescue Errno::ECONNREFUSED
183
- return false
184
- end
185
- end
186
-
187
- # Clear down the Mirage Server and load any defaults that are in Mirages default responses directory.
188
- def prime
189
- puts "#{@url}/defaults"
190
- build_response(http_put("#{@url}/defaults", ''))
191
- end
192
-
193
- private
194
- def build_response response
195
- case response.code.to_i
196
- when 500 then
197
- raise ::Mirage::InternalServerException.new(response.body, response.code.to_i)
198
- when 404 then
199
- raise ::Mirage::ResponseNotFound.new(response.body, response.code.to_i)
200
- else
201
- response.body
202
- end
203
- end
204
-
205
- end
206
-
207
-
208
- end
3
+ require 'client/error'
4
+ require 'client/runner'
5
+ require 'client/response'
6
+ require 'client/client'
data/mirage.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "mirage"
8
- s.version = "2.2.3"
8
+ s.version = "2.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Leon Davis"]
12
- s.date = "2012-07-15"
12
+ s.date = "2012-08-26"
13
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
14
  s.executables = ["mirage"]
15
15
  s.extra_rdoc_files = [
@@ -24,13 +24,16 @@ Gem::Specification.new do |s|
24
24
  "VERSION",
25
25
  "bin/mirage",
26
26
  "features/client/clear.feature",
27
- "features/client/command_line_interface.feature",
28
- "features/client/mirage_client.feature",
27
+ "features/client/preview_responses.feature",
29
28
  "features/client/put.feature",
30
- "features/client/request.feature",
31
- "features/client/response.feature",
29
+ "features/client/requests.feature",
30
+ "features/client/running.feature",
32
31
  "features/client/save_and_revert.feature",
33
- "features/server/command_line_iterface.feature",
32
+ "features/client/start.feature",
33
+ "features/client/stop.feature",
34
+ "features/server/commandline_interface/help.feature",
35
+ "features/server/commandline_interface/start.feature",
36
+ "features/server/commandline_interface/stop.feature",
34
37
  "features/server/logging.feature",
35
38
  "features/server/prime.feature",
36
39
  "features/server/requests/delete.feature",
@@ -45,10 +48,16 @@ Gem::Specification.new do |s|
45
48
  "features/server/templates/put/put_with_substitutions.feature",
46
49
  "features/server/web_user_interface.feature",
47
50
  "features/step_definitions/my_steps.rb",
51
+ "features/support/command_line.rb",
48
52
  "features/support/env.rb",
53
+ "features/support/hooks.rb",
54
+ "features/support/mirage.rb",
49
55
  "full_build.sh",
50
- "lib/mirage/cli.rb",
51
56
  "lib/mirage/client.rb",
57
+ "lib/mirage/client/client.rb",
58
+ "lib/mirage/client/error.rb",
59
+ "lib/mirage/client/response.rb",
60
+ "lib/mirage/client/runner.rb",
52
61
  "lib/mirage/client/web.rb",
53
62
  "mirage.gemspec",
54
63
  "mirage_server.rb",
@@ -57,6 +66,8 @@ Gem::Specification.new do |s|
57
66
  "server/extensions/hash.rb",
58
67
  "server/extensions/object.rb",
59
68
  "server/mock_response.rb",
69
+ "spec/running_via_api_spec.rb",
70
+ "spec/running_via_api_windows_spec.rb",
60
71
  "test.rb",
61
72
  "views/index.erb"
62
73
  ]
@@ -72,8 +83,10 @@ Gem::Specification.new do |s|
72
83
 
73
84
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
74
85
  s.add_runtime_dependency(%q<sinatra>, [">= 0"])
86
+ s.add_runtime_dependency(%q<eventmachine>, ["= 1.0.0.rc.4"])
75
87
  s.add_runtime_dependency(%q<childprocess>, [">= 0"])
76
88
  s.add_runtime_dependency(%q<waitforit>, [">= 0"])
89
+ s.add_runtime_dependency(%q<thor>, [">= 0"])
77
90
  s.add_development_dependency(%q<thin>, [">= 0"])
78
91
  s.add_development_dependency(%q<rake>, [">= 0"])
79
92
  s.add_development_dependency(%q<cucumber>, [">= 0"])
@@ -85,8 +98,10 @@ Gem::Specification.new do |s|
85
98
  s.add_development_dependency(%q<jruby-openssl>, [">= 0"])
86
99
  else
87
100
  s.add_dependency(%q<sinatra>, [">= 0"])
101
+ s.add_dependency(%q<eventmachine>, ["= 1.0.0.rc.4"])
88
102
  s.add_dependency(%q<childprocess>, [">= 0"])
89
103
  s.add_dependency(%q<waitforit>, [">= 0"])
104
+ s.add_dependency(%q<thor>, [">= 0"])
90
105
  s.add_dependency(%q<thin>, [">= 0"])
91
106
  s.add_dependency(%q<rake>, [">= 0"])
92
107
  s.add_dependency(%q<cucumber>, [">= 0"])
@@ -99,8 +114,10 @@ Gem::Specification.new do |s|
99
114
  end
100
115
  else
101
116
  s.add_dependency(%q<sinatra>, [">= 0"])
117
+ s.add_dependency(%q<eventmachine>, ["= 1.0.0.rc.4"])
102
118
  s.add_dependency(%q<childprocess>, [">= 0"])
103
119
  s.add_dependency(%q<waitforit>, [">= 0"])
120
+ s.add_dependency(%q<thor>, [">= 0"])
104
121
  s.add_dependency(%q<thin>, [">= 0"])
105
122
  s.add_dependency(%q<rake>, [">= 0"])
106
123
  s.add_dependency(%q<cucumber>, [">= 0"])
data/mirage_server.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'rubygems'
2
- $0='Mirage Server'
3
2
  ROOT_DIR = File.dirname(__FILE__)
4
3
  $LOAD_PATH.unshift("#{ROOT_DIR}/lib")
5
4
  $LOAD_PATH.unshift("#{ROOT_DIR}/server")
@@ -17,9 +16,10 @@ module Mirage
17
16
  class Server < Sinatra::Base
18
17
 
19
18
  configure do
20
- options = Mirage::CLI.parse_options(ARGV)
21
- set :defaults, options[:defaults]
22
- set :port, options[:port]
19
+ options = Hash[*ARGV]
20
+ set :defaults, options["defaults"]
21
+ set :port, options["port"]
22
+ $0="Mirage Server port #{settings.port}"
23
23
  set :show_exceptions, false
24
24
  set :logging, true
25
25
  set :dump_errors, true
@@ -109,12 +109,13 @@ module Mirage
109
109
 
110
110
  put '/mirage/defaults' do
111
111
  MockResponse.delete_all
112
-
113
- Dir["#{settings.defaults}/**/*.rb"].each do |default|
114
- begin
115
- eval File.read(default)
116
- rescue Exception => e
117
- raise "Unable to load default responses from: #{default}"
112
+ if File.directory?(settings.defaults.to_s)
113
+ Dir["#{settings.defaults}/**/*.rb"].each do |default|
114
+ begin
115
+ eval File.read(default)
116
+ rescue Exception => e
117
+ raise "Unable to load default responses from: #{default}"
118
+ end
118
119
  end
119
120
  end
120
121
  200
@@ -131,6 +132,10 @@ module Mirage
131
132
  200
132
133
  end
133
134
 
135
+ get '/mirage/pid' do
136
+ "#{$$}"
137
+ end
138
+
134
139
  error ServerResponseNotFound do
135
140
  404
136
141
  end
data/rakefile CHANGED
@@ -1,6 +1,7 @@
1
1
  $LOAD_PATH.unshift('lib')
2
2
  require 'rubygems'
3
3
  require 'bundler'
4
+
4
5
  begin
5
6
  Bundler.setup(:default, :development)
6
7
  rescue Bundler::BundlerError => e
@@ -10,6 +11,9 @@ rescue Bundler::BundlerError => e
10
11
  end
11
12
 
12
13
  require 'rake'
14
+ require 'rspec/core/rake_task'
15
+
16
+ RSpec::Core::RakeTask.new
13
17
 
14
18
  require 'jeweler'
15
19
  Jeweler::Tasks.new do |gem|
@@ -59,4 +63,6 @@ task :stop do
59
63
  end
60
64
 
61
65
 
62
- task :default => [:install,:features,:clean]
66
+
67
+
68
+ task :default => [:spec, :install,:features,:clean]
@@ -0,0 +1,147 @@
1
+ $LOAD_PATH.unshift "../lib"
2
+ require 'rspec'
3
+ require 'mirage/client'
4
+
5
+ def process_string_for_mirage(mirage_port, pid)
6
+ "team #{pid} 6.2 0.4 84328 20760 pts/1 Sl 22:15 0:00 Mirage Server port #{mirage_port}"
7
+ end
8
+
9
+ include Mirage
10
+
11
+ unless ChildProcess.windows?
12
+ describe Mirage do
13
+
14
+ describe 'starting' do
15
+ before(:each) do
16
+ @runner = mock
17
+ Runner.should_receive(:new).and_return(@runner)
18
+ end
19
+
20
+ it 'should start Mirage on port 7001 by default' do
21
+ @runner.should_receive(:invoke).with(:start, [], {:port => 7001})
22
+ Mirage.start
23
+ end
24
+
25
+ it 'should start mirage on the given port' do
26
+ options = {:port => 9001}
27
+ @runner.should_receive(:invoke).with(:start, [], options)
28
+ Mirage.start options
29
+ end
30
+ end
31
+
32
+ describe 'stopping' do
33
+ before(:each) do
34
+ @runner = mock
35
+ Runner.stub(:new).and_return(@runner)
36
+ end
37
+
38
+ it 'should supply single port argument in an array to the runner' do
39
+ port = 7001
40
+ @runner.should_receive(:invoke).with(:stop, [], :port => [port])
41
+ @runner.should_receive(:invoke).with(:stop, [], :port => [:all])
42
+ Mirage.stop(:port => port)
43
+ Mirage.stop(:all)
44
+ end
45
+
46
+ it 'should stop multiple instances of Mirage' do
47
+ ports = 7001, 7002
48
+ @runner.should_receive(:invoke).with(:stop, [], :port => ports)
49
+ Mirage.stop(:port => ports)
50
+ end
51
+
52
+ end
53
+
54
+ describe Mirage::Runner do
55
+ it 'should stop the running instance of Mirage' do
56
+ IO.should_receive(:popen).with(/ps aux.*/).any_number_of_times.and_return(process_string_for_mirage(7001, 18903))
57
+
58
+ IO.should_receive(:popen).with("kill -9 18903") do
59
+ IO.rspec_reset
60
+ IO.stub(:popen).and_return("")
61
+ end
62
+ Mirage::Runner.new.stop
63
+ end
64
+
65
+ it 'should not stop any instances when more than one is running' do
66
+ ps_aux_output =<<PS
67
+ #{process_string_for_mirage(7001, 18901)}
68
+ #{process_string_for_mirage(7002, 18902)}
69
+ #{process_string_for_mirage(7003, 18903)}
70
+ PS
71
+ IO.should_receive(:popen).with(/ps aux.*/).any_number_of_times.and_return(ps_aux_output)
72
+ IO.should_not_receive(:popen).with(/kill.*/)
73
+
74
+ lambda { Mirage::Runner.new.stop }.should raise_error(Mirage::ClientError)
75
+
76
+ end
77
+
78
+
79
+ it 'should stop the instance running on the given port' do
80
+ ps_aux_output =<<PS
81
+ #{process_string_for_mirage(7001, 18901)}
82
+ #{process_string_for_mirage(7002, 18902)}
83
+ PS
84
+ IO.should_receive(:popen).with(/ps aux.*/).any_number_of_times.and_return(ps_aux_output)
85
+ IO.should_receive(:popen).with(/kill -9 18901/) do
86
+ IO.rspec_reset
87
+ IO.stub(:popen).and_return(process_string_for_mirage(7002, 18902))
88
+ end
89
+
90
+ Mirage::Runner.new.invoke(:stop, [], {:port => [7001]})
91
+ end
92
+
93
+ it 'should stop the instance running on the given ports' do
94
+ ps_aux_output =<<PS
95
+ #{process_string_for_mirage(7001, 18901)}
96
+ #{process_string_for_mirage(7002, 18902)}
97
+ #{process_string_for_mirage(7003, 18903)}
98
+ PS
99
+ IO.should_receive(:popen).with(/ps aux.*/).any_number_of_times.and_return(ps_aux_output)
100
+ IO.should_receive(:popen).with(/kill -9 18901/)
101
+ IO.should_receive(:popen).with(/kill -9 18902/) do
102
+ IO.rspec_reset
103
+ IO.stub(:popen).and_return(process_string_for_mirage("7003", 18903))
104
+ end
105
+
106
+ Mirage::Runner.new.invoke(:stop, [], {:port => [7001, 7002]})
107
+ end
108
+
109
+ it 'should stop all running instances' do
110
+ ps_aux_output =<<PS
111
+ #{process_string_for_mirage(7001, 18901)}
112
+ #{process_string_for_mirage(7002, 18902)}
113
+ #{process_string_for_mirage(7003, 18903)}
114
+ PS
115
+ IO.should_receive(:popen).with(/ps aux.*/).any_number_of_times.and_return(ps_aux_output)
116
+ IO.should_receive(:popen).with(/kill -9 18901/)
117
+ IO.should_receive(:popen).with(/kill -9 18902/)
118
+ IO.should_receive(:popen).with(/kill -9 18903/) do
119
+ IO.rspec_reset
120
+ IO.stub(:popen).and_return("")
121
+ end
122
+
123
+ Mirage::Runner.new.invoke(:stop, [], {:port => [:all]})
124
+
125
+ end
126
+
127
+ it 'should not error when asked to stop Mirage on a port that it is not running on' do
128
+ ps_aux_output =<<PS
129
+ #{process_string_for_mirage(7001, 18901)}
130
+ PS
131
+ IO.should_receive(:popen).with(/ps aux.*/).any_number_of_times.and_return(ps_aux_output)
132
+ IO.should_not_receive(:popen).with(/kill -9 18901/)
133
+ lambda { Mirage::Runner.new.invoke(:stop, [], {:port => [7002]}) }.should_not raise_error(Mirage::ClientError)
134
+ end
135
+
136
+ # it 'should not start mirage on the same port' do
137
+ # ps_aux_output =<<PS
138
+ ##{process_string_for_mirage(7001, 18901)}
139
+ #PS
140
+ # IO.should_receive(:popen).with(/ps aux.*/).any_number_of_times.and_return(ps_aux_output)
141
+ # lambda{Mirage::Runner.new.invoke(:start, [], {:port => 7001})}.should raise_error(Mirage::ClientError)
142
+ # end
143
+
144
+
145
+ end
146
+ end
147
+ end