tshield 0.8.0.0 → 0.9.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +3 -2
  3. data/README.md +147 -4
  4. data/Rakefile +13 -2
  5. data/bin/tshield +5 -5
  6. data/config/tshield.yml +9 -0
  7. data/lib/tshield/after_filter.rb +3 -2
  8. data/lib/tshield/before_filter.rb +3 -2
  9. data/lib/tshield/configuration.rb +57 -36
  10. data/lib/tshield/controller.rb +22 -10
  11. data/lib/tshield/controllers/requests.rb +20 -21
  12. data/lib/tshield/controllers/sessions.rb +2 -3
  13. data/lib/tshield/counter.rb +5 -5
  14. data/lib/tshield/logger.rb +10 -0
  15. data/lib/tshield/options.rb +61 -27
  16. data/lib/tshield/request.rb +25 -28
  17. data/lib/tshield/response.rb +2 -0
  18. data/lib/tshield/server.rb +24 -19
  19. data/lib/tshield/sessions.rb +6 -4
  20. data/lib/tshield/simple_tcp_server.rb +3 -2
  21. data/lib/tshield/version.rb +4 -2
  22. data/lib/tshield.rb +3 -2
  23. data/spec/spec_helper.rb +6 -6
  24. data/spec/tshield/after_filter_spec.rb +7 -0
  25. data/spec/tshield/configuration_spec.rb +57 -20
  26. data/spec/tshield/fixtures/config/tshield.yml +7 -1
  27. data/spec/tshield/fixtures/filters/example_filter.rb +9 -0
  28. data/spec/tshield/request_spec.rb +43 -2
  29. data/tshield.gemspec +28 -22
  30. metadata +139 -67
  31. data/lib/tshield/assets/favicon.ico +0 -0
  32. data/lib/tshield/assets/javascripts/application.js +0 -0
  33. data/lib/tshield/assets/javascripts/bootstrap.min.js +0 -7
  34. data/lib/tshield/assets/javascripts/jquery.min.js +0 -4
  35. data/lib/tshield/assets/stylesheets/application.css +0 -49
  36. data/lib/tshield/assets/stylesheets/bootstrap-theme.min.css +0 -6
  37. data/lib/tshield/assets/stylesheets/bootstrap.min.css +0 -6
  38. data/lib/tshield/controllers/admin/requests.rb +0 -62
  39. data/lib/tshield/controllers/admin/sessions.rb +0 -40
  40. data/lib/tshield/views/admin/requests/index.haml +0 -6
  41. data/lib/tshield/views/admin/requests/show.haml +0 -25
  42. data/lib/tshield/views/admin/sessions/index.haml +0 -6
  43. data/lib/tshield/views/layout/base.haml +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 21eb1813abe621fbbd5239e1b80aa3f0c3985aac
4
- data.tar.gz: 63e502ed3dd6663f90befd4da0a97a91a62b7551
2
+ SHA256:
3
+ metadata.gz: b2bb0faafe574abb4aae439e22b68758271aecc2db875e7075d43a327ee7bc3e
4
+ data.tar.gz: 818926f43b10948fa156028b758c5e9750fc3638c3f8f84c6cf102abe145d292
5
5
  SHA512:
6
- metadata.gz: 7dddf275f556989113f2ab0be6fdc1a3ef431e2e223a5042eb734fcccf016d3a2c5d5bcd5d22e2f1eca70133f7f0aec5351d854eed681dd36e9d3c0f2d971496
7
- data.tar.gz: f1795cd4c6da1c31904a45831d887d82b27affae09fca7794d7e2484e5f62b8133b495e098d6acc70f344cead810aa279d55dcb3a711a67cc507005a6bd8bc50
6
+ metadata.gz: 5fe988d83f69aa0d0053e928fc78c326ee7f08d08a39a6aea3aba4321289efe9e09c91be1f2c5d75e3e61c3202b5651256962c4ad7a66f001e39480e1f6dce92
7
+ data.tar.gz: 658b408f3fb7cd82d67278ac2c8569bd5b2801671630a72a6ca074089ea62ae28cd5f896c9994ff6ad02ee6dec00f3de2590819bee060587d8726efd511b2b63
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- gemspec
3
+ source 'https://rubygems.org'
4
4
 
