tshield 0.11.20.0 → 0.13.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 1880df41008713100967696d1bf1695b1e830851877f0ed5340f1f3f75cabd5e
4
- data.tar.gz: 2a540ed72557ad9f9ba32073a5e98ed9b22812c1d0b96feaec00eeed35494386
2
+ SHA1:
3
+ metadata.gz: ff8ebc5fc00636cb1f4a14e64c431db07fc5b018
4
+ data.tar.gz: 2a3931e85a3869b2f39b19512352117bf664c750
5
5
  SHA512:
6
- metadata.gz: 7187004fa9e86545dcf81ebf70ea3059e04a0a8dcfe0143be3714ead2df3b9fc7d3e981641514f38192d69e57f826c85b14c46965f5d8171e3813e1bd9188574
7
- data.tar.gz: d1e5e07ff88b722a944d78e22f1d3089214fb1ae9bed74c7bd42943700fc63bc096fc7916368513c83e660cb7936044dffd52e0f5c5b927d2618364a1411074e
6
+ metadata.gz: 2d6affb50388b0f3e39b13806c5079c19f708a9d62f6bff8b89f70c21ec02ff19b33e9f635b6aee9398525bea000bfbd6efa1aed3f3de1f5b5279c6a0c2761d7
7
+ data.tar.gz: 7c3646904d2f38a5f4d608b9f76e3355c26e311eb2ac2518d09eb5e4a139bdddc506a41ce0078b395dddf551c775e7b654a00a15e8de9734ac97033772de90d3
data/README.md CHANGED
@@ -3,9 +3,10 @@ TShield
3
3
 
