tshield 0.12.0.0 → 0.13.4.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 +4 -4
- data/README.md +14 -1
- data/lib/tshield/configuration.rb +10 -0
- data/lib/tshield/controllers/requests.rb +15 -0
- data/lib/tshield/grpc/vcr.rb +2 -6
- data/lib/tshield/request_matching.rb +32 -7
- data/lib/tshield/request_vcr.rb +19 -0
- data/lib/tshield/server.rb +2 -2
- data/lib/tshield/version.rb +2 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/tshield/configuration_spec.rb +33 -5
- data/spec/tshield/controllers/requests_spec.rb +92 -0
- data/spec/tshield/fixtures/config/tshield-with-send-content-type-header.yml +18 -0
- data/spec/tshield/fixtures/config/tshield-with-send-content-type-header_as_false.yml +18 -0
- data/spec/tshield/fixtures/matching/empty.json +0 -0
- data/spec/tshield/fixtures/matching/invalid_matching_file.json +1 -0
- data/spec/tshield/request_matching_spec.rb +32 -0
- data/spec/tshield/request_vcr_spec.rb +44 -0
- metadata +23 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66ce1246fb18f0ac3ca8988aa3dcbdaf6ac93f3605181bffd79ad0b831bf94c5
|
4
|
+
data.tar.gz: a640d69531493ef2c8513377b1671e51b9f2d231a0eeaf158b175526a42f45f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec4005538a4fdbe3352874f7485e8e60303ab2e8a51441621cd181d73dd236267d08d03363052632e794f1701e6de0eafaa9448a6ca8cabec7680505e1902234
|
7
|
+
data.tar.gz: 319ccdbccc47a05d783403de7fff5022f928520f18d1aedb06929de0b40f1d6a74e6db94219835f8e8edd15636acbc0ff3f3d2999a787446420fdda916e3bf12
|
data/README.md
CHANGED
@@ -3,9 +3,10 @@ TShield
|
|
3
3
|
|
4
4
|
[](https://travis-ci.org/diegorubin/tshield)
|
5
5
|
[](https://coveralls.io/github/diegorubin/tshield?branch=master)
|
6
|
-
[](https://app.sourcelevel.io/github/diegorubin/-/tshield)
|
7
7
|
[](https://gitter.im/diegorubin/tshield?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
8
8
|
[](https://badge.fury.io/rb/tshield)
|
9
|
+

|
9
10
|
|
10
11
|
## API mocks for development and testing
|
11
12
|
TShield is an open source proxy for mocks API responses.
|
@@ -104,6 +105,10 @@ Optional request attributes:
|
|
104
105
|
this stub will be returned if all headers are in request.
|
105
106
|
* **query**: works like headers but use query params.
|
106
107
|
|
108
|
+
Optional response attributes:
|
109
|
+
|
110
|
+
* **delay**: integer that represents time in seconds that the response will be delayed to return
|
111
|
+
|
107
112
|
**Important**: If VCR config conflicts with Matching config Matching will be
|
108
113
|
used. Matching config have priority.
|
109
114
|
|
@@ -166,6 +171,7 @@ To register stub into a session create an object with following attributes:
|
|
166
171
|
"method": "GET",
|
167
172
|
"path": "/matching/example",
|
168
173
|
"response": {
|
174
|
+
"delay": 5,
|
169
175
|
"body": "matching-example-response-in-session",
|
170
176
|
"headers": {},
|
171
177
|
"status": 200
|
@@ -186,6 +192,7 @@ domains:
|
|
186
192
|
headers:
|
187
193
|
HTTP_AUTHORIZATION: Authorization
|
188
194
|
HTTP_COOKIE: Cookie
|
195
|
+
send_header_content_type: true
|
189
196
|
not_save_headers:
|
190
197
|
- transfer-encoding
|
191
198
|
cache_request: <<value>>
|
@@ -206,6 +213,8 @@ domains:
|
|
206
213
|
- transfer-encoding
|
207
214
|
paths:
|
208
215
|
- /secure
|
216
|
+
delay:
|
217
|
+
'/secure': 10
|
209
218
|
|
210
219
|
'http://localhost:9092':
|
211
220
|
name: 'my-other-service'
|
@@ -216,6 +225,8 @@ domains:
|
|
216
225
|
- transfer-encoding
|
217
226
|
paths:
|
218
227
|
- /users
|
228
|
+
delay:
|
229
|
+
'/users': 5
|
219
230
|
```
|
220
231
|
**request**
|
221
232
|
* **timeout**: wait time for real service in seconds
|
@@ -225,12 +236,14 @@ domains:
|
|
225
236
|
* Define Base URI of service
|
226
237
|
* **name**: Name to identify the domain in the generated files
|
227
238
|
* **headers**: github-issue #17
|
239
|
+
* **send_header_content_type**: Boolean domain config to send header 'Content-Type' when requesting this domain
|
228
240
|
* **not_save_headers**: List of headers that should be ignored in generated file
|
229
241
|
* **skip_query_params**: List of query params that should be ignored in generated file
|
230
242
|
* **cache_request**: <<some_description>>
|
231
243
|
* **filters**: Implementation of before or after filters used in domain requests
|
232
244
|
* **excluded_headers**: <<some_description>>
|
233
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
|
234
247
|
|
235
248
|
## Manage Sessions
|
236
249
|
|
@@ -100,6 +100,11 @@ module TShield
|
|
100
100
|
domains[domain]['not_save_headers'] || []
|
101
101
|
end
|
102
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
|
+
|
103
108
|
def read_session_path
|
104
109
|
session_path || '/sessions'
|
105
110
|
end
|
@@ -131,5 +136,10 @@ module TShield
|
|
131
136
|
)
|
132
137
|
raise 'Startup aborted'
|
133
138
|
end
|
139
|
+
|
140
|
+
def get_delay(domain, path)
|
141
|
+
((domains[domain] || {})['delay'] || {})[path] || 0
|
142
|
+
end
|
143
|
+
|
134
144
|
end
|
135
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
|
data/lib/tshield/grpc/vcr.rb
CHANGED
@@ -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
|
-
|
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
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'tshield/logger'
|
3
4
|
require 'tshield/matching/filters'
|
4
5
|
require 'tshield/request'
|
5
6
|
|
@@ -29,6 +30,7 @@ module TShield
|
|
29
30
|
|
30
31
|
@matched = current_response
|
31
32
|
|
33
|
+
sleep matched['delay'] || 0
|
32
34
|
TShield::Response.new(self.class.read_body(matched['body']),
|
33
35
|
matched['headers'],
|
34
36
|
matched['status'])
|
@@ -58,15 +60,38 @@ module TShield
|
|
58
60
|
end
|
59
61
|
|
60
62
|
def load_stub(file)
|
61
|
-
content =
|
63
|
+
content = read_stub_file(file)
|
62
64
|
content.each do |stub|
|
63
|
-
|
65
|
+
next unless valid_stub?(file, stub)
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
load_valid_stub(stub)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def read_stub_file(file)
|
72
|
+
JSON.parse File.open(file).read
|
73
|
+
rescue StandardError
|
74
|
+
TShield.logger.error "error in loading matching file #{file}"
|
75
|
+
[]
|
76
|
+
end
|
77
|
+
|
78
|
+
def valid_stub?(file, stub)
|
79
|
+
is_valid = stub.is_a?(Hash) && mandatory_attributes?(stub)
|
80
|
+
TShield.logger.info "loading matching file #{file}" if is_valid
|
81
|
+
is_valid
|
82
|
+
end
|
83
|
+
|
84
|
+
def mandatory_attributes?(stub)
|
85
|
+
(stub['method'] && stub['path'] && stub['response']) || (stub['session'] && stub['stubs'])
|
86
|
+
end
|
87
|
+
|
88
|
+
def load_valid_stub(stub)
|
89
|
+
stub_session_name = init_stub_session(stub)
|
90
|
+
|
91
|
+
if stub['stubs']
|
92
|
+
load_items(stub['stubs'] || [], stub_session_name)
|
93
|
+
else
|
94
|
+
load_item(stub, stub_session_name)
|
70
95
|
end
|
71
96
|
end
|
72
97
|
|
data/lib/tshield/request_vcr.rb
CHANGED
@@ -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,
|
data/lib/tshield/server.rb
CHANGED
@@ -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'] = '
|
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
|
|
data/lib/tshield/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -108,14 +108,42 @@ describe TShield::Configuration do
|
|
108
108
|
|
109
109
|
context 'on config exists without grpc entry' do
|
110
110
|
before :each do
|
111
|
-
|
112
|
-
|
113
|
-
.and_return('spec/tshield/fixtures/config/tshield-without-grpc.yml')
|
114
|
-
allow(TShield::Options).to receive(:instance).and_return(options_instance)
|
115
|
-
@configuration = TShield::Configuration.singleton
|
111
|
+
@configuration = generate_configuration_from_file('spec/tshield/fixtures/config/tshield-without-grpc.yml')
|
112
|
+
TShield::Configuration.clear
|
116
113
|
end
|
117
114
|
it 'should set default value for port' do
|
118
115
|
expect(@configuration.grpc).to eql('port' => 5678, 'proto_dir' => 'proto', 'services' => {})
|
119
116
|
end
|
120
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
|
121
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'
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
[]
|
@@ -36,6 +36,38 @@ describe TShield::RequestMatching do
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
context 'invalid matching file' do
|
40
|
+
before :each do
|
41
|
+
allow(Dir).to receive(:glob)
|
42
|
+
.and_return(['spec/tshield/fixtures/matching/invalid_matching_file.json'])
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'on loading stubs' do
|
46
|
+
before :each do
|
47
|
+
@request_matching = TShield::RequestMatching.new('/')
|
48
|
+
end
|
49
|
+
it 'should stubs be empty' do
|
50
|
+
expect(@request_matching.class.stubs[DEFAULT_SESSION]).to be_nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'empty matching file' do
|
56
|
+
before :each do
|
57
|
+
allow(Dir).to receive(:glob)
|
58
|
+
.and_return(['spec/tshield/fixtures/matching/empty.json'])
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'on loading stubs' do
|
62
|
+
before :each do
|
63
|
+
@request_matching = TShield::RequestMatching.new('/')
|
64
|
+
end
|
65
|
+
it 'should stubs be empty' do
|
66
|
+
expect(@request_matching.class.stubs[DEFAULT_SESSION]).to be_nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
39
71
|
context 'matching path' do
|
40
72
|
before :each do
|
41
73
|
allow(Dir).to receive(:glob)
|
@@ -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')
|
@@ -144,8 +163,33 @@ describe TShield::RequestVCR do
|
|
144
163
|
'this is the body'
|
145
164
|
end
|
146
165
|
|
166
|
+
def get_fields(field = "")
|
167
|
+
[]
|
168
|
+
end
|
169
|
+
|
147
170
|
def code
|
148
171
|
200
|
149
172
|
end
|
150
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
|
+
|
151
193
|
end
|
194
|
+
|
195
|
+
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tshield
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Diego Rubin
|
8
8
|
- Eduardo Garcia
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-04-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: grpc
|
@@ -430,10 +430,14 @@ files:
|
|
430
430
|
- spec/tshield/after_filter_spec.rb
|
431
431
|
- spec/tshield/configuration_spec.rb
|
432
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
|
433
435
|
- spec/tshield/fixtures/config/tshield-without-grpc.yml
|
434
436
|
- spec/tshield/fixtures/config/tshield.yml
|
435
437
|
- spec/tshield/fixtures/filters/example_filter.rb
|
438
|
+
- spec/tshield/fixtures/matching/empty.json
|
436
439
|
- spec/tshield/fixtures/matching/example.json
|
440
|
+
- spec/tshield/fixtures/matching/invalid_matching_file.json
|
437
441
|
- spec/tshield/fixtures/proto/test_services_pb.rb
|
438
442
|
- spec/tshield/grpc_spec.rb
|
439
443
|
- spec/tshield/options_spec.rb
|
@@ -445,7 +449,7 @@ homepage: https://github.com/diegorubin/tshield
|
|
445
449
|
licenses:
|
446
450
|
- MIT
|
447
451
|
metadata: {}
|
448
|
-
post_install_message:
|
452
|
+
post_install_message:
|
449
453
|
rdoc_options: []
|
450
454
|
require_paths:
|
451
455
|
- lib
|
@@ -461,21 +465,25 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
461
465
|
version: '0'
|
462
466
|
requirements: []
|
463
467
|
rubygems_version: 3.0.8
|
464
|
-
signing_key:
|
468
|
+
signing_key:
|
465
469
|
specification_version: 4
|
466
470
|
summary: Proxy for mocks API responses
|
467
471
|
test_files:
|
468
|
-
- spec/spec_helper.rb
|
469
|
-
- spec/tshield/request_matching_spec.rb
|
470
|
-
- spec/tshield/grpc_spec.rb
|
471
|
-
- spec/tshield/configuration_spec.rb
|
472
|
-
- spec/tshield/sessions_spec.rb
|
473
|
-
- spec/tshield/request_vcr_spec.rb
|
474
|
-
- spec/tshield/controllers/requests_spec.rb
|
475
472
|
- spec/tshield/options_spec.rb
|
473
|
+
- spec/tshield/controllers/requests_spec.rb
|
474
|
+
- spec/tshield/configuration_spec.rb
|
476
475
|
- spec/tshield/after_filter_spec.rb
|
477
|
-
- spec/tshield/
|
476
|
+
- spec/tshield/request_vcr_spec.rb
|
477
|
+
- spec/tshield/sessions_spec.rb
|
478
|
+
- spec/tshield/request_matching_spec.rb
|
479
|
+
- spec/tshield/grpc_spec.rb
|
480
|
+
- spec/tshield/fixtures/config/tshield-without-grpc.yml
|
481
|
+
- spec/tshield/fixtures/config/tshield.yml
|
482
|
+
- spec/tshield/fixtures/config/tshield-with-send-content-type-header_as_false.yml
|
483
|
+
- spec/tshield/fixtures/config/tshield-with-send-content-type-header.yml
|
478
484
|
- spec/tshield/fixtures/proto/test_services_pb.rb
|
479
485
|
- spec/tshield/fixtures/filters/example_filter.rb
|
480
|
-
- spec/tshield/fixtures/
|
481
|
-
- spec/tshield/fixtures/
|
486
|
+
- spec/tshield/fixtures/matching/empty.json
|
487
|
+
- spec/tshield/fixtures/matching/invalid_matching_file.json
|
488
|
+
- spec/tshield/fixtures/matching/example.json
|
489
|
+
- spec/spec_helper.rb
|