5
+ gemspec
data/README.md CHANGED
@@ -1,17 +1,33 @@
1
1
  TShield
2
2
  =======
3
3
 
4
- ## Install
4
+ [![Build Status](https://travis-ci.org/diegorubin/tshield.svg)](https://travis-ci.org/diegorubin/tshield)
5
+ [![SourceLevel](https://app.sourcelevel.io/github/diegorubin/tshield.svg)](https://app.sourcelevel.io/github/diegorubin/tshield)[![Join the chat at https://gitter.im/diegorubin/tshield](https://badges.gitter.im/diegorubin/tshield.svg)](https://gitter.im/diegorubin/tshield?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6
+
7
+ ## API mocks for development and testing
8
+ TShield is an open source proxy for mocks API responses.
9
+
10
+ * REST
11
+ * SOAP
12
+ * Session manager to separate multiple scenarios (success, error, sucess variation, ...)
13
+ * Lightweight
14
+ * MIT license
15
+
16
+ ## Basic Usage
17
+ ### Install
5
18
 
6
19
  gem install tshield
7
20
 
8
- ## Using
21
+ ### Using
9
22
 
10
23
  To run server execute this command
11
24
 
12
25
  tshield
26
+
27
+ Default port is **4567**
28
+
13
29
 
14
- ### Config example
30
+ #### Config example
15
31
 
16
32
  Before run `tshield` command is necessary to create config file.
17
33
  This is an example of `config/tshield.yml`
@@ -33,7 +49,93 @@ domains:
33
49
  - /users
34
50
  ```
35
51
 
36
- ### Custom controllers
52
+ ## Config options
53
+ ```yaml
54
+ request:
55
+ timeout: 8
56
+ verify_ssl: <<value>>
57
+ domains:
58
+ 'http://my-soap-service:80':
59
+ name: 'my-soap-service'
60
+ headers:
61
+ HTTP_AUTHORIZATION: Authorization
62
+ HTTP_COOKIE: Cookie
63
+ not_save_headers:
64
+ - transfer-encoding
65
+ cache_request: <<value>>
66
+ filters:
67
+ - <<value>>
68
+ excluded_headers:
69
+ - <<value>>
70
+ paths:
71
+ - /Operation
72
+
73
+ 'http://localhost:9090':
74
+ name: 'my-service'
75
+ headers:
76
+ HTTP_AUTHORIZATION: Authorization
77
+ HTTP_COOKIE: Cookie
78
+ HTTP_DOCUMENTID: DocumentId
79
+ not_save_headers:
80
+ - transfer-encoding
81
+ paths:
82
+ - /secure
83
+
84
+ 'http://localhost:9092':
85
+ name: 'my-other-service'
86
+ headers:
87
+ HTTP_AUTHORIZATION: Authorization
88
+ HTTP_COOKIE: Cookie
89
+ not_save_headers:
90
+ - transfer-encoding
91
+ paths:
92
+ - /users
93
+ ```
94
+ **request**
95
+ * **timeout**: wait time for real service in seconds
96
+ * **verify_ssl**: ignores invalid ssl if false
97
+
98
+ **domain**
99
+ * Define Base URI of service
100
+ * **name**: Name to identify the domain in the generated files
101
+ * **headers**: github-issue #17
102
+ * **not_save_headers**: List of headers that should be ignored in generated file
103
+ * **cache_request**: <<some_description>>
104
+ * **filters**: Implementation of before or after filters used in domain requests
105
+ * **excluded_headers**: <<some_description>>
106
+ * **paths**: Paths list of all services that will be called. Used to filter what domain will "receive the request"
107
+
108
+ ## Manage Sessions
109
+
110
+ You can use TShield sessions to separate multiple scenarios for your mocks
111
+
112
+ By default TShield save request/response into
113
+
114
+ requests/<<domain_name>>/<<resource_with_param>>/<<http_verb>>/<<index_based.content and json>>
115
+
116
+ If you start a session a folder with de **session_name** will be placed between **"requests/"** and **"<<domain_name>>"**
117
+
118
+ ### Start TShield session
119
+ **Start new or existing session**
120
+
121
+ _POST_ to http://localhost:4567/sessions?name=<<same_name>>
122
+
123
+ ```
124
+ curl -X POST \
125
+ 'http://localhost:4567/sessions?name=my_valid'
126
+ ```
127
+
128
+ ### Stop TShield session
129
+ **Stop current session**
130
+
131
+ _DELETE_ to http://localhost:4567/sessions
132
+
133
+ ```
134
+ curl -X DELETE \
135
+ http://localhost:4567/sessions
136
+ ```
137
+
138
+ ## Custom controllers
37
139
 
38
140
  All custom controller should be created in `controllers` directory.
39
141
 
@@ -57,4 +159,45 @@ module FooController
57
159
  end
58
160
  ```
59
161
 
162
+ ## Features
163
+
164
+ Description of some tshield features can be found in the features directory.
165
+ This features files are used as base for the component tests.
166
+
167
+ ## Samples
168
+ #### Basic sample for a client app requesting a server API
169
+ [examples/client-api-nodejs](examples/client-api-nodejs)
170
+ #### Basic sample for componente/integration test
171
+ **[WIP]**
172
+
173
+ ## Setup for local development
174
+
175
+ First install dependencies.
176
+ _We recommend use of the RVM to manage project dependencies.__
177
+
178
+ ```
179
+ bundle install
180
+ ```
181
+
182
+ ### Run server to development
183
+
184
+ To start server execute:
185
+
186
+ `rake server`
187
+
188
+ ### Build
189
+
190
+ To generate ruby gem execute:
191
+
192
+ `rake build`
193
+
194
+ ### Test
195
+
196
+ To run all unit tests:
197
+
198
+ `rake spec`
199
+
200
+ To run all component tests:
201
+
202
+ `rake component__tests`
60
203
 
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'bundler/setup'
3
5
  rescue LoadError
@@ -18,8 +20,17 @@ Bundler::GemHelper.install_tasks
18
20
 
19
21
  require 'rspec/core'
20
22
  require 'rspec/core/rake_task'
21
- desc "Run all specs in spec directory (excluding plugin specs)"
23
+ desc 'Run all specs in spec directory (excluding plugin specs)'
22
24
  RSpec::Core::RakeTask.new
23
25
 
24
- task :default => :spec
26
+ task default: :spec
27
+
28
+ task :component_tests do
29
+ $LOAD_PATH.unshift File.dirname('./lib/tshield.rb')
30
+ exec 'component_tests/run'
31
+ end
25
32
 
33
+ task :server do
34
+ $LOAD_PATH.unshift File.dirname('./lib/tshield.rb')
35
+ exec 'bin/tshield'
36
+ end
data/bin/tshield CHANGED
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require 'tshield'
4
-
4
+ require 'tshield/options'
5
5
  TShield::Options.init
6
6
 
7
- tshield = Thread.new {TShield::Server.run!}
7
+ require 'tshield'
8
+ tshield = Thread.new { TShield::Server.run! }
8
9
 
9
10
  configuration = TShield::Configuration.load_configuration
10
11
  (configuration.tcp_servers || []).each do |tcp_server|
11
12
  puts "initializing #{tcp_server['name']}"
12
13
  require "./servers/#{tcp_server['file']}"
13
- klass = Object.const_get(tcp_server['name'])
14
+ klass = Object.const_get(tcp_server['name'])
14
15
  Thread.new { klass.new.listen(tcp_server['port']) }
15
16
  end
16
17
 
17
18
  tshield.join
18
-
@@ -0,0 +1,9 @@
1
+ ---
2
+ request:
3
+ timeout: 8
4
+
5
+ domains:
6
+ 'https://service.com':
7
+ name: 'service'
8
+ paths:
9
+ - /users
@@ -1,11 +1,12 @@
1
- module TShield
1
+ # frozen_string_literal: true
2
2
 
3
+ module TShield
3
4
  # Example:
4
5
  # def filter(response)
5
6
  # response
6
7
  # end
7
8
  class AfterFilter
8
- def filter(response)
9
+ def filter(_response)
9
10
  raise 'should implement method filter and returns response'
10
11
  end
11
12
  end
@@ -1,11 +1,12 @@
1
- module TShield
1
+ # frozen_string_literal: true
2
2
 
3
+ module TShield
3
4
  # Example:
4
5
  # def filter(method, url, options)
5
6
  # [method, url, options]
6
7
  # end
7
8
  class BeforeFilter
8
- def filter(method, url, options)
9
+ def filter(_method, _url, _options)
9
10
  raise 'should implement method filter and returns method, url, options'
10
11
  end
11
12
  end
@@ -1,38 +1,63 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
 
3
5
  require 'tshield/after_filter'
4
6
  require 'tshield/before_filter'
7
+ require 'tshield/options'
8
+ require 'tshield/logger'
5
9
 
6
10
  module TShield
11
+ # Class for read configuration file
7
12
  class Configuration
8
-
9
- attr_accessor :request
10
- attr_accessor :domains
11
- attr_accessor :tcp_servers
12
- attr_writer :session_path
13
+ # Configuration file
14
+ #
15
+ # Possible attributes
16
+ # request:
17
+ # timeout: wait time for real service in seconds
18
+ # verify_ssl: ignores invalid ssl if false
19
+ # domains:
20
+ # 'url':
21
+ # name: Name to identify the domain in the generated files
22
+ # headers: Object to translate received header in tshield to send to
23
+ # original service. Sinatra change keys. Example:
24
+ # HTTP_AUTHORIZATION should be mapped to Authorization
25
+ # (NEED IMPROVEMENT github-issue #https://github.com/diegorubin/tshield/issues/17)
26
+ # not_save_headers: List of headers that should be ignored in generated
27
+ # file
28
+ #
29
+ attr_reader :request
30
+ attr_reader :domains
31
+ attr_reader :tcp_servers
13
32
 
14
33
  def initialize(attributes)
15
- attributes.each do |key, value|
16
- send("#{key}=", value)
17
- end
34
+ attributes.each { |key, value| instance_variable_set("@#{key}", value) }
18
35
 
19
- if File.exists?('filters')
20
- Dir.entries('filters').each do |entry|
21
- next if entry =~ /^\.\.?$/
22
- puts "loading filter #{entry}"
23
- entry.gsub!('.rb', '')
24
- require File.join('.', 'filters', entry)
25
- end
36
+ return unless File.exist?('filters')
37
+
38
+ Dir.entries('filters').each do |entry|
39
+ next if entry =~ /^\.\.?$/
40
+
41
+ TShield.logger.info("loading filter #{entry}")
42
+ entry.gsub!('.rb', '')
43
+
44
+ require File.join('.', 'filters', entry)
26
45
  end
27
46
  end
28
47
 
29
48
  def self.singleton
30
- @@configuration ||= load_configuration
49
+ @singleton ||= load_configuration
50
+ end
51
+
52
+ def self.clear
53
+ @singleton = nil
31
54
  end
32
55
 
33
56
  def get_domain_for(path)
34
57
  domains.each do |url, config|
35
- config['paths'].each { |p| return url if path =~ Regexp.new(p) }
58
+ config['paths'].each do |pattern|
59
+ return url if path =~ Regexp.new(pattern)
60
+ end
36
61
  end
37
62
  nil
38
63
  end
@@ -42,27 +67,26 @@ module TShield
42
67
  end
43
68
 
44
69
  def get_name(domain)
45
- domains[domain]['name'] || domain.gsub(/.*:\/\//, '')
70
+ domains[domain]['name'] || domain.gsub(%r{.*://}, '')
46
71
  end
47
72
 
48
73
  def get_before_filters(domain)
49
74
  get_filters(domain)
50
- .select { |k| k.ancestors.include?(TShield::BeforeFilter) }
75
+ .select { |klass| klass.ancestors.include?(TShield::BeforeFilter) }
51
76
  end
52
77
 
53
78
  def get_after_filters(domain)
54
79
  get_filters(domain)
55
- .select { |k| k.ancestors.include?(TShield::AfterFilter) }
80
+ .select { |klass| klass.ancestors.include?(TShield::AfterFilter) }
56
81
  end
57
82
 
58
83
  def cache_request?(domain)
59
- return true unless domains[domain].include?('cache_request')
60
- domains[domain]['cache_request']
84
+ domains[domain]['cache_request'] || true
61
85
  end
62
86
 
63
87
  def get_filters(domain)
64
88
  (domains[domain]['filters'] || [])
65
- .collect { |f| Class.const_get(f) }
89
+ .collect { |filter| Class.const_get(filter) }
66
90
  end
67
91
 
68
92
  def get_excluded_headers(domain)
@@ -77,22 +101,19 @@ module TShield
77
101
  @session_path || '/sessions'
78
102
  end
79
103
 
80
- def admin_session_path
81
- @admin_session_path || '/admin/sessions'
82
- end
83
-
84
- def admin_request_path
85
- @admin_request_path || '/admin/requests'
104
+ def self.read_configuration_file(config_path)
105
+ configs = YAML.safe_load(File.open(config_path).read)
106
+ Configuration.new(configs)
86
107
  end
87
108
 
88
- private
89
109
  def self.load_configuration
90
- config_path = File.join('config', 'tshield.yml')
91
- file = File.open(config_path)
92
- configs = YAML::load(file.read)
93
- Configuration.new(configs)
110
+ configuration_file = TShield::Options.instance.configuration_file
111
+ read_configuration_file(configuration_file)
112
+ rescue Errno::ENOENT => e
113
+ TShield.logger.fatal(
114
+ "Load configuration file #{configuration_file} failed!\n#{e}"
115
+ )
116
+ raise 'Startup aborted'
94
117
  end
95
-
96
118
  end
97
119
  end
98
-
@@ -1,29 +1,41 @@
1
+ # frozen_string_literal: false
2
+
1
3
  require 'sinatra'
2
4
 
5
+ require 'tshield/logger'
6
+
3
7
  module TShield
8
+ # TShield Controller
4
9
  module Controller
5
-
6
10
  def self.included(base)
7
11
  base.extend ClassMethods
8
12
  end
9
13
 
14
+ # Implementation of actions
10
15
  module ClassMethods
11
16
  def action(class_method, options)
12
- @@actions = {} unless defined? @@actions
13
- @@actions[class_method] = options
17
+ @actions = {} unless defined? @actions
18
+ @actions[class_method] = options
14
19
  end
15
20
 
16
21
  def registered(app)
17
- @@actions.each do |class_method, options|
18
- puts "== registering #{options[:path]} for methods #{options[:methods].join(',')} with action #{class_method}"
19
- options[:methods].each do |method|
20
- app.send(method, options[:path]) { send(class_method, params, request) }
21
- end
22
+ @actions.each do |class_method, options|
23
+ load_action(app, class_method, options)
22
24
  end
23
25
  end
24
26
 
25
- end
27
+ def load_action(app, class_method, options)
28
+ msg = "== registering #{options[:path]}"
29
+ msg << " for methods #{options[:methods].join(',')}"
30
+ msg << " with action #{class_method}"
26
31
 
32
+ TShield.logger.info(msg)
33
+ options[:methods].each do |method|
34
+ app.send(method, options[:path]) do
35
+ send(class_method, params, request)
36
+ end
37
+ end
38
+ end
39
+ end
27
40
  end
28
41
  end
29
-
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'sinatra'
4
4
 
@@ -12,40 +12,40 @@ require 'tshield/sessions'
12
12
  module TShield
13
13
  module Controllers
14
14
  module Requests
15
- PATHP = /([a-zA-Z0-9\/\._-]+)/
15
+ PATHP = %r{([a-zA-Z0-9/\._-]+)}.freeze
16
16
 
17
17
  def self.registered(app)
18
18
  app.configure :production, :development do
19
19
  app.enable :logging
20
20
  end
21
-
22
- app.get (PATHP) do
21
+
22
+ app.get(PATHP) do
23
23
  treat(params, request, response)
24
24
  end
25
25
 
26
- app.post (PATHP) do
26
+ app.post(PATHP) do
27
27
  treat(params, request, response)
28
28
  end
29
29
 
30
- app.put (PATHP) do
30
+ app.put(PATHP) do
31
31
  treat(params, request, response)
32
32
  end
33
33
 
34
- app.patch (PATHP) do
34
+ app.patch(PATHP) do
35
35
  treat(params, request, response)
36
36
  end
37
37
 
38
- app.head (PATHP) do
38
+ app.head(PATHP) do
39
39
  treat(params, request, response)
40
40
  end
41
41
 
42
- app.delete (PATHP) do
42
+ app.delete(PATHP) do
43
43
  treat(params, request, response)
44
44
  end
45
45
  end
46
46
 
47
47
  module Helpers
48
- def treat(params, request, response)
48
+ def treat(params, request, _response)
49
49
  path = params.fetch('captures', [])[0]
50
50
 
51
51
  debugger if TShield::Options.instance.break?(path: path, moment: :before)
@@ -66,12 +66,11 @@ module TShield
66
66
  ip: request.ip
67
67
  }
68
68
 
69
- if ['POST', 'PUT', 'PATCH'].include? method
70
- result = request.body.read.encode('UTF-8', {
71
- :invalid => :replace,
72
- :undef => :replace,
73
- :replace => ''
74
- })
69
+ if %w[POST PUT PATCH].include? method
70
+ result = request.body.read.encode('UTF-8',
71
+ invalid: :replace,
72
+ undef: :replace,
73
+ replace: '')
75
74
  options[:body] = result
76
75
  end
77
76
 
@@ -80,14 +79,15 @@ module TShield
80
79
  api_response = TShield::Request.new(path, options).response
81
80
 
82
81
  logger.info(
83
- "original=#{api_response.original} method=#{method} path=#{path} content-type=#{request_content_type} session=#{current_session_name(request)}")
82
+ "original=#{api_response.original} method=#{method} path=#{path} content-type=#{request_content_type} session=#{current_session_name(request)}"
83
+ )
84
84
 
85
85
  status api_response.status
86
- headers api_response.headers.reject { |k,v| configuration.get_excluded_headers(domain(path)).include?(k) }
86
+ headers api_response.headers.reject { |k, _v| configuration.get_excluded_headers(domain(path)).include?(k) }
87
87
  body api_response.body
88
88
  end
89
89
 
90
- def set_content_type(request_content_type)
90
+ def set_content_type(_request_content_type)
91
91
  content_type :json
92
92
  end
93
93
 
@@ -97,7 +97,7 @@ module TShield
97
97
  end
98
98
 
99
99
  def add_headers(headers, path)
100
- configuration.get_headers(domain(path)).each do |source, destiny|
100
+ configuration.get_headers(domain(path)).each do |source, destiny|
101
101
  headers[destiny] = request.env[source] unless request.env[source].nil?
102
102
  end
103
103
  end
@@ -113,4 +113,3 @@ module TShield
113
113
  end
114
114
  end
115
115
  end
116
-
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sinatra/base'
2
4
 
3
5
  require 'tshield/configuration'
@@ -7,7 +9,6 @@ module TShield
7
9
  module Controllers
8
10
  module Sessions
9
11
  def self.registered(app)
10
-
11
12
  app.get TShield::Configuration.singleton.session_path do
12
13
  TShield::Sessions.current(request.ip).to_json
13
14
  end
@@ -19,9 +20,7 @@ module TShield
19
20
  app.delete TShield::Configuration.singleton.session_path do
20
21
  TShield::Sessions.stop(request.ip).to_json
21
22
  end
22
-
23
23
  end
24
24
  end
25
25
  end
26
26
  end
27
-
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TShield
4
+ # Increment counter for sessions requests
2
5
  class Counter
3
-
4
6
  def initialize
5
7
  @requests = {}
6
8
  end
@@ -9,7 +11,7 @@ module TShield
9
11
  requests_to_path = @requests.fetch(path, {})
10
12
  requests_to_method = requests_to_path.fetch(method, 0)
11
13
 
12
- requests_to_path[method] = requests_to_method += 1
14
+ requests_to_path[method] = requests_to_method + 1
13
15
  @requests[path] = requests_to_path
14
16
  end
15
17
 
@@ -18,9 +20,7 @@ module TShield
18
20
  end
19
21
 
20
22
  def to_json(options = {})
21
- @requests.to_json
23
+ @requests.to_json(options)
22
24
  end
23
-
24
25
  end
25
26
  end
26
-
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ # Logger instance for application
6
+ module TShield
7
+ def self.logger
8
+ @logger ||= Logger.new(STDOUT)
9
+ end
10
+ end