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,68 @@
1
+ class ResponseMate::Manifest
2
+ include ResponseMate::ManifestParser
3
+
4
+ attr_accessor :filename, :requests, :requests_text, :base_url, :oauth,
5
+ :default_headers, :environment
6
+
7
+ def initialize(filename, environment = nil)
8
+ @filename = filename || ResponseMate.configuration.requests_manifest
9
+ @oauth = ResponseMate::Oauth.new
10
+ @environment = environment
11
+ parse
12
+ end
13
+
14
+ def preprocess_manifest
15
+ begin
16
+ @requests_text = File.read filename
17
+ rescue Errno::ENOENT
18
+ puts filename.red << ' does not seem to exist'
19
+ exit 1
20
+ end
21
+
22
+ @requests_text = Mustache.render(@requests_text, environment.try(:env) || {})
23
+ end
24
+
25
+ def parse
26
+ preprocess_manifest
27
+ @request_hashes = YAML.load(requests_text)
28
+ @base_url = @request_hashes['base_url']
29
+ @requests = @request_hashes['requests'].map { |rh| ResponseMate::Request.new(rh) }
30
+ @default_headers = @request_hashes['default_headers']
31
+ add_oauth_to_requests
32
+ end
33
+
34
+ def add_oauth_to_requests
35
+ @requests.each do |req|
36
+ if req[:params].present?
37
+ req[:params].merge!('oauth_token' => oauth.token)
38
+ else
39
+ req[:params] = { 'oauth_token' => oauth.token }
40
+ end
41
+ end
42
+ end
43
+
44
+ class << self
45
+ def parse_request(request)
46
+ return parse_request_string(request) if request.is_a? String
47
+ parse_request_hash(request) if request.is_a? Hash
48
+ end
49
+
50
+ def parse_request_hash(hash)
51
+ self::DEFAULT_REQUEST.merge(hash.symbolize_keys)
52
+ end
53
+
54
+ def parse_request_string(request_string)
55
+ raise ArgumentError if request_string !~ self::REQUEST_MATCHER
56
+ { verb: $~[:verb] || self::DEFAULT_REQUEST[:verb] }
57
+ .merge(extract_path_query($~[:path]))
58
+ end
59
+
60
+ def extract_path_query(str)
61
+ parsed = Addressable::URI.parse(str)
62
+ {
63
+ path: parsed.path,
64
+ params: parsed.query_values
65
+ }
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,7 @@
1
+ module ResponseMate::ManifestParser
2
+ HTTP_VERBS = %w(GET POST PUT PATCH DELETE HEAD OPTIONS)
3
+ REQUEST_MATCHER = /^(?<verb>(#{HTTP_VERBS.join('|')})) (?<path>(.)*)$/im
4
+ DEFAULT_REQUEST = {
5
+ verb: 'GET'
6
+ }
7
+ end
@@ -0,0 +1,17 @@
1
+ # coding: utf-8
2
+
3
+ module ResponseMate
4
+ class Oauth
5
+ attr_accessor :manifest
6
+
7
+ def initialize
8
+ @manifest = YAML.load_file(ResponseMate.configuration.oauth_manifest)
9
+ rescue Errno::ENOENT
10
+ @manifest = nil
11
+ end
12
+
13
+ def token
14
+ manifest['token']
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+
3
+ module ResponseMate
4
+ # Handles recording requests
5
+ class Recorder
6
+ include ResponseMate::ManifestParser
7
+
8
+ attr_accessor :base_url, :conn, :manifest, :oauth, :keys
9
+
10
+ def initialize(args = {})
11
+ @manifest = args[:manifest]
12
+
13
+ @keys = args[:keys]
14
+ @base_url = args[:base_url] || manifest.base_url
15
+
16
+ @conn = ResponseMate::Connection.new(base_url)
17
+ @conn.set_headers_from_manifest(manifest)
18
+ end
19
+
20
+ def record
21
+ requests = manifest.requests
22
+ requests.select! { |r| keys.include? r.key } if keys.present?
23
+ requests.each do |request|
24
+ process request.key, request
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def process(key, request)
31
+ meta = request.meta
32
+ request = ResponseMate::Manifest.parse_request(request.request)
33
+
34
+ puts "[#{key}] #{request[:verb]}".cyan_on_black.bold << " #{request[:path]}"
35
+ puts "\tparams #{request[:params]}" if request[:params].present?
36
+ ResponseMate::Tape.new.write(key, request, conn.fetch(request), meta)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,2 @@
1
+ class ResponseMate::Request < OpenStruct
2
+ end
@@ -0,0 +1,18 @@
1
+ class ResponseMate::Tape
2
+ def write(key, request, response, meta = {})
3
+ File.open("#{ResponseMate.configuration.output_dir}#{key}.yml", 'w') do |f|
4
+ file_content = {
5
+ request: request.select { |_, v| !v.nil? },
6
+ status: response.status,
7
+ headers: response.headers.to_hash,
8
+ body: response.body
9
+ }
10
+
11
+ file_content.merge!(meta: meta) if meta.present?
12
+
13
+ f << file_content.to_yaml
14
+ end
15
+ rescue Errno::ENOENT
16
+ raise ResponseMate::OutputDirError
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module ResponseMate
2
+ VERSION = '0.1.1'
3
+ end
data/oauth.yml.sample ADDED
@@ -0,0 +1,12 @@
1
+ ---
2
+ token: Vr/AzbfQt3ywQlKUonZk25VqRg2ILFAFV/voi69FD9xlJl5Yp9DmDWb6PAEsVwuI1KckH3aa1/vxRaj/Mbwg==
3
+ application_token: false
4
+ expires_at: 2013-12-16 15:27:33.304654000 Z
5
+ user_id: 147606
6
+ oauth2_client_id: 1330
7
+ :permissions:
8
+ - favorites
9
+ - notifications
10
+ - easy
11
+ - public
12
+ - current_user_profile
@@ -0,0 +1,16 @@
1
+ base_url: http://localhost:3000/api
2
+ default_headers:
3
+ accept: 'application/vnd.github.beta+json'
4
+ requests:
5
+ -
6
+ key: user_repos
7
+ request: 'GET /user/repos'
8
+ -
9
+ key: user_issues
10
+ request:
11
+ path: '/user/issues'
12
+ params:
13
+ sort: 'updated'
14
+ -
15
+ key: users_repos
16
+ request: 'GET /users/{{some_user_id}}/repos'
@@ -0,0 +1,41 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'response_mate/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "response_mate"
8
+ spec.version = ResponseMate::VERSION
9
+ spec.authors = ["Dimitris Zorbas"]
10
+ spec.email = ["zorbash@skroutz.gr"]
11
+ spec.description = <<-DESC
12
+ Cli tool to make inspecting and recording HTTP requests fun again
13
+ DESC
14
+ spec.summary = %q{}
15
+ spec.homepage = ""
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "pry"
26
+ spec.add_development_dependency "pry-remote"
27
+ spec.add_development_dependency "pry-nav"
28
+ spec.add_development_dependency "rspec", "~> 2.14"
29
+ spec.add_development_dependency 'fakefs'
30
+ spec.add_development_dependency 'rubocop'
31
+
32
+ spec.add_dependency "thor", "~> 0.18.1"
33
+ spec.add_dependency "awesome_print"
34
+ spec.add_dependency "activesupport"
35
+ spec.add_dependency "colored"
36
+ spec.add_dependency "faraday"
37
+ spec.add_dependency "faraday_middleware"
38
+ spec.add_dependency "addressable"
39
+ spec.add_dependency "highline"
40
+ spec.add_dependency "mustache"
41
+ end
data/roadmap.md ADDED
@@ -0,0 +1,24 @@
1
+ ## Milestone 0.1.0
2
+ - Make the list command prompt you to perform any of the listed requests ✓
3
+ - Recording is optional, you may just perform requests to inspect their
4
+ - output. [Done]
5
+ - Support mustache templates in favor of erb ✓
6
+ - Extract Manifest to a separate class ✓
7
+ - Add usage instructions in README.md [Done]
8
+ - Remove support for .yml.erb request manifests [Done]
9
+ - Export Connection as a separate class [Done]
10
+ - Export Tape as a separate class [Done]
11
+
12
+ ## Milestone 0.2.0
13
+ - Request helpers (random ids, uuids).
14
+ - Paraller requests.
15
+ - Expectations, a expectations.yml file will contain a list of keys and
16
+ - status codes to match against the recordings.
17
+ - response_mate server command that serves the recorded responses when
18
+ - requests matching requests.yml are replayed.
19
+ - Curl exporter.
20
+ - Export environment.yml to postman format
21
+ - Accept extra params/headers from cli
22
+ - Support request types: [:raw, urlencoded]
23
+ - read manifest file from url
24
+ - Allow multiline input for inspect
@@ -0,0 +1,8 @@
1
+ base_url: http://localhost:3000/api
2
+ requests:
3
+ -
4
+ key: one
5
+ request: 'GET /categories?page=1&per=5'
6
+ -
7
+ key: two
8
+ request: 'GET /categories/root'
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe ResponseMate::CLI do
4
+ describe '.package_name' do
5
+ it 'names the tool response_mate' do
6
+ content = capture(:stdout) { ResponseMate::CLI.start %w[help] }
7
+ expect(content).to match(/response_mate commands:/m)
8
+ end
9
+ end
10
+
11
+ let(:command) { double(run: 'yay') }
12
+
13
+ describe '#record' do
14
+ before do
15
+ allow(ResponseMate::Commands::Record).to receive(:new).and_return(command)
16
+ end
17
+
18
+ it 'initializes ResponseMate::Commands::Record' do
19
+ expect(ResponseMate::Commands::Record).to receive(:new)
20
+ capture(:stdout) { ResponseMate::CLI.start %w[record] }
21
+ end
22
+
23
+ it 'runs the command passing any given options, arguments' do
24
+ expect(command).to receive(:run)
25
+ capture(:stdout) { ResponseMate::CLI.start %w[record] }
26
+ end
27
+ end
28
+
29
+ describe'#inspect' do
30
+ before do
31
+ allow(ResponseMate::Commands::Inspect).to receive(:new).and_return(command)
32
+ end
33
+
34
+ it 'initializes ResponseMate::Commands::Inspect' do
35
+ expect(ResponseMate::Commands::Inspect).to receive(:new)
36
+ capture(:stdout) { ResponseMate::CLI.start %w[inspect] }
37
+ end
38
+
39
+ it 'runs the command passing any given options, arguments' do
40
+ expect(command).to receive(:run)
41
+ capture(:stdout) { ResponseMate::CLI.start %w[inspect] }
42
+ end
43
+ end
44
+
45
+ describe '#setup' do
46
+ before do
47
+ allow(ResponseMate::Commands::Setup).to receive(:new).and_return(command)
48
+ end
49
+
50
+ it 'initializes ResponseMate::Commands::setup' do
51
+ expect(ResponseMate::Commands::Setup).to receive(:new)
52
+ capture(:stdout) { ResponseMate::CLI.start %w[setup] }
53
+ end
54
+
55
+ it 'runs the command passing any given options, arguments' do
56
+ expect(command).to receive(:run)
57
+ capture(:stdout) { ResponseMate::CLI.start %w[setup] }
58
+ end
59
+ end
60
+
61
+ describe '#clear' do
62
+ before do
63
+ allow(ResponseMate::Commands::Clear).to receive(:new).and_return(command)
64
+ end
65
+
66
+ it 'initializes ResponseMate::Commands::Clear' do
67
+ expect(ResponseMate::Commands::Clear).to receive(:new)
68
+ capture(:stdout) { ResponseMate::CLI.start %w[clear] }
69
+ end
70
+
71
+ it 'runs the command passing any given options, arguments' do
72
+ expect(command).to receive(:run)
73
+ capture(:stdout) { ResponseMate::CLI.start %w[clear] }
74
+ end
75
+ end
76
+
77
+ describe '#list' do
78
+ before do
79
+ allow(ResponseMate::Commands::List).to receive(:new).and_return(command)
80
+ end
81
+
82
+ it 'initializes ResponseMate::Commands::List' do
83
+ expect(ResponseMate::Commands::List).to receive(:new)
84
+ capture(:stdout) { ResponseMate::CLI.start %w[list] }
85
+ end
86
+
87
+ it 'runs the command passing any given options, arguments' do
88
+ expect(command).to receive(:run)
89
+ capture(:stdout) { ResponseMate::CLI.start %w[list] }
90
+ end
91
+ end
92
+
93
+ describe '#export' do
94
+ before do
95
+ allow(ResponseMate::Commands::Export).to receive(:new).and_return(command)
96
+ end
97
+
98
+ it 'initializes ResponseMate::Commands::Export' do
99
+ expect(ResponseMate::Commands::Export).to receive(:new)
100
+ capture(:stdout) { ResponseMate::CLI.start %w[export] }
101
+ end
102
+
103
+ it 'runs the command passing any given options, arguments' do
104
+ expect(command).to receive(:run)
105
+ capture(:stdout) { ResponseMate::CLI.start %w[export] }
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe ResponseMate::Configuration do
4
+ describe '.initialize' do
5
+ let(:subject) { ResponseMate::Configuration.new }
6
+
7
+ it 'assigns @output_dir' do
8
+ expect(subject.output_dir).to be_present
9
+ end
10
+
11
+ it 'assigns @requests_manifest' do
12
+ expect(subject.requests_manifest).to be_present
13
+ end
14
+
15
+ it 'assigns @oauth_manifest' do
16
+ expect(subject.oauth_manifest).to be_present
17
+ end
18
+ end
19
+ end
20
+
21
+ describe ResponseMate do
22
+ describe '.setup' do
23
+ context '@configuration is nil' do
24
+ before { ResponseMate.configuration = nil }
25
+
26
+ it 'assigns @configuration to a new ResponseMate::Configuration' do
27
+ expect(ResponseMate::Configuration).to receive(:new)
28
+ ResponseMate.setup
29
+ end
30
+ end
31
+
32
+ context '@configuration is not nil' do
33
+ before { ResponseMate.configuration = ResponseMate::Configuration.new }
34
+
35
+ it 'does not assign @configuration to a new ResponseMate::Configuration' do
36
+ ResponseMate::Configuration.should_not_receive(:new)
37
+ ResponseMate.setup
38
+ end
39
+ end
40
+
41
+ describe 'configuration block' do
42
+ before do
43
+ ResponseMate.setup do |config|
44
+ config.output_dir = 'foo'
45
+ config.requests_manifest = 'bar'
46
+ config.oauth_manifest = 'koko'
47
+ end
48
+ end
49
+
50
+ after do
51
+ ResponseMate.setup do |config|
52
+ config.output_dir = './output/responses/'
53
+ config.requests_manifest = './requests.yml.erb'
54
+ config.oauth_manifest = './oauth.yml'
55
+ end
56
+ end
57
+
58
+ it 'properly assigns ivars' do
59
+ expect(ResponseMate.configuration.output_dir).to eq('foo')
60
+ expect(ResponseMate.configuration.requests_manifest).to eq('bar')
61
+ expect(ResponseMate.configuration.oauth_manifest).to eq('koko')
62
+ end
63
+ end
64
+ end
65
+ end