4
4
  [![Build Status](https://travis-ci.org/diegorubin/tshield.svg)](https://travis-ci.org/diegorubin/tshield)
5
5
  [![Coverage Status](https://coveralls.io/repos/github/diegorubin/tshield/badge.svg?branch=master)](https://coveralls.io/github/diegorubin/tshield?branch=master)
6
- [![SourceLevel](https://app.sourcelevel.io/github/diegorubin/tshield.svg)](https://app.sourcelevel.io/github/diegorubin/tshield)
6
+ [![SourceLevel](https://app.sourcelevel.io/github/diegorubin/-/tshield.svg)](https://app.sourcelevel.io/github/diegorubin/-/tshield)
7
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)
8
8
  [![Gem Version](https://badge.fury.io/rb/tshield.svg)](https://badge.fury.io/rb/tshield)
9
+ ![TShield Publish](https://github.com/diegorubin/tshield/workflows/TShield%20Publish/badge.svg)
9
10
 
10
11
  ## API mocks for development and testing
11
12
  TShield is an open source proxy for mocks API responses.
@@ -68,6 +69,17 @@ domains:
68
69
  - /users
69
70
  ```
70
71
 
72
+ **Windows Compatibility:** If you need to use Tshield in Windows SO, change the config file and set the windows_compatibility to true.
73
+
74
+ Eg:
75
+ ```yaml
76
+ windows_compatibility: true
77
+ request:
78
+ # wait time for real service
79
+ timeout: 8
80
+ ...
81
+ ```
82
+
71
83
  ## Config options for Pattern Matching
72
84
 
73
85
  An example of file to create a stub:
@@ -93,6 +105,10 @@ Optional request attributes:
93
105
  this stub will be returned if all headers are in request.
94
106
  * **query**: works like headers but use query params.
95
107
 
108
+ Optional response attributes:
109
+
110
+ * **delay**: integer that represents time in seconds that the response will be delayed to return
111
+
96
112
  **Important**: If VCR config conflicts with Matching config Matching will be
97
113
  used. Matching config have priority.
98
114
 
@@ -155,6 +171,7 @@ To register stub into a session create an object with following attributes:
155
171
  "method": "GET",
156
172
  "path": "/matching/example",
157
173
  "response": {
174
+ "delay": 5,
158
175
  "body": "matching-example-response-in-session",
159
176
  "headers": {},
160
177
  "status": 200
@@ -175,6 +192,7 @@ domains:
175
192
  headers:
176
193
  HTTP_AUTHORIZATION: Authorization
177
194
  HTTP_COOKIE: Cookie
195
+ send_header_content_type: true
178
196
  not_save_headers:
179
197
  - transfer-encoding
180
198
  cache_request: <<value>>
@@ -195,6 +213,8 @@ domains:
195
213
  - transfer-encoding
196
214
  paths:
197
215
  - /secure
216
+ delay:
217
+ '/secure': 10
198
218
 
199
219
  'http://localhost:9092':
200
220
  name: 'my-other-service'
@@ -205,6 +225,8 @@ domains:
205
225
  - transfer-encoding
206
226
  paths:
207
227
  - /users
228
+ delay:
229
+ '/users': 5
208
230
  ```
209
231
  **request**
210
232
  * **timeout**: wait time for real service in seconds
@@ -214,12 +236,14 @@ domains:
214
236
  * Define Base URI of service
215
237
  * **name**: Name to identify the domain in the generated files
216
238
  * **headers**: github-issue #17
239
+ * **send_header_content_type**: Boolean domain config to send header 'Content-Type' when requesting this domain
217
240
  * **not_save_headers**: List of headers that should be ignored in generated file
218
241
  * **skip_query_params**: List of query params that should be ignored in generated file
219
242
  * **cache_request**: <<some_description>>
220
243
  * **filters**: Implementation of before or after filters used in domain requests
221
244
  * **excluded_headers**: <<some_description>>
222
245
  * **paths**: Paths list of all services that will be called. Used to filter what domain will "receive the request"
246
+ * **delay**: List of times in seconds that the response will be delayed to return for an specific path defined above
223
247
 
224
248
  ## Manage Sessions
225
249
 
@@ -32,6 +32,7 @@ module TShield
32
32
  attr_reader :domains
33
33
  attr_reader :tcp_servers
34
34
  attr_reader :session_path
35
+ attr_reader :windows_compatibility
35
36
 
36
37
  def initialize(attributes)
37
38
  attributes.each { |key, value| instance_variable_set("@#{key}", value) }
@@ -99,10 +100,19 @@ module TShield
99
100
  domains[domain]['not_save_headers'] || []
100
101
  end
101
102
 
103
+ def send_header_content_type(domain)
104
+ return domains[domain]['send_header_content_type'] != false if domains[domain]
105
+ true
106
+ end
107
+
102
108
  def read_session_path
103
109
  session_path || '/sessions'
104
110
  end
105
111
 
112
+ def get_questionmark_char
113
+ windows_compatibility ? '%3f' : '?'
114
+ end
115
+
106
116
  def grpc
107
117
  defaults = { 'port' => 5678, 'proto_dir' => 'proto', 'services' => {} }
108
118
  defaults.merge(@grpc || {})
@@ -126,5 +136,10 @@ module TShield
126
136
  )
127
137
  raise 'Startup aborted'
128
138
  end
139
+
140
+ def get_delay(domain, path)
141
+ ((domains[domain] || {})['delay'] || {})[path] || 0
142
+ end
143
+
129
144
  end
130
145
  end
@@ -57,6 +57,8 @@ module TShield
57
57
  ip: request.ip
58
58
  }
59
59
 
60
+ treat_headers_by_domain(options, path)
61
+
60
62
  if %w[POST PUT PATCH].include? method
61
63
  result = request.body.read.encode('UTF-8',
62
64
  invalid: :replace,
@@ -82,6 +84,7 @@ module TShield
82
84
  )
83
85
  TShield::Controllers::Helpers::SessionHelpers.update_session_call(request, callid, method)
84
86
 
87
+ delay(path)
85
88
  status api_response.status
86
89
  headers api_response.headers
87
90
  body api_response.body
@@ -93,6 +96,11 @@ module TShield
93
96
  end
94
97
  end
95
98
 
99
+ def treat_headers_by_domain(options, path)
100
+ @send_header_content_type = configuration.send_header_content_type(domain(path))
101
+ options[:headers].delete('Content-Type') unless @send_header_content_type
102
+ end
103
+
96
104
  def configuration
97
105
  @configuration ||= TShield::Configuration.singleton
98
106
  end
@@ -100,6 +108,13 @@ module TShield
100
108
  def domain(path)
101
109
  @domain ||= configuration.get_domain_for(path)
102
110
  end
111
+
112
+ def delay(path)
113
+ delay_in_seconds = configuration.get_delay(domain(path), path) || 0
114
+ logger.info("Response with delay of #{delay_in_seconds} seconds")
115
+ sleep delay_in_seconds
116
+ end
117
+
103
118
  end
104
119
  end
105
120
  end
@@ -16,6 +16,7 @@ module TShield
16
16
  module_name = options['module']
17
17
 
18
18
  path = create_destiny(module_name, method_name, request)
19
+ save_request(path, request)
19
20
  response = saved_response(path)
20
21
  if response
21
22
  TShield.logger.info("returning saved response for request #{request.to_json} saved into #{hexdigest(request)}")
@@ -26,7 +27,7 @@ module TShield
26
27
  client_class = Object.const_get("#{module_name}::Stub")
27
28
  client_instance = client_class.new(options['hostname'], :this_channel_is_insecure)
28
29
  response = client_instance.send(method_name, request)
29
- save_request_and_response(path, request, response)
30
+ save_response(path, response)
30
31
  response
31
32
  end
32
33
 
@@ -39,11 +40,6 @@ module TShield
39
40
  Kernel.const_get(response_class).new(content)
40
41
  end
41
42
 
42
- def save_request_and_response(path, request, response)
43
- save_request(path, request)
44
- save_response(path, response)
45
- end
46
-
47
43
  def save_request(path, request)
48
44
  file = File.open(File.join(path, 'original_request'), 'w')
49
45
  file.puts request.to_json
@@ -29,6 +29,7 @@ module TShield
29
29
 
30
30
  @matched = current_response
31
31
 
32
+ sleep matched['delay'] || 0
32
33
  TShield::Response.new(self.class.read_body(matched['body']),
33
34
  matched['headers'],
34
35
  matched['status'])
@@ -78,12 +78,31 @@ module TShield
78
78
  @method ||= @options[:method].downcase
79
79
  end
80
80
 
81
+ def apply_set_cookie_header_values(raw_response, headers = {})
82
+
83
+ headers_clone = headers.clone
84
+
85
+ field = raw_response.get_fields('Set-Cookie')
86
+
87
+ if !field.nil? && !field.empty?
88
+ cookies_values = []
89
+ field.each { |value| cookies_values.push(value) }
90
+ headers_clone['Set-Cookie'] = cookies_values
91
+ end
92
+
93
+ headers_clone
94
+ end
95
+
81
96
  def save(raw_response)
82
97
  headers = {}
98
+
83
99
  raw_response.headers.each do |k, v|
100
+ next if k == 'set-cookie'
84
101
  headers[k] = v unless configuration.not_save_headers(domain).include? k
85
102
  end
86
103
 
104
+ headers = apply_set_cookie_header_values(raw_response, headers)
105
+
87
106
  content = {
88
107
  body: raw_response.body,
89
108
  status: raw_response.code,
@@ -140,9 +159,9 @@ module TShield
140
159
  if url.size > 225
141
160
  path = url.gsub(/(\?.*)/, '')
142
161
  params = Digest::SHA1.hexdigest Regexp.last_match(1)
143
- "#{path.gsub(%r{/}, '-').gsub(/^-/, '')}?#{params}"
162
+ "#{path.gsub(%r{/}, '-').gsub(/^-/, '')}#{configuration.get_questionmark_char}#{params}"
144
163
  else
145
- url.gsub(%r{/}, '-').gsub(/^-/, '')
164
+ url.gsub(%r{/}, '-').gsub(/^-/, '').gsub('?', configuration.get_questionmark_char)
146
165
  end
147
166
  end
148
167
  end
@@ -29,9 +29,9 @@ module TShield
29
29
 
30
30
  options '*' do
31
31
  response.headers['Allow'] = 'GET, PUT, POST, DELETE, OPTIONS'
32
- response.headers['Access-Control-Allow-Headers'] = 'Authorization, Content-Type,
33
- Accept, X-User-Email, X-Auth-Token'
32
+ response.headers['Access-Control-Allow-Headers'] = '*'
34
33
  response.headers['Access-Control-Allow-Origin'] = '*'
34
+ response.headers['Access-Control-Allow-Methods'] = '*'
35
35
  200
36
36
  end
37
37
 
@@ -4,8 +4,8 @@ module TShield
4
4
  # Control version of gem
5
5
  class Version
6
6
  MAJOR = 0
7
- MINOR = 11
8
- PATCH = 20
7
+ MINOR = 13
8
+ PATCH = 3
9
9
  PRE = 0
10
10
 
11
11
  class << self
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: false
2
2
 
3
- require 'coveralls'
4
- Coveralls.wear!
3
+ if ENV['COVERALLS_REPO_TOKEN']
4
+ require 'coveralls'
5
+ Coveralls.wear!
6
+ end
5
7
 
6
8
  require 'bundler/setup'
7
9
  Bundler.setup
@@ -64,6 +64,33 @@ describe TShield::Configuration do
64
64
  expect(@configuration.get_domain_for('/api/four')).to be_nil
65
65
  end
66
66
  end
67
+
68
+ describe 'SO compatibility' do
69
+ it 'should be compatible with windows when configuration is true' do
70
+ allow(YAML).to receive(:safe_load).and_return({:windows_compatibility => true })
71
+ TShield::Configuration.clear
72
+ @configuration = TShield::Configuration.singleton
73
+
74
+ expect(@configuration.get_questionmark_char).to eq('%3f')
75
+ end
76
+
77
+ it 'should be compatible with Unix when configuration is false' do
78
+ allow(YAML).to receive(:safe_load).and_return({:windows_compatibility => false })
79
+ TShield::Configuration.clear
80
+ @configuration = TShield::Configuration.singleton
81
+
82
+ expect(@configuration.get_questionmark_char).to eq('?')
83
+ end
84
+
85
+ it 'should be compatible with Unix when configuration is missing' do
86
+ allow(YAML).to receive(:safe_load).and_return({})
87
+ TShield::Configuration.clear
88
+ @configuration = TShield::Configuration.singleton
89
+
90
+ expect(@configuration.get_questionmark_char).to eq('?')
91
+ end
92
+
93
+ end
67
94
  end
68
95
  context 'on config not exist' do
69
96
  before :each do
@@ -81,14 +108,42 @@ describe TShield::Configuration do
81
108
 
82
109
  context 'on config exists without grpc entry' do
83
110
  before :each do
84
- options_instance = double
85
- allow(options_instance).to receive(:configuration_file)
86
- .and_return('spec/tshield/fixtures/config/tshield-without-grpc.yml')
87
- allow(TShield::Options).to receive(:instance).and_return(options_instance)
88
- @configuration = TShield::Configuration.singleton
111
+ @configuration = generate_configuration_from_file('spec/tshield/fixtures/config/tshield-without-grpc.yml')
112
+ TShield::Configuration.clear
89
113
  end
90
114
  it 'should set default value for port' do
91
115
  expect(@configuration.grpc).to eql('port' => 5678, 'proto_dir' => 'proto', 'services' => {})
92
116
  end
93
117
  end
118
+
119
+ context 'on config property request.domains.domain.send_header_content_type does not exists' do
120
+ before :each do
121
+ @configuration = generate_configuration_from_file('spec/tshield/fixtures/config/tshield-without-grpc.yml')
122
+ TShield::Configuration.clear
123
+ end
124
+ it 'should return send_header_content_type as true when property is not set' do
125
+ expect(@configuration.send_header_content_type('example.org')).to be true
126
+ end
127
+ end
128
+
129
+ context 'on config property request.domains.domain.send_header_content_type does exists' do
130
+ before :each do
131
+ TShield::Configuration.clear
132
+ end
133
+ it 'should return send_header_content_type as true when property is true' do
134
+ @configuration = generate_configuration_from_file('spec/tshield/fixtures/config/tshield-with-send-content-type-header.yml')
135
+ expect(@configuration.send_header_content_type('example.org')).to be true
136
+ end
137
+ it 'should return send_header_content_type as false when property is false' do
138
+ @configuration = generate_configuration_from_file('spec/tshield/fixtures/config/tshield-with-send-content-type-header_as_false.yml')
139
+ expect(@configuration.send_header_content_type('example.org')).to be false
140
+ end
141
+ end
142
+ end
143
+
144
+ def generate_configuration_from_file(file)
145
+ options_instance = double
146
+ allow(options_instance).to receive(:configuration_file).and_return(file)
147
+ allow(TShield::Options).to receive(:instance).and_return(options_instance)
148
+ TShield::Configuration.singleton
94
149
  end
@@ -58,3 +58,95 @@ describe TShield::Controllers::Requests do
58
58
  end
59
59
  end
60
60
  end
61
+
62
+ describe TShield::Controllers::Requests do
63
+ before :each do
64
+ @configuration = double
65
+ allow(TShield::Configuration)
66
+ .to receive(:singleton).and_return(@configuration)
67
+ allow(@configuration).to receive(:get_before_filters).and_return([])
68
+ allow(@configuration).to receive(:not_save_headers).and_return([])
69
+ allow(@configuration).to receive(:get_after_filters).and_return([])
70
+ allow(@configuration).to receive(:get_headers).and_return([])
71
+ allow(@configuration).to receive(:request).and_return('timeout' => 10)
72
+ allow(@configuration).to receive(:get_name).and_return('example.org')
73
+ allow(@configuration).to receive(:get_domain_for).and_return('example.org')
74
+ allow(@configuration).to receive(:get_delay).and_return(0)
75
+
76
+
77
+ allow(TShield::Options).to receive_message_chain(:instance, :break?)
78
+ @mock_logger = double
79
+ @controller = MockController.new(@mock_logger)
80
+ end
81
+ context 'when send_header_content_type is false for a single domain' do
82
+ it 'should remove application/json header when making a request' do
83
+ params = { 'captures' => ['/'] }
84
+ request = double
85
+ matcher = double
86
+ matched_response = double
87
+
88
+ allow(@configuration).to receive(:send_header_content_type).and_return(false)
89
+ allow(request).to receive(:request_method).and_return('GET')
90
+ allow(request).to receive(:content_type).and_return('application/json')
91
+ allow(request).to receive(:ip).and_return('0.0.0.0')
92
+ allow(request).to receive(:env).and_return('QUERY_STRING' => 'a=b')
93
+ allow(TShield::RequestMatching).to receive(:new).and_return(matcher)
94
+ allow(matcher).to receive(:match_request).and_return(nil)
95
+ allow(TShield::RequestVCR).to receive(:new).and_return(matcher)
96
+ allow(matcher).to receive(:vcr_response).and_return(matched_response)
97
+ allow(matched_response).to receive(:original).and_return(false)
98
+ allow(matched_response).to receive(:status).and_return(200)
99
+ allow(matched_response).to receive(:headers).and_return({})
100
+ allow(matched_response).to receive(:body).and_return('')
101
+ allow(@mock_logger).to receive(:info)
102
+
103
+ expect(TShield::RequestVCR).to receive(:new).with("/",{
104
+ call: 0,
105
+ headers: {},
106
+ ip: "0.0.0.0",
107
+ method: "GET",
108
+ raw_query: "a=b",
109
+ secondary_sessions: nil,
110
+ session: nil
111
+ })
112
+ @controller.treat(params, request, nil)
113
+ end
114
+ end
115
+
116
+ context 'when send_header_content_type is true for a single domain' do
117
+ it 'should NOT remove application/json header when making a request' do
118
+ params = { 'captures' => ['/'] }
119
+ request = double
120
+ matcher = double
121
+ matched_response = double
122
+
123
+ allow(@configuration).to receive(:send_header_content_type).and_return(true)
124
+ allow(request).to receive(:request_method).and_return('GET')
125
+ allow(request).to receive(:content_type).and_return('application/json')
126
+ allow(request).to receive(:ip).and_return('0.0.0.0')
127
+ allow(request).to receive(:env).and_return('QUERY_STRING' => 'a=b')
128
+ allow(TShield::RequestMatching).to receive(:new).and_return(matcher)
129
+ allow(matcher).to receive(:match_request).and_return(nil)
130
+ allow(TShield::RequestVCR).to receive(:new).and_return(matcher)
131
+ allow(matcher).to receive(:vcr_response).and_return(matched_response)
132
+ allow(matched_response).to receive(:original).and_return(false)
133
+ allow(matched_response).to receive(:status).and_return(200)
134
+ allow(matched_response).to receive(:headers).and_return({})
135
+ allow(matched_response).to receive(:body).and_return('')
136
+ allow(@mock_logger).to receive(:info)
137
+
138
+ expect(TShield::RequestVCR).to receive(:new).with("/",{
139
+ call: 0,
140
+ headers: {'Content-Type' => 'application/json'},
141
+ ip: "0.0.0.0",
142
+ method: "GET",
143
+ raw_query: "a=b",
144
+ secondary_sessions: nil,
145
+ session: nil
146
+ })
147
+
148
+
149
+ @controller.treat(params, request, nil)
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,18 @@
1
+ ---
2
+ request:
3
+ timeout: 0
4
+ domains:
5
+ 'example.org':
6
+ name: 'example.org'
7
+ send_header_content_type: true
8
+ filters:
9
+ - 'ExampleFilter'
10
+ paths:
11
+ - '/api/one'
12
+ - '/api/two'
13
+ skip_query_params:
14
+ - 'a'
15
+ 'example.com':
16
+ name: 'example.com'
17
+ paths:
18
+ - '/api/three'
@@ -0,0 +1,18 @@
1
+ ---
2
+ request:
3
+ timeout: 0
4
+ domains:
5
+ 'example.org':
6
+ name: 'example.org'
7
+ send_header_content_type: false
8
+ filters:
9
+ - 'ExampleFilter'
10
+ paths:
11
+ - '/api/one'
12
+ - '/api/two'
13
+ skip_query_params:
14
+ - 'a'
15
+ 'example.com':
16
+ name: 'example.com'
17
+ paths:
18
+ - '/api/three'
@@ -10,6 +10,7 @@ describe TShield::RequestVCR do
10
10
  allow(TShield::Configuration)
11
11
  .to receive(:singleton).and_return(@configuration)
12
12
  allow(@configuration).to receive(:get_before_filters).and_return([])
13
+ allow(@configuration).to receive(:not_save_headers).and_return([])
13
14
  allow(@configuration).to receive(:get_after_filters).and_return([])
14
15
  allow(@configuration).to receive(:request).and_return('timeout' => 10)
15
16
  allow(@configuration).to receive(:get_domain_for).and_return('example.org')
@@ -35,6 +36,24 @@ describe TShield::RequestVCR do
35
36
  TShield::RequestVCR.new '/', method: 'GET'
36
37
  end
37
38
 
39
+ it 'should write response headers as multiple occcurences when has more than one with same key' do
40
+ allow_any_instance_of(TShield::RequestVCR).to receive(:exists)
41
+ .and_return(false)
42
+ allow_any_instance_of(TShield::RequestVCR).to receive(:destiny)
43
+ allow(HTTParty).to receive(:send).and_return(RawResponseCookiesMultipleValues.new)
44
+
45
+ write_spy = double
46
+ allow(File).to receive(:open).and_return(write_spy)
47
+
48
+ expect(write_spy).to receive(:write).ordered.with('this is the body')
49
+ expect(write_spy).to receive(:write)
50
+ .ordered
51
+ .with("{\n \"status\": 200,\n \"headers\": {\n \"Set-Cookie\": [\n \"FirstCookie=An Value\",\n \"SecondCookie=An Value\"\n ]\n }\n}")
52
+ allow(write_spy).to receive(:close)
53
+
54
+ TShield::RequestVCR.new '/', method: 'GET'
55
+ end
56
+
38
57
  describe 'and query params exists in list to skip' do
39
58
  before :each do
40
59
  allow(@configuration).to receive(:get_name).and_return('example.org')
@@ -62,6 +81,8 @@ describe TShield::RequestVCR do
62
81
  }
63
82
  )
64
83
 
84
+ allow(@configuration).to receive(:get_questionmark_char).and_return('?')
85
+
65
86
  allow(HTTParty).to receive(:send).and_return(RawResponse.new)
66
87
  file_double = double
67
88
 
@@ -83,6 +104,53 @@ describe TShield::RequestVCR do
83
104
  method: 'GET',
84
105
  call: 0
85
106
  end
107
+
108
+ it 'should create response directory in windows standard' do
109
+
110
+ allow(@configuration).to receive(:domains).and_return(
111
+ 'example.org' => {
112
+ 'skip_query_params' => []
113
+ }
114
+ )
115
+
116
+ allow(@configuration).to receive(:get_questionmark_char).and_return('%3f')
117
+
118
+ allow(HTTParty).to receive(:send).and_return(RawResponse.new)
119
+ file_double = double
120
+
121
+ allow(File).to receive(:join)
122
+ .with('./requests/example.org', '%3fparam=value')
123
+ .and_return('./requests/example.org/%3fparam=value')
124
+ allow(File).to receive(:join)
125
+ .with('./requests/example.org/%3fparam=value', 'get')
126
+ .and_return('./requests/example.org/%3fparam=value/get')
127
+ allow(File).to receive(:join)
128
+ .with('./requests/example.org/%3fparam=value/get', '0')
129
+ .and_return('./requests/example.org/%3fparam=value/get/0')
130
+
131
+ allow(file_double).to receive(:read).and_return('{}')
132
+
133
+ expect(File).to receive('open')
134
+ .with('./requests/example.org/%3fparam=value/get/0.content', 'w')
135
+ .and_return(file_double)
136
+
137
+ expect(File).to receive('open')
138
+ .with('./requests/example.org/%3fparam=value/get/0.json', 'w')
139
+ .and_return(file_double)
140
+
141
+ expect(file_double).to receive(:write).ordered.with('this is the body')
142
+ expect(file_double).to receive(:write)
143
+ .with("{\n \"status\": 200,\n \"headers\": {\n }\n}")
144
+ expect(file_double).to receive(:close)
145
+ expect(file_double).to receive(:close)
146
+
147
+ TShield::RequestVCR.new '/',
148
+ raw_query: 'param=value',
149
+ method: 'GET',
150
+ call: 0
151
+ end
152
+
153
+
86
154
  end
87
155
  end
88
156
 
@@ -95,8 +163,33 @@ describe TShield::RequestVCR do
95
163
  'this is the body'
96
164
  end
97
165
 
166
+ def get_fields(field = "")
167
+ []
168
+ end
169
+
98
170
  def code
99
171
  200
100
172
  end
101
173
  end
174
+
175
+ class RawResponseCookiesMultipleValues
176
+ def headers
177
+ {'Set-Cookie' => ['FirstCookie=An Value', 'SecondCookie=An Value']}
178
+ end
179
+
180
+ def body
181
+ 'this is the body'
182
+ end
183
+
184
+ def get_fields(field = "")
185
+ self.headers[filed] unless self.headers.key?(field)
186
+ end
187
+
188
+ def code
189
+ 200
190
+ end
191
+ end
192
+
102
193
  end
194
+
195
+
data/tshield.gemspec CHANGED
@@ -22,19 +22,18 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.test_files = Dir['spec/**/*']
24
24
 
25
- s.required_ruby_version = '>= 2.3'
25
+ s.required_ruby_version = '>= 2.4'
26
26
 
27
- s.add_dependency('byebug', '~> 11.0', '>= 11.0.1')
28
27
  s.add_dependency('grpc', '~> 1.28', '>= 1.28.0')
29
28
  s.add_dependency('grpc-tools', '~> 1.28', '>= 1.28.0')
30
29
  s.add_dependency('httparty', '~> 0.14', '>= 0.14.0')
31
30
  s.add_dependency('json', '~> 2.0', '>= 2.0')
32
31
  s.add_dependency('puma', '~> 4.3', '>= 4.3.3')
33
- s.add_dependency('sinatra', '~> 1.4', '>= 1.4.0')
32
+ s.add_dependency('sinatra', '~> 2.1', '>= 2.1.0')
34
33
  s.add_dependency('sinatra-cross_origin', '~> 0.4.0', '>= 0.4')
35
- s.add_development_dependency('coveralls')
34
+ s.add_development_dependency('coveralls', '~> 0.8', '>= 0.8.23')
36
35
  s.add_development_dependency('cucumber', '~> 3.1', '>= 3.1.2')
37
- s.add_development_dependency('guard', '~> 2.15', '>= 2.15.0')
36
+ s.add_development_dependency('guard', '~> 2.16', '>= 2.16.2')
38
37
  s.add_development_dependency('guard-rspec', '~> 4.7', '>= 4.7.3')
39
38
  s.add_development_dependency('rake', '>= 10.0', '~> 13.0')
40
39
  s.add_development_dependency('rdoc', '~> 6.0', '>= 6.0')
@@ -42,6 +41,6 @@ Gem::Specification.new do |s|
42
41
  s.add_development_dependency('rspec', '~> 3.5', '>= 3.5.0')
43
42
  s.add_development_dependency('rubocop', '~> 0.73.0', '>= 0.73.0')
44
43
  s.add_development_dependency('rubocop-rails', '~> 2.2.0', '>= 2.2.1')
45
- s.add_development_dependency('simplecov', '~> 0.12', '>= 0.12.0')
44
+ s.add_development_dependency('simplecov', '~> 0.16', '>= 0.16.1')
46
45
  s.add_development_dependency('webmock', '~> 2.1', '>= 2.1.0')
47
46
  end
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.20.0
4
+ version: 0.13.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Diego Rubin
@@ -9,106 +9,86 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-07-26 00:00:00.000000000 Z
12
+ date: 2021-02-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: byebug
15
+ name: grpc
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '11.0'
20
+ version: '1.28'
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 11.0.1
23
+ version: 1.28.0
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
- - - "~>"
29
- - !ruby/object:Gem::Version
30
- version: '11.0'
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 11.0.1
34
- - !ruby/object:Gem::Dependency
35
- name: grpc
36
- requirement: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 1.28.0
41
28
  - - "~>"
42
29
  - !ruby/object:Gem::Version
43
30
  version: '1.28'
44
- type: :runtime
45
- prerelease: false
46
- version_requirements: !ruby/object:Gem::Requirement
47
- requirements:
48
31
  - - ">="
49
32
  - !ruby/object:Gem::Version
50
33
  version: 1.28.0
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '1.28'
54
34
  - !ruby/object:Gem::Dependency
55
35
  name: grpc-tools
56
36
  requirement: !ruby/object:Gem::Requirement
57
37
  requirements:
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: 1.28.0
61
38
  - - "~>"
62
39
  - !ruby/object:Gem::Version
63
40
  version: '1.28'
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.28.0
64
44
  type: :runtime
65
45
  prerelease: false
66
46
  version_requirements: !ruby/object:Gem::Requirement
67
47
  requirements:
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- version: 1.28.0
71
48
  - - "~>"
72
49
  - !ruby/object:Gem::Version
73
50
  version: '1.28'
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.28.0
74
54
  - !ruby/object:Gem::Dependency
75
55
  name: httparty
76
56
  requirement: !ruby/object:Gem::Requirement
77
57
  requirements:
78
- - - ">="
79
- - !ruby/object:Gem::Version
80
- version: 0.14.0
81
58
  - - "~>"
82
59
  - !ruby/object:Gem::Version
83
60
  version: '0.14'
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.14.0
84
64
  type: :runtime
85
65
  prerelease: false
86
66
  version_requirements: !ruby/object:Gem::Requirement
87
67
  requirements:
88
- - - ">="
89
- - !ruby/object:Gem::Version
90
- version: 0.14.0
91
68
  - - "~>"
92
69
  - !ruby/object:Gem::Version
93
70
  version: '0.14'
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 0.14.0
94
74
  - !ruby/object:Gem::Dependency
95
75
  name: json
96
76
  requirement: !ruby/object:Gem::Requirement
97
77
  requirements:
98
- - - ">="
78
+ - - "~>"
99
79
  - !ruby/object:Gem::Version
100
80
  version: '2.0'
101
- - - "~>"
81
+ - - ">="
102
82
  - !ruby/object:Gem::Version
103
83
  version: '2.0'
104
84
  type: :runtime
105
85
  prerelease: false
106
86
  version_requirements: !ruby/object:Gem::Requirement
107
87
  requirements:
108
- - - ">="
88
+ - - "~>"
109
89
  - !ruby/object:Gem::Version
110
90
  version: '2.0'
111
- - - "~>"
91
+ - - ">="
112
92
  - !ruby/object:Gem::Version
113
93
  version: '2.0'
114
94
  - !ruby/object:Gem::Dependency
@@ -135,56 +115,62 @@ dependencies:
135
115
  name: sinatra
136
116
  requirement: !ruby/object:Gem::Requirement
137
117
  requirements:
138
- - - ">="
139
- - !ruby/object:Gem::Version
140
- version: 1.4.0
141
118
  - - "~>"
142
119
  - !ruby/object:Gem::Version
143
- version: '1.4'
120
+ version: '2.1'
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: 2.1.0
144
124
  type: :runtime
145
125
  prerelease: false
146
126
  version_requirements: !ruby/object:Gem::Requirement
147
127
  requirements:
148
- - - ">="
149
- - !ruby/object:Gem::Version
150
- version: 1.4.0
151
128
  - - "~>"
152
129
  - !ruby/object:Gem::Version
153
- version: '1.4'
130
+ version: '2.1'
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: 2.1.0
154
134
  - !ruby/object:Gem::Dependency
155
135
  name: sinatra-cross_origin
156
136
  requirement: !ruby/object:Gem::Requirement
157
137
  requirements:
158
- - - ">="
159
- - !ruby/object:Gem::Version
160
- version: '0.4'
161
138
  - - "~>"
162
139
  - !ruby/object:Gem::Version
163
140
  version: 0.4.0
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0.4'
164
144
  type: :runtime
165
145
  prerelease: false
166
146
  version_requirements: !ruby/object:Gem::Requirement
167
147
  requirements:
168
- - - ">="
169
- - !ruby/object:Gem::Version
170
- version: '0.4'
171
148
  - - "~>"
172
149
  - !ruby/object:Gem::Version
173
150
  version: 0.4.0
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0.4'
174
154
  - !ruby/object:Gem::Dependency
175
155
  name: coveralls
176
156
  requirement: !ruby/object:Gem::Requirement
177
157
  requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: '0.8'
178
161
  - - ">="
179
162
  - !ruby/object:Gem::Version
180
- version: '0'
163
+ version: 0.8.23
181
164
  type: :development
182
165
  prerelease: false
183
166
  version_requirements: !ruby/object:Gem::Requirement
184
167
  requirements:
168
+ - - "~>"
169
+ - !ruby/object:Gem::Version
170
+ version: '0.8'
185
171
  - - ">="
186
172
  - !ruby/object:Gem::Version
187
- version: '0'
173
+ version: 0.8.23
188
174
  - !ruby/object:Gem::Dependency
189
175
  name: cucumber
190
176
  requirement: !ruby/object:Gem::Requirement
@@ -209,22 +195,22 @@ dependencies:
209
195
  name: guard
210
196
  requirement: !ruby/object:Gem::Requirement
211
197
  requirements:
212
- - - ">="
213
- - !ruby/object:Gem::Version
214
- version: 2.15.0
215
198
  - - "~>"
216
199
  - !ruby/object:Gem::Version
217
- version: '2.15'
200
+ version: '2.16'
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: 2.16.2
218
204
  type: :development
219
205
  prerelease: false
220
206
  version_requirements: !ruby/object:Gem::Requirement
221
207
  requirements:
222
- - - ">="
223
- - !ruby/object:Gem::Version
224
- version: 2.15.0
225
208
  - - "~>"
226
209
  - !ruby/object:Gem::Version
227
- version: '2.15'
210
+ version: '2.16'
211
+ - - ">="
212
+ - !ruby/object:Gem::Version
213
+ version: 2.16.2
228
214
  - !ruby/object:Gem::Dependency
229
215
  name: guard-rspec
230
216
  requirement: !ruby/object:Gem::Requirement
@@ -269,80 +255,80 @@ dependencies:
269
255
  name: rdoc
270
256
  requirement: !ruby/object:Gem::Requirement
271
257
  requirements:
272
- - - ">="
258
+ - - "~>"
273
259
  - !ruby/object:Gem::Version
274
260
  version: '6.0'
275
- - - "~>"
261
+ - - ">="
276
262
  - !ruby/object:Gem::Version
277
263
  version: '6.0'
278
264
  type: :development
279
265
  prerelease: false
280
266
  version_requirements: !ruby/object:Gem::Requirement
281
267
  requirements:
282
- - - ">="
268
+ - - "~>"
283
269
  - !ruby/object:Gem::Version
284
270
  version: '6.0'
285
- - - "~>"
271
+ - - ">="
286
272
  - !ruby/object:Gem::Version
287
273
  version: '6.0'
288
274
  - !ruby/object:Gem::Dependency
289
275
  name: reek
290
276
  requirement: !ruby/object:Gem::Requirement
291
277
  requirements:
292
- - - ">="
278
+ - - "~>"
293
279
  - !ruby/object:Gem::Version
294
280
  version: 5.4.0
295
- - - "~>"
281
+ - - ">="
296
282
  - !ruby/object:Gem::Version
297
283
  version: 5.4.0
298
284
  type: :development
299
285
  prerelease: false
300
286
  version_requirements: !ruby/object:Gem::Requirement
301
287
  requirements:
302
- - - ">="
288
+ - - "~>"
303
289
  - !ruby/object:Gem::Version
304
290
  version: 5.4.0
305
- - - "~>"
291
+ - - ">="
306
292
  - !ruby/object:Gem::Version
307
293
  version: 5.4.0
308
294
  - !ruby/object:Gem::Dependency
309
295
  name: rspec
310
296
  requirement: !ruby/object:Gem::Requirement
311
297
  requirements:
312
- - - ">="
313
- - !ruby/object:Gem::Version
314
- version: 3.5.0
315
298
  - - "~>"
316
299
  - !ruby/object:Gem::Version
317
300
  version: '3.5'
301
+ - - ">="
302
+ - !ruby/object:Gem::Version
303
+ version: 3.5.0
318
304
  type: :development
319
305
  prerelease: false
320
306
  version_requirements: !ruby/object:Gem::Requirement
321
307
  requirements:
322
- - - ">="
323
- - !ruby/object:Gem::Version
324
- version: 3.5.0
325
308
  - - "~>"
326
309
  - !ruby/object:Gem::Version
327
310
  version: '3.5'
311
+ - - ">="
312
+ - !ruby/object:Gem::Version
313
+ version: 3.5.0
328
314
  - !ruby/object:Gem::Dependency
329
315
  name: rubocop
330
316
  requirement: !ruby/object:Gem::Requirement
331
317
  requirements:
332
- - - ">="
318
+ - - "~>"
333
319
  - !ruby/object:Gem::Version
334
320
  version: 0.73.0
335
- - - "~>"
321
+ - - ">="
336
322
  - !ruby/object:Gem::Version
337
323
  version: 0.73.0
338
324
  type: :development
339
325
  prerelease: false
340
326
  version_requirements: !ruby/object:Gem::Requirement
341
327
  requirements:
342
- - - ">="
328
+ - - "~>"
343
329
  - !ruby/object:Gem::Version
344
330
  version: 0.73.0
345
- - - "~>"
331
+ - - ">="
346
332
  - !ruby/object:Gem::Version
347
333
  version: 0.73.0
348
334
  - !ruby/object:Gem::Dependency
@@ -369,42 +355,42 @@ dependencies:
369
355
  name: simplecov
370
356
  requirement: !ruby/object:Gem::Requirement
371
357
  requirements:
372
- - - ">="
373
- - !ruby/object:Gem::Version
374
- version: 0.12.0
375
358
  - - "~>"
376
359
  - !ruby/object:Gem::Version
377
- version: '0.12'
360
+ version: '0.16'
361
+ - - ">="
362
+ - !ruby/object:Gem::Version
363
+ version: 0.16.1
378
364
  type: :development
379
365
  prerelease: false
380
366
  version_requirements: !ruby/object:Gem::Requirement
381
367
  requirements:
382
- - - ">="
383
- - !ruby/object:Gem::Version
384
- version: 0.12.0
385
368
  - - "~>"
386
369
  - !ruby/object:Gem::Version
387
- version: '0.12'
370
+ version: '0.16'
371
+ - - ">="
372
+ - !ruby/object:Gem::Version
373
+ version: 0.16.1
388
374
  - !ruby/object:Gem::Dependency
389
375
  name: webmock
390
376
  requirement: !ruby/object:Gem::Requirement
391
377
  requirements:
392
- - - ">="
393
- - !ruby/object:Gem::Version
394
- version: 2.1.0
395
378
  - - "~>"
396
379
  - !ruby/object:Gem::Version
397
380
  version: '2.1'
381
+ - - ">="
382
+ - !ruby/object:Gem::Version
383
+ version: 2.1.0
398
384
  type: :development
399
385
  prerelease: false
400
386
  version_requirements: !ruby/object:Gem::Requirement
401
387
  requirements:
402
- - - ">="
403
- - !ruby/object:Gem::Version
404
- version: 2.1.0
405
388
  - - "~>"
406
389
  - !ruby/object:Gem::Version
407
390
  version: '2.1'
391
+ - - ">="
392
+ - !ruby/object:Gem::Version
393
+ version: 2.1.0
408
394
  description: Proxy for mocks API responses
409
395
  email: rubin.diego@gmail.com
410
396
  executables:
@@ -444,6 +430,8 @@ files:
444
430
  - spec/tshield/after_filter_spec.rb
445
431
  - spec/tshield/configuration_spec.rb
446
432
  - spec/tshield/controllers/requests_spec.rb
433
+ - spec/tshield/fixtures/config/tshield-with-send-content-type-header.yml
434
+ - spec/tshield/fixtures/config/tshield-with-send-content-type-header_as_false.yml
447
435
  - spec/tshield/fixtures/config/tshield-without-grpc.yml
448
436
  - spec/tshield/fixtures/config/tshield.yml
449
437
  - spec/tshield/fixtures/filters/example_filter.rb
@@ -467,29 +455,32 @@ required_ruby_version: !ruby/object:Gem::Requirement
467
455
  requirements:
468
456
  - - ">="
469
457
  - !ruby/object:Gem::Version
470
- version: '2.3'
458
+ version: '2.4'
471
459
  required_rubygems_version: !ruby/object:Gem::Requirement
472
460
  requirements:
473
461
  - - ">="
474
462
  - !ruby/object:Gem::Version
475
463
  version: '0'
476
464
  requirements: []
477
- rubygems_version: 3.0.8
465
+ rubyforge_project:
466
+ rubygems_version: 2.6.14.4
478
467
  signing_key:
479
468
  specification_version: 4
480
469
  summary: Proxy for mocks API responses
481
470
  test_files:
482
471
  - spec/spec_helper.rb
483
- - spec/tshield/request_matching_spec.rb
484
- - spec/tshield/grpc_spec.rb
485
- - spec/tshield/configuration_spec.rb
486
472
  - spec/tshield/sessions_spec.rb
487
- - spec/tshield/request_vcr_spec.rb
473
+ - spec/tshield/configuration_spec.rb
488
474
  - spec/tshield/controllers/requests_spec.rb
489
- - spec/tshield/options_spec.rb
490
- - spec/tshield/after_filter_spec.rb
491
475
  - spec/tshield/fixtures/matching/example.json
492
476
  - spec/tshield/fixtures/proto/test_services_pb.rb
493
- - spec/tshield/fixtures/filters/example_filter.rb
477
+ - spec/tshield/fixtures/config/tshield-with-send-content-type-header.yml
478
+ - spec/tshield/fixtures/config/tshield-with-send-content-type-header_as_false.yml
494
479
  - spec/tshield/fixtures/config/tshield.yml
495
480
  - spec/tshield/fixtures/config/tshield-without-grpc.yml
481
+ - spec/tshield/fixtures/filters/example_filter.rb
482
+ - spec/tshield/grpc_spec.rb
483
+ - spec/tshield/after_filter_spec.rb
484
+ - spec/tshield/request_vcr_spec.rb
485
+ - spec/tshield/request_matching_spec.rb
486
+ - spec/tshield/options_spec.rb