tshield 0.13.0.0 → 0.13.5.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 +5 -5
- data/README.md +4 -1
- data/lib/tshield/configuration.rb +9 -4
- data/lib/tshield/controllers/requests.rb +8 -1
- data/lib/tshield/grpc/vcr.rb +11 -6
- data/lib/tshield/request_matching.rb +31 -7
- data/lib/tshield/request_vcr.rb +30 -2
- data/lib/tshield/server.rb +2 -2
- data/lib/tshield/version.rb +1 -1
- data/spec/spec_helper.rb +4 -2
- data/spec/tshield/configuration_spec.rb +36 -8
- 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/request_matching_spec.rb +32 -0
- data/spec/tshield/request_vcr_spec.rb +46 -4
- data/tshield.gemspec +1 -1
- metadata +81 -78
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ab5c5057fe81ae295f572912c6955ce0ea0bd9be6b42fb515a7832fe3451459a
|
4
|
+
data.tar.gz: 9c785dc23adb245fdfcc416698c551f7a45eaa32b5892a2cabea708f16fa2859
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58fd33ddf9e466af5882e6522612b2b0fa05c95f728578fe50b014dca0777357bf5ccfa17605a86309c5742cb828dd2e52eb9bb2839096f594e1e75fef80e81b
|
7
|
+
data.tar.gz: f085f1dcc7a3d861da1b28a0d07f3338f03dd5b27cdd234c283cecf0bce8a0dc66f26193755ea8f5b442cbf4953fb2bd4ce295f90257b76121ac7fdbcbdd38b0
|
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.
|
@@ -191,6 +192,7 @@ domains:
|
|
191
192
|
headers:
|
192
193
|
HTTP_AUTHORIZATION: Authorization
|
193
194
|
HTTP_COOKIE: Cookie
|
195
|
+
send_header_content_type: true
|
194
196
|
not_save_headers:
|
195
197
|
- transfer-encoding
|
196
198
|
cache_request: <<value>>
|
@@ -234,6 +236,7 @@ domains:
|
|
234
236
|
* Define Base URI of service
|
235
237
|
* **name**: Name to identify the domain in the generated files
|
236
238
|
* **headers**: github-issue #17
|
239
|
+
* **send_header_content_type**: Boolean domain config to send header 'Content-Type' when requesting this domain
|
237
240
|
* **not_save_headers**: List of headers that should be ignored in generated file
|
238
241
|
* **skip_query_params**: List of query params that should be ignored in generated file
|
239
242
|
* **cache_request**: <<some_description>>
|
@@ -65,6 +65,10 @@ module TShield
|
|
65
65
|
nil
|
66
66
|
end
|
67
67
|
|
68
|
+
def windows_compatibility?
|
69
|
+
windows_compatibility || false
|
70
|
+
end
|
71
|
+
|
68
72
|
def get_headers(domain)
|
69
73
|
(domains[domain] || {})['headers'] || {}
|
70
74
|
end
|
@@ -100,12 +104,13 @@ module TShield
|
|
100
104
|
domains[domain]['not_save_headers'] || []
|
101
105
|
end
|
102
106
|
|
103
|
-
def
|
104
|
-
|
107
|
+
def send_header_content_type(domain)
|
108
|
+
return domains[domain]['send_header_content_type'] != false if domains[domain]
|
109
|
+
true
|
105
110
|
end
|
106
111
|
|
107
|
-
def
|
108
|
-
|
112
|
+
def read_session_path
|
113
|
+
session_path || '/sessions'
|
109
114
|
end
|
110
115
|
|
111
116
|
def grpc
|
@@ -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,
|
@@ -74,7 +76,7 @@ module TShield
|
|
74
76
|
configuration.get_excluded_headers(domain(path)).include?(key)
|
75
77
|
end
|
76
78
|
end
|
77
|
-
|
79
|
+
|
78
80
|
logger.info(
|
79
81
|
"original=#{api_response.original} method=#{method} path=#{path} "\
|
80
82
|
"content-type=#{request_content_type} "\
|
@@ -94,6 +96,11 @@ module TShield
|
|
94
96
|
end
|
95
97
|
end
|
96
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
|
+
|
97
104
|
def configuration
|
98
105
|
@configuration ||= TShield::Configuration.singleton
|
99
106
|
end
|
data/lib/tshield/grpc/vcr.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'tshield/configuration'
|
3
4
|
require 'tshield/sessions'
|
4
5
|
|
5
6
|
module TShield
|
6
7
|
module Grpc
|
7
8
|
module VCR
|
9
|
+
def initialize
|
10
|
+
@configuration = TShield::Configuration.singleton
|
11
|
+
end
|
8
12
|
def handler_in_vcr_mode(method_name, request, parameters, options)
|
9
13
|
parameters.peer =~ /ipv6:\[(.+?)\]|ipv4:(.+?):/
|
10
14
|
peer = Regexp.last_match(1) || Regexp.last_match(2)
|
@@ -16,6 +20,7 @@ module TShield
|
|
16
20
|
module_name = options['module']
|
17
21
|
|
18
22
|
path = create_destiny(module_name, method_name, request)
|
23
|
+
save_request(path, request)
|
19
24
|
response = saved_response(path)
|
20
25
|
if response
|
21
26
|
TShield.logger.info("returning saved response for request #{request.to_json} saved into #{hexdigest(request)}")
|
@@ -26,10 +31,14 @@ module TShield
|
|
26
31
|
client_class = Object.const_get("#{module_name}::Stub")
|
27
32
|
client_instance = client_class.new(options['hostname'], :this_channel_is_insecure)
|
28
33
|
response = client_instance.send(method_name, request)
|
29
|
-
|
34
|
+
save_response(path, response)
|
30
35
|
response
|
31
36
|
end
|
32
37
|
|
38
|
+
def encode_colon(value)
|
39
|
+
value.gsub(':','%3a')
|
40
|
+
end
|
41
|
+
|
33
42
|
def saved_response(path)
|
34
43
|
response_file = File.join(path, 'response')
|
35
44
|
return false unless File.exist? response_file
|
@@ -39,11 +48,6 @@ module TShield
|
|
39
48
|
Kernel.const_get(response_class).new(content)
|
40
49
|
end
|
41
50
|
|
42
|
-
def save_request_and_response(path, request, response)
|
43
|
-
save_request(path, request)
|
44
|
-
save_response(path, response)
|
45
|
-
end
|
46
|
-
|
47
51
|
def save_request(path, request)
|
48
52
|
file = File.open(File.join(path, 'original_request'), 'w')
|
49
53
|
file.puts request.to_json
|
@@ -62,6 +66,7 @@ module TShield
|
|
62
66
|
|
63
67
|
def complete_path(module_name, method_name, request)
|
64
68
|
@session_name = (@session || {})[:name]
|
69
|
+
module_name = @configuration.windows_compatibility? ? encode_colon(module_name) : module_name
|
65
70
|
path = ['requests', 'grpc', @session_name, module_name, method_name.to_s, hexdigest(request)].compact
|
66
71
|
path
|
67
72
|
end
|
@@ -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
|
|
@@ -59,15 +60,38 @@ module TShield
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def load_stub(file)
|
62
|
-
content =
|
63
|
+
content = read_stub_file(file)
|
63
64
|
content.each do |stub|
|
64
|
-
|
65
|
+
next unless valid_stub?(file, stub)
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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)
|
71
95
|
end
|
72
96
|
end
|
73
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,
|
@@ -136,14 +155,23 @@ module TShield
|
|
136
155
|
content[:body] = body
|
137
156
|
end
|
138
157
|
|
158
|
+
def encode_for_windows_dir(directory)
|
159
|
+
replace = [['<','%3c'],['>','%3e'],[':','%3a'],['"','%22'],['?','%3f'],[' ','%20'],['*','%2a'],['/','%2f']]
|
160
|
+
replace.each do |value|
|
161
|
+
directory = directory.gsub(value.first,value.last)
|
162
|
+
end
|
163
|
+
directory
|
164
|
+
end
|
165
|
+
|
139
166
|
def safe_dir(url)
|
140
167
|
if url.size > 225
|
141
168
|
path = url.gsub(/(\?.*)/, '')
|
142
169
|
params = Digest::SHA1.hexdigest Regexp.last_match(1)
|
143
|
-
"#{path.gsub(%r{/}, '-').gsub(/^-/, '')}
|
170
|
+
directory = "#{path.gsub(%r{/}, '-').gsub(/^-/, '')}?#{params}"
|
144
171
|
else
|
145
|
-
url.gsub(%r{/}, '-').gsub(/^-/, '')
|
172
|
+
directory = url.gsub(%r{/}, '-').gsub(/^-/, '')
|
146
173
|
end
|
174
|
+
configuration.windows_compatibility? ? encode_for_windows_dir(directory) : directory
|
147
175
|
end
|
148
176
|
end
|
149
177
|
end
|
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
@@ -71,7 +71,7 @@ describe TShield::Configuration do
|
|
71
71
|
TShield::Configuration.clear
|
72
72
|
@configuration = TShield::Configuration.singleton
|
73
73
|
|
74
|
-
expect(@configuration.
|
74
|
+
expect(@configuration.windows_compatibility?).to eq(true)
|
75
75
|
end
|
76
76
|
|
77
77
|
it 'should be compatible with Unix when configuration is false' do
|
@@ -79,7 +79,7 @@ describe TShield::Configuration do
|
|
79
79
|
TShield::Configuration.clear
|
80
80
|
@configuration = TShield::Configuration.singleton
|
81
81
|
|
82
|
-
expect(@configuration.
|
82
|
+
expect(@configuration.windows_compatibility?).to eq(false)
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'should be compatible with Unix when configuration is missing' do
|
@@ -87,7 +87,7 @@ describe TShield::Configuration do
|
|
87
87
|
TShield::Configuration.clear
|
88
88
|
@configuration = TShield::Configuration.singleton
|
89
89
|
|
90
|
-
expect(@configuration.
|
90
|
+
expect(@configuration.windows_compatibility?).to eq(false)
|
91
91
|
end
|
92
92
|
|
93
93
|
end
|
@@ -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'
|
@@ -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')
|
@@ -62,7 +81,7 @@ describe TShield::RequestVCR do
|
|
62
81
|
}
|
63
82
|
)
|
64
83
|
|
65
|
-
allow(@configuration).to receive(:
|
84
|
+
allow(@configuration).to receive(:windows_compatibility?).and_return(false)
|
66
85
|
|
67
86
|
allow(HTTParty).to receive(:send).and_return(RawResponse.new)
|
68
87
|
file_double = double
|
@@ -87,14 +106,13 @@ describe TShield::RequestVCR do
|
|
87
106
|
end
|
88
107
|
|
89
108
|
it 'should create response directory in windows standard' do
|
90
|
-
|
91
109
|
allow(@configuration).to receive(:domains).and_return(
|
92
110
|
'example.org' => {
|
93
111
|
'skip_query_params' => []
|
94
112
|
}
|
95
113
|
)
|
96
114
|
|
97
|
-
allow(@configuration).to receive(:
|
115
|
+
allow(@configuration).to receive(:windows_compatibility?).and_return(true)
|
98
116
|
|
99
117
|
allow(HTTParty).to receive(:send).and_return(RawResponse.new)
|
100
118
|
file_double = double
|
@@ -131,7 +149,6 @@ describe TShield::RequestVCR do
|
|
131
149
|
call: 0
|
132
150
|
end
|
133
151
|
|
134
|
-
|
135
152
|
end
|
136
153
|
end
|
137
154
|
|
@@ -144,8 +161,33 @@ describe TShield::RequestVCR do
|
|
144
161
|
'this is the body'
|
145
162
|
end
|
146
163
|
|
164
|
+
def get_fields(field = "")
|
165
|
+
[]
|
166
|
+
end
|
167
|
+
|
168
|
+
def code
|
169
|
+
200
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class RawResponseCookiesMultipleValues
|
174
|
+
def headers
|
175
|
+
{'Set-Cookie' => ['FirstCookie=An Value', 'SecondCookie=An Value']}
|
176
|
+
end
|
177
|
+
|
178
|
+
def body
|
179
|
+
'this is the body'
|
180
|
+
end
|
181
|
+
|
182
|
+
def get_fields(field = "")
|
183
|
+
self.headers[filed] unless self.headers.key?(field)
|
184
|
+
end
|
185
|
+
|
147
186
|
def code
|
148
187
|
200
|
149
188
|
end
|
150
189
|
end
|
190
|
+
|
151
191
|
end
|
192
|
+
|
193
|
+
|
data/tshield.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_dependency('grpc-tools', '~> 1.28', '>= 1.28.0')
|
29
29
|
s.add_dependency('httparty', '~> 0.14', '>= 0.14.0')
|
30
30
|
s.add_dependency('json', '~> 2.0', '>= 2.0')
|
31
|
-
s.add_dependency('puma', '
|
31
|
+
s.add_dependency('puma', '>= 4.3.3', '< 6.0')
|
32
32
|
s.add_dependency('sinatra', '~> 2.1', '>= 2.1.0')
|
33
33
|
s.add_dependency('sinatra-cross_origin', '~> 0.4.0', '>= 0.4')
|
34
34
|
s.add_development_dependency('coveralls', '~> 0.8', '>= 0.8.23')
|
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.13.
|
4
|
+
version: 0.13.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Diego Rubin
|
@@ -9,148 +9,148 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-06-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: grpc
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - "~>"
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: '1.28'
|
21
18
|
- - ">="
|
22
19
|
- !ruby/object:Gem::Version
|
23
20
|
version: 1.28.0
|
21
|
+
- - "~>"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '1.28'
|
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: '1.28'
|
31
28
|
- - ">="
|
32
29
|
- !ruby/object:Gem::Version
|
33
30
|
version: 1.28.0
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.28'
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: grpc-tools
|
36
36
|
requirement: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '1.28'
|
41
38
|
- - ">="
|
42
39
|
- !ruby/object:Gem::Version
|
43
40
|
version: 1.28.0
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.28'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
46
|
version_requirements: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
|
-
- - "~>"
|
49
|
-
- !ruby/object:Gem::Version
|
50
|
-
version: '1.28'
|
51
48
|
- - ">="
|
52
49
|
- !ruby/object:Gem::Version
|
53
50
|
version: 1.28.0
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.28'
|
54
54
|
- !ruby/object:Gem::Dependency
|
55
55
|
name: httparty
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
|
-
- - "~>"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '0.14'
|
61
58
|
- - ">="
|
62
59
|
- !ruby/object:Gem::Version
|
63
60
|
version: 0.14.0
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0.14'
|
64
64
|
type: :runtime
|
65
65
|
prerelease: false
|
66
66
|
version_requirements: !ruby/object:Gem::Requirement
|
67
67
|
requirements:
|
68
|
-
- - "~>"
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
version: '0.14'
|
71
68
|
- - ">="
|
72
69
|
- !ruby/object:Gem::Version
|
73
70
|
version: 0.14.0
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0.14'
|
74
74
|
- !ruby/object:Gem::Dependency
|
75
75
|
name: json
|
76
76
|
requirement: !ruby/object:Gem::Requirement
|
77
77
|
requirements:
|
78
|
-
- - "
|
78
|
+
- - ">="
|
79
79
|
- !ruby/object:Gem::Version
|
80
80
|
version: '2.0'
|
81
|
-
- - "
|
81
|
+
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '2.0'
|
84
84
|
type: :runtime
|
85
85
|
prerelease: false
|
86
86
|
version_requirements: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- - "
|
88
|
+
- - ">="
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: '2.0'
|
91
|
-
- - "
|
91
|
+
- - "~>"
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '2.0'
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
95
|
name: puma
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
requirements:
|
98
|
-
- - "~>"
|
99
|
-
- !ruby/object:Gem::Version
|
100
|
-
version: '4.3'
|
101
98
|
- - ">="
|
102
99
|
- !ruby/object:Gem::Version
|
103
100
|
version: 4.3.3
|
101
|
+
- - "<"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '6.0'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '4.3'
|
111
108
|
- - ">="
|
112
109
|
- !ruby/object:Gem::Version
|
113
110
|
version: 4.3.3
|
111
|
+
- - "<"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '6.0'
|
114
114
|
- !ruby/object:Gem::Dependency
|
115
115
|
name: sinatra
|
116
116
|
requirement: !ruby/object:Gem::Requirement
|
117
117
|
requirements:
|
118
|
-
- - "~>"
|
119
|
-
- !ruby/object:Gem::Version
|
120
|
-
version: '2.1'
|
121
118
|
- - ">="
|
122
119
|
- !ruby/object:Gem::Version
|
123
120
|
version: 2.1.0
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '2.1'
|
124
124
|
type: :runtime
|
125
125
|
prerelease: false
|
126
126
|
version_requirements: !ruby/object:Gem::Requirement
|
127
127
|
requirements:
|
128
|
-
- - "~>"
|
129
|
-
- !ruby/object:Gem::Version
|
130
|
-
version: '2.1'
|
131
128
|
- - ">="
|
132
129
|
- !ruby/object:Gem::Version
|
133
130
|
version: 2.1.0
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '2.1'
|
134
134
|
- !ruby/object:Gem::Dependency
|
135
135
|
name: sinatra-cross_origin
|
136
136
|
requirement: !ruby/object:Gem::Requirement
|
137
137
|
requirements:
|
138
|
-
- - "~>"
|
139
|
-
- !ruby/object:Gem::Version
|
140
|
-
version: 0.4.0
|
141
138
|
- - ">="
|
142
139
|
- !ruby/object:Gem::Version
|
143
140
|
version: '0.4'
|
141
|
+
- - "~>"
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: 0.4.0
|
144
144
|
type: :runtime
|
145
145
|
prerelease: false
|
146
146
|
version_requirements: !ruby/object:Gem::Requirement
|
147
147
|
requirements:
|
148
|
-
- - "~>"
|
149
|
-
- !ruby/object:Gem::Version
|
150
|
-
version: 0.4.0
|
151
148
|
- - ">="
|
152
149
|
- !ruby/object:Gem::Version
|
153
150
|
version: '0.4'
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 0.4.0
|
154
154
|
- !ruby/object:Gem::Dependency
|
155
155
|
name: coveralls
|
156
156
|
requirement: !ruby/object:Gem::Requirement
|
@@ -255,80 +255,80 @@ dependencies:
|
|
255
255
|
name: rdoc
|
256
256
|
requirement: !ruby/object:Gem::Requirement
|
257
257
|
requirements:
|
258
|
-
- - "
|
258
|
+
- - ">="
|
259
259
|
- !ruby/object:Gem::Version
|
260
260
|
version: '6.0'
|
261
|
-
- - "
|
261
|
+
- - "~>"
|
262
262
|
- !ruby/object:Gem::Version
|
263
263
|
version: '6.0'
|
264
264
|
type: :development
|
265
265
|
prerelease: false
|
266
266
|
version_requirements: !ruby/object:Gem::Requirement
|
267
267
|
requirements:
|
268
|
-
- - "
|
268
|
+
- - ">="
|
269
269
|
- !ruby/object:Gem::Version
|
270
270
|
version: '6.0'
|
271
|
-
- - "
|
271
|
+
- - "~>"
|
272
272
|
- !ruby/object:Gem::Version
|
273
273
|
version: '6.0'
|
274
274
|
- !ruby/object:Gem::Dependency
|
275
275
|
name: reek
|
276
276
|
requirement: !ruby/object:Gem::Requirement
|
277
277
|
requirements:
|
278
|
-
- - "
|
278
|
+
- - ">="
|
279
279
|
- !ruby/object:Gem::Version
|
280
280
|
version: 5.4.0
|
281
|
-
- - "
|
281
|
+
- - "~>"
|
282
282
|
- !ruby/object:Gem::Version
|
283
283
|
version: 5.4.0
|
284
284
|
type: :development
|
285
285
|
prerelease: false
|
286
286
|
version_requirements: !ruby/object:Gem::Requirement
|
287
287
|
requirements:
|
288
|
-
- - "
|
288
|
+
- - ">="
|
289
289
|
- !ruby/object:Gem::Version
|
290
290
|
version: 5.4.0
|
291
|
-
- - "
|
291
|
+
- - "~>"
|
292
292
|
- !ruby/object:Gem::Version
|
293
293
|
version: 5.4.0
|
294
294
|
- !ruby/object:Gem::Dependency
|
295
295
|
name: rspec
|
296
296
|
requirement: !ruby/object:Gem::Requirement
|
297
297
|
requirements:
|
298
|
-
- - "~>"
|
299
|
-
- !ruby/object:Gem::Version
|
300
|
-
version: '3.5'
|
301
298
|
- - ">="
|
302
299
|
- !ruby/object:Gem::Version
|
303
300
|
version: 3.5.0
|
301
|
+
- - "~>"
|
302
|
+
- !ruby/object:Gem::Version
|
303
|
+
version: '3.5'
|
304
304
|
type: :development
|
305
305
|
prerelease: false
|
306
306
|
version_requirements: !ruby/object:Gem::Requirement
|
307
307
|
requirements:
|
308
|
-
- - "~>"
|
309
|
-
- !ruby/object:Gem::Version
|
310
|
-
version: '3.5'
|
311
308
|
- - ">="
|
312
309
|
- !ruby/object:Gem::Version
|
313
310
|
version: 3.5.0
|
311
|
+
- - "~>"
|
312
|
+
- !ruby/object:Gem::Version
|
313
|
+
version: '3.5'
|
314
314
|
- !ruby/object:Gem::Dependency
|
315
315
|
name: rubocop
|
316
316
|
requirement: !ruby/object:Gem::Requirement
|
317
317
|
requirements:
|
318
|
-
- - "
|
318
|
+
- - ">="
|
319
319
|
- !ruby/object:Gem::Version
|
320
320
|
version: 0.73.0
|
321
|
-
- - "
|
321
|
+
- - "~>"
|
322
322
|
- !ruby/object:Gem::Version
|
323
323
|
version: 0.73.0
|
324
324
|
type: :development
|
325
325
|
prerelease: false
|
326
326
|
version_requirements: !ruby/object:Gem::Requirement
|
327
327
|
requirements:
|
328
|
-
- - "
|
328
|
+
- - ">="
|
329
329
|
- !ruby/object:Gem::Version
|
330
330
|
version: 0.73.0
|
331
|
-
- - "
|
331
|
+
- - "~>"
|
332
332
|
- !ruby/object:Gem::Version
|
333
333
|
version: 0.73.0
|
334
334
|
- !ruby/object:Gem::Dependency
|
@@ -375,22 +375,22 @@ dependencies:
|
|
375
375
|
name: webmock
|
376
376
|
requirement: !ruby/object:Gem::Requirement
|
377
377
|
requirements:
|
378
|
-
- - "~>"
|
379
|
-
- !ruby/object:Gem::Version
|
380
|
-
version: '2.1'
|
381
378
|
- - ">="
|
382
379
|
- !ruby/object:Gem::Version
|
383
380
|
version: 2.1.0
|
381
|
+
- - "~>"
|
382
|
+
- !ruby/object:Gem::Version
|
383
|
+
version: '2.1'
|
384
384
|
type: :development
|
385
385
|
prerelease: false
|
386
386
|
version_requirements: !ruby/object:Gem::Requirement
|
387
387
|
requirements:
|
388
|
-
- - "~>"
|
389
|
-
- !ruby/object:Gem::Version
|
390
|
-
version: '2.1'
|
391
388
|
- - ">="
|
392
389
|
- !ruby/object:Gem::Version
|
393
390
|
version: 2.1.0
|
391
|
+
- - "~>"
|
392
|
+
- !ruby/object:Gem::Version
|
393
|
+
version: '2.1'
|
394
394
|
description: Proxy for mocks API responses
|
395
395
|
email: rubin.diego@gmail.com
|
396
396
|
executables:
|
@@ -430,6 +430,8 @@ 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
|
@@ -460,23 +462,24 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
460
462
|
- !ruby/object:Gem::Version
|
461
463
|
version: '0'
|
462
464
|
requirements: []
|
463
|
-
|
464
|
-
rubygems_version: 2.6.14.4
|
465
|
+
rubygems_version: 3.0.3.1
|
465
466
|
signing_key:
|
466
467
|
specification_version: 4
|
467
468
|
summary: Proxy for mocks API responses
|
468
469
|
test_files:
|
469
|
-
- spec/
|
470
|
+
- spec/tshield/controllers/requests_spec.rb
|
471
|
+
- spec/tshield/after_filter_spec.rb
|
472
|
+
- spec/tshield/configuration_spec.rb
|
473
|
+
- spec/tshield/fixtures/proto/test_services_pb.rb
|
474
|
+
- spec/tshield/fixtures/config/tshield-without-grpc.yml
|
475
|
+
- spec/tshield/fixtures/config/tshield-with-send-content-type-header_as_false.yml
|
476
|
+
- spec/tshield/fixtures/config/tshield.yml
|
477
|
+
- spec/tshield/fixtures/config/tshield-with-send-content-type-header.yml
|
478
|
+
- spec/tshield/fixtures/matching/example.json
|
479
|
+
- spec/tshield/fixtures/filters/example_filter.rb
|
470
480
|
- spec/tshield/request_vcr_spec.rb
|
471
481
|
- spec/tshield/sessions_spec.rb
|
472
|
-
- spec/tshield/controllers/requests_spec.rb
|
473
|
-
- spec/tshield/request_matching_spec.rb
|
474
482
|
- spec/tshield/grpc_spec.rb
|
475
483
|
- spec/tshield/options_spec.rb
|
476
|
-
- spec/tshield/
|
477
|
-
- spec/
|
478
|
-
- spec/tshield/fixtures/matching/example.json
|
479
|
-
- spec/tshield/fixtures/config/tshield.yml
|
480
|
-
- spec/tshield/fixtures/config/tshield-without-grpc.yml
|
481
|
-
- spec/tshield/configuration_spec.rb
|
482
|
-
- spec/tshield/after_filter_spec.rb
|
484
|
+
- spec/tshield/request_matching_spec.rb
|
485
|
+
- spec/spec_helper.rb
|