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.
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