mirage 2.2.3 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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