tshield 0.11.5.0 → 0.11.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7581fed92c9b0af76120edc8d9a4b9eff62e1f37c8eafa6a33a5712e918382d6
4
- data.tar.gz: '018a8ca426a9af1bc6e374461e6f4748673cecf24358b332fd6c30a5ec433028'
3
+ metadata.gz: c640cd371996f18c70873cdb29f9ebddd56feec72a2a28f97ab12e8c2dea7c79
4
+ data.tar.gz: db3eafdb27d4b6c6aa7b5f3ccd8480f045f8629beaf61ac431e6d038d8bf3dd2
5
5
  SHA512:
6
- metadata.gz: 8afb34fe21d6e9d8813c46c42e2c8d64908d9f72badd51bd11e1c92ea4b37b23e159cc03f2ad85932cceda146446db351f32b3167f5a52200df5af8df7cbaf59
7
- data.tar.gz: 5bf25b51e864b9f4b89a05158e5532582f86f21ceca0e24e2dafce2c2eb37235867686ecd8514ee6cecc061f4dd3247d83113f11f24eca25b89e9027103a1519
6
+ metadata.gz: '08a7fa0ab19a76dfbd9f1c262836c5c6e67b2c5ea85db39271162ccce204291e08a27962327f2e95c5921f696c3cfb6cdc541d69eaa8f441af994d63c7246053'
7
+ data.tar.gz: b8c45e92156a2f1fcbd2016338eaa9aa424edecff1b6248bb11c0cabc747f58ff82012d6fd048dc548825b6b46c208b8ed0bbb2b96a27036c6ce9bdf4accf413
data/README.md CHANGED
@@ -2,6 +2,7 @@ TShield
2
2
  =======
3
3
 
