tshield 0.11.20.0 → 0.13.3.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
- 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