tshield 0.13.2.0 → 0.14.0.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 +2 -0
- data/lib/tshield/configuration.rb +11 -9
- data/lib/tshield/controllers/requests.rb +8 -2
- data/lib/tshield/grpc/grpc_counter.rb +24 -0
- data/lib/tshield/grpc/vcr.rb +81 -24
- data/lib/tshield/grpc.rb +3 -3
- data/lib/tshield/logger.rb +1 -1
- data/lib/tshield/request_matching.rb +31 -7
- data/lib/tshield/request_vcr.rb +13 -3
- data/lib/tshield/sessions.rb +2 -0
- data/lib/tshield/version.rb +2 -2
- data/spec/tshield/configuration_spec.rb +38 -11
- data/spec/tshield/controllers/requests_spec.rb +90 -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 +20 -26
- data/tshield.gemspec +1 -1
- metadata +81 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 83eb12f572bdfd5f6fade21d83ee7d4883253aa9e42cad7fe0e9feac380d7ae6
|
4
|
+
data.tar.gz: c1718a13671ee6899321dcda86c6d6dbaad23c1389cc24c0b6ea3b684024c725
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 003b70dbe21e80655ebfe6eae9e0260137a3f6e3e478200c04eefbc238ae72d8d172b62c4d980a934fd56a08eb7d2ad59d93b4d762a3c019e88d3e2e6cc39d46
|
7
|
+
data.tar.gz: 6c4ada87361e89edff1b8fe7353389861c3748986631ad9693d01f148c71fb2dbe06547b318d94c3247dc584081c047fc915f5d1d014d6026172b8cf406b5753
|
data/README.md
CHANGED
@@ -192,6 +192,7 @@ domains:
|
|
192
192
|
headers:
|
193
193
|
HTTP_AUTHORIZATION: Authorization
|
194
194
|
HTTP_COOKIE: Cookie
|
195
|
+
send_header_content_type: true
|
195
196
|
not_save_headers:
|
196
197
|
- transfer-encoding
|
197
198
|
cache_request: <<value>>
|
@@ -235,6 +236,7 @@ domains:
|
|
235
236
|
* Define Base URI of service
|
236
237
|
* **name**: Name to identify the domain in the generated files
|
237
238
|
* **headers**: github-issue #17
|
239
|
+
* **send_header_content_type**: Boolean domain config to send header 'Content-Type' when requesting this domain
|
238
240
|
* **not_save_headers**: List of headers that should be ignored in generated file
|
239
241
|
* **skip_query_params**: List of query params that should be ignored in generated file
|
240
242
|
* **cache_request**: <<some_description>>
|
@@ -29,10 +29,7 @@ module TShield
|
|
29
29
|
# generated directory
|
30
30
|
#
|
31
31
|
attr_reader :request
|
32
|
-
attr_reader :domains
|
33
|
-
attr_reader :tcp_servers
|
34
|
-
attr_reader :session_path
|
35
|
-
attr_reader :windows_compatibility
|
32
|
+
attr_reader :domains, :tcp_servers, :session_path, :windows_compatibility
|
36
33
|
|
37
34
|
def initialize(attributes)
|
38
35
|
attributes.each { |key, value| instance_variable_set("@#{key}", value) }
|
@@ -65,6 +62,10 @@ module TShield
|
|
65
62
|
nil
|
66
63
|
end
|
67
64
|
|
65
|
+
def windows_compatibility?
|
66
|
+
windows_compatibility || false
|
67
|
+
end
|
68
|
+
|
68
69
|
def get_headers(domain)
|
69
70
|
(domains[domain] || {})['headers'] || {}
|
70
71
|
end
|
@@ -100,12 +101,14 @@ module TShield
|
|
100
101
|
domains[domain]['not_save_headers'] || []
|
101
102
|
end
|
102
103
|
|
103
|
-
def
|
104
|
-
|
104
|
+
def send_header_content_type(domain)
|
105
|
+
return domains[domain]['send_header_content_type'] != false if domains[domain]
|
106
|
+
|
107
|
+
true
|
105
108
|
end
|
106
109
|
|
107
|
-
def
|
108
|
-
|
110
|
+
def read_session_path
|
111
|
+
session_path || '/sessions'
|
109
112
|
end
|
110
113
|
|
111
114
|
def grpc
|
@@ -135,6 +138,5 @@ module TShield
|
|
135
138
|
def get_delay(domain, path)
|
136
139
|
((domains[domain] || {})['delay'] || {})[path] || 0
|
137
140
|
end
|
138
|
-
|
139
141
|
end
|
140
142
|
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,
|
@@ -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
|
@@ -107,7 +114,6 @@ module TShield
|
|
107
114
|
logger.info("Response with delay of #{delay_in_seconds} seconds")
|
108
115
|
sleep delay_in_seconds
|
109
116
|
end
|
110
|
-
|
111
117
|
end
|
112
118
|
end
|
113
119
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TShield
|
4
|
+
# Increment counter for sessions requests
|
5
|
+
class GrpcCounter
|
6
|
+
def initialize
|
7
|
+
@requests = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(hexdigest)
|
11
|
+
count = @requests.fetch(hexdigest, 0)
|
12
|
+
count += 1
|
13
|
+
@requests[hexdigest] = count
|
14
|
+
end
|
15
|
+
|
16
|
+
def current(hexdigest)
|
17
|
+
@requests.fetch(hexdigest, 0)
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_json(options = {})
|
21
|
+
@requests.to_json(options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/tshield/grpc/vcr.rb
CHANGED
@@ -1,74 +1,131 @@
|
|
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
|
8
|
+
# Grpc vcr module
|
7
9
|
module VCR
|
10
|
+
# Path file to save Grpc request/response
|
11
|
+
class FilePath
|
12
|
+
attr_reader :path, :count
|
13
|
+
|
14
|
+
def initialize(path, count)
|
15
|
+
@path = path
|
16
|
+
@count = count
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@configuration = TShield::Configuration.singleton
|
22
|
+
end
|
23
|
+
|
8
24
|
def handler_in_vcr_mode(method_name, request, parameters, options)
|
9
25
|
parameters.peer =~ /ipv6:\[(.+?)\]|ipv4:(.+?):/
|
10
26
|
peer = Regexp.last_match(1) || Regexp.last_match(2)
|
11
27
|
|
12
28
|
TShield.logger.info("request from #{parameters.peer}")
|
13
29
|
@session = TShield::Sessions.current(peer)
|
30
|
+
@digest = hexdigest(request)
|
31
|
+
counter = @session ? request_count.current(@digest) : 0
|
14
32
|
|
15
33
|
TShield.logger.info("grpc using session #{@session || 'default'}")
|
16
34
|
module_name = options['module']
|
17
35
|
|
18
|
-
path = create_destiny(module_name, method_name
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
36
|
+
path = create_destiny(module_name, method_name)
|
37
|
+
@file_path = FilePath.new(path, counter)
|
38
|
+
save_request(request)
|
39
|
+
response = {}
|
40
|
+
saved_error
|
41
|
+
begin
|
42
|
+
response = saved_response
|
43
|
+
if response
|
44
|
+
TShield.logger.info("returning saved response for request #{request.to_json} saved into #{@digest}")
|
45
|
+
request_count.add(@digest) if @session
|
46
|
+
return response
|
47
|
+
end
|
48
|
+
|
49
|
+
response = send_request(request, module_name, options, method_name)
|
50
|
+
save_response(response)
|
51
|
+
rescue GRPC::BadStatus => e
|
52
|
+
save_error({ code: e.code, details: e.details })
|
53
|
+
raise e
|
24
54
|
end
|
55
|
+
request_count.add(@digest) if @session
|
56
|
+
response
|
57
|
+
end
|
25
58
|
|
59
|
+
def send_request(request, module_name, options, method_name)
|
26
60
|
TShield.logger.info("calling server to get response for #{request.to_json}")
|
27
61
|
client_class = Object.const_get("#{module_name}::Stub")
|
28
62
|
client_instance = client_class.new(options['hostname'], :this_channel_is_insecure)
|
29
|
-
|
30
|
-
save_response(path, response)
|
31
|
-
response
|
63
|
+
client_instance.send(method_name, request)
|
32
64
|
end
|
33
65
|
|
34
|
-
def
|
35
|
-
|
66
|
+
def request_count
|
67
|
+
@session[:grpc_counter]
|
68
|
+
end
|
69
|
+
|
70
|
+
def encode_colon(value)
|
71
|
+
value.gsub(':', '%3a')
|
72
|
+
end
|
73
|
+
|
74
|
+
def saved_response
|
75
|
+
response_file = File.join(@file_path.path, "#{@file_path.count}.response")
|
36
76
|
return false unless File.exist? response_file
|
37
77
|
|
38
78
|
content = JSON.parse File.open(response_file).read
|
39
|
-
response_class = File.open(File.join(path,
|
79
|
+
response_class = File.open(File.join(@file_path.path, "#{@file_path.count}.response_class")).read.strip
|
40
80
|
Kernel.const_get(response_class).new(content)
|
41
81
|
end
|
42
82
|
|
43
|
-
def
|
44
|
-
|
83
|
+
def saved_error
|
84
|
+
error_file = File.join(@file_path.path, "#{@file_path.count}.error")
|
85
|
+
return false unless File.exist? error_file
|
86
|
+
|
87
|
+
request_count.add(@digest) if @session
|
88
|
+
content = JSON.parse File.open(error_file).read
|
89
|
+
grpc_error = GRPC::BadStatus.new(content['code'], content['details'])
|
90
|
+
raise grpc_error
|
91
|
+
end
|
92
|
+
|
93
|
+
def save_request(request)
|
94
|
+
file = File.open(File.join(@file_path.path, "#{@file_path.count}.original_request"), 'w')
|
45
95
|
file.puts request.to_json
|
46
96
|
file.close
|
47
97
|
end
|
48
98
|
|
49
|
-
def
|
50
|
-
file = File.open(File.join(path,
|
99
|
+
def save_error(error)
|
100
|
+
file = File.open(File.join(@file_path.path, "#{@file_path.count}.error"), 'w')
|
101
|
+
file.puts error.to_json
|
102
|
+
file.close
|
103
|
+
request_count.add(@digest) if @session
|
104
|
+
end
|
105
|
+
|
106
|
+
def save_response(response)
|
107
|
+
file = File.open(File.join(@file_path.path, "#{@file_path.count}.response"), 'w')
|
51
108
|
file.puts response.to_json
|
52
109
|
file.close
|
53
110
|
|
54
|
-
response_class = File.open(File.join(path,
|
111
|
+
response_class = File.open(File.join(@file_path.path, "#{@file_path.count}.response_class"), 'w')
|
55
112
|
response_class.puts response.class.to_s
|
56
113
|
response_class.close
|
57
114
|
end
|
58
115
|
|
59
|
-
def complete_path(module_name, method_name
|
116
|
+
def complete_path(module_name, method_name)
|
60
117
|
@session_name = (@session || {})[:name]
|
61
|
-
|
62
|
-
|
118
|
+
module_name = @configuration.windows_compatibility? ? encode_colon(module_name) : module_name
|
119
|
+
['requests', @session_name, module_name, method_name.to_s, @digest].compact
|
63
120
|
end
|
64
121
|
|
65
|
-
def create_destiny(module_name, method_name
|
122
|
+
def create_destiny(module_name, method_name)
|
66
123
|
current_path = []
|
67
124
|
|
68
|
-
path = complete_path(module_name, method_name
|
125
|
+
path = complete_path(module_name, method_name)
|
69
126
|
TShield.logger.info("using path #{path}")
|
70
|
-
path.each do |
|
71
|
-
current_path <<
|
127
|
+
path.each do |inner_path|
|
128
|
+
current_path << inner_path
|
72
129
|
destiny = File.join current_path
|
73
130
|
Dir.mkdir destiny unless File.exist? destiny
|
74
131
|
end
|
data/lib/tshield/grpc.rb
CHANGED
@@ -4,7 +4,6 @@ require 'grpc'
|
|
4
4
|
|
5
5
|
require 'tshield/configuration'
|
6
6
|
require 'tshield/grpc/vcr'
|
7
|
-
|
8
7
|
module TShield
|
9
8
|
module Grpc
|
10
9
|
module RequestHandler
|
@@ -14,6 +13,7 @@ module TShield
|
|
14
13
|
handler_in_vcr_mode(method_name, request, parameters, options)
|
15
14
|
end
|
16
15
|
end
|
16
|
+
|
17
17
|
def self.run!
|
18
18
|
@configuration = TShield::Configuration.singleton.grpc
|
19
19
|
|
@@ -41,6 +41,7 @@ module TShield
|
|
41
41
|
handlers = []
|
42
42
|
number_of_handlers = 0
|
43
43
|
services.each do |file, options|
|
44
|
+
|
44
45
|
require file
|
45
46
|
|
46
47
|
base = Object.const_get("#{options['module']}::Service")
|
@@ -55,8 +56,7 @@ module TShield
|
|
55
56
|
def self.build_handler(base, descriptions, number_of_handlers, options)
|
56
57
|
handler = Class.new(base) do
|
57
58
|
class << self
|
58
|
-
|
59
|
-
attr_reader :options
|
59
|
+
attr_accessor :options
|
60
60
|
end
|
61
61
|
descriptions.each do |service_name, description|
|
62
62
|
puts description
|
data/lib/tshield/logger.rb
CHANGED
@@ -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
@@ -79,7 +79,6 @@ module TShield
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def apply_set_cookie_header_values(raw_response, headers = {})
|
82
|
-
|
83
82
|
headers_clone = headers.clone
|
84
83
|
|
85
84
|
field = raw_response.get_fields('Set-Cookie')
|
@@ -98,6 +97,7 @@ module TShield
|
|
98
97
|
|
99
98
|
raw_response.headers.each do |k, v|
|
100
99
|
next if k == 'set-cookie'
|
100
|
+
|
101
101
|
headers[k] = v unless configuration.not_save_headers(domain).include? k
|
102
102
|
end
|
103
103
|
|
@@ -155,14 +155,24 @@ module TShield
|
|
155
155
|
content[:body] = body
|
156
156
|
end
|
157
157
|
|
158
|
+
def encode_for_windows_dir(directory)
|
159
|
+
replace = [['<', '%3c'], ['>', '%3e'], [':', '%3a'], ['"', '%22'], ['?', '%3f'], [' ', '%20'], ['*', '%2a'],
|
160
|
+
['/', '%2f']]
|
161
|
+
replace.each do |value|
|
162
|
+
directory = directory.gsub(value.first, value.last)
|
163
|
+
end
|
164
|
+
directory
|
165
|
+
end
|
166
|
+
|
158
167
|
def safe_dir(url)
|
159
168
|
if url.size > 225
|
160
169
|
path = url.gsub(/(\?.*)/, '')
|
161
170
|
params = Digest::SHA1.hexdigest Regexp.last_match(1)
|
162
|
-
"#{path.gsub(%r{/}, '-').gsub(/^-/, '')}
|
171
|
+
directory = "#{path.gsub(%r{/}, '-').gsub(/^-/, '')}?#{params}"
|
163
172
|
else
|
164
|
-
url.gsub(%r{/}, '-').gsub(/^-/, '')
|
173
|
+
directory = url.gsub(%r{/}, '-').gsub(/^-/, '')
|
165
174
|
end
|
175
|
+
configuration.windows_compatibility? ? encode_for_windows_dir(directory) : directory
|
166
176
|
end
|
167
177
|
end
|
168
178
|
end
|
data/lib/tshield/sessions.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'tshield/logger'
|
4
4
|
require 'tshield/counter'
|
5
|
+
require 'tshield/grpc/grpc_counter'
|
5
6
|
require 'tshield/errors'
|
6
7
|
|
7
8
|
module TShield
|
@@ -14,6 +15,7 @@ module TShield
|
|
14
15
|
sessions[normalize_ip(ip)] = {
|
15
16
|
name: name,
|
16
17
|
counter: TShield::Counter.new,
|
18
|
+
grpc_counter: TShield::GrpcCounter.new,
|
17
19
|
secondary_sessions: []
|
18
20
|
}
|
19
21
|
end
|
data/lib/tshield/version.rb
CHANGED
@@ -67,19 +67,19 @@ describe TShield::Configuration do
|
|
67
67
|
|
68
68
|
describe 'SO compatibility' do
|
69
69
|
it 'should be compatible with windows when configuration is true' do
|
70
|
-
allow(YAML).to receive(:safe_load).and_return({:
|
70
|
+
allow(YAML).to receive(:safe_load).and_return({ windows_compatibility: true })
|
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
|
78
|
-
allow(YAML).to receive(:safe_load).and_return({:
|
78
|
+
allow(YAML).to receive(:safe_load).and_return({ windows_compatibility: false })
|
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,9 +87,8 @@ 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
|
-
|
93
92
|
end
|
94
93
|
end
|
95
94
|
context 'on config not exist' do
|
@@ -108,14 +107,42 @@ describe TShield::Configuration do
|
|
108
107
|
|
109
108
|
context 'on config exists without grpc entry' do
|
110
109
|
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
|
110
|
+
@configuration = generate_configuration_from_file('spec/tshield/fixtures/config/tshield-without-grpc.yml')
|
111
|
+
TShield::Configuration.clear
|
116
112
|
end
|
117
113
|
it 'should set default value for port' do
|
118
114
|
expect(@configuration.grpc).to eql('port' => 5678, 'proto_dir' => 'proto', 'services' => {})
|
119
115
|
end
|
120
116
|
end
|
117
|
+
|
118
|
+
context 'on config property request.domains.domain.send_header_content_type does not exists' do
|
119
|
+
before :each do
|
120
|
+
@configuration = generate_configuration_from_file('spec/tshield/fixtures/config/tshield-without-grpc.yml')
|
121
|
+
TShield::Configuration.clear
|
122
|
+
end
|
123
|
+
it 'should return send_header_content_type as true when property is not set' do
|
124
|
+
expect(@configuration.send_header_content_type('example.org')).to be true
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'on config property request.domains.domain.send_header_content_type does exists' do
|
129
|
+
before :each do
|
130
|
+
TShield::Configuration.clear
|
131
|
+
end
|
132
|
+
it 'should return send_header_content_type as true when property is true' do
|
133
|
+
@configuration = generate_configuration_from_file('spec/tshield/fixtures/config/tshield-with-send-content-type-header.yml')
|
134
|
+
expect(@configuration.send_header_content_type('example.org')).to be true
|
135
|
+
end
|
136
|
+
it 'should return send_header_content_type as false when property is false' do
|
137
|
+
@configuration = generate_configuration_from_file('spec/tshield/fixtures/config/tshield-with-send-content-type-header_as_false.yml')
|
138
|
+
expect(@configuration.send_header_content_type('example.org')).to be false
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def generate_configuration_from_file(file)
|
144
|
+
options_instance = double
|
145
|
+
allow(options_instance).to receive(:configuration_file).and_return(file)
|
146
|
+
allow(TShield::Options).to receive(:instance).and_return(options_instance)
|
147
|
+
TShield::Configuration.singleton
|
121
148
|
end
|
@@ -58,3 +58,93 @@ 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
|
+
allow(TShield::Options).to receive_message_chain(:instance, :break?)
|
77
|
+
@mock_logger = double
|
78
|
+
@controller = MockController.new(@mock_logger)
|
79
|
+
end
|
80
|
+
context 'when send_header_content_type is false for a single domain' do
|
81
|
+
it 'should remove application/json header when making a request' do
|
82
|
+
params = { 'captures' => ['/'] }
|
83
|
+
request = double
|
84
|
+
matcher = double
|
85
|
+
matched_response = double
|
86
|
+
|
87
|
+
allow(@configuration).to receive(:send_header_content_type).and_return(false)
|
88
|
+
allow(request).to receive(:request_method).and_return('GET')
|
89
|
+
allow(request).to receive(:content_type).and_return('application/json')
|
90
|
+
allow(request).to receive(:ip).and_return('0.0.0.0')
|
91
|
+
allow(request).to receive(:env).and_return('QUERY_STRING' => 'a=b')
|
92
|
+
allow(TShield::RequestMatching).to receive(:new).and_return(matcher)
|
93
|
+
allow(matcher).to receive(:match_request).and_return(nil)
|
94
|
+
allow(TShield::RequestVCR).to receive(:new).and_return(matcher)
|
95
|
+
allow(matcher).to receive(:vcr_response).and_return(matched_response)
|
96
|
+
allow(matched_response).to receive(:original).and_return(false)
|
97
|
+
allow(matched_response).to receive(:status).and_return(200)
|
98
|
+
allow(matched_response).to receive(:headers).and_return({})
|
99
|
+
allow(matched_response).to receive(:body).and_return('')
|
100
|
+
allow(@mock_logger).to receive(:info)
|
101
|
+
|
102
|
+
expect(TShield::RequestVCR).to receive(:new).with('/', {
|
103
|
+
call: 0,
|
104
|
+
headers: {},
|
105
|
+
ip: '0.0.0.0',
|
106
|
+
method: 'GET',
|
107
|
+
raw_query: 'a=b',
|
108
|
+
secondary_sessions: nil,
|
109
|
+
session: nil
|
110
|
+
})
|
111
|
+
@controller.treat(params, request, nil)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when send_header_content_type is true for a single domain' do
|
116
|
+
it 'should NOT remove application/json header when making a request' do
|
117
|
+
params = { 'captures' => ['/'] }
|
118
|
+
request = double
|
119
|
+
matcher = double
|
120
|
+
matched_response = double
|
121
|
+
|
122
|
+
allow(@configuration).to receive(:send_header_content_type).and_return(true)
|
123
|
+
allow(request).to receive(:request_method).and_return('GET')
|
124
|
+
allow(request).to receive(:content_type).and_return('application/json')
|
125
|
+
allow(request).to receive(:ip).and_return('0.0.0.0')
|
126
|
+
allow(request).to receive(:env).and_return('QUERY_STRING' => 'a=b')
|
127
|
+
allow(TShield::RequestMatching).to receive(:new).and_return(matcher)
|
128
|
+
allow(matcher).to receive(:match_request).and_return(nil)
|
129
|
+
allow(TShield::RequestVCR).to receive(:new).and_return(matcher)
|
130
|
+
allow(matcher).to receive(:vcr_response).and_return(matched_response)
|
131
|
+
allow(matched_response).to receive(:original).and_return(false)
|
132
|
+
allow(matched_response).to receive(:status).and_return(200)
|
133
|
+
allow(matched_response).to receive(:headers).and_return({})
|
134
|
+
allow(matched_response).to receive(:body).and_return('')
|
135
|
+
allow(@mock_logger).to receive(:info)
|
136
|
+
|
137
|
+
expect(TShield::RequestVCR).to receive(:new).with('/', {
|
138
|
+
call: 0,
|
139
|
+
headers: { 'Content-Type' => 'application/json' },
|
140
|
+
ip: '0.0.0.0',
|
141
|
+
method: 'GET',
|
142
|
+
raw_query: 'a=b',
|
143
|
+
secondary_sessions: nil,
|
144
|
+
session: nil
|
145
|
+
})
|
146
|
+
|
147
|
+
@controller.treat(params, request, nil)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
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)
|
@@ -81,7 +81,7 @@ describe TShield::RequestVCR do
|
|
81
81
|
}
|
82
82
|
)
|
83
83
|
|
84
|
-
allow(@configuration).to receive(:
|
84
|
+
allow(@configuration).to receive(:windows_compatibility?).and_return(false)
|
85
85
|
|
86
86
|
allow(HTTParty).to receive(:send).and_return(RawResponse.new)
|
87
87
|
file_double = double
|
@@ -106,41 +106,40 @@ describe TShield::RequestVCR do
|
|
106
106
|
end
|
107
107
|
|
108
108
|
it 'should create response directory in windows standard' do
|
109
|
-
|
110
109
|
allow(@configuration).to receive(:domains).and_return(
|
111
|
-
|
112
|
-
|
113
|
-
|
110
|
+
'example.org' => {
|
111
|
+
'skip_query_params' => []
|
112
|
+
}
|
114
113
|
)
|
115
114
|
|
116
|
-
allow(@configuration).to receive(:
|
115
|
+
allow(@configuration).to receive(:windows_compatibility?).and_return(true)
|
117
116
|
|
118
117
|
allow(HTTParty).to receive(:send).and_return(RawResponse.new)
|
119
118
|
file_double = double
|
120
119
|
|
121
120
|
allow(File).to receive(:join)
|
122
|
-
|
123
|
-
|
121
|
+
.with('./requests/example.org', '%3fparam=value')
|
122
|
+
.and_return('./requests/example.org/%3fparam=value')
|
124
123
|
allow(File).to receive(:join)
|
125
|
-
|
126
|
-
|
124
|
+
.with('./requests/example.org/%3fparam=value', 'get')
|
125
|
+
.and_return('./requests/example.org/%3fparam=value/get')
|
127
126
|
allow(File).to receive(:join)
|
128
|
-
|
129
|
-
|
127
|
+
.with('./requests/example.org/%3fparam=value/get', '0')
|
128
|
+
.and_return('./requests/example.org/%3fparam=value/get/0')
|
130
129
|
|
131
130
|
allow(file_double).to receive(:read).and_return('{}')
|
132
131
|
|
133
132
|
expect(File).to receive('open')
|
134
|
-
|
135
|
-
|
133
|
+
.with('./requests/example.org/%3fparam=value/get/0.content', 'w')
|
134
|
+
.and_return(file_double)
|
136
135
|
|
137
136
|
expect(File).to receive('open')
|
138
|
-
|
139
|
-
|
137
|
+
.with('./requests/example.org/%3fparam=value/get/0.json', 'w')
|
138
|
+
.and_return(file_double)
|
140
139
|
|
141
140
|
expect(file_double).to receive(:write).ordered.with('this is the body')
|
142
141
|
expect(file_double).to receive(:write)
|
143
|
-
|
142
|
+
.with("{\n \"status\": 200,\n \"headers\": {\n }\n}")
|
144
143
|
expect(file_double).to receive(:close)
|
145
144
|
expect(file_double).to receive(:close)
|
146
145
|
|
@@ -149,8 +148,6 @@ describe TShield::RequestVCR do
|
|
149
148
|
method: 'GET',
|
150
149
|
call: 0
|
151
150
|
end
|
152
|
-
|
153
|
-
|
154
151
|
end
|
155
152
|
end
|
156
153
|
|
@@ -163,7 +160,7 @@ describe TShield::RequestVCR do
|
|
163
160
|
'this is the body'
|
164
161
|
end
|
165
162
|
|
166
|
-
def get_fields(
|
163
|
+
def get_fields(_field = '')
|
167
164
|
[]
|
168
165
|
end
|
169
166
|
|
@@ -174,22 +171,19 @@ describe TShield::RequestVCR do
|
|
174
171
|
|
175
172
|
class RawResponseCookiesMultipleValues
|
176
173
|
def headers
|
177
|
-
|
174
|
+
{ 'Set-Cookie' => ['FirstCookie=An Value', 'SecondCookie=An Value'] }
|
178
175
|
end
|
179
176
|
|
180
177
|
def body
|
181
178
|
'this is the body'
|
182
179
|
end
|
183
180
|
|
184
|
-
def get_fields(field =
|
185
|
-
|
181
|
+
def get_fields(field = '')
|
182
|
+
headers[filed] unless headers.key?(field)
|
186
183
|
end
|
187
184
|
|
188
185
|
def code
|
189
186
|
200
|
190
187
|
end
|
191
188
|
end
|
192
|
-
|
193
189
|
end
|
194
|
-
|
195
|
-
|
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.
|
4
|
+
version: 0.14.0.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: 2021-
|
12
|
+
date: 2021-10-18 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:
|
@@ -415,6 +415,7 @@ files:
|
|
415
415
|
- lib/tshield/errors.rb
|
416
416
|
- lib/tshield/extensions/string_extensions.rb
|
417
417
|
- lib/tshield/grpc.rb
|
418
|
+
- lib/tshield/grpc/grpc_counter.rb
|
418
419
|
- lib/tshield/grpc/vcr.rb
|
419
420
|
- lib/tshield/logger.rb
|
420
421
|
- lib/tshield/matching/filters.rb
|
@@ -430,6 +431,8 @@ files:
|
|
430
431
|
- spec/tshield/after_filter_spec.rb
|
431
432
|
- spec/tshield/configuration_spec.rb
|
432
433
|
- spec/tshield/controllers/requests_spec.rb
|
434
|
+
- spec/tshield/fixtures/config/tshield-with-send-content-type-header.yml
|
435
|
+
- spec/tshield/fixtures/config/tshield-with-send-content-type-header_as_false.yml
|
433
436
|
- spec/tshield/fixtures/config/tshield-without-grpc.yml
|
434
437
|
- spec/tshield/fixtures/config/tshield.yml
|
435
438
|
- spec/tshield/fixtures/filters/example_filter.rb
|
@@ -460,23 +463,24 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
460
463
|
- !ruby/object:Gem::Version
|
461
464
|
version: '0'
|
462
465
|
requirements: []
|
463
|
-
|
464
|
-
rubygems_version: 2.6.14.4
|
466
|
+
rubygems_version: 3.0.3.1
|
465
467
|
signing_key:
|
466
468
|
specification_version: 4
|
467
469
|
summary: Proxy for mocks API responses
|
468
470
|
test_files:
|
469
471
|
- spec/spec_helper.rb
|
470
|
-
- spec/tshield/
|
472
|
+
- spec/tshield/request_matching_spec.rb
|
473
|
+
- spec/tshield/sessions_spec.rb
|
474
|
+
- spec/tshield/request_vcr_spec.rb
|
475
|
+
- spec/tshield/after_filter_spec.rb
|
476
|
+
- spec/tshield/grpc_spec.rb
|
477
|
+
- spec/tshield/options_spec.rb
|
471
478
|
- spec/tshield/fixtures/config/tshield-without-grpc.yml
|
479
|
+
- spec/tshield/fixtures/config/tshield-with-send-content-type-header_as_false.yml
|
480
|
+
- spec/tshield/fixtures/config/tshield-with-send-content-type-header.yml
|
472
481
|
- spec/tshield/fixtures/config/tshield.yml
|
473
|
-
- spec/tshield/fixtures/filters/example_filter.rb
|
474
482
|
- spec/tshield/fixtures/proto/test_services_pb.rb
|
475
|
-
- spec/tshield/
|
476
|
-
- spec/tshield/
|
477
|
-
- spec/tshield/sessions_spec.rb
|
478
|
-
- spec/tshield/request_matching_spec.rb
|
483
|
+
- spec/tshield/fixtures/matching/example.json
|
484
|
+
- spec/tshield/fixtures/filters/example_filter.rb
|
479
485
|
- spec/tshield/controllers/requests_spec.rb
|
480
|
-
- spec/tshield/
|
481
|
-
- spec/tshield/request_vcr_spec.rb
|
482
|
-
- spec/tshield/after_filter_spec.rb
|
486
|
+
- spec/tshield/configuration_spec.rb
|