4
4
  [![Build Status](https://travis-ci.org/diegorubin/tshield.svg)](https://travis-ci.org/diegorubin/tshield)
5
+ [![Coverage Status](https://coveralls.io/repos/github/diegorubin/tshield/badge.svg?branch=master)](https://coveralls.io/github/diegorubin/tshield?branch=master)
5
6
  [![SourceLevel](https://app.sourcelevel.io/github/diegorubin/tshield.svg)](https://app.sourcelevel.io/github/diegorubin/tshield)
6
7
  [![Join the chat at https://gitter.im/diegorubin/tshield](https://badges.gitter.im/diegorubin/tshield.svg)](https://gitter.im/diegorubin/tshield?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
7
8
  [![Gem Version](https://badge.fury.io/rb/tshield.svg)](https://badge.fury.io/rb/tshield)
@@ -15,6 +16,17 @@ TShield is an open source proxy for mocks API responses.
15
16
  * Lightweight
16
17
  * MIT license
17
18
 
19
+ #### Table of Contents:
20
+
21
+ * [Basic Usage](#basic-usage)
22
+ * [Config options for Pattern Matching](#config-options-for-pattern-matching)
23
+ * [Config options for VCR](#config-options-for-vcr)
24
+ * [Manage Sessions](#manage-sessions)
25
+ * [Custom controllers](#custom-controllers)
26
+ * [Features](#features)
27
+ * [Examples](#examples)
28
+ * [Contributing](#contributing)
29
+
18
30
  ## Basic Usage
19
31
  ### Install
20
32
 
@@ -26,7 +38,7 @@ To run server execute this command
26
38
 
27
39
  tshield
28
40
 
29
- Default port is **4567**
41
+ Default port is `4567`
30
42
 
31
43
  #### Command Line Options
32
44
 
@@ -65,7 +77,7 @@ at least the following attributes:
65
77
 
66
78
  * __method__: a http method.
67
79
  * __path__: url path.
68
- * __response__: object with response data.
80
+ * __response__: object with response data. Into session can be used an array of objects to return different responses like vcr mode. See example: [multiples_response.json](https://github.com/diegorubin/tshield/blob/master/component_tests/matching/examples/multiple_response.json)
69
81
 
70
82
  Response must be contain the following attributes:
71
83
 
@@ -201,6 +213,7 @@ domains:
201
213
  * **name**: Name to identify the domain in the generated files
202
214
  * **headers**: github-issue #17
203
215
  * **not_save_headers**: List of headers that should be ignored in generated file
216
+ * **skip_query_params**: List of query params that should be ignored in generated file
204
217
  * **cache_request**: <<some_description>>
205
218
  * **filters**: Implementation of before or after filters used in domain requests
206
219
  * **excluded_headers**: <<some_description>>
@@ -265,9 +278,12 @@ end
265
278
  Description of some tshield features can be found in the features directory.
266
279
  This features files are used as base for the component tests.
267
280
 
268
- ## Samples
269
- #### Basic sample for a client app requesting a server API
281
+ ## Examples
282
+ #### Basic example for a client app requesting an API
270
283
  [examples/client-api-nodejs](examples/client-api-nodejs)
271
284
 
285
+ #### Basic example for component/acceptance test
286
+ **[WIP]**
287
+
272
288
  ## Contributing
273
- [Hacking or Contributing to Tshield](CONTRIBUTING.md)
289
+ [Hacking or Contributing to TShield](CONTRIBUTING.md)
@@ -31,6 +31,7 @@ module TShield
31
31
  attr_reader :request
32
32
  attr_reader :domains
33
33
  attr_reader :tcp_servers
34
+ attr_reader :session_path
34
35
 
35
36
  def initialize(attributes)
36
37
  attributes.each { |key, value| instance_variable_set("@#{key}", value) }
@@ -57,9 +58,8 @@ module TShield
57
58
 
58
59
  def get_domain_for(path)
59
60
  domains.each do |url, config|
60
- config['paths'].each do |pattern|
61
- return url if path =~ Regexp.new(pattern)
62
- end
61
+ result = self.class.get_url_for_domain_by_path(path, config)
62
+ return url if result
63
63
  end
64
64
  nil
65
65
  end
@@ -99,8 +99,12 @@ module TShield
99
99
  domains[domain]['not_save_headers'] || []
100
100
  end
101
101
 
102
- def session_path
103
- @session_path || '/sessions'
102
+ def read_session_path
103
+ session_path || '/sessions'
104
+ end
105
+
106
+ def self.get_url_for_domain_by_path(path, config)
107
+ config['paths'].select { |pattern| path =~ Regexp.new(pattern) }[0]
104
108
  end
105
109
 
106
110
  def self.read_configuration_file(config_path)
@@ -7,7 +7,17 @@ module TShield
7
7
  module SessionHelpers
8
8
  def self.current_session_name(request)
9
9
  session = TShield::Sessions.current(request.ip)
10
- session ? session[:name] : 'no-session'
10
+ session[:name] if session
11
+ end
12
+
13
+ def self.current_session_call(request, path, method)
14
+ session = TShield::Sessions.current(request.ip)
15
+ session ? session[:counter].current(path, method) : 0
16
+ end
17
+
18
+ def self.update_session_call(request, path, method)
19
+ session = TShield::Sessions.current(request.ip)
20
+ session[:counter].add(path, method) if session
11
21
  end
12
22
  end
13
23
  end
@@ -59,12 +59,15 @@ module TShield
59
59
  method = request.request_method
60
60
  request_content_type = request.content_type
61
61
  session_name = TShield::Controllers::Helpers::SessionHelpers.current_session_name(request)
62
+ session_call = TShield::Controllers::Helpers::SessionHelpers
63
+ .current_session_call(request, path, method)
62
64
 
63
65
  options = {
64
66
  method: method,
65
67
  headers: Helpers.build_headers(request),
66
68
  raw_query: request.env['QUERY_STRING'],
67
69
  session: session_name,
70
+ call: session_call,
68
71
  ip: request.ip
69
72
  }
70
73
 
@@ -75,12 +78,12 @@ module TShield
75
78
  replace: '')
76
79
  options[:body] = result
77
80
  end
78
- api_response = TShield::RequestMatching.new(path, options).match_request
81
+ api_response = TShield::RequestMatching.new(path, options.clone).match_request
79
82
 
80
83
  unless api_response
81
84
  add_headers(headers, path)
82
85
 
83
- api_response ||= TShield::RequestVCR.new(path, options).response
86
+ api_response ||= TShield::RequestVCR.new(path, options.clone).response
84
87
  api_response.headers.reject! do |key, _v|
85
88
  configuration.get_excluded_headers(domain(path)).include?(key)
86
89
  end
@@ -89,8 +92,9 @@ module TShield
89
92
  logger.info(
90
93
  "original=#{api_response.original} method=#{method} path=#{path} "\
91
94
  "content-type=#{request_content_type} "\
92
- "session=#{session_name}"
95
+ "session=#{session_name} call=#{session_call}"
93
96
  )
97
+ TShield::Controllers::Helpers::SessionHelpers.update_session_call(request, path, method)
94
98
 
95
99
  status api_response.status
96
100
  headers api_response.headers
@@ -10,7 +10,7 @@ module TShield
10
10
  # Actions to handle sessions
11
11
  module Sessions
12
12
  def self.registered(app)
13
- session_path = TShield::Configuration.singleton.session_path
13
+ session_path = TShield::Configuration.singleton.read_session_path
14
14
  register_get(app, session_path)
15
15
  register_post(app, session_path)
16
16
  register_delete(app, session_path)
@@ -6,7 +6,6 @@ module TShield
6
6
  # Base of request mock methods
7
7
  class Request
8
8
  attr_reader :configuration
9
- attr_writer :content_idx
10
9
 
11
10
  def initialize
12
11
  @configuration = TShield::Configuration.singleton
@@ -14,15 +13,11 @@ module TShield
14
13
 
15
14
  protected
16
15
 
17
- def current_session
18
- TShield::Sessions.current(@options[:ip])
19
- end
20
-
21
16
  def session_destiny(request_path)
22
- session = current_session
17
+ session = @options[:session]
23
18
  return request_path unless session
24
19
 
25
- request_path = File.join(request_path, session[:name])
20
+ request_path = File.join(request_path, session)
26
21
  Dir.mkdir(request_path) unless File.exist?(request_path)
27
22
  request_path
28
23
  end
@@ -52,7 +47,7 @@ module TShield
52
47
  method_path = File.join(path_path, method)
53
48
  Dir.mkdir(method_path) unless File.exist?(method_path)
54
49
 
55
- File.join(method_path, @content_idx.to_s)
50
+ File.join(method_path, @options[:call].to_s)
56
51
  end
57
52
 
58
53
  def clear_path(path)
@@ -67,9 +62,5 @@ module TShield
67
62
 
68
63
  [url_path, cleared_params].join('?')
69
64
  end
70
-
71
- def method
72
- @options[:method].downcase
73
- end
74
65
  end
75
66
  end
@@ -27,11 +27,19 @@ module TShield
27
27
  @matched = find_stub(self.class.stubs)
28
28
  return unless matched
29
29
 
30
+ @matched = current_response
31
+
30
32
  TShield::Response.new(self.class.read_body(matched['body']),
31
33
  matched['headers'],
32
34
  matched['status'])
33
35
  end
34
36
 
37
+ def current_response
38
+ return matched[@options[:call]] if matched.is_a? Array
39
+
40
+ matched
41
+ end
42
+
35
43
  class << self
36
44
  attr_reader :stubs
37
45
 
@@ -14,8 +14,6 @@ require 'tshield/response'
14
14
  module TShield
15
15
  # Module to write and read saved responses
16
16
  class RequestVCR < TShield::Request
17
- attr_reader :response
18
-
19
17
  def initialize(path, options = {})
20
18
  super()
21
19
  @path = path
@@ -28,33 +26,35 @@ module TShield
28
26
  end
29
27
 
30
28
  def request
31
- unless @options[:raw_query].nil? || @options[:raw_query].empty?
32
- @path = "#{@path}?#{@options[:raw_query]}"
33
- end
29
+ raw_query = @options[:raw_query]
30
+ @path = "#{@path}?#{raw_query}" unless !raw_query || raw_query.empty?
34
31
 
35
32
  @url = "#{domain}#{@path}"
36
33
 
37
34
  if exists
38
- @response = current_response
39
- @response.original = false
35
+ response.original = false
36
+ response
40
37
  else
41
- @method = method
42
38
  configuration.get_before_filters(domain).each do |filter|
43
- @method, @url, @options = filter.new.filter(@method, @url, @options)
39
+ _method, @url, @options = filter.new.filter(method, @url, @options)
44
40
  end
45
41
 
46
- raw = HTTParty.send(@method.to_s, @url, @options)
42
+ raw = HTTParty.send(method.to_s, @url, @options)
47
43
 
48
44
  configuration.get_after_filters(domain).each do |filter|
49
45
  raw = filter.new.filter(raw)
50
46
  end
51
47
 
52
- @response = save(raw)
53
-
54
- @response.original = true
48
+ original_response = save(raw)
49
+ original_response.original = true
50
+ original_response
55
51
  end
56
- current_session[:counter].add(@path, method) if current_session
57
- @response
52
+ end
53
+
54
+ def response
55
+ @response ||= TShield::Response.new(saved_content['body'],
56
+ saved_content['headers'] || [],
57
+ saved_content['status'] || 200)
58
58
  end
59
59
 
60
60
  private
@@ -67,6 +67,10 @@ module TShield
67
67
  @name ||= configuration.get_name(domain)
68
68
  end
69
69
 
70
+ def method
71
+ @method ||= @options[:method].downcase
72
+ end
73
+
70
74
  def save(raw_response)
71
75
  headers = {}
72
76
  raw_response.headers.each do |k, v|
@@ -93,8 +97,6 @@ module TShield
93
97
  end
94
98
 
95
99
  def file_exists
96
- session = current_session
97
- @content_idx = session ? session[:counter].current(@path, method) : 0
98
100
  File.exist?(content_destiny)
99
101
  end
100
102
 
@@ -102,12 +104,6 @@ module TShield
102
104
  file_exists && configuration.cache_request?(domain)
103
105
  end
104
106
 
105
- def current_response
106
- TShield::Response.new(saved_content['body'],
107
- saved_content['headers'] || [],
108
- saved_content['status'] || 200)
109
- end
110
-
111
107
  def key
112
108
  @key ||= Digest::SHA1.hexdigest "#{@url}|#{method}"
113
109
  end
@@ -5,7 +5,7 @@ module TShield
5
5
  class Version
6
6
  MAJOR = 0
7
7
  MINOR = 11
8
- PATCH = 5
8
+ PATCH = 6
9
9
  PRE = 0
10
10
 
11
11
  class << self
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
 
3
+ require 'coveralls'
4
+ Coveralls.wear!
5
+
3
6
  require 'bundler/setup'
4
7
  Bundler.setup
5
8
 
@@ -53,6 +53,23 @@
53
53
  "body": "post content"
54
54
  }
55
55
  },
56
+ {
57
+ "method": "GET",
58
+ "path": "/matching/twice",
59
+ "response": [{
60
+ "status": 200,
61
+ "headers": {
62
+ "try": 1
63
+ },
64
+ "body": "first call"
65
+ }, {
66
+ "status": 201,
67
+ "headers": {
68
+ "try": 2
69
+ },
70
+ "body": "second call"
71
+ }]
72
+ },
56
73
  {
57
74
  "session": "a-session",
58
75
  "stubs": [{
@@ -128,6 +128,31 @@ describe TShield::RequestMatching do
128
128
  expect(@response.status).to eql(200)
129
129
  end
130
130
  end
131
+ context 'on match have multiples responses' do
132
+ before :each do
133
+ @responses = []
134
+ 2.times.each do |time|
135
+ @responses << TShield::RequestMatching
136
+ .new('/matching/twice',
137
+ method: 'GET',
138
+ call: time).match_request
139
+ end
140
+ end
141
+
142
+ it 'should return response object in first call' do
143
+ response = @responses[0]
144
+ expect(response.body).to eql('first call')
145
+ expect(response.headers).to eql('try' => 1)
146
+ expect(response.status).to eql(200)
147
+ end
148
+
149
+ it 'should return response object in second call' do
150
+ response = @responses[1]
151
+ expect(response.body).to eql('second call')
152
+ expect(response.headers).to eql('try' => 2)
153
+ expect(response.status).to eql(201)
154
+ end
155
+ end
131
156
  context 'on not match' do
132
157
  before :each do
133
158
  @request_matching = TShield::RequestMatching.new('/')
@@ -80,7 +80,8 @@ describe TShield::RequestVCR do
80
80
 
81
81
  TShield::RequestVCR.new '/',
82
82
  raw_query: 'allowed=true&skipped=1',
83
- method: 'GET'
83
+ method: 'GET',
84
+ call: 0
84
85
  end
85
86
  end
86
87
  end
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
29
29
  s.add_dependency('httparty', '~> 0.14', '>= 0.14.0')
30
30
  s.add_dependency('json', '~> 2.0', '>= 2.0')
31
31
  s.add_dependency('sinatra', '~> 1.4', '>= 1.4.0')
32
+ s.add_development_dependency('coveralls')
32
33
  s.add_development_dependency('cucumber', '~> 3.1', '>= 3.1.2')
33
34
  s.add_development_dependency('guard', '~> 2.15', '>= 2.15.0')
34
35
  s.add_development_dependency('guard-rspec', '~> 4.7', '>= 4.7.3')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tshield
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.5.0
4
+ version: 0.11.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Diego Rubin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-09-06 00:00:00.000000000 Z
12
+ date: 2019-09-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: byebug
@@ -111,6 +111,20 @@ dependencies:
111
111
  - - "~>"
112
112
  - !ruby/object:Gem::Version
113
113
  version: '1.4'
114
+ - !ruby/object:Gem::Dependency
115
+ name: coveralls
116
+ requirement: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
114
128
  - !ruby/object:Gem::Dependency
115
129
  name: cucumber
116
130
  requirement: !ruby/object:Gem::Requirement