soaspec 0.2.33 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -15
  3. data/.gitlab-ci.yml +62 -62
  4. data/.rspec +3 -3
  5. data/.rubocop.yml +2 -2
  6. data/CODE_OF_CONDUCT.md +74 -74
  7. data/ChangeLog +643 -632
  8. data/Dockerfile +7 -7
  9. data/Gemfile +8 -8
  10. data/LICENSE.txt +21 -21
  11. data/README.md +253 -231
  12. data/Rakefile +52 -52
  13. data/Todo.md +16 -16
  14. data/exe/soaspec +140 -138
  15. data/exe/xml_to_yaml_file +43 -43
  16. data/lib/soaspec.rb +118 -106
  17. data/lib/soaspec/baseline.rb +82 -22
  18. data/lib/soaspec/core_ext/hash.rb +44 -44
  19. data/lib/soaspec/cucumber/generic_steps.rb +94 -94
  20. data/lib/soaspec/demo.rb +6 -6
  21. data/lib/soaspec/errors.rb +24 -24
  22. data/lib/soaspec/exchange/exchange.rb +131 -129
  23. data/lib/soaspec/exchange/exchange_extractor.rb +105 -90
  24. data/lib/soaspec/exchange/exchange_properties.rb +28 -28
  25. data/lib/soaspec/exchange/exchange_repeater.rb +21 -21
  26. data/lib/soaspec/exchange/request_builder.rb +108 -70
  27. data/lib/soaspec/exchange/variable_storer.rb +24 -24
  28. data/lib/soaspec/exchange_handlers/exchange_handler.rb +98 -98
  29. data/lib/soaspec/exchange_handlers/exchange_handler_defaults.rb +61 -61
  30. data/lib/soaspec/exchange_handlers/handler_accessors.rb +132 -132
  31. data/lib/soaspec/exchange_handlers/request/rest_request.rb +77 -59
  32. data/lib/soaspec/exchange_handlers/request/soap_request.rb +41 -41
  33. data/lib/soaspec/exchange_handlers/response_extractor.rb +84 -84
  34. data/lib/soaspec/exchange_handlers/rest_exchanger_factory.rb +111 -111
  35. data/lib/soaspec/exchange_handlers/rest_handler.rb +307 -307
  36. data/lib/soaspec/exchange_handlers/rest_methods.rb +65 -65
  37. data/lib/soaspec/exchange_handlers/rest_parameters.rb +112 -112
  38. data/lib/soaspec/exchange_handlers/rest_parameters_defaults.rb +42 -42
  39. data/lib/soaspec/exchange_handlers/soap_handler.rb +241 -241
  40. data/lib/soaspec/exe_helpers.rb +94 -94
  41. data/lib/soaspec/generate_server.rb +48 -48
  42. data/lib/soaspec/generator/.rspec.erb +5 -5
  43. data/lib/soaspec/generator/.travis.yml.erb +5 -5
  44. data/lib/soaspec/generator/Gemfile.erb +8 -8
  45. data/lib/soaspec/generator/README.md.erb +29 -29
  46. data/lib/soaspec/generator/Rakefile.erb +20 -19
  47. data/lib/soaspec/generator/config/data/default.yml.erb +2 -2
  48. data/lib/soaspec/generator/css/bootstrap.css +6833 -6833
  49. data/lib/soaspec/generator/features/support/env.rb.erb +3 -3
  50. data/lib/soaspec/generator/generate_exchange.html.erb +47 -47
  51. data/lib/soaspec/generator/lib/blz_service.rb.erb +26 -26
  52. data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -12
  53. data/lib/soaspec/generator/lib/new_rest_service.rb.erb +56 -56
  54. data/lib/soaspec/generator/lib/new_soap_service.rb.erb +29 -29
  55. data/lib/soaspec/generator/lib/package_service.rb.erb +2 -2
  56. data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -8
  57. data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +12 -12
  58. data/lib/soaspec/generator/spec/rest_spec.rb.erb +9 -9
  59. data/lib/soaspec/generator/spec/soap_spec.rb.erb +51 -51
  60. data/lib/soaspec/generator/spec/spec_helper.rb.erb +23 -23
  61. data/lib/soaspec/generator/template/soap_template.xml +6 -6
  62. data/lib/soaspec/indifferent_hash.rb +9 -9
  63. data/lib/soaspec/interpreter.rb +70 -70
  64. data/lib/soaspec/matchers.rb +136 -140
  65. data/lib/soaspec/o_auth2.rb +142 -142
  66. data/lib/soaspec/soaspec_shared_examples.rb +26 -26
  67. data/lib/soaspec/spec_logger.rb +143 -143
  68. data/lib/soaspec/template_reader.rb +30 -30
  69. data/lib/soaspec/test_server/bank.wsdl +90 -90
  70. data/lib/soaspec/test_server/get_bank.rb +166 -166
  71. data/lib/soaspec/test_server/id_manager.rb +41 -41
  72. data/lib/soaspec/test_server/invoices.rb +29 -29
  73. data/lib/soaspec/test_server/namespace.xml +14 -14
  74. data/lib/soaspec/test_server/note.xml +5 -5
  75. data/lib/soaspec/test_server/puppy_service.rb +21 -21
  76. data/lib/soaspec/test_server/test_attribute.rb +14 -14
  77. data/lib/soaspec/test_server/test_namespace.rb +14 -14
  78. data/lib/soaspec/version.rb +6 -6
  79. data/lib/soaspec/virtual_server.rb +193 -190
  80. data/lib/soaspec/wait.rb +43 -43
  81. data/lib/soaspec/wsdl_generator.rb +215 -215
  82. data/soaspec.gemspec +58 -58
  83. data/test.wsdl +116 -116
  84. data/test.xml +10 -10
  85. data/test_wsdl.rb +43 -43
  86. metadata +3 -3
