response_mate 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +5 -0
  5. data/Gemfile.lock +107 -0
  6. data/LICENSE +20 -0
  7. data/README.md +107 -0
  8. data/Rakefile +12 -0
  9. data/bin/response_mate +5 -0
  10. data/environment.yml.sample +4 -0
  11. data/lib/response_mate.rb +43 -0
  12. data/lib/response_mate/cli.rb +58 -0
  13. data/lib/response_mate/commands.rb +1 -0
  14. data/lib/response_mate/commands/base.rb +12 -0
  15. data/lib/response_mate/commands/clear.rb +24 -0
  16. data/lib/response_mate/commands/export.rb +29 -0
  17. data/lib/response_mate/commands/inspect.rb +42 -0
  18. data/lib/response_mate/commands/list.rb +48 -0
  19. data/lib/response_mate/commands/record.rb +27 -0
  20. data/lib/response_mate/commands/setup.rb +24 -0
  21. data/lib/response_mate/connection.rb +36 -0
  22. data/lib/response_mate/core.rb +29 -0
  23. data/lib/response_mate/environment.rb +22 -0
  24. data/lib/response_mate/exporter.rb +18 -0
  25. data/lib/response_mate/exporters/postman.rb +61 -0
  26. data/lib/response_mate/helpers/application.rb +3 -0
  27. data/lib/response_mate/http.rb +41 -0
  28. data/lib/response_mate/inspector.rb +54 -0
  29. data/lib/response_mate/manifest.rb +68 -0
  30. data/lib/response_mate/manifest_parser.rb +7 -0
  31. data/lib/response_mate/oauth.rb +17 -0
  32. data/lib/response_mate/recorder.rb +39 -0
  33. data/lib/response_mate/request.rb +2 -0
  34. data/lib/response_mate/tape.rb +18 -0
  35. data/lib/response_mate/version.rb +3 -0
  36. data/oauth.yml.sample +12 -0
  37. data/requests.yml.sample +16 -0
  38. data/response_mate.gemspec +41 -0
  39. data/roadmap.md +24 -0
  40. data/spec/fixtures/two_keys.yml.erb +8 -0
  41. data/spec/lib/response_mate/cli_spec.rb +108 -0
  42. data/spec/lib/response_mate/core_spec.rb +65 -0
  43. data/spec/lib/response_mate/recorder_spec.rb +103 -0
  44. data/spec/lib/response_mate_spec.rb +7 -0
  45. data/spec/spec_helper.rb +32 -0
  46. 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,3 @@
1
+ module ResponseMate::Helpers
2
+ def self.headerize(string); string.split('_').map(&:capitalize).join('-') end
3
+ 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