tshield 0.11.19.0 → 0.13.2.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 +33 -1
- data/config/tshield.yml +1 -0
- data/lib/tshield/configuration.rb +10 -0
- data/lib/tshield/controllers/helpers/session_helpers.rb +5 -0
- data/lib/tshield/controllers/requests.rb +12 -2
- data/lib/tshield/controllers/sessions.rb +3 -0
- data/lib/tshield/errors.rb +4 -0
- data/lib/tshield/grpc/vcr.rb +2 -6
- data/lib/tshield/matching/filters.rb +8 -0
- data/lib/tshield/request.rb +8 -8
- data/lib/tshield/request_matching.rb +1 -0
- data/lib/tshield/request_vcr.rb +55 -23
- data/lib/tshield/server.rb +2 -2
- data/lib/tshield/sessions.rb +17 -1
- data/lib/tshield/version.rb +2 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/tshield/configuration_spec.rb +27 -0
- data/spec/tshield/fixtures/matching/example.json +12 -0
- data/spec/tshield/request_matching_spec.rb +12 -0
- data/spec/tshield/request_vcr_spec.rb +93 -0
- data/spec/tshield/sessions_spec.rb +18 -0
- data/tshield.gemspec +5 -6
- metadata +97 -107
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 87b26d114e278df9af5848487fbe41a5783b69e9
|
|
4
|
+
data.tar.gz: 36fd3d713a4c30d82631d7141c83154c90659281
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5bd5f43cc13647026b199ad55ab149b842d6bbedae8dcfccb9a345dcc99abb72c132641ede6cd80bff36bd7e5e9123deb8dde882c4573b2d441a8c9c3e430df9
|
|
7
|
+
data.tar.gz: 956d0f30dcf1c57ba98e3488deb0d8d80367c8c5ffa6c5b6c383eed282bf17f679463df5403e93ba17033ca1dcb8bfc69afe3deeff778a44b9431b47089c7f47
|
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.
|
|
@@ -68,6 +69,17 @@ domains:
|
|
|
68
69
|
- /users
|
|
69
70
|
```
|
|
70
71
|
|
|
72
|
+
**Windows Compatibility:** If you need to use Tshield in Windows SO, change the config file and set the windows_compatibility to true.
|
|
73
|
+
|
|
74
|
+
Eg:
|
|
75
|
+
```yaml
|
|
76
|
+
windows_compatibility: true
|
|
77
|
+
request:
|
|
78
|
+
# wait time for real service
|
|
79
|
+
timeout: 8
|
|
80
|
+
...
|
|
81
|
+
```
|
|
82
|
+
|
|
71
83
|
## Config options for Pattern Matching
|
|
72
84
|
|
|
73
85
|
An example of file to create a stub:
|
|
@@ -93,6 +105,10 @@ Optional request attributes:
|
|
|
93
105
|
this stub will be returned if all headers are in request.
|
|
94
106
|
* **query**: works like headers but use query params.
|
|
95
107
|
|
|
108
|
+
Optional response attributes:
|
|
109
|
+
|
|
110
|
+
* **delay**: integer that represents time in seconds that the response will be delayed to return
|
|
111
|
+
|
|
96
112
|
**Important**: If VCR config conflicts with Matching config Matching will be
|
|
97
113
|
used. Matching config have priority.
|
|
98
114
|
|
|
@@ -155,6 +171,7 @@ To register stub into a session create an object with following attributes:
|
|
|
155
171
|
"method": "GET",
|
|
156
172
|
"path": "/matching/example",
|
|
157
173
|
"response": {
|
|
174
|
+
"delay": 5,
|
|
158
175
|
"body": "matching-example-response-in-session",
|
|
159
176
|
"headers": {},
|
|
160
177
|
"status": 200
|
|
@@ -195,6 +212,8 @@ domains:
|
|
|
195
212
|
- transfer-encoding
|
|
196
213
|
paths:
|
|
197
214
|
- /secure
|
|
215
|
+
delay:
|
|
216
|
+
'/secure': 10
|
|
198
217
|
|
|
199
218
|
'http://localhost:9092':
|
|
200
219
|
name: 'my-other-service'
|
|
@@ -205,6 +224,8 @@ domains:
|
|
|
205
224
|
- transfer-encoding
|
|
206
225
|
paths:
|
|
207
226
|
- /users
|
|
227
|
+
delay:
|
|
228
|
+
'/users': 5
|
|
208
229
|
```
|
|
209
230
|
**request**
|
|
210
231
|
* **timeout**: wait time for real service in seconds
|
|
@@ -220,6 +241,7 @@ domains:
|
|
|
220
241
|
* **filters**: Implementation of before or after filters used in domain requests
|
|
221
242
|
* **excluded_headers**: <<some_description>>
|
|
222
243
|
* **paths**: Paths list of all services that will be called. Used to filter what domain will "receive the request"
|
|
244
|
+
* **delay**: List of times in seconds that the response will be delayed to return for an specific path defined above
|
|
223
245
|
|
|
224
246
|
## Manage Sessions
|
|
225
247
|
|
|
@@ -250,6 +272,16 @@ _DELETE_ to http://localhost:4567/sessions
|
|
|
250
272
|
curl -X DELETE \
|
|
251
273
|
http://localhost:4567/sessions
|
|
252
274
|
```
|
|
275
|
+
### Append secondary TShield session
|
|
276
|
+
**Append session. Secondary sessions will used only for read content in VCR mode, writes will be do in the main session. Append only works if exists a current session setted.**
|
|
277
|
+
|
|
278
|
+
_POST_ to http://localhost:4567/sessions?name=<<same_name>>
|
|
279
|
+
|
|
280
|
+
```
|
|
281
|
+
curl -X POST \
|
|
282
|
+
'http://localhost:4567/sessions/append?name=my_valid'
|
|
283
|
+
```
|
|
284
|
+
|
|
253
285
|
## [Experimental] Config options for gRPC
|
|
254
286
|
|
|
255
287
|
```yaml
|
data/config/tshield.yml
CHANGED
|
@@ -32,6 +32,7 @@ module TShield
|
|
|
32
32
|
attr_reader :domains
|
|
33
33
|
attr_reader :tcp_servers
|
|
34
34
|
attr_reader :session_path
|
|
35
|
+
attr_reader :windows_compatibility
|
|
35
36
|
|
|
36
37
|
def initialize(attributes)
|
|
37
38
|
attributes.each { |key, value| instance_variable_set("@#{key}", value) }
|
|
@@ -103,6 +104,10 @@ module TShield
|
|
|
103
104
|
session_path || '/sessions'
|
|
104
105
|
end
|
|
105
106
|
|
|
107
|
+
def get_questionmark_char
|
|
108
|
+
windows_compatibility ? '%3f' : '?'
|
|
109
|
+
end
|
|
110
|
+
|
|
106
111
|
def grpc
|
|
107
112
|
defaults = { 'port' => 5678, 'proto_dir' => 'proto', 'services' => {} }
|
|
108
113
|
defaults.merge(@grpc || {})
|
|
@@ -126,5 +131,10 @@ module TShield
|
|
|
126
131
|
)
|
|
127
132
|
raise 'Startup aborted'
|
|
128
133
|
end
|
|
134
|
+
|
|
135
|
+
def get_delay(domain, path)
|
|
136
|
+
((domains[domain] || {})['delay'] || {})[path] || 0
|
|
137
|
+
end
|
|
138
|
+
|
|
129
139
|
end
|
|
130
140
|
end
|
|
@@ -10,6 +10,11 @@ module TShield
|
|
|
10
10
|
session[:name] if session
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
def self.secondary_sessions(request)
|
|
14
|
+
session = TShield::Sessions.current(request.ip)
|
|
15
|
+
session[:secondary_sessions] if session
|
|
16
|
+
end
|
|
17
|
+
|
|
13
18
|
def self.current_session_call(request, callid, method)
|
|
14
19
|
session = TShield::Sessions.current(request.ip)
|
|
15
20
|
session ? session[:counter].current(callid, method) : 0
|
|
@@ -43,6 +43,7 @@ module TShield
|
|
|
43
43
|
request_content_type = request.content_type
|
|
44
44
|
|
|
45
45
|
session_name = TShield::Controllers::Helpers::SessionHelpers.current_session_name(request)
|
|
46
|
+
secondary_sessions = TShield::Controllers::Helpers::SessionHelpers.secondary_sessions(request)
|
|
46
47
|
session_call = TShield::Controllers::Helpers::SessionHelpers
|
|
47
48
|
.current_session_call(request, callid, method)
|
|
48
49
|
|
|
@@ -51,6 +52,7 @@ module TShield
|
|
|
51
52
|
headers: Helpers.build_headers(request),
|
|
52
53
|
raw_query: request.env['QUERY_STRING'],
|
|
53
54
|
session: session_name,
|
|
55
|
+
secondary_sessions: secondary_sessions,
|
|
54
56
|
call: session_call,
|
|
55
57
|
ip: request.ip
|
|
56
58
|
}
|
|
@@ -67,12 +69,12 @@ module TShield
|
|
|
67
69
|
unless api_response
|
|
68
70
|
add_headers(options, path)
|
|
69
71
|
|
|
70
|
-
api_response ||= TShield::RequestVCR.new(path, options.clone).
|
|
72
|
+
api_response ||= TShield::RequestVCR.new(path, options.clone).vcr_response
|
|
71
73
|
api_response.headers.reject! do |key, _v|
|
|
72
74
|
configuration.get_excluded_headers(domain(path)).include?(key)
|
|
73
75
|
end
|
|
74
76
|
end
|
|
75
|
-
|
|
77
|
+
|
|
76
78
|
logger.info(
|
|
77
79
|
"original=#{api_response.original} method=#{method} path=#{path} "\
|
|
78
80
|
"content-type=#{request_content_type} "\
|
|
@@ -80,6 +82,7 @@ module TShield
|
|
|
80
82
|
)
|
|
81
83
|
TShield::Controllers::Helpers::SessionHelpers.update_session_call(request, callid, method)
|
|
82
84
|
|
|
85
|
+
delay(path)
|
|
83
86
|
status api_response.status
|
|
84
87
|
headers api_response.headers
|
|
85
88
|
body api_response.body
|
|
@@ -98,6 +101,13 @@ module TShield
|
|
|
98
101
|
def domain(path)
|
|
99
102
|
@domain ||= configuration.get_domain_for(path)
|
|
100
103
|
end
|
|
104
|
+
|
|
105
|
+
def delay(path)
|
|
106
|
+
delay_in_seconds = configuration.get_delay(domain(path), path) || 0
|
|
107
|
+
logger.info("Response with delay of #{delay_in_seconds} seconds")
|
|
108
|
+
sleep delay_in_seconds
|
|
109
|
+
end
|
|
110
|
+
|
|
101
111
|
end
|
|
102
112
|
end
|
|
103
113
|
end
|
|
@@ -23,6 +23,9 @@ module TShield
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def self.register_post(app, session_path)
|
|
26
|
+
app.post "#{session_path}/append" do
|
|
27
|
+
TShield::Sessions.append(request.ip, params[:name]).to_json
|
|
28
|
+
end
|
|
26
29
|
app.post session_path do
|
|
27
30
|
TShield::Sessions.start(request.ip, params[:name]).to_json
|
|
28
31
|
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
|
|
@@ -8,6 +8,14 @@ module TShield
|
|
|
8
8
|
result = filter_stubs(stubs[@options[:session]] || {})
|
|
9
9
|
return result if result
|
|
10
10
|
|
|
11
|
+
find_in_secondary_sessions(stubs, @options[:secondary_sessions] || [])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def find_in_secondary_sessions(stubs, sessions)
|
|
15
|
+
sessions.each do |session|
|
|
16
|
+
result = filter_stubs(stubs[session] || {})
|
|
17
|
+
return result if result
|
|
18
|
+
end
|
|
11
19
|
filter_stubs(stubs[DEFAULT_SESSION] || {}) unless @options[:session] == DEFAULT_SESSION
|
|
12
20
|
end
|
|
13
21
|
|
data/lib/tshield/request.rb
CHANGED
|
@@ -13,8 +13,8 @@ module TShield
|
|
|
13
13
|
|
|
14
14
|
protected
|
|
15
15
|
|
|
16
|
-
def session_destiny(request_path)
|
|
17
|
-
session = @options[:session]
|
|
16
|
+
def session_destiny(request_path, current_session = nil)
|
|
17
|
+
session = current_session || @options[:session]
|
|
18
18
|
return request_path unless session
|
|
19
19
|
|
|
20
20
|
request_path = File.join(request_path, session)
|
|
@@ -22,19 +22,19 @@ module TShield
|
|
|
22
22
|
request_path
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
def content_destiny
|
|
26
|
-
"#{destiny}.content"
|
|
25
|
+
def content_destiny(current_session = nil)
|
|
26
|
+
"#{destiny(current_session)}.content"
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def headers_destiny
|
|
30
|
-
"#{destiny}.json"
|
|
29
|
+
def headers_destiny(current_session = nil)
|
|
30
|
+
"#{destiny(current_session)}.json"
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def destiny
|
|
33
|
+
def destiny(current_session = nil)
|
|
34
34
|
request_path = File.join('requests')
|
|
35
35
|
Dir.mkdir(request_path) unless File.exist?(request_path)
|
|
36
36
|
|
|
37
|
-
request_path = session_destiny(request_path)
|
|
37
|
+
request_path = session_destiny(request_path, current_session)
|
|
38
38
|
|
|
39
39
|
name_path = File.join(request_path, name)
|
|
40
40
|
Dir.mkdir(name_path) unless File.exist?(name_path)
|
data/lib/tshield/request_vcr.rb
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
require 'httparty'
|
|
4
4
|
require 'json'
|
|
5
|
-
require 'byebug'
|
|
6
5
|
|
|
7
6
|
require 'digest/sha1'
|
|
8
7
|
|
|
9
8
|
require 'tshield/configuration'
|
|
9
|
+
require 'tshield/logger'
|
|
10
10
|
require 'tshield/options'
|
|
11
11
|
require 'tshield/request'
|
|
12
12
|
require 'tshield/response'
|
|
@@ -14,6 +14,8 @@ require 'tshield/response'
|
|
|
14
14
|
module TShield
|
|
15
15
|
# Module to write and read saved responses
|
|
16
16
|
class RequestVCR < TShield::Request
|
|
17
|
+
attr_reader :vcr_response
|
|
18
|
+
|
|
17
19
|
def initialize(path, options = {})
|
|
18
20
|
super()
|
|
19
21
|
@path = path
|
|
@@ -35,27 +37,31 @@ module TShield
|
|
|
35
37
|
_method, @url, @options = filter.new.filter(method, @url, @options)
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
in_session = find_in_sessions
|
|
41
|
+
if in_session
|
|
42
|
+
# TODO: create concept of global session in vcr
|
|
43
|
+
in_session = nil if in_session == 'global'
|
|
44
|
+
@vcr_response = response(in_session)
|
|
45
|
+
@vcr_response.original = false
|
|
41
46
|
else
|
|
47
|
+
TShield.logger.info("calling original service for request with options #{@options}")
|
|
42
48
|
raw = HTTParty.send(method.to_s, @url, @options)
|
|
43
49
|
|
|
44
50
|
original_response = save(raw)
|
|
45
51
|
original_response.original = true
|
|
46
|
-
|
|
52
|
+
@vcr_response = original_response
|
|
47
53
|
end
|
|
48
54
|
|
|
49
55
|
configuration.get_after_filters(domain).each do |filter|
|
|
50
|
-
|
|
56
|
+
@vcr_response = filter.new.filter(@vcr_response)
|
|
51
57
|
end
|
|
52
|
-
resp
|
|
53
58
|
end
|
|
54
59
|
|
|
55
|
-
def response
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
def response(session)
|
|
61
|
+
response_content = saved_content(session)
|
|
62
|
+
TShield::Response.new(response_content['body'],
|
|
63
|
+
response_content['headers'] || [],
|
|
64
|
+
response_content['status'] || 200)
|
|
59
65
|
end
|
|
60
66
|
|
|
61
67
|
private
|
|
@@ -72,12 +78,31 @@ module TShield
|
|
|
72
78
|
@method ||= @options[:method].downcase
|
|
73
79
|
end
|
|
74
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
|
+
|
|
75
96
|
def save(raw_response)
|
|
76
97
|
headers = {}
|
|
98
|
+
|
|
77
99
|
raw_response.headers.each do |k, v|
|
|
100
|
+
next if k == 'set-cookie'
|
|
78
101
|
headers[k] = v unless configuration.not_save_headers(domain).include? k
|
|
79
102
|
end
|
|
80
103
|
|
|
104
|
+
headers = apply_set_cookie_header_values(raw_response, headers)
|
|
105
|
+
|
|
81
106
|
content = {
|
|
82
107
|
body: raw_response.body,
|
|
83
108
|
status: raw_response.code,
|
|
@@ -89,20 +114,27 @@ module TShield
|
|
|
89
114
|
TShield::Response.new(raw_response.body, headers, raw_response.code)
|
|
90
115
|
end
|
|
91
116
|
|
|
92
|
-
def saved_content
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
@saved_content['body'] = File.open(content_destiny).read unless @saved_content['body']
|
|
97
|
-
@saved_content
|
|
117
|
+
def saved_content(session)
|
|
118
|
+
content = JSON.parse(File.open(headers_destiny(session)).read)
|
|
119
|
+
content['body'] = File.open(content_destiny(session)).read unless content['body']
|
|
120
|
+
content
|
|
98
121
|
end
|
|
99
122
|
|
|
100
|
-
def file_exists
|
|
101
|
-
File.exist?(content_destiny)
|
|
123
|
+
def file_exists(session)
|
|
124
|
+
File.exist?(content_destiny(session))
|
|
102
125
|
end
|
|
103
126
|
|
|
104
|
-
def
|
|
105
|
-
|
|
127
|
+
def find_in_sessions
|
|
128
|
+
in_session = nil
|
|
129
|
+
|
|
130
|
+
([@options[:session]] + (@options[:secondary_sessions] || [])).each do |session|
|
|
131
|
+
if file_exists(session) && configuration.cache_request?(domain)
|
|
132
|
+
in_session = (session || 'global')
|
|
133
|
+
break
|
|
134
|
+
end
|
|
135
|
+
TShield.logger.info("saved response not found in #{session}")
|
|
136
|
+
end
|
|
137
|
+
in_session
|
|
106
138
|
end
|
|
107
139
|
|
|
108
140
|
def key
|
|
@@ -127,9 +159,9 @@ module TShield
|
|
|
127
159
|
if url.size > 225
|
|
128
160
|
path = url.gsub(/(\?.*)/, '')
|
|
129
161
|
params = Digest::SHA1.hexdigest Regexp.last_match(1)
|
|
130
|
-
"#{path.gsub(%r{/}, '-').gsub(/^-/, '')}
|
|
162
|
+
"#{path.gsub(%r{/}, '-').gsub(/^-/, '')}#{configuration.get_questionmark_char}#{params}"
|
|
131
163
|
else
|
|
132
|
-
url.gsub(%r{/}, '-').gsub(/^-/, '')
|
|
164
|
+
url.gsub(%r{/}, '-').gsub(/^-/, '').gsub('?', configuration.get_questionmark_char)
|
|
133
165
|
end
|
|
134
166
|
end
|
|
135
167
|
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/sessions.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'tshield/logger'
|
|
3
4
|
require 'tshield/counter'
|
|
5
|
+
require 'tshield/errors'
|
|
4
6
|
|
|
5
7
|
module TShield
|
|
6
8
|
# Manage sessions
|
|
@@ -9,7 +11,11 @@ module TShield
|
|
|
9
11
|
module Sessions
|
|
10
12
|
def self.start(ip, name)
|
|
11
13
|
TShield.logger.info("starting session #{name} for ip #{normalize_ip(ip)}")
|
|
12
|
-
sessions[normalize_ip(ip)] = {
|
|
14
|
+
sessions[normalize_ip(ip)] = {
|
|
15
|
+
name: name,
|
|
16
|
+
counter: TShield::Counter.new,
|
|
17
|
+
secondary_sessions: []
|
|
18
|
+
}
|
|
13
19
|
end
|
|
14
20
|
|
|
15
21
|
def self.stop(ip)
|
|
@@ -22,6 +28,16 @@ module TShield
|
|
|
22
28
|
sessions[normalize_ip(ip)]
|
|
23
29
|
end
|
|
24
30
|
|
|
31
|
+
def self.append(ip, name)
|
|
32
|
+
TShield.logger.info("appeding session #{name} for ip #{normalize_ip(ip)}")
|
|
33
|
+
|
|
34
|
+
current_session = sessions[normalize_ip(ip)]
|
|
35
|
+
raise AppendSessionWithoutMainSessionError, "not found main session for #{ip}" unless current_session
|
|
36
|
+
|
|
37
|
+
current_session[:secondary_sessions] << name
|
|
38
|
+
current_session
|
|
39
|
+
end
|
|
40
|
+
|
|
25
41
|
def self.sessions
|
|
26
42
|
@sessions ||= {}
|
|
27
43
|
end
|
data/lib/tshield/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
|
@@ -64,6 +64,33 @@ describe TShield::Configuration do
|
|
|
64
64
|
expect(@configuration.get_domain_for('/api/four')).to be_nil
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
|
+
|
|
68
|
+
describe 'SO compatibility' do
|
|
69
|
+
it 'should be compatible with windows when configuration is true' do
|
|
70
|
+
allow(YAML).to receive(:safe_load).and_return({:windows_compatibility => true })
|
|
71
|
+
TShield::Configuration.clear
|
|
72
|
+
@configuration = TShield::Configuration.singleton
|
|
73
|
+
|
|
74
|
+
expect(@configuration.get_questionmark_char).to eq('%3f')
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'should be compatible with Unix when configuration is false' do
|
|
78
|
+
allow(YAML).to receive(:safe_load).and_return({:windows_compatibility => false })
|
|
79
|
+
TShield::Configuration.clear
|
|
80
|
+
@configuration = TShield::Configuration.singleton
|
|
81
|
+
|
|
82
|
+
expect(@configuration.get_questionmark_char).to eq('?')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'should be compatible with Unix when configuration is missing' do
|
|
86
|
+
allow(YAML).to receive(:safe_load).and_return({})
|
|
87
|
+
TShield::Configuration.clear
|
|
88
|
+
@configuration = TShield::Configuration.singleton
|
|
89
|
+
|
|
90
|
+
expect(@configuration.get_questionmark_char).to eq('?')
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
67
94
|
end
|
|
68
95
|
context 'on config not exist' do
|
|
69
96
|
before :each do
|
|
@@ -99,5 +99,17 @@
|
|
|
99
99
|
"body": "body content in session"
|
|
100
100
|
}
|
|
101
101
|
}]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"session": "second-session",
|
|
105
|
+
"stubs": [{
|
|
106
|
+
"method": "GET",
|
|
107
|
+
"path": "/matching/second-example",
|
|
108
|
+
"response": {
|
|
109
|
+
"status": 200,
|
|
110
|
+
"headers": {},
|
|
111
|
+
"body": "body content in second-session"
|
|
112
|
+
}
|
|
113
|
+
}]
|
|
102
114
|
}
|
|
103
115
|
]
|
|
@@ -235,6 +235,18 @@ describe TShield::RequestMatching do
|
|
|
235
235
|
expect(@response.headers).to eql({})
|
|
236
236
|
expect(@response.status).to eql(201)
|
|
237
237
|
end
|
|
238
|
+
context 'with secondary session' do
|
|
239
|
+
it 'should return response object from session settings' do
|
|
240
|
+
@request_matching = TShield::RequestMatching.new('/matching/second-example',
|
|
241
|
+
method: 'GET',
|
|
242
|
+
session: 'a-session',
|
|
243
|
+
secondary_sessions: ['second-session'])
|
|
244
|
+
@response = @request_matching.match_request
|
|
245
|
+
expect(@response.body).to eql('body content in second-session')
|
|
246
|
+
expect(@response.headers).to eql({})
|
|
247
|
+
expect(@response.status).to eql(200)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
238
250
|
end
|
|
239
251
|
end
|
|
240
252
|
end
|
|
@@ -10,6 +10,7 @@ describe TShield::RequestVCR do
|
|
|
10
10
|
allow(TShield::Configuration)
|
|
11
11
|
.to receive(:singleton).and_return(@configuration)
|
|
12
12
|
allow(@configuration).to receive(:get_before_filters).and_return([])
|
|
13
|
+
allow(@configuration).to receive(:not_save_headers).and_return([])
|
|
13
14
|
allow(@configuration).to receive(:get_after_filters).and_return([])
|
|
14
15
|
allow(@configuration).to receive(:request).and_return('timeout' => 10)
|
|
15
16
|
allow(@configuration).to receive(:get_domain_for).and_return('example.org')
|
|
@@ -35,6 +36,24 @@ describe TShield::RequestVCR do
|
|
|
35
36
|
TShield::RequestVCR.new '/', method: 'GET'
|
|
36
37
|
end
|
|
37
38
|
|
|
39
|
+
it 'should write response headers as multiple occcurences when has more than one with same key' do
|
|
40
|
+
allow_any_instance_of(TShield::RequestVCR).to receive(:exists)
|
|
41
|
+
.and_return(false)
|
|
42
|
+
allow_any_instance_of(TShield::RequestVCR).to receive(:destiny)
|
|
43
|
+
allow(HTTParty).to receive(:send).and_return(RawResponseCookiesMultipleValues.new)
|
|
44
|
+
|
|
45
|
+
write_spy = double
|
|
46
|
+
allow(File).to receive(:open).and_return(write_spy)
|
|
47
|
+
|
|
48
|
+
expect(write_spy).to receive(:write).ordered.with('this is the body')
|
|
49
|
+
expect(write_spy).to receive(:write)
|
|
50
|
+
.ordered
|
|
51
|
+
.with("{\n \"status\": 200,\n \"headers\": {\n \"Set-Cookie\": [\n \"FirstCookie=An Value\",\n \"SecondCookie=An Value\"\n ]\n }\n}")
|
|
52
|
+
allow(write_spy).to receive(:close)
|
|
53
|
+
|
|
54
|
+
TShield::RequestVCR.new '/', method: 'GET'
|
|
55
|
+
end
|
|
56
|
+
|
|
38
57
|
describe 'and query params exists in list to skip' do
|
|
39
58
|
before :each do
|
|
40
59
|
allow(@configuration).to receive(:get_name).and_return('example.org')
|
|
@@ -62,6 +81,8 @@ describe TShield::RequestVCR do
|
|
|
62
81
|
}
|
|
63
82
|
)
|
|
64
83
|
|
|
84
|
+
allow(@configuration).to receive(:get_questionmark_char).and_return('?')
|
|
85
|
+
|
|
65
86
|
allow(HTTParty).to receive(:send).and_return(RawResponse.new)
|
|
66
87
|
file_double = double
|
|
67
88
|
|
|
@@ -83,6 +104,53 @@ describe TShield::RequestVCR do
|
|
|
83
104
|
method: 'GET',
|
|
84
105
|
call: 0
|
|
85
106
|
end
|
|
107
|
+
|
|
108
|
+
it 'should create response directory in windows standard' do
|
|
109
|
+
|
|
110
|
+
allow(@configuration).to receive(:domains).and_return(
|
|
111
|
+
'example.org' => {
|
|
112
|
+
'skip_query_params' => []
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
allow(@configuration).to receive(:get_questionmark_char).and_return('%3f')
|
|
117
|
+
|
|
118
|
+
allow(HTTParty).to receive(:send).and_return(RawResponse.new)
|
|
119
|
+
file_double = double
|
|
120
|
+
|
|
121
|
+
allow(File).to receive(:join)
|
|
122
|
+
.with('./requests/example.org', '%3fparam=value')
|
|
123
|
+
.and_return('./requests/example.org/%3fparam=value')
|
|
124
|
+
allow(File).to receive(:join)
|
|
125
|
+
.with('./requests/example.org/%3fparam=value', 'get')
|
|
126
|
+
.and_return('./requests/example.org/%3fparam=value/get')
|
|
127
|
+
allow(File).to receive(:join)
|
|
128
|
+
.with('./requests/example.org/%3fparam=value/get', '0')
|
|
129
|
+
.and_return('./requests/example.org/%3fparam=value/get/0')
|
|
130
|
+
|
|
131
|
+
allow(file_double).to receive(:read).and_return('{}')
|
|
132
|
+
|
|
133
|
+
expect(File).to receive('open')
|
|
134
|
+
.with('./requests/example.org/%3fparam=value/get/0.content', 'w')
|
|
135
|
+
.and_return(file_double)
|
|
136
|
+
|
|
137
|
+
expect(File).to receive('open')
|
|
138
|
+
.with('./requests/example.org/%3fparam=value/get/0.json', 'w')
|
|
139
|
+
.and_return(file_double)
|
|
140
|
+
|
|
141
|
+
expect(file_double).to receive(:write).ordered.with('this is the body')
|
|
142
|
+
expect(file_double).to receive(:write)
|
|
143
|
+
.with("{\n \"status\": 200,\n \"headers\": {\n }\n}")
|
|
144
|
+
expect(file_double).to receive(:close)
|
|
145
|
+
expect(file_double).to receive(:close)
|
|
146
|
+
|
|
147
|
+
TShield::RequestVCR.new '/',
|
|
148
|
+
raw_query: 'param=value',
|
|
149
|
+
method: 'GET',
|
|
150
|
+
call: 0
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
|
|
86
154
|
end
|
|
87
155
|
end
|
|
88
156
|
|
|
@@ -95,8 +163,33 @@ describe TShield::RequestVCR do
|
|
|
95
163
|
'this is the body'
|
|
96
164
|
end
|
|
97
165
|
|
|
166
|
+
def get_fields(field = "")
|
|
167
|
+
[]
|
|
168
|
+
end
|
|
169
|
+
|
|
98
170
|
def code
|
|
99
171
|
200
|
|
100
172
|
end
|
|
101
173
|
end
|
|
174
|
+
|
|
175
|
+
class RawResponseCookiesMultipleValues
|
|
176
|
+
def headers
|
|
177
|
+
{'Set-Cookie' => ['FirstCookie=An Value', 'SecondCookie=An Value']}
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def body
|
|
181
|
+
'this is the body'
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def get_fields(field = "")
|
|
185
|
+
self.headers[filed] unless self.headers.key?(field)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def code
|
|
189
|
+
200
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
102
193
|
end
|
|
194
|
+
|
|
195
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'tshield/sessions'
|
|
4
|
+
require 'spec_helper'
|
|
5
|
+
|
|
6
|
+
describe TShield::Sessions do
|
|
7
|
+
context 'on append session' do
|
|
8
|
+
it 'should raise error if not has a main session' do
|
|
9
|
+
expect { TShield::Sessions.append 'ip', 'secondary-session' }
|
|
10
|
+
.to raise_error(AppendSessionWithoutMainSessionError)
|
|
11
|
+
end
|
|
12
|
+
it 'should append if has main session' do
|
|
13
|
+
TShield::Sessions.start 'ip', 'main-session'
|
|
14
|
+
result = TShield::Sessions.append 'ip', 'secondary-session'
|
|
15
|
+
expect(result[:secondary_sessions]).to include('secondary-session')
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/tshield.gemspec
CHANGED
|
@@ -22,19 +22,18 @@ Gem::Specification.new do |s|
|
|
|
22
22
|
|
|
23
23
|
s.test_files = Dir['spec/**/*']
|
|
24
24
|
|
|
25
|
-
s.required_ruby_version = '>= 2.
|
|
25
|
+
s.required_ruby_version = '>= 2.4'
|
|
26
26
|
|
|
27
|
-
s.add_dependency('byebug', '~> 11.0', '>= 11.0.1')
|
|
28
27
|
s.add_dependency('grpc', '~> 1.28', '>= 1.28.0')
|
|
29
28
|
s.add_dependency('grpc-tools', '~> 1.28', '>= 1.28.0')
|
|
30
29
|
s.add_dependency('httparty', '~> 0.14', '>= 0.14.0')
|
|
31
30
|
s.add_dependency('json', '~> 2.0', '>= 2.0')
|
|
32
31
|
s.add_dependency('puma', '~> 4.3', '>= 4.3.3')
|
|
33
|
-
s.add_dependency('sinatra', '~> 1
|
|
32
|
+
s.add_dependency('sinatra', '~> 2.1', '>= 2.1.0')
|
|
34
33
|
s.add_dependency('sinatra-cross_origin', '~> 0.4.0', '>= 0.4')
|
|
35
|
-
s.add_development_dependency('coveralls')
|
|
34
|
+
s.add_development_dependency('coveralls', '~> 0.8', '>= 0.8.23')
|
|
36
35
|
s.add_development_dependency('cucumber', '~> 3.1', '>= 3.1.2')
|
|
37
|
-
s.add_development_dependency('guard', '~> 2.
|
|
36
|
+
s.add_development_dependency('guard', '~> 2.16', '>= 2.16.2')
|
|
38
37
|
s.add_development_dependency('guard-rspec', '~> 4.7', '>= 4.7.3')
|
|
39
38
|
s.add_development_dependency('rake', '>= 10.0', '~> 13.0')
|
|
40
39
|
s.add_development_dependency('rdoc', '~> 6.0', '>= 6.0')
|
|
@@ -42,6 +41,6 @@ Gem::Specification.new do |s|
|
|
|
42
41
|
s.add_development_dependency('rspec', '~> 3.5', '>= 3.5.0')
|
|
43
42
|
s.add_development_dependency('rubocop', '~> 0.73.0', '>= 0.73.0')
|
|
44
43
|
s.add_development_dependency('rubocop-rails', '~> 2.2.0', '>= 2.2.1')
|
|
45
|
-
s.add_development_dependency('simplecov', '~> 0.
|
|
44
|
+
s.add_development_dependency('simplecov', '~> 0.16', '>= 0.16.1')
|
|
46
45
|
s.add_development_dependency('webmock', '~> 2.1', '>= 2.1.0')
|
|
47
46
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tshield
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.13.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Diego Rubin
|
|
@@ -9,106 +9,86 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2021-01-06 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
|
-
name:
|
|
15
|
+
name: grpc
|
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
|
17
17
|
requirements:
|
|
18
18
|
- - "~>"
|
|
19
19
|
- !ruby/object:Gem::Version
|
|
20
|
-
version: '
|
|
20
|
+
version: '1.28'
|
|
21
21
|
- - ">="
|
|
22
22
|
- !ruby/object:Gem::Version
|
|
23
|
-
version:
|
|
23
|
+
version: 1.28.0
|
|
24
24
|
type: :runtime
|
|
25
25
|
prerelease: false
|
|
26
26
|
version_requirements: !ruby/object:Gem::Requirement
|
|
27
27
|
requirements:
|
|
28
|
-
- - "~>"
|
|
29
|
-
- !ruby/object:Gem::Version
|
|
30
|
-
version: '11.0'
|
|
31
|
-
- - ">="
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: 11.0.1
|
|
34
|
-
- !ruby/object:Gem::Dependency
|
|
35
|
-
name: grpc
|
|
36
|
-
requirement: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - ">="
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: 1.28.0
|
|
41
28
|
- - "~>"
|
|
42
29
|
- !ruby/object:Gem::Version
|
|
43
30
|
version: '1.28'
|
|
44
|
-
type: :runtime
|
|
45
|
-
prerelease: false
|
|
46
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
47
|
-
requirements:
|
|
48
31
|
- - ">="
|
|
49
32
|
- !ruby/object:Gem::Version
|
|
50
33
|
version: 1.28.0
|
|
51
|
-
- - "~>"
|
|
52
|
-
- !ruby/object:Gem::Version
|
|
53
|
-
version: '1.28'
|
|
54
34
|
- !ruby/object:Gem::Dependency
|
|
55
35
|
name: grpc-tools
|
|
56
36
|
requirement: !ruby/object:Gem::Requirement
|
|
57
37
|
requirements:
|
|
58
|
-
- - ">="
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: 1.28.0
|
|
61
38
|
- - "~>"
|
|
62
39
|
- !ruby/object:Gem::Version
|
|
63
40
|
version: '1.28'
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: 1.28.0
|
|
64
44
|
type: :runtime
|
|
65
45
|
prerelease: false
|
|
66
46
|
version_requirements: !ruby/object:Gem::Requirement
|
|
67
47
|
requirements:
|
|
68
|
-
- - ">="
|
|
69
|
-
- !ruby/object:Gem::Version
|
|
70
|
-
version: 1.28.0
|
|
71
48
|
- - "~>"
|
|
72
49
|
- !ruby/object:Gem::Version
|
|
73
50
|
version: '1.28'
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 1.28.0
|
|
74
54
|
- !ruby/object:Gem::Dependency
|
|
75
55
|
name: httparty
|
|
76
56
|
requirement: !ruby/object:Gem::Requirement
|
|
77
57
|
requirements:
|
|
78
|
-
- - ">="
|
|
79
|
-
- !ruby/object:Gem::Version
|
|
80
|
-
version: 0.14.0
|
|
81
58
|
- - "~>"
|
|
82
59
|
- !ruby/object:Gem::Version
|
|
83
60
|
version: '0.14'
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: 0.14.0
|
|
84
64
|
type: :runtime
|
|
85
65
|
prerelease: false
|
|
86
66
|
version_requirements: !ruby/object:Gem::Requirement
|
|
87
67
|
requirements:
|
|
88
|
-
- - ">="
|
|
89
|
-
- !ruby/object:Gem::Version
|
|
90
|
-
version: 0.14.0
|
|
91
68
|
- - "~>"
|
|
92
69
|
- !ruby/object:Gem::Version
|
|
93
70
|
version: '0.14'
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: 0.14.0
|
|
94
74
|
- !ruby/object:Gem::Dependency
|
|
95
75
|
name: json
|
|
96
76
|
requirement: !ruby/object:Gem::Requirement
|
|
97
77
|
requirements:
|
|
98
|
-
- - "
|
|
78
|
+
- - "~>"
|
|
99
79
|
- !ruby/object:Gem::Version
|
|
100
80
|
version: '2.0'
|
|
101
|
-
- - "
|
|
81
|
+
- - ">="
|
|
102
82
|
- !ruby/object:Gem::Version
|
|
103
83
|
version: '2.0'
|
|
104
84
|
type: :runtime
|
|
105
85
|
prerelease: false
|
|
106
86
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
87
|
requirements:
|
|
108
|
-
- - "
|
|
88
|
+
- - "~>"
|
|
109
89
|
- !ruby/object:Gem::Version
|
|
110
90
|
version: '2.0'
|
|
111
|
-
- - "
|
|
91
|
+
- - ">="
|
|
112
92
|
- !ruby/object:Gem::Version
|
|
113
93
|
version: '2.0'
|
|
114
94
|
- !ruby/object:Gem::Dependency
|
|
@@ -135,56 +115,62 @@ dependencies:
|
|
|
135
115
|
name: sinatra
|
|
136
116
|
requirement: !ruby/object:Gem::Requirement
|
|
137
117
|
requirements:
|
|
138
|
-
- - ">="
|
|
139
|
-
- !ruby/object:Gem::Version
|
|
140
|
-
version: 1.4.0
|
|
141
118
|
- - "~>"
|
|
142
119
|
- !ruby/object:Gem::Version
|
|
143
|
-
version: '1
|
|
120
|
+
version: '2.1'
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: 2.1.0
|
|
144
124
|
type: :runtime
|
|
145
125
|
prerelease: false
|
|
146
126
|
version_requirements: !ruby/object:Gem::Requirement
|
|
147
127
|
requirements:
|
|
148
|
-
- - ">="
|
|
149
|
-
- !ruby/object:Gem::Version
|
|
150
|
-
version: 1.4.0
|
|
151
128
|
- - "~>"
|
|
152
129
|
- !ruby/object:Gem::Version
|
|
153
|
-
version: '1
|
|
130
|
+
version: '2.1'
|
|
131
|
+
- - ">="
|
|
132
|
+
- !ruby/object:Gem::Version
|
|
133
|
+
version: 2.1.0
|
|
154
134
|
- !ruby/object:Gem::Dependency
|
|
155
135
|
name: sinatra-cross_origin
|
|
156
136
|
requirement: !ruby/object:Gem::Requirement
|
|
157
137
|
requirements:
|
|
158
|
-
- - ">="
|
|
159
|
-
- !ruby/object:Gem::Version
|
|
160
|
-
version: '0.4'
|
|
161
138
|
- - "~>"
|
|
162
139
|
- !ruby/object:Gem::Version
|
|
163
140
|
version: 0.4.0
|
|
141
|
+
- - ">="
|
|
142
|
+
- !ruby/object:Gem::Version
|
|
143
|
+
version: '0.4'
|
|
164
144
|
type: :runtime
|
|
165
145
|
prerelease: false
|
|
166
146
|
version_requirements: !ruby/object:Gem::Requirement
|
|
167
147
|
requirements:
|
|
168
|
-
- - ">="
|
|
169
|
-
- !ruby/object:Gem::Version
|
|
170
|
-
version: '0.4'
|
|
171
148
|
- - "~>"
|
|
172
149
|
- !ruby/object:Gem::Version
|
|
173
150
|
version: 0.4.0
|
|
151
|
+
- - ">="
|
|
152
|
+
- !ruby/object:Gem::Version
|
|
153
|
+
version: '0.4'
|
|
174
154
|
- !ruby/object:Gem::Dependency
|
|
175
155
|
name: coveralls
|
|
176
156
|
requirement: !ruby/object:Gem::Requirement
|
|
177
157
|
requirements:
|
|
158
|
+
- - "~>"
|
|
159
|
+
- !ruby/object:Gem::Version
|
|
160
|
+
version: '0.8'
|
|
178
161
|
- - ">="
|
|
179
162
|
- !ruby/object:Gem::Version
|
|
180
|
-
version:
|
|
163
|
+
version: 0.8.23
|
|
181
164
|
type: :development
|
|
182
165
|
prerelease: false
|
|
183
166
|
version_requirements: !ruby/object:Gem::Requirement
|
|
184
167
|
requirements:
|
|
168
|
+
- - "~>"
|
|
169
|
+
- !ruby/object:Gem::Version
|
|
170
|
+
version: '0.8'
|
|
185
171
|
- - ">="
|
|
186
172
|
- !ruby/object:Gem::Version
|
|
187
|
-
version:
|
|
173
|
+
version: 0.8.23
|
|
188
174
|
- !ruby/object:Gem::Dependency
|
|
189
175
|
name: cucumber
|
|
190
176
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -209,22 +195,22 @@ dependencies:
|
|
|
209
195
|
name: guard
|
|
210
196
|
requirement: !ruby/object:Gem::Requirement
|
|
211
197
|
requirements:
|
|
212
|
-
- - ">="
|
|
213
|
-
- !ruby/object:Gem::Version
|
|
214
|
-
version: 2.15.0
|
|
215
198
|
- - "~>"
|
|
216
199
|
- !ruby/object:Gem::Version
|
|
217
|
-
version: '2.
|
|
200
|
+
version: '2.16'
|
|
201
|
+
- - ">="
|
|
202
|
+
- !ruby/object:Gem::Version
|
|
203
|
+
version: 2.16.2
|
|
218
204
|
type: :development
|
|
219
205
|
prerelease: false
|
|
220
206
|
version_requirements: !ruby/object:Gem::Requirement
|
|
221
207
|
requirements:
|
|
222
|
-
- - ">="
|
|
223
|
-
- !ruby/object:Gem::Version
|
|
224
|
-
version: 2.15.0
|
|
225
208
|
- - "~>"
|
|
226
209
|
- !ruby/object:Gem::Version
|
|
227
|
-
version: '2.
|
|
210
|
+
version: '2.16'
|
|
211
|
+
- - ">="
|
|
212
|
+
- !ruby/object:Gem::Version
|
|
213
|
+
version: 2.16.2
|
|
228
214
|
- !ruby/object:Gem::Dependency
|
|
229
215
|
name: guard-rspec
|
|
230
216
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -269,80 +255,80 @@ dependencies:
|
|
|
269
255
|
name: rdoc
|
|
270
256
|
requirement: !ruby/object:Gem::Requirement
|
|
271
257
|
requirements:
|
|
272
|
-
- - "
|
|
258
|
+
- - "~>"
|
|
273
259
|
- !ruby/object:Gem::Version
|
|
274
260
|
version: '6.0'
|
|
275
|
-
- - "
|
|
261
|
+
- - ">="
|
|
276
262
|
- !ruby/object:Gem::Version
|
|
277
263
|
version: '6.0'
|
|
278
264
|
type: :development
|
|
279
265
|
prerelease: false
|
|
280
266
|
version_requirements: !ruby/object:Gem::Requirement
|
|
281
267
|
requirements:
|
|
282
|
-
- - "
|
|
268
|
+
- - "~>"
|
|
283
269
|
- !ruby/object:Gem::Version
|
|
284
270
|
version: '6.0'
|
|
285
|
-
- - "
|
|
271
|
+
- - ">="
|
|
286
272
|
- !ruby/object:Gem::Version
|
|
287
273
|
version: '6.0'
|
|
288
274
|
- !ruby/object:Gem::Dependency
|
|
289
275
|
name: reek
|
|
290
276
|
requirement: !ruby/object:Gem::Requirement
|
|
291
277
|
requirements:
|
|
292
|
-
- - "
|
|
278
|
+
- - "~>"
|
|
293
279
|
- !ruby/object:Gem::Version
|
|
294
280
|
version: 5.4.0
|
|
295
|
-
- - "
|
|
281
|
+
- - ">="
|
|
296
282
|
- !ruby/object:Gem::Version
|
|
297
283
|
version: 5.4.0
|
|
298
284
|
type: :development
|
|
299
285
|
prerelease: false
|
|
300
286
|
version_requirements: !ruby/object:Gem::Requirement
|
|
301
287
|
requirements:
|
|
302
|
-
- - "
|
|
288
|
+
- - "~>"
|
|
303
289
|
- !ruby/object:Gem::Version
|
|
304
290
|
version: 5.4.0
|
|
305
|
-
- - "
|
|
291
|
+
- - ">="
|
|
306
292
|
- !ruby/object:Gem::Version
|
|
307
293
|
version: 5.4.0
|
|
308
294
|
- !ruby/object:Gem::Dependency
|
|
309
295
|
name: rspec
|
|
310
296
|
requirement: !ruby/object:Gem::Requirement
|
|
311
297
|
requirements:
|
|
312
|
-
- - ">="
|
|
313
|
-
- !ruby/object:Gem::Version
|
|
314
|
-
version: 3.5.0
|
|
315
298
|
- - "~>"
|
|
316
299
|
- !ruby/object:Gem::Version
|
|
317
300
|
version: '3.5'
|
|
301
|
+
- - ">="
|
|
302
|
+
- !ruby/object:Gem::Version
|
|
303
|
+
version: 3.5.0
|
|
318
304
|
type: :development
|
|
319
305
|
prerelease: false
|
|
320
306
|
version_requirements: !ruby/object:Gem::Requirement
|
|
321
307
|
requirements:
|
|
322
|
-
- - ">="
|
|
323
|
-
- !ruby/object:Gem::Version
|
|
324
|
-
version: 3.5.0
|
|
325
308
|
- - "~>"
|
|
326
309
|
- !ruby/object:Gem::Version
|
|
327
310
|
version: '3.5'
|
|
311
|
+
- - ">="
|
|
312
|
+
- !ruby/object:Gem::Version
|
|
313
|
+
version: 3.5.0
|
|
328
314
|
- !ruby/object:Gem::Dependency
|
|
329
315
|
name: rubocop
|
|
330
316
|
requirement: !ruby/object:Gem::Requirement
|
|
331
317
|
requirements:
|
|
332
|
-
- - "
|
|
318
|
+
- - "~>"
|
|
333
319
|
- !ruby/object:Gem::Version
|
|
334
320
|
version: 0.73.0
|
|
335
|
-
- - "
|
|
321
|
+
- - ">="
|
|
336
322
|
- !ruby/object:Gem::Version
|
|
337
323
|
version: 0.73.0
|
|
338
324
|
type: :development
|
|
339
325
|
prerelease: false
|
|
340
326
|
version_requirements: !ruby/object:Gem::Requirement
|
|
341
327
|
requirements:
|
|
342
|
-
- - "
|
|
328
|
+
- - "~>"
|
|
343
329
|
- !ruby/object:Gem::Version
|
|
344
330
|
version: 0.73.0
|
|
345
|
-
- - "
|
|
331
|
+
- - ">="
|
|
346
332
|
- !ruby/object:Gem::Version
|
|
347
333
|
version: 0.73.0
|
|
348
334
|
- !ruby/object:Gem::Dependency
|
|
@@ -369,42 +355,42 @@ dependencies:
|
|
|
369
355
|
name: simplecov
|
|
370
356
|
requirement: !ruby/object:Gem::Requirement
|
|
371
357
|
requirements:
|
|
372
|
-
- - ">="
|
|
373
|
-
- !ruby/object:Gem::Version
|
|
374
|
-
version: 0.12.0
|
|
375
358
|
- - "~>"
|
|
376
359
|
- !ruby/object:Gem::Version
|
|
377
|
-
version: '0.
|
|
360
|
+
version: '0.16'
|
|
361
|
+
- - ">="
|
|
362
|
+
- !ruby/object:Gem::Version
|
|
363
|
+
version: 0.16.1
|
|
378
364
|
type: :development
|
|
379
365
|
prerelease: false
|
|
380
366
|
version_requirements: !ruby/object:Gem::Requirement
|
|
381
367
|
requirements:
|
|
382
|
-
- - ">="
|
|
383
|
-
- !ruby/object:Gem::Version
|
|
384
|
-
version: 0.12.0
|
|
385
368
|
- - "~>"
|
|
386
369
|
- !ruby/object:Gem::Version
|
|
387
|
-
version: '0.
|
|
370
|
+
version: '0.16'
|
|
371
|
+
- - ">="
|
|
372
|
+
- !ruby/object:Gem::Version
|
|
373
|
+
version: 0.16.1
|
|
388
374
|
- !ruby/object:Gem::Dependency
|
|
389
375
|
name: webmock
|
|
390
376
|
requirement: !ruby/object:Gem::Requirement
|
|
391
377
|
requirements:
|
|
392
|
-
- - ">="
|
|
393
|
-
- !ruby/object:Gem::Version
|
|
394
|
-
version: 2.1.0
|
|
395
378
|
- - "~>"
|
|
396
379
|
- !ruby/object:Gem::Version
|
|
397
380
|
version: '2.1'
|
|
381
|
+
- - ">="
|
|
382
|
+
- !ruby/object:Gem::Version
|
|
383
|
+
version: 2.1.0
|
|
398
384
|
type: :development
|
|
399
385
|
prerelease: false
|
|
400
386
|
version_requirements: !ruby/object:Gem::Requirement
|
|
401
387
|
requirements:
|
|
402
|
-
- - ">="
|
|
403
|
-
- !ruby/object:Gem::Version
|
|
404
|
-
version: 2.1.0
|
|
405
388
|
- - "~>"
|
|
406
389
|
- !ruby/object:Gem::Version
|
|
407
390
|
version: '2.1'
|
|
391
|
+
- - ">="
|
|
392
|
+
- !ruby/object:Gem::Version
|
|
393
|
+
version: 2.1.0
|
|
408
394
|
description: Proxy for mocks API responses
|
|
409
395
|
email: rubin.diego@gmail.com
|
|
410
396
|
executables:
|
|
@@ -426,6 +412,7 @@ files:
|
|
|
426
412
|
- lib/tshield/controllers/requests.rb
|
|
427
413
|
- lib/tshield/controllers/sessions.rb
|
|
428
414
|
- lib/tshield/counter.rb
|
|
415
|
+
- lib/tshield/errors.rb
|
|
429
416
|
- lib/tshield/extensions/string_extensions.rb
|
|
430
417
|
- lib/tshield/grpc.rb
|
|
431
418
|
- lib/tshield/grpc/vcr.rb
|
|
@@ -452,6 +439,7 @@ files:
|
|
|
452
439
|
- spec/tshield/options_spec.rb
|
|
453
440
|
- spec/tshield/request_matching_spec.rb
|
|
454
441
|
- spec/tshield/request_vcr_spec.rb
|
|
442
|
+
- spec/tshield/sessions_spec.rb
|
|
455
443
|
- tshield.gemspec
|
|
456
444
|
homepage: https://github.com/diegorubin/tshield
|
|
457
445
|
licenses:
|
|
@@ -465,28 +453,30 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
465
453
|
requirements:
|
|
466
454
|
- - ">="
|
|
467
455
|
- !ruby/object:Gem::Version
|
|
468
|
-
version: '2.
|
|
456
|
+
version: '2.4'
|
|
469
457
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
470
458
|
requirements:
|
|
471
459
|
- - ">="
|
|
472
460
|
- !ruby/object:Gem::Version
|
|
473
461
|
version: '0'
|
|
474
462
|
requirements: []
|
|
475
|
-
|
|
463
|
+
rubyforge_project:
|
|
464
|
+
rubygems_version: 2.6.14.4
|
|
476
465
|
signing_key:
|
|
477
466
|
specification_version: 4
|
|
478
467
|
summary: Proxy for mocks API responses
|
|
479
468
|
test_files:
|
|
480
469
|
- spec/spec_helper.rb
|
|
470
|
+
- spec/tshield/fixtures/matching/example.json
|
|
471
|
+
- spec/tshield/fixtures/config/tshield-without-grpc.yml
|
|
472
|
+
- spec/tshield/fixtures/config/tshield.yml
|
|
473
|
+
- spec/tshield/fixtures/filters/example_filter.rb
|
|
474
|
+
- spec/tshield/fixtures/proto/test_services_pb.rb
|
|
475
|
+
- spec/tshield/options_spec.rb
|
|
476
|
+
- spec/tshield/configuration_spec.rb
|
|
477
|
+
- spec/tshield/sessions_spec.rb
|
|
481
478
|
- spec/tshield/request_matching_spec.rb
|
|
479
|
+
- spec/tshield/controllers/requests_spec.rb
|
|
482
480
|
- spec/tshield/grpc_spec.rb
|
|
483
|
-
- spec/tshield/configuration_spec.rb
|
|
484
481
|
- spec/tshield/request_vcr_spec.rb
|
|
485
|
-
- spec/tshield/controllers/requests_spec.rb
|
|
486
|
-
- spec/tshield/options_spec.rb
|
|
487
482
|
- spec/tshield/after_filter_spec.rb
|
|
488
|
-
- spec/tshield/fixtures/matching/example.json
|
|
489
|
-
- spec/tshield/fixtures/proto/test_services_pb.rb
|
|
490
|
-
- spec/tshield/fixtures/filters/example_filter.rb
|
|
491
|
-
- spec/tshield/fixtures/config/tshield.yml
|
|
492
|
-
- spec/tshield/fixtures/config/tshield-without-grpc.yml
|