@@ -1,142 +1,142 @@
1
- # frozen_string_literal: true
2
-
3
- require 'erb'
4
-
5
- module Soaspec
6
- # Handles working with OAuth2
7
- class OAuth2
8
- # How often to refresh access token
9
- @refresh_token = :always
10
- # List of access tokens. They are mapped according to the OAuth parameters used
11
- @access_tokens = {}
12
- # List of instance URLs. They are mapped according to the OAuth parameters used
13
- @instance_urls = {}
14
- # Whether to see params sent to & received from oauth URL
15
- @request_message = true
16
- # How many times to attempt to authenticate before raising exception
17
- @retry_limit = 2
18
- class << self
19
- # Default token url used across entire suite
20
- attr_accessor :token_url
21
- # @attr [Symbol] refresh_token How often to refresh access token
22
- # Values are:
23
- # * :always - (Default) Request token from token url every time it is needed
24
- # * :once - Request token once for the entire execution of the suite
25
- attr_accessor :refresh_token
26
- # @attr [Hash] access_tokens List of access tokens. They are mapped according to the OAuth parameters used
27
- attr_accessor :access_tokens
28
- # List of URLs to that define the instance of an application
29
- attr_accessor :instance_urls
30
- # Specify whether to see params sent to and retrieved from oauth. This will put password in log file, only recommended for debugging
31
- attr_writer :debug_oauth
32
- # @return [Boolean] Whether to include request message describing OAuth (either full or simplified)
33
- attr_writer :request_message
34
- # @return [Integer] How many times to attempt to authenticate before raising exception
35
- attr_accessor :retry_limit
36
- # @return [Boolean] Whether to see params sent to & received from oauth URL
37
- def debug_oauth?
38
- @debug_oauth || false
39
- end
40
-
41
- # @return [Boolean] Whether to include request message describing OAuth (either full or simplified)
42
- def request_message?
43
- @request_message
44
- end
45
- end
46
-
47
- # @attr [Hash] OAuth parameters
48
- attr_accessor :params
49
- # @attr [Integer] Count of tries to obtain access token
50
- attr_accessor :retry_count
51
-
52
- # @param [Hash] params_sent Parameters to make OAuth request
53
- # @option params_sent [token_url] URL to retrieve OAuth token from. @Note this can be set globally instead of here
54
- # @option params_sent [client_id] Client ID
55
- # @option params_sent [client_secret] Client Secret
56
- # @option params_sent [username] Username used in password grant
57
- # @option params_sent [password] Password used in password grant
58
- # @option params_sent [security_token] Security Token used in password grant
59
- # @param [String] api_username Username to use which can be set by Soaspec::ExchangeHandler
60
- def initialize(params_sent, api_username = nil)
61
- self.retry_count = 0 # No initial tries at getting access token
62
- params = params_sent.transform_keys_to_symbols
63
- params[:token_url] ||= Soaspec::OAuth2.token_url
64
- raise ArgumentError, 'client_id and client_secret not set' unless params[:client_id] && params[:client_secret]
65
- raise ArgumentError, 'token_url mandatory' unless params[:token_url]
66
-
67
- self.params = params
68
- params[:username] = api_username || ERB.new(params[:username]).result(binding) if params[:username]
69
- params[:security_token] = ERB.new(params[:security_token]).result(binding) if params[:security_token]
70
- params[:token_url] = ERB.new(params[:token_url]).result(binding) if params[:token_url]
71
- params[:password] = ERB.new(params[:password]).result(binding) if params[:password]
72
- end
73
-
74
- # Retrieve whether to debug oauth parameters based on global settings
75
- # @return [Boolean] Whether to see params sent to & received from oauth URL
76
- def debug_oauth?
77
- self.class.debug_oauth?
78
- end
79
-
80
- # Retrieve instance_url according to access token response.
81
- # Some applications have a different instance
82
- # It's assumed this will be constant for a set of oauth parameters
83
- # @return [String] Instance url
84
- def instance_url
85
- Soaspec::OAuth2.instance_urls[params] ||= response['instance_url']
86
- end
87
-
88
- # @return [String] Existing or new access token, dependent on refresh_token attribute
89
- def access_token
90
- Soaspec::SpecLogger.info request_message if self.class.request_message?
91
- case Soaspec::OAuth2.refresh_token
92
- when :once
93
- Soaspec::OAuth2.access_tokens[params] ||= response['access_token']
94
- else # Default is :always
95
- response['access_token']
96
- end
97
- end
98
-
99
- # @return [Hash] Hash containing access token parameters
100
- def response
101
- Soaspec::SpecLogger.info "using oauth_params: #{params}" if debug_oauth?
102
- response = RestClient.post(params[:token_url], payload, cache_control: 'no_cache', verify_ssl: false)
103
- rescue RestClient::Exception => e
104
- Soaspec::SpecLogger.info(["oauth_error: #{e.message}", "oauth_response: #{e.response}"])
105
- self.retry_count += 1
106
- sleep 0.1 # Wait if a bit before retying obtaining access token
107
- retry if retry_count < self.class.retry_limit
108
- raise e
109
- else
110
- Soaspec::SpecLogger.info(["response: \n headers: #{response&.headers}\n body: #{response}\n"]) if debug_oauth?
111
- JSON.parse(response)
112
- end
113
-
114
- # @return [String] String to represent OAuth for logging logs
115
- def request_message
116
- if debug_oauth?
117
- "request_params: #{payload}"
118
- else
119
- params[:username] ? "User '#{params[:username]}'" : 'client_credentials'
120
- end
121
- end
122
-
123
- # @return [String] Password to use in OAuth request
124
- def password
125
- params[:security_token] ? (params[:password] + params[:security_token]) : params[:password]
126
- end
127
-
128
- # Payload to add to o-auth request dependent on params provided
129
- # @return [Hash] Payload for retrieving OAuth access token
130
- def payload
131
- payload = { client_id: params[:client_id], client_secret: params[:client_secret] }
132
- payload.merge(if params[:password] && params[:username]
133
- {
134
- grant_type: 'password', username: params[:username],
135
- password: password, multipart: true
136
- }
137
- else
138
- { grant_type: 'client_credentials' }
139
- end)
140
- end
141
- end
142
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'erb'
4
+
5
+ module Soaspec
6
+ # Handles working with OAuth2
7
+ class OAuth2
8
+ # How often to refresh access token
9
+ @refresh_token = :always
10
+ # List of access tokens. They are mapped according to the OAuth parameters used
11
+ @access_tokens = {}
12
+ # List of instance URLs. They are mapped according to the OAuth parameters used
13
+ @instance_urls = {}
14
+ # Whether to see params sent to & received from oauth URL
15
+ @request_message = true
16
+ # How many times to attempt to authenticate before raising exception
17
+ @retry_limit = 2
18
+ class << self
19
+ # Default token url used across entire suite
20
+ attr_accessor :token_url
21
+ # @attr [Symbol] refresh_token How often to refresh access token
22
+ # Values are:
23
+ # * :always - (Default) Request token from token url every time it is needed
24
+ # * :once - Request token once for the entire execution of the suite
25
+ attr_accessor :refresh_token
26
+ # @attr [Hash] access_tokens List of access tokens. They are mapped according to the OAuth parameters used
27
+ attr_accessor :access_tokens
28
+ # List of URLs to that define the instance of an application
29
+ attr_accessor :instance_urls
30
+ # Specify whether to see params sent to and retrieved from oauth. This will put password in log file, only recommended for debugging
31
+ attr_writer :debug_oauth
32
+ # @return [Boolean] Whether to include request message describing OAuth (either full or simplified)
33
+ attr_writer :request_message
34
+ # @return [Integer] How many times to attempt to authenticate before raising exception
35
+ attr_accessor :retry_limit
36
+ # @return [Boolean] Whether to see params sent to & received from oauth URL
37
+ def debug_oauth?
38
+ @debug_oauth || false
39
+ end
40
+
41
+ # @return [Boolean] Whether to include request message describing OAuth (either full or simplified)
42
+ def request_message?
43
+ @request_message
44
+ end
45
+ end
46
+
47
+ # @attr [Hash] OAuth parameters
48
+ attr_accessor :params
49
+ # @attr [Integer] Count of tries to obtain access token
50
+ attr_accessor :retry_count
51
+
52
+ # @param [Hash] params_sent Parameters to make OAuth request
53
+ # @option params_sent [token_url] URL to retrieve OAuth token from. @Note this can be set globally instead of here
54
+ # @option params_sent [client_id] Client ID
55
+ # @option params_sent [client_secret] Client Secret
56
+ # @option params_sent [username] Username used in password grant
57
+ # @option params_sent [password] Password used in password grant
58
+ # @option params_sent [security_token] Security Token used in password grant
59
+ # @param [String] api_username Username to use which can be set by Soaspec::ExchangeHandler
60
+ def initialize(params_sent, api_username = nil)
61
+ self.retry_count = 0 # No initial tries at getting access token
62
+ params = params_sent.transform_keys_to_symbols
63
+ params[:token_url] ||= Soaspec::OAuth2.token_url
64
+ raise ArgumentError, 'client_id and client_secret not set' unless params[:client_id] && params[:client_secret]
65
+ raise ArgumentError, 'token_url mandatory' unless params[:token_url]
66
+
67
+ self.params = params
68
+ params[:username] = api_username || ERB.new(params[:username]).result(binding) if params[:username]
69
+ params[:security_token] = ERB.new(params[:security_token]).result(binding) if params[:security_token]
70
+ params[:token_url] = ERB.new(params[:token_url]).result(binding) if params[:token_url]
71
+ params[:password] = ERB.new(params[:password]).result(binding) if params[:password]
72
+ end
73
+
74
+ # Retrieve whether to debug oauth parameters based on global settings
75
+ # @return [Boolean] Whether to see params sent to & received from oauth URL
76
+ def debug_oauth?
77
+ self.class.debug_oauth?
78
+ end
79
+
80
+ # Retrieve instance_url according to access token response.
81
+ # Some applications have a different instance
82
+ # It's assumed this will be constant for a set of oauth parameters
83
+ # @return [String] Instance url
84
+ def instance_url
85
+ Soaspec::OAuth2.instance_urls[params] ||= response['instance_url']
86
+ end
87
+
88
+ # @return [String] Existing or new access token, dependent on refresh_token attribute
89
+ def access_token
90
+ Soaspec::SpecLogger.info request_message if self.class.request_message?
91
+ case Soaspec::OAuth2.refresh_token
92
+ when :once
93
+ Soaspec::OAuth2.access_tokens[params] ||= response['access_token']
94
+ else # Default is :always
95
+ response['access_token']
96
+ end
97
+ end
98
+
99
+ # @return [Hash] Hash containing access token parameters
100
+ def response
101
+ Soaspec::SpecLogger.info "using oauth_params: #{params}" if debug_oauth?
102
+ response = RestClient.post(params[:token_url], payload, cache_control: 'no_cache', verify_ssl: false)
103
+ rescue RestClient::Exception => e
104
+ Soaspec::SpecLogger.info(["oauth_error: #{e.message}", "oauth_response: #{e.response}"])
105
+ self.retry_count += 1
106
+ sleep 0.1 # Wait if a bit before retying obtaining access token
107
+ retry if retry_count < self.class.retry_limit
108
+ raise e
109
+ else
110
+ Soaspec::SpecLogger.info(["response: \n headers: #{response&.headers}\n body: #{response}\n"]) if debug_oauth?
111
+ JSON.parse(response)
112
+ end
113
+
114
+ # @return [String] String to represent OAuth for logging logs
115
+ def request_message
116
+ if debug_oauth?
117
+ "request_params: #{payload}"
118
+ else
119
+ params[:username] ? "User '#{params[:username]}'" : 'client_credentials'
120
+ end
121
+ end
122
+
123
+ # @return [String] Password to use in OAuth request
124
+ def password
125
+ params[:security_token] ? (params[:password] + params[:security_token]) : params[:password]
126
+ end
127
+
128
+ # Payload to add to o-auth request dependent on params provided
129
+ # @return [Hash] Payload for retrieving OAuth access token
130
+ def payload
131
+ payload = { client_id: params[:client_id], client_secret: params[:client_secret] }
132
+ payload.merge(if params[:password] && params[:username]
133
+ {
134
+ grant_type: 'password', username: params[:username],
135
+ password: password, multipart: true
136
+ }
137
+ else
138
+ { grant_type: 'client_credentials' }
139
+ end)
140
+ end
141
+ end
142
+ end
@@ -1,26 +1,26 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rspec'
4
-
5
- RSpec.shared_examples_for 'success scenario' do
6
- it 'has successful status code' do
7
- expect(described_class.successful_status_code?).to be true
8
- end
9
- context 'has expected mandatory elements' do
10
- described_class.exchange_handler.expected_mandatory_elements.each do |mandatory_element|
11
- it mandatory_element do
12
- expect(described_class).to contain_key mandatory_element
13
- end
14
- end
15
- end
16
- described_class.exchange_handler.expected_mandatory_xpath_values.each do |xpath, value|
17
- it "has xpath '#{xpath}' equal to '#{value}'" do
18
- expect(described_class).to have_xpath_value(xpath => value)
19
- end
20
- end
21
- described_class.exchange_handler.expected_mandatory_json_values.each do |xpath, value|
22
- it "has json '#{xpath}' equal to '#{value}'" do
23
- expect(described_class).to have_xpath_value(xpath => value)
24
- end
25
- end
26
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+
5
+ RSpec.shared_examples_for 'success scenario' do
6
+ it 'has successful status code' do
7
+ expect(described_class.successful_status_code?).to be true
8
+ end
9
+ context 'has expected mandatory elements' do
10
+ described_class.exchange_handler.expected_mandatory_elements.each do |mandatory_element|
11
+ it mandatory_element do
12
+ expect(described_class).to contain_key mandatory_element
13
+ end
14
+ end
15
+ end
16
+ described_class.exchange_handler.expected_mandatory_xpath_values.each do |xpath, value|
17
+ it "has xpath '#{xpath}' equal to '#{value}'" do
18
+ expect(described_class).to have_xpath_value(xpath => value)
19
+ end
20
+ end
21
+ described_class.exchange_handler.expected_mandatory_json_values.each do |xpath, value|
22
+ it "has json '#{xpath}' equal to '#{value}'" do
23
+ expect(described_class).to have_xpath_value(xpath => value)
24
+ end
25
+ end
26
+ end
@@ -1,143 +1,143 @@
1
- # frozen_string_literal: true
2
-
3
- require 'logger'
4
- require 'fileutils'
5
- require 'colorize'
6
-
7
- module Soaspec
8
- # Custom class for logging API traffic
9
- class ApiLogger < Logger
10
- #
11
- # Rewrite << to use info logger with formatting
12
- #
13
- def <<(msg)
14
- info msg
15
- end
16
- end
17
-
18
- # Handles logs of API requests and responses
19
- class SpecLogger
20
- # Folder to put API traffic logs
21
- @traffic_folder = 'logs'
22
- # Whether to output api traffic to terminal
23
- @output_to_terminal = false
24
- # Color shown when displaying in terminal
25
- @terminal_color = :light_blue
26
- # Whether to output API traffic to log file
27
- @output_to_file = true
28
- # Time test run. Will only be calculated once once called
29
- @time_test_run = Time.now.strftime('%Y-%m-%d_%H_%M_%S')
30
- # By default file is based on time
31
- @traffic_file = nil
32
- # Name of program to include in logs
33
- @progname
34
- class << self
35
- # Folder to put API traffic logs
36
- attr_accessor :traffic_folder
37
- # Color shown when displaying in terminal
38
- attr_accessor :terminal_color
39
- # Readers for log parameters
40
- attr_reader :output_to_terminal, :output_to_file, :time_test_run
41
- # @return [String] Name of program to include in logs
42
- attr_accessor :progname
43
- # @return [String] String representing date format to use for traffic
44
- attr_writer :time_format
45
- # Logger used to log API requests
46
- attr_accessor :logger
47
-
48
- # String representing date format to use for traffic
49
- def time_format
50
- @time_format || '%H:%M:%S'
51
- end
52
-
53
- # Set file to log traffic to
54
- # @param [String] file Path to traffic file to use
55
- def traffic_file=(file)
56
- @traffic_file = file
57
- reset_log
58
- end
59
-
60
- # @return [String] Traffic file to create logs at
61
- def traffic_file
62
- return File.join(traffic_folder, @traffic_file) if @traffic_file
63
-
64
- filename = "traffic_#{time_test_run}.log"
65
- File.join(traffic_folder, filename)
66
- end
67
-
68
- # Unset Logger object. It will be recreated on next time 'info' is called
69
- def reset_log
70
- @logger = nil
71
- RestClient.log = nil
72
- end
73
-
74
- # Whether to log all API traffic
75
- def log_api_traffic=(set)
76
- @log_api_traffic = set
77
- reset_log
78
- end
79
-
80
- # @return [Boolean] Whether to log all API traffic
81
- def log_api_traffic?
82
- @log_api_traffic.nil? ? true : @log_api_traffic
83
- end
84
-
85
- # @param [Symbol, Boolean] value # Whether to output API traffic to log file
86
- def output_to_file=(value)
87
- @output_to_file = value
88
- reset_log
89
- end
90
-
91
- # @param [Symbol, Boolean] value # Whether to output API traffic to STDOUT
92
- def output_to_terminal=(value)
93
- @output_to_terminal = value
94
- reset_log
95
- end
96
-
97
- # Create new log file if necessary and setup logging level
98
- # @return [Logger] Logger class to record API traffic
99
- def create
100
- create_log_file
101
- @logger = ApiLogger.new(traffic_file) # Where request and responses of APIs are stored
102
- @logger.progname = progname || 'SpecLog'
103
- @logger.formatter = proc do |_severity, datetime, progname, msg|
104
- message = "#{progname}, [#{datetime.strftime(time_format)}] : #{msg}\n"
105
- print message.colorize(terminal_color) if @output_to_terminal
106
- message if @output_to_file
107
- end
108
- RestClient.log = @logger
109
- @logger
110
- end
111
-
112
- # Log a message using Soaspec logger
113
- # Logger (and it's file) will be created if it's not already set
114
- # @param [String, Array] message The message to add to the logger or list of messages
115
- def info(message)
116
- return unless log_api_traffic?
117
-
118
- create unless @logger
119
- if message.respond_to? :each
120
- message.each do |message_item|
121
- info(message_item)
122
- end
123
- else
124
- if block_given?
125
- @logger.info(message) { yield }
126
- else
127
- @logger.info(message)
128
- end
129
- end
130
- end
131
-
132
- private
133
-
134
- # Create folder and file to store logs
135
- def create_log_file
136
- return if File.exist?(traffic_file)
137
-
138
- FileUtils.mkdir_p traffic_folder
139
- FileUtils.touch traffic_file
140
- end
141
- end
142
- end
143
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'fileutils'
5
+ require 'colorize'
6
+
7
+ module Soaspec
8
+ # Custom class for logging API traffic
9
+ class ApiLogger < Logger
10
+ #
11
+ # Rewrite << to use info logger with formatting
12
+ #
13
+ def <<(msg)
14
+ info msg
15
+ end
16
+ end
17
+
18
+ # Handles logs of API requests and responses
19
+ class SpecLogger
20
+ # Folder to put API traffic logs
21
+ @traffic_folder = 'logs'
22
+ # Whether to output api traffic to terminal
23
+ @output_to_terminal = false
24
+ # Color shown when displaying in terminal
25
+ @terminal_color = :light_blue
26
+ # Whether to output API traffic to log file
27
+ @output_to_file = true
28
+ # Time test run. Will only be calculated once once called
29
+ @time_test_run = Time.now.strftime('%Y-%m-%d_%H_%M_%S')
30
+ # By default file is based on time
31
+ @traffic_file = nil
32
+ # Name of program to include in logs
33
+ @progname
34
+ class << self
35
+ # Folder to put API traffic logs
36
+ attr_accessor :traffic_folder
37
+ # Color shown when displaying in terminal
38
+ attr_accessor :terminal_color
39
+ # Readers for log parameters
40
+ attr_reader :output_to_terminal, :output_to_file, :time_test_run
41
+ # @return [String] Name of program to include in logs
42
+ attr_accessor :progname
43
+ # @return [String] String representing date format to use for traffic
44
+ attr_writer :time_format
45
+ # Logger used to log API requests
46
+ attr_accessor :logger
47
+
48
+ # String representing date format to use for traffic
49
+ def time_format
50
+ @time_format || '%H:%M:%S'
51
+ end
52
+
53
+ # Set file to log traffic to
54
+ # @param [String] file Path to traffic file to use
55
+ def traffic_file=(file)
56
+ @traffic_file = file
57
+ reset_log
58
+ end
59
+
60
+ # @return [String] Traffic file to create logs at
61
+ def traffic_file
62
+ return File.join(traffic_folder, @traffic_file) if @traffic_file
63
+
64
+ filename = "traffic_#{time_test_run}.log"
65
+ File.join(traffic_folder, filename)
66
+ end
67
+
68
+ # Unset Logger object. It will be recreated on next time 'info' is called
69
+ def reset_log
70
+ @logger = nil
71
+ RestClient.log = nil
72
+ end
73
+
74
+ # Whether to log all API traffic
75
+ def log_api_traffic=(set)
76
+ @log_api_traffic = set
77
+ reset_log
78
+ end
79
+
80
+ # @return [Boolean] Whether to log all API traffic
81
+ def log_api_traffic?
82
+ @log_api_traffic.nil? ? true : @log_api_traffic
83
+ end
84
+
85
+ # @param [Symbol, Boolean] value # Whether to output API traffic to log file
86
+ def output_to_file=(value)
87
+ @output_to_file = value
88
+ reset_log
89
+ end
90
+
91
+ # @param [Symbol, Boolean] value # Whether to output API traffic to STDOUT
92
+ def output_to_terminal=(value)
93
+ @output_to_terminal = value
94
+ reset_log
95
+ end
96
+
97
+ # Create new log file if necessary and setup logging level
98
+ # @return [Logger] Logger class to record API traffic
99
+ def create
100
+ create_log_file
101
+ @logger = ApiLogger.new(traffic_file) # Where request and responses of APIs are stored
102
+ @logger.progname = progname || 'SpecLog'
103
+ @logger.formatter = proc do |_severity, datetime, progname, msg|
104
+ message = "#{progname}, [#{datetime.strftime(time_format)}] : #{msg}\n"
105
+ print message.colorize(terminal_color) if @output_to_terminal
106
+ message if @output_to_file
107
+ end
108
+ RestClient.log = @logger
109
+ @logger
110
+ end
111
+
112
+ # Log a message using Soaspec logger
113
+ # Logger (and it's file) will be created if it's not already set
114
+ # @param [String, Array] message The message to add to the logger or list of messages
115
+ def info(message)
116
+ return unless log_api_traffic?
117
+
118
+ create unless @logger
119
+ if message.respond_to? :each
120
+ message.each do |message_item|
121
+ info(message_item)
122
+ end
123
+ else
124
+ if block_given?
125
+ @logger.info(message) { yield }
126
+ else
127
+ @logger.info(message)
128
+ end
129
+ end
130
+ end
131
+
132
+ private
133
+
134
+ # Create folder and file to store logs
135
+ def create_log_file
136
+ return if File.exist?(traffic_file)
137
+
138
+ FileUtils.mkdir_p traffic_folder
139
+ FileUtils.touch traffic_file
140
+ end
141
+ end
142
+ end
143
+ end