response_mate 0.1.1
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.
- checksums.yaml +15 -0
- data/.gitignore +15 -0
- data/.travis.yml +10 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +107 -0
- data/LICENSE +20 -0
- data/README.md +107 -0
- data/Rakefile +12 -0
- data/bin/response_mate +5 -0
- data/environment.yml.sample +4 -0
- data/lib/response_mate.rb +43 -0
- data/lib/response_mate/cli.rb +58 -0
- data/lib/response_mate/commands.rb +1 -0
- data/lib/response_mate/commands/base.rb +12 -0
- data/lib/response_mate/commands/clear.rb +24 -0
- data/lib/response_mate/commands/export.rb +29 -0
- data/lib/response_mate/commands/inspect.rb +42 -0
- data/lib/response_mate/commands/list.rb +48 -0
- data/lib/response_mate/commands/record.rb +27 -0
- data/lib/response_mate/commands/setup.rb +24 -0
- data/lib/response_mate/connection.rb +36 -0
- data/lib/response_mate/core.rb +29 -0
- data/lib/response_mate/environment.rb +22 -0
- data/lib/response_mate/exporter.rb +18 -0
- data/lib/response_mate/exporters/postman.rb +61 -0
- data/lib/response_mate/helpers/application.rb +3 -0
- data/lib/response_mate/http.rb +41 -0
- data/lib/response_mate/inspector.rb +54 -0
- data/lib/response_mate/manifest.rb +68 -0
- data/lib/response_mate/manifest_parser.rb +7 -0
- data/lib/response_mate/oauth.rb +17 -0
- data/lib/response_mate/recorder.rb +39 -0
- data/lib/response_mate/request.rb +2 -0
- data/lib/response_mate/tape.rb +18 -0
- data/lib/response_mate/version.rb +3 -0
- data/oauth.yml.sample +12 -0
- data/requests.yml.sample +16 -0
- data/response_mate.gemspec +41 -0
- data/roadmap.md +24 -0
- data/spec/fixtures/two_keys.yml.erb +8 -0
- data/spec/lib/response_mate/cli_spec.rb +108 -0
- data/spec/lib/response_mate/core_spec.rb +65 -0
- data/spec/lib/response_mate/recorder_spec.rb +103 -0
- data/spec/lib/response_mate_spec.rb +7 -0
- data/spec/spec_helper.rb +32 -0
- metadata +336 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module ResponseMate
|
2
|
+
module Commands
|
3
|
+
class ResponseMate::Commands::Export < Base
|
4
|
+
|
5
|
+
def initialize(args, options)
|
6
|
+
super(args, options)
|
7
|
+
@type = args.first || 'requests'
|
8
|
+
|
9
|
+
@options[:manifest] = ResponseMate::Manifest.new(options[:requests_manifest])
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
unless options[:format].present?
|
14
|
+
@options[:format] = choose { |menu|
|
15
|
+
menu.prompt = 'Please pick one of the available formats'
|
16
|
+
menu.choice(:postman)
|
17
|
+
}.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
output = ResponseMate::Exporter.new(options).export
|
21
|
+
if options[:pretty]
|
22
|
+
puts JSON.pretty_generate(output)
|
23
|
+
else
|
24
|
+
puts output.to_json
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ResponseMate
|
2
|
+
module Commands
|
3
|
+
class ResponseMate::Commands::Inspect < Base
|
4
|
+
attr_reader :inspector
|
5
|
+
attr_accessor :history
|
6
|
+
|
7
|
+
def initialize(args, options)
|
8
|
+
super(args, options)
|
9
|
+
|
10
|
+
@options[:manifest] = ResponseMate::Manifest.new(options[:requests_manifest])
|
11
|
+
@inspector = ResponseMate::Inspector.new(@options)
|
12
|
+
@history = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
if options[:interactive]
|
17
|
+
interactive
|
18
|
+
else
|
19
|
+
args.each do |key|
|
20
|
+
inspector.inspect_key(key)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def interactive
|
26
|
+
loop do
|
27
|
+
input = ask('response_mate> ')
|
28
|
+
case input
|
29
|
+
when 'history'
|
30
|
+
input = choose { |menu|
|
31
|
+
menu.prompt = 'Replay any?'
|
32
|
+
menu.choices(*([:no] + history))
|
33
|
+
}.to_s
|
34
|
+
else
|
35
|
+
history << input
|
36
|
+
end
|
37
|
+
inspector.inspect_interactive(input)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ResponseMate
|
2
|
+
module Commands
|
3
|
+
class ResponseMate::Commands::List < Base
|
4
|
+
attr_accessor :type
|
5
|
+
|
6
|
+
def initialize(args, options)
|
7
|
+
super(args, options)
|
8
|
+
@type = args.first || 'requests'
|
9
|
+
|
10
|
+
@options[:manifest] = ResponseMate::Manifest.new(options[:requests_manifest])
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
if type == 'requests'
|
15
|
+
choices = options[:manifest].requests.map { |r| r.key.to_sym }
|
16
|
+
elsif type == 'recordings'
|
17
|
+
choices = Dir.glob('output/responses/*.yml').map do |f|
|
18
|
+
File.basename(f).gsub(/\.yml/, '').to_sym
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
puts choices.join "\n"
|
23
|
+
puts "\n\n"
|
24
|
+
action = choose { |menu|
|
25
|
+
menu.prompt = 'Want to perform any of the actions above?'
|
26
|
+
menu.choices(:record, :inspect, :no)
|
27
|
+
}
|
28
|
+
|
29
|
+
unless action == :no
|
30
|
+
key = choose { |menu|
|
31
|
+
menu.prompt = 'Which one?'
|
32
|
+
menu.choices(*choices)
|
33
|
+
}.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
if key
|
37
|
+
case action
|
38
|
+
when :record
|
39
|
+
ResponseMate::Recorder.new({ manifest: options[:manifest], keys: [key] }).
|
40
|
+
record
|
41
|
+
when :inspect
|
42
|
+
ResponseMate::Inspector.new(manifest: options[:manifest]).inspect_key(key)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ResponseMate
|
2
|
+
module Commands
|
3
|
+
# Handles the invocation of the record command
|
4
|
+
class ResponseMate::Commands::Record < Base
|
5
|
+
def initialize(args, options)
|
6
|
+
super(args, options)
|
7
|
+
@options = options.dup
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
environment = ResponseMate::Environment.new(options[:environment])
|
12
|
+
|
13
|
+
manifest = ResponseMate::Manifest.
|
14
|
+
new(options[:requests_manifest], environment)
|
15
|
+
|
16
|
+
options[:manifest] = manifest
|
17
|
+
recorder = ResponseMate::Recorder.new(options)
|
18
|
+
|
19
|
+
recorder.record
|
20
|
+
|
21
|
+
File.open(ResponseMate.configuration.output_dir + '.last_recording', 'w') do |f|
|
22
|
+
f << Time.current
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ResponseMate
|
2
|
+
module Commands
|
3
|
+
# Handles the invocation of the setup command
|
4
|
+
class ResponseMate::Commands::Setup < Base
|
5
|
+
attr_accessor :output_dir
|
6
|
+
|
7
|
+
def initialize(args, options)
|
8
|
+
super(args, options)
|
9
|
+
@options = options.dup
|
10
|
+
|
11
|
+
@output_dir = if args.present?
|
12
|
+
args.first
|
13
|
+
else
|
14
|
+
ResponseMate.configuration.output_dir
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
FileUtils.mkdir_p(output_dir)
|
20
|
+
puts "[Setup] Initialized empty directory #{output_dir}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ResponseMate::Connection
|
2
|
+
delegate :params, to: :client
|
3
|
+
delegate(*(ResponseMate::ManifestParser::HTTP_VERBS), to: :client)
|
4
|
+
|
5
|
+
attr_accessor :client, :base_url
|
6
|
+
|
7
|
+
def initialize(base_url = nil)
|
8
|
+
@base_url = base_url
|
9
|
+
@client = Faraday.new do |c|
|
10
|
+
c.use FaradayMiddleware::FollowRedirects, limit: 5
|
11
|
+
c.adapter Faraday.default_adapter
|
12
|
+
end
|
13
|
+
|
14
|
+
client.headers.merge(ResponseMate::DEFAULT_HEADERS)
|
15
|
+
client.url_prefix = base_url if base_url
|
16
|
+
end
|
17
|
+
|
18
|
+
def fetch(request)
|
19
|
+
client.params = request[:params] if !request[:params].nil?
|
20
|
+
unless base_url || request[:path] =~ /^http:\/\//
|
21
|
+
request[:path] = 'http://' + request[:path]
|
22
|
+
end
|
23
|
+
client.send request[:verb].downcase.to_sym, "#{base_url}#{request[:path]}"
|
24
|
+
rescue Faraday::Error::ConnectionFailed
|
25
|
+
puts "Is a server up and running at #{request[:path]}?".red
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_headers_from_manifest(manifest)
|
30
|
+
if manifest.try(:[], 'default_headers')
|
31
|
+
manifest['default_headers'].each_pair do |k, v|
|
32
|
+
client.headers[ResponseMate::Helpers.headerize(k)] = v
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# The main module of the tool contains configuration code and some constats
|
3
|
+
module ResponseMate
|
4
|
+
class OutputDirError < StandardError; end
|
5
|
+
|
6
|
+
DEFAULT_HEADERS = {
|
7
|
+
'User-Agent' => 'Response-Mate'
|
8
|
+
}
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :configuration
|
12
|
+
end
|
13
|
+
|
14
|
+
class Configuration
|
15
|
+
attr_accessor :output_dir, :requests_manifest, :oauth_manifest, :environment
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@output_dir = './output/responses/'
|
19
|
+
@requests_manifest = './requests.yml'
|
20
|
+
@oauth_manifest = './oauth.yml'
|
21
|
+
@environment = './environment.yml'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.setup
|
26
|
+
self.configuration ||= Configuration.new
|
27
|
+
yield(configuration) if block_given?
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ResponseMate::Environment
|
2
|
+
attr_accessor :filename, :env, :environment_text
|
3
|
+
|
4
|
+
delegate :[], to: :env
|
5
|
+
|
6
|
+
def initialize(filename)
|
7
|
+
@filename = filename || ResponseMate.configuration.environment
|
8
|
+
@env = {}
|
9
|
+
parse
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse
|
13
|
+
begin
|
14
|
+
@environment_text = File.read filename
|
15
|
+
rescue Errno::ENOENT
|
16
|
+
puts filename.red << ' does not seem to exist'
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
@env = YAML.load(environment_text)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module ResponseMate
|
4
|
+
class Exporter
|
5
|
+
attr_accessor :format, :handler, :manifest
|
6
|
+
|
7
|
+
def initialize(args = {})
|
8
|
+
@format = args[:format]
|
9
|
+
@manifest = args[:manifest]
|
10
|
+
end
|
11
|
+
|
12
|
+
def export
|
13
|
+
@handler = "ResponseMate::Exporters::#{format.capitalize}".safe_constantize.
|
14
|
+
new manifest
|
15
|
+
handler.export
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module ResponseMate::Exporters
|
2
|
+
# Handles exporting to postman format
|
3
|
+
# Example output
|
4
|
+
# https://www.getpostman.com/collections/dbc0521911e45471ff4a
|
5
|
+
class Postman
|
6
|
+
include ResponseMate::ManifestParser
|
7
|
+
|
8
|
+
attr_accessor :manifest, :out
|
9
|
+
|
10
|
+
def initialize(manifest)
|
11
|
+
@manifest = manifest
|
12
|
+
@out = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def export
|
16
|
+
build_structure
|
17
|
+
build_requests
|
18
|
+
out
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_structure
|
24
|
+
out.merge!(
|
25
|
+
id: SecureRandom.uuid,
|
26
|
+
name: 'latest_export',
|
27
|
+
requests: [],
|
28
|
+
order: [],
|
29
|
+
timestamp: Time.now.to_i
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_requests
|
34
|
+
manifest.requests.each do |request|
|
35
|
+
req = ResponseMate::Manifest.parse_request(request.request)
|
36
|
+
url = if req['params'].present?
|
37
|
+
"#{req['path']}?#{req['params'].to_query}"
|
38
|
+
else
|
39
|
+
req['path']
|
40
|
+
end
|
41
|
+
|
42
|
+
out_req = {
|
43
|
+
id: SecureRandom.uuid,
|
44
|
+
collectionId: out[:id],
|
45
|
+
data: [],
|
46
|
+
description: '',
|
47
|
+
method: req['verb'],
|
48
|
+
name: request['key'],
|
49
|
+
url: url,
|
50
|
+
version: 2,
|
51
|
+
responses: [],
|
52
|
+
dataMode: 'params',
|
53
|
+
headers: request['headers'] || manifest.default_headers
|
54
|
+
}
|
55
|
+
|
56
|
+
out[:order] << out_req[:id]
|
57
|
+
out[:requests] << out_req
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ResponseMate::Http
|
2
|
+
STATUS_CODES = {
|
3
|
+
100 => 'Continue',
|
4
|
+
101 => 'Switching Protocols',
|
5
|
+
200 => 'OK',
|
6
|
+
201 => 'Created',
|
7
|
+
202 => 'Accepted',
|
8
|
+
203 => 'Non-Authoritative Information',
|
9
|
+
204 => 'No Content',
|
10
|
+
205 => 'Reset Content',
|
11
|
+
206 => 'Partial Content',
|
12
|
+
300 => 'Multiple Choices',
|
13
|
+
301 => 'Moved Permanently',
|
14
|
+
302 => 'Moved Temporarily',
|
15
|
+
303 => 'See Other',
|
16
|
+
304 => 'Not Modified',
|
17
|
+
305 => 'Use Proxy',
|
18
|
+
400 => 'Bad Request',
|
19
|
+
401 => 'Unauthorized',
|
20
|
+
402 => 'Payment Required',
|
21
|
+
403 => 'Forbidden',
|
22
|
+
404 => 'Not Found',
|
23
|
+
405 => 'Method Not Allowed',
|
24
|
+
406 => 'Not Acceptable',
|
25
|
+
407 => 'Proxy Authentication Required',
|
26
|
+
408 => 'Request Time-out',
|
27
|
+
409 => 'Conflict',
|
28
|
+
410 => 'Gone',
|
29
|
+
411 => 'Length Required',
|
30
|
+
412 => 'Precondition Failed',
|
31
|
+
413 => 'Request Entity Too Large',
|
32
|
+
414 => 'Request-URI Too Large',
|
33
|
+
415 => 'Unsupported Media Type',
|
34
|
+
500 => 'Internal Server Error',
|
35
|
+
501 => 'Not Implemented',
|
36
|
+
502 => 'Bad Gateway',
|
37
|
+
503 => 'Service Unavailable',
|
38
|
+
504 => 'Gateway Time-out',
|
39
|
+
505 => 'HTTP Version not supported'
|
40
|
+
}
|
41
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class ResponseMate::Inspector
|
2
|
+
attr_accessor :conn, :base_url, :oauth, :manifest, :print_type
|
3
|
+
|
4
|
+
def initialize(args = {})
|
5
|
+
@manifest = args[:manifest]
|
6
|
+
@oauth = ResponseMate::Oauth.new
|
7
|
+
@base_url = args[:base_url] || manifest.base_url
|
8
|
+
@print_type = args[:print] || 'raw'
|
9
|
+
|
10
|
+
if !args[:interactive]
|
11
|
+
@conn = ResponseMate::Connection.new(base_url)
|
12
|
+
@conn.set_headers_from_manifest(manifest)
|
13
|
+
else
|
14
|
+
@conn = ResponseMate::Connection.new
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect_key(key, options = {})
|
19
|
+
request = manifest.requests.find { |r| r.key == key }
|
20
|
+
request = ResponseMate::Manifest.parse_request(request.request)
|
21
|
+
|
22
|
+
puts "[#{key}] #{request[:verb]}".cyan_on_black.bold << " #{request[:path]}"
|
23
|
+
puts "\tparams #{request[:params]}" if request[:params].present?
|
24
|
+
|
25
|
+
print(conn.fetch(request))
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect_interactive(input)
|
29
|
+
request = ResponseMate::Manifest.parse_request(input)
|
30
|
+
print(conn.fetch(request))
|
31
|
+
end
|
32
|
+
|
33
|
+
def print(response)
|
34
|
+
__send__ "print_#{print_type}", response
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_raw(response)
|
38
|
+
puts "\n"
|
39
|
+
status = "#{response.status} #{ResponseMate::Http::STATUS_CODES[response.status]}"
|
40
|
+
puts "HTTP/1.1 #{status}"
|
41
|
+
response.headers.each_pair do |k, v|
|
42
|
+
puts "#{ResponseMate::Helpers.headerize(k)}: #{v}"
|
43
|
+
end
|
44
|
+
puts response.body
|
45
|
+
end
|
46
|
+
|
47
|
+
def print_pretty(response)
|
48
|
+
ap(
|
49
|
+
status: response.status,
|
50
|
+
headers: response.headers,
|
51
|
+
body: response.body
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|