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,22 @@
1
+ module Mirage
2
+ class MirageError < ::Exception
3
+ attr_reader :code
4
+
5
+ def initialize message, code
6
+ super message
7
+ @code = message, code
8
+ end
9
+ end
10
+
11
+ class InternalServerException < MirageError
12
+ end
13
+
14
+ class TemplateNotFound < ::Exception
15
+ end
16
+
17
+ class ClientError < ::Exception
18
+ def initialize message
19
+ super message
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ module Mirage
2
+ module Helpers
3
+ module MethodBuilder
4
+ def builder_methods *method_names
5
+
6
+ method_names.each do |method_name|
7
+ method_name = method_name.to_sym
8
+ define_method method_name do |arg=nil|
9
+ return instance_variable_get("@#{method_name}".to_sym) if arg.nil?
10
+ instance_variable_set("@#{method_name}".to_sym, arg)
11
+ self
12
+ end
13
+ end
14
+
15
+ end
16
+ alias builder_method builder_methods
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ require 'hashie/mash'
2
+ module Mirage
3
+ class Request
4
+ include HTTParty
5
+
6
+ class << self
7
+ alias_method :backedup_get, :get
8
+ def get url
9
+ result = Hashie::Mash.new(backedup_get(url, format: :json))
10
+ request = new
11
+ request.parameters = result.parameters
12
+ request.headers = result.headers
13
+ request.request_url = result.request_url
14
+ request.body = result.body
15
+ request.id = result.id
16
+ request
17
+ end
18
+ end
19
+
20
+ attr_accessor :parameters, :headers, :body, :request_url, :id
21
+
22
+ def delete
23
+ self.class.delete(id)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module Mirage
2
+ class Requests
3
+ include HTTParty
4
+
5
+ def initialize base_url
6
+ @url = "#{base_url}/requests"
7
+ end
8
+
9
+ def delete_all
10
+ self.class.delete(@url)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,103 @@
1
+ require 'thor'
2
+ require 'waitforit'
3
+ require 'childprocess'
4
+ require 'uri'
5
+ require 'httparty'
6
+ module Mirage
7
+ class << self
8
+
9
+ # Start Mirage locally on a given port
10
+ # Example Usage:
11
+ #
12
+ # Mirage.start :port => 9001 -> Configured MirageClient ready to use.
13
+ def start options={}
14
+ options={:port => 7001}.merge(options)
15
+ Runner.new.invoke(:start, [], options)
16
+ Mirage::Client.new(options)
17
+ end
18
+
19
+ # Stop locally running instance(s) of Mirage
20
+ #
21
+ # Example Usage:
22
+ # Mirage.stop -> Will stop mirage if there is only instance running. Can be running on any port.
23
+ # Mirage.stop :port => port -> stop mirage on a given port
24
+ # Mirage.stop :port => [port1, port2...] -> stops multiple running instances of Mirage
25
+ def stop options={:port => []}
26
+ options = {:port => :all} if options == :all
27
+
28
+ if options[:port]
29
+ options[:port] = [options[:port]] unless options[:port].is_a?(Array)
30
+ end
31
+
32
+ Runner.new.invoke(:stop, [], options)
33
+ rescue ClientError => e
34
+ raise ClientError.new("Mirage is running multiple ports, please specify the port(s) see api/tests for details")
35
+ end
36
+
37
+
38
+ # Detect if Mirage is running on a URL or a local port
39
+ #
40
+ # Example Usage:
41
+ # Mirage.running? -> boolean indicating whether Mirage is running on *locally* on port 7001
42
+ # Mirage.running? :port => port -> boolean indicating whether Mirage is running on *locally* on the given port
43
+ # Mirage.running? url -> boolean indicating whether Mirage is running on the given URL
44
+ def running? options_or_url = {:port => 7001}
45
+ url = options_or_url.kind_of?(Hash) ? "http://localhost:#{options_or_url[:port]}" : options_or_url
46
+ HTTParty.get(url) and return true
47
+ rescue Errno::ECONNREFUSED
48
+ return false
49
+ end
50
+
51
+ end
52
+
53
+ class Runner < Thor
54
+ include CLIBridge
55
+ RUBY_CMD = ChildProcess.jruby? ? 'jruby' : 'ruby'
56
+
57
+ desc "start", "Starts mirage"
58
+ method_option :port, :aliases => "-p", :type => :numeric, :default => 7001, :desc => "port that mirage should be started on"
59
+ method_option :defaults, :aliases => "-d", :type => :string, :default => 'mirage', :desc => "location to load default responses from"
60
+ method_option :debug, :type => :boolean, :default => false, :desc => "run in debug mode"
61
+
62
+ def start
63
+ port = options[:port]
64
+ process_ids = mirage_process_ids([port])
65
+ unless process_ids.empty?
66
+ warn "Mirage is already running: #{process_ids.values.join(",")}"
67
+ return
68
+ end
69
+
70
+ mirage_server_file = "#{File.dirname(__FILE__)}/../../../mirage_server.rb"
71
+
72
+ if ChildProcess.windows?
73
+ command = ["cmd", "/C", "start", "mirage server port #{port}", RUBY_CMD, mirage_server_file]
74
+ else
75
+ command = [RUBY_CMD, mirage_server_file]
76
+ end
77
+
78
+
79
+ command = command.concat(options.to_a).flatten.collect { |arg| arg.to_s }
80
+ ChildProcess.build(*command).start
81
+
82
+ wait_until(:timeout_after => 30.seconds) { Mirage.running?(options) }
83
+
84
+ begin
85
+ Mirage::Client.new(options).prime
86
+ rescue Mirage::InternalServerException => e
87
+ puts "WARN: #{e.message}"
88
+ end
89
+ end
90
+
91
+ desc "stop", "Stops mirage"
92
+ method_option :port, :aliases => "-p", :type => :array, :default => [], :banner => "[port_1 port_2|all]", :desc => "port(s) of mirage instance(s). ALL stops all running instances"
93
+
94
+ def stop
95
+ ports = options[:port].collect{|port| port=~/\d+/ ? port.to_i : port}
96
+ process_ids = mirage_process_ids(ports)
97
+ raise ClientError.new("Mirage is running on ports #{process_ids.keys.sort.join(", ")}. Please run mirage stop -p [PORT(s)] instead") if (process_ids.size > 1 && ports.empty?)
98
+ process_ids.values.each { |process_id| kill process_id }
99
+ wait_until { mirage_process_ids(options[:port]).empty? }
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,56 @@
1
+ require 'ostruct'
2
+ require 'json'
3
+ require 'httparty'
4
+ require 'hashie/mash'
5
+
6
+ require 'client/template/configuration'
7
+ require 'client/template/model'
8
+
9
+ module Mirage
10
+
11
+ class Template
12
+
13
+ include HTTParty
14
+ include Model::InstanceMethods
15
+ include Model::CommonMethods
16
+
17
+ class << self
18
+ alias_method :backedup_get, :get
19
+
20
+ def get url
21
+ response = backedup_get(url, :format => :json)
22
+ raise TemplateNotFound if response.code == 404
23
+ response_hashie = Hashie::Mash.new response
24
+
25
+ response_config = response_hashie.response
26
+ request_config = response_hashie.request
27
+
28
+ template = new(response_hashie.endpoint, Base64.decode64(response_config.body))
29
+
30
+ template.id response_hashie.id
31
+ template.default response_config['default']
32
+ template.delay response_config.delay
33
+ template.content_type response_config.content_type
34
+ template.status response_config.status
35
+ template.headers response_config.headers
36
+
37
+ template.required_parameters request_config.parameters
38
+ template.required_body_content request_config.body_content
39
+ template.http_method request_config.http_method
40
+ template.url url
41
+ template.requests_url response_hashie.requests_url
42
+ template.required_headers request_config.headers
43
+
44
+ template
45
+ end
46
+ end
47
+
48
+ def initialize *args
49
+ endpoint = args.first
50
+
51
+ raise ArgumentError, "You must specify a string endpoint as the first argument" unless endpoint && endpoint.is_a?(String)
52
+ super *args
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,44 @@
1
+ require 'client/helpers/method_builder'
2
+
3
+ module Mirage
4
+ class Template
5
+ class Configuration
6
+ extend Helpers::MethodBuilder
7
+ builder_methods :http_method, :status, :delay, :content_type, :default
8
+ attr_accessor :caller_binding
9
+ DEFAULT_HTTP_METHOD=:get
10
+ DEFAULT_STATUS=200
11
+ DEFAULT_DELAY=0
12
+ DEFAULT_CONTENT_TYPE="text/plain"
13
+ DEFAULT_DEFAULT=false
14
+
15
+ def initialize
16
+ reset
17
+ end
18
+
19
+ def reset
20
+ @http_method = DEFAULT_HTTP_METHOD
21
+ @status = DEFAULT_STATUS
22
+ @delay = DEFAULT_DELAY
23
+ @content_type = DEFAULT_CONTENT_TYPE
24
+ @default = DEFAULT_DEFAULT
25
+ end
26
+
27
+
28
+ def method_missing(method, *args, &block)
29
+ @caller_binding.send method, *args, &block if @caller_binding
30
+ end
31
+
32
+ def == config
33
+ config.is_a?(Configuration) &&
34
+ http_method == config.http_method &&
35
+ status == config.status &&
36
+ delay == config.delay &&
37
+ content_type == config.content_type &&
38
+ default == config.default
39
+
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,48 @@
1
+ require 'client/helpers/method_builder'
2
+ require 'client/template/model/common_methods'
3
+ require 'client/template/model/instance_methods'
4
+
5
+ module Mirage
6
+ class Template
7
+ module Model
8
+
9
+ class << self
10
+ def extended clazz
11
+ clazz.extend(CommonMethods)
12
+ clazz.extend(Helpers::MethodBuilder)
13
+ clazz.send(:include, HTTParty)
14
+ clazz.send(:include, CommonMethods)
15
+ clazz.send(:include, InstanceMethods)
16
+
17
+
18
+ mod = Module.new do
19
+ def initialize *args
20
+
21
+ super *args
22
+ [:content_type,
23
+ :http_method,
24
+ :default,
25
+ :status,
26
+ :delay,
27
+ :required_parameters,
28
+ :required_body_content,
29
+ :required_headers,
30
+ :headers,
31
+ :endpoint, :delay].each do |attribute|
32
+ eval("#{attribute} self.class.#{attribute} if self.class.#{attribute}")
33
+ end
34
+
35
+
36
+ end
37
+ end
38
+
39
+ clazz.send(:include, mod)
40
+
41
+ clazz.format :json
42
+ clazz
43
+ end
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ module Mirage
2
+
3
+ class Template
4
+ module Model
5
+ module CommonMethods
6
+ extend Helpers::MethodBuilder
7
+
8
+ builder_methods :content_type,
9
+ :http_method,
10
+ :default,
11
+ :status,
12
+ :delay,
13
+ :required_parameters,
14
+ :required_body_content,
15
+ :required_headers,
16
+ :headers,
17
+ :endpoint,
18
+ :body
19
+ end
20
+
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,95 @@
1
+ module Mirage
2
+ class Template
3
+ module Model
4
+ module InstanceMethods
5
+ extend Helpers::MethodBuilder
6
+ include CommonMethods
7
+
8
+ attr_accessor :caller_binding
9
+
10
+ def initialize *args
11
+ if args.last.is_a?(Template::Configuration)
12
+ default_config = args.delete_at(-1)
13
+ else
14
+ default_config = Template::Configuration.new
15
+ end
16
+
17
+ @endpoint, @body = *args
18
+ @content_type = default_config.content_type
19
+ @http_method = default_config.http_method
20
+ @status = default_config.status
21
+ @delay = default_config.delay
22
+ @required_parameters = {}
23
+ @required_headers = {}
24
+ @required_body_content = []
25
+ @headers = {}
26
+ @default = default_config.default
27
+ end
28
+
29
+ builder_method :id,
30
+ :url,
31
+ :requests_url
32
+
33
+
34
+ def create
35
+ @id = self.class.put("#{@endpoint}", :body => self.to_json, :headers => {'content-type' => 'application/json'})['id']
36
+ self
37
+ end
38
+
39
+ def delete
40
+ self.class.delete(url)
41
+ Request.delete requests_url
42
+ end
43
+
44
+
45
+ def to_json
46
+ {
47
+ :response => {
48
+ :body => Base64.encode64(body),
49
+ :status => status,
50
+ :default => default,
51
+ :content_type => content_type,
52
+ :headers => headers,
53
+ :delay => delay
54
+ },
55
+ :request => {
56
+ :parameters => encode_regexs(required_parameters),
57
+ :headers => encode_regexs(required_headers),
58
+ :body_content => encode_regexs(required_body_content),
59
+ :http_method => http_method,
60
+ }
61
+ }.to_json
62
+ end
63
+
64
+
65
+ def encode_regexs hash_or_array
66
+ case hash_or_array
67
+ when Array
68
+ hash_or_array.collect { |value| encode(value) }
69
+ else
70
+ encoded = {}
71
+ hash_or_array.each do |key, value|
72
+ encoded[key] = encode(value)
73
+ end
74
+ encoded
75
+ end
76
+ end
77
+
78
+ def encode(value)
79
+ value.is_a?(Regexp) ? "%r{#{value.source}}" : value
80
+ end
81
+
82
+ def method_missing(method, *args, &block)
83
+
84
+ if @caller_binding
85
+ @caller_binding.send method, *args, &block
86
+ else
87
+ super method, *args, &block
88
+ end
89
+
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end