appsignal 1.4.0.beta.1 → 2.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,9 +2,15 @@ module Appsignal
2
2
  class CLI
3
3
  class NotifyOfDeploy
4
4
  class << self
5
- def run(options, config)
5
+ def run(options)
6
+ config = config_for(options[:environment])
7
+ config[:name] = options[:name] if options[:name]
8
+
6
9
  validate_active_config(config)
7
- validate_required_options(options, [:revision, :user, :environment])
10
+ required_config = [:revision, :user]
11
+ required_config << :environment if config.env.empty?
12
+ required_config << :name if !config[:name] || config[:name].empty?
13
+ validate_required_options(options, required_config)
8
14
 
9
15
  Appsignal::Marker.new(
10
16
  {
@@ -15,24 +21,33 @@ module Appsignal
15
21
  ).transmit
16
22
  end
17
23
 
18
- protected
24
+ private
19
25
 
20
26
  def validate_required_options(options, required_options)
21
27
  missing = required_options.select do |required_option|
22
28
  val = options[required_option]
23
29
  val.nil? || (val.respond_to?(:empty?) && val.empty?)
24
30
  end
25
- if missing.any?
26
- puts "Missing options: #{missing.join(', ')}"
27
- exit 1
28
- end
31
+ return unless missing.any?
32
+
33
+ puts "Error: Missing options: #{missing.join(', ')}"
34
+ exit 1
29
35
  end
30
36
 
31
37
  def validate_active_config(config)
32
- unless config.active?
33
- puts 'Exiting: No config file or push api key env var found'
34
- exit 1
35
- end
38
+ return if config.active?
39
+
40
+ puts "Error: No valid config found."
41
+ exit 1
42
+ end
43
+
44
+ def config_for(environment)
45
+ Appsignal::Config.new(
46
+ Dir.pwd,
47
+ environment,
48
+ {},
49
+ Logger.new(StringIO.new)
50
+ )
36
51
  end
37
52
  end
38
53
  end
@@ -8,6 +8,7 @@ module Appsignal
8
8
  SYSTEM_TMP_DIR = '/tmp'
9
9
  DEFAULT_CONFIG = {
10
10
  :debug => false,
11
+ :log => 'file',
11
12
  :ignore_errors => [],
12
13
  :ignore_actions => [],
13
14
  :filter_parameters => [],
@@ -35,6 +36,7 @@ module Appsignal
35
36
  'APPSIGNAL_PUSH_API_ENDPOINT' => :endpoint,
36
37
  'APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH' => :frontend_error_catching_path,
37
38
  'APPSIGNAL_DEBUG' => :debug,
39
+ 'APPSIGNAL_LOG' => :log,
38
40
  'APPSIGNAL_LOG_PATH' => :log_path,
39
41
  'APPSIGNAL_INSTRUMENT_NET_HTTP' => :instrument_net_http,
40
42
  'APPSIGNAL_INSTRUMENT_REDIS' => :instrument_redis,
@@ -96,7 +98,7 @@ module Appsignal
96
98
  if File.writable? SYSTEM_TMP_DIR
97
99
  $stdout.puts "appsignal: Unable to log to '#{path}'. Logging to "\
98
100
  "'#{SYSTEM_TMP_DIR}' instead. Please check the "\
99
- "permissions for the application's log directory."
101
+ "permissions for the application's (log) directory."
100
102
  File.join(SYSTEM_TMP_DIR, 'appsignal.log')
101
103
  else
102
104
  $stdout.puts "appsignal: Unable to log to '#{path}' or the "\
@@ -119,7 +121,7 @@ module Appsignal
119
121
  ENV['APPSIGNAL_AGENT_PATH'] = File.expand_path('../../../ext', __FILE__).to_s
120
122
  ENV['APPSIGNAL_ENVIRONMENT'] = env
121
123
  ENV['APPSIGNAL_AGENT_VERSION'] = Appsignal::Extension.agent_version
122
- ENV['APPSIGNAL_LANGUAGE_INTEGRATION_VERSION'] = Appsignal::VERSION
124
+ ENV['APPSIGNAL_LANGUAGE_INTEGRATION_VERSION'] = "ruby-#{Appsignal::VERSION}"
123
125
  ENV['APPSIGNAL_DEBUG_LOGGING'] = config_hash[:debug].to_s
124
126
  ENV['APPSIGNAL_LOG_FILE_PATH'] = log_file_path.to_s if log_file_path
125
127
  ENV['APPSIGNAL_PUSH_API_ENDPOINT'] = config_hash[:endpoint]
@@ -146,7 +148,8 @@ module Appsignal
146
148
  end
147
149
 
148
150
  def detect_from_system
149
- self[:running_in_container] = true if Appsignal::System.container?
151
+ config_hash[:running_in_container] = true if Appsignal::System.container?
152
+ config_hash[:log] = 'stdout' if Appsignal::System.heroku?
150
153
  end
151
154
 
152
155
  def load_from_disk
@@ -184,8 +187,9 @@ module Appsignal
184
187
 
185
188
  # Configuration with string type
186
189
  %w(APPSIGNAL_PUSH_API_KEY APPSIGNAL_APP_NAME APPSIGNAL_PUSH_API_ENDPOINT
187
- APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH APPSIGNAL_HTTP_PROXY APPSIGNAL_LOG_PATH
188
- APPSIGNAL_WORKING_DIR_PATH APPSIGNAL_HOSTNAME APPSIGNAL_CA_FILE_PATH).each do |var|
190
+ APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH APPSIGNAL_HTTP_PROXY
191
+ APPSIGNAL_LOG APPSIGNAL_LOG_PATH APPSIGNAL_WORKING_DIR_PATH
192
+ APPSIGNAL_HOSTNAME APPSIGNAL_CA_FILE_PATH).each do |var|
189
193
  if env_var = ENV[var]
190
194
  config[ENV_TO_KEY_MAPPING[var]] = env_var
191
195
  end
@@ -1,41 +1,48 @@
1
1
  module Appsignal
2
2
  module Grape
3
3
  class Middleware < ::Grape::Middleware::Base
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
4
  def call(env)
9
5
  if Appsignal.active?
10
6
  call_with_appsignal_monitoring(env)
11
7
  else
12
- @app.call(env)
8
+ app.call(env)
13
9
  end
14
10
  end
15
11
 
16
12
  def call_with_appsignal_monitoring(env)
17
- request = ::Rack::Request.new(env)
18
- transaction = Appsignal::Transaction.create(
13
+ request = ::Rack::Request.new(env)
14
+ transaction = Appsignal::Transaction.create(
19
15
  SecureRandom.uuid,
20
16
  Appsignal::Transaction::HTTP_REQUEST,
21
17
  request
22
18
  )
23
19
  begin
24
- @app.call(env)
20
+ app.call(env)
25
21
  rescue => error
26
22
  transaction.set_error(error)
27
23
  raise error
28
24
  ensure
29
- api_endpoint = env['api.endpoint']
30
- if api_endpoint && options = api_endpoint.options
31
- method = options[:method].first
32
- klass = options[:for]
33
- action = options[:path].first
34
- transaction.set_action("#{method}::#{klass}##{action}")
25
+ request_method = request.request_method
26
+ path = request.path # Path without namespaces
27
+ endpoint = env["api.endpoint"]
28
+
29
+ if endpoint && endpoint.options
30
+ options = endpoint.options
31
+ request_method = options[:method].first
32
+ klass = options[:for]
33
+ namespace = endpoint.namespace
34
+ namespace = "" if namespace == "/"
35
+
36
+ path = options[:path].first.to_s
37
+ path = "/#{path}" if path[0] != "/"
38
+ path = "#{namespace}#{path}"
39
+
40
+ transaction.set_action("#{request_method}::#{klass}##{path}")
35
41
  end
42
+
36
43
  transaction.set_http_or_background_queue_start
37
- transaction.set_metadata('path', request.path)
38
- transaction.set_metadata('method', env['REQUEST_METHOD'])
44
+ transaction.set_metadata("path", path)
45
+ transaction.set_metadata("method", request_method)
39
46
  Appsignal::Transaction.complete_current!
40
47
  end
41
48
  end
@@ -14,7 +14,7 @@ module Appsignal
14
14
  end
15
15
 
16
16
  def set_action
17
- @ext.set_action(@data['action'])
17
+ @ext.set_action(@data['action']) if @data['action']
18
18
  end
19
19
 
20
20
  def set_metadata
@@ -26,8 +26,8 @@ module Appsignal
26
26
  def set_error
27
27
  @ext.set_error(
28
28
  @data['name'],
29
- @data['message'],
30
- Appsignal::Utils.data_generate(@data['backtrace'])
29
+ @data['message'] || '',
30
+ Appsignal::Utils.data_generate(@data['backtrace'] || [])
31
31
  )
32
32
  end
33
33
 
@@ -10,16 +10,17 @@ module Appsignal
10
10
 
11
11
  def transmit
12
12
  transmitter = Transmitter.new(ACTION, config)
13
- puts "Notifying Appsignal of deploy with: "\
13
+ puts "Notifying AppSignal of deploy with: "\
14
14
  "revision: #{marker_data[:revision]}, user: #{marker_data[:user]}"
15
+
15
16
  result = transmitter.transmit(marker_data)
16
17
  if result == '200'
17
- puts 'Appsignal has been notified of this deploy!'
18
+ puts 'AppSignal has been notified of this deploy!'
18
19
  else
19
20
  raise "#{result} at #{transmitter.uri}"
20
21
  end
21
22
  rescue => e
22
- puts "Something went wrong while trying to notify Appsignal: #{e}"
23
+ puts "Something went wrong while trying to notify AppSignal: #{e}"
23
24
  end
24
25
  end
25
26
  end
@@ -8,11 +8,18 @@ module Appsignal
8
8
 
9
9
  def call(env)
10
10
  if env['PATH_INFO'] == Appsignal.config[:frontend_error_catching_path]
11
- body = JSON.parse(env['rack.input'].read)
12
- transaction = JSExceptionTransaction.new(body)
13
- transaction.complete!
11
+ body = JSON.parse(env['rack.input'].read)
14
12
 
15
- return [ 200, {}, []]
13
+ if body['name'].is_a?(String) && body['name'].length > 0
14
+ transaction = JSExceptionTransaction.new(body)
15
+ transaction.complete!
16
+ code = 200
17
+ else
18
+ Appsignal.logger.debug "JSExceptionCatcher: Could not send exception, 'name' is empty."
19
+ code = 422
20
+ end
21
+
22
+ return [code, {}, []]
16
23
  else
17
24
  @app.call(env)
18
25
  end
@@ -3,17 +3,6 @@ require 'appsignal/utils/query_params_sanitizer'
3
3
 
4
4
  module Appsignal
5
5
  module Utils
6
- module ClassMethods
7
- extend Gem::Deprecate
8
-
9
- def sanitize(params, only_top_level = false, key_sanitizer = nil)
10
- QueryParamsSanitizer.sanitize(params, only_top_level, key_sanitizer)
11
- end
12
-
13
- deprecate :sanitize, "AppSignal::Utils::QueryParamsSanitizer.sanitize", 2016, 9
14
- end
15
- extend ClassMethods
16
-
17
6
  def self.data_generate(body)
18
7
  Data.generate(body)
19
8
  end
@@ -126,5 +115,4 @@ module Appsignal
126
115
  end
127
116
  end
128
117
  end
129
-
130
118
  end
@@ -1,5 +1,5 @@
1
1
  require 'yaml'
2
2
 
3
3
  module Appsignal
4
- VERSION = '1.4.0.beta.1'
4
+ VERSION = '2.0.0.beta.1'
5
5
  end
@@ -134,8 +134,8 @@ if DependencyHelper.capistrano2_present?
134
134
  capistrano_config.find_and_execute_task('appsignal:deploy')
135
135
 
136
136
  expect(out_stream.string).to include \
137
- 'Notifying Appsignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman',
138
- 'Appsignal has been notified of this deploy!'
137
+ 'Notifying AppSignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman',
138
+ 'AppSignal has been notified of this deploy!'
139
139
  end
140
140
 
141
141
  context "with overridden revision" do
@@ -147,8 +147,8 @@ if DependencyHelper.capistrano2_present?
147
147
 
148
148
  it "transmits the overriden revision" do
149
149
  expect(out_stream.string).to include \
150
- 'Notifying Appsignal of deploy with: revision: abc123, user: batman',
151
- 'Appsignal has been notified of this deploy!'
150
+ 'Notifying AppSignal of deploy with: revision: abc123, user: batman',
151
+ 'AppSignal has been notified of this deploy!'
152
152
  end
153
153
  end
154
154
 
@@ -161,9 +161,9 @@ if DependencyHelper.capistrano2_present?
161
161
  it "does not transmit marker" do
162
162
  output = out_stream.string
163
163
  expect(output).to include \
164
- 'Notifying Appsignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman',
165
- 'Something went wrong while trying to notify Appsignal:'
166
- expect(output).to_not include 'Appsignal has been notified of this deploy!'
164
+ 'Notifying AppSignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman',
165
+ 'Something went wrong while trying to notify AppSignal:'
166
+ expect(output).to_not include 'AppSignal has been notified of this deploy!'
167
167
  end
168
168
  end
169
169
 
@@ -135,8 +135,8 @@ if DependencyHelper.capistrano3_present?
135
135
  invoke('appsignal:deploy')
136
136
 
137
137
  expect(out_stream.string).to include \
138
- 'Notifying Appsignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman',
139
- 'Appsignal has been notified of this deploy!'
138
+ 'Notifying AppSignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman',
139
+ 'AppSignal has been notified of this deploy!'
140
140
  end
141
141
 
142
142
  context "with overridden revision" do
@@ -148,8 +148,8 @@ if DependencyHelper.capistrano3_present?
148
148
 
149
149
  it "transmits the overriden revision" do
150
150
  expect(out_stream.string).to include \
151
- 'Notifying Appsignal of deploy with: revision: abc123, user: batman',
152
- 'Appsignal has been notified of this deploy!'
151
+ 'Notifying AppSignal of deploy with: revision: abc123, user: batman',
152
+ 'AppSignal has been notified of this deploy!'
153
153
  end
154
154
  end
155
155
 
@@ -162,9 +162,9 @@ if DependencyHelper.capistrano3_present?
162
162
  it "does not transmit marker" do
163
163
  output = out_stream.string
164
164
  expect(output).to include \
165
- 'Notifying Appsignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman',
166
- 'Something went wrong while trying to notify Appsignal:'
167
- expect(output).to_not include 'Appsignal has been notified of this deploy!'
165
+ 'Notifying AppSignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman',
166
+ 'Something went wrong while trying to notify AppSignal:'
167
+ expect(output).to_not include 'AppSignal has been notified of this deploy!'
168
168
  end
169
169
  end
170
170
  end
@@ -1,29 +1,336 @@
1
- require 'appsignal/cli'
1
+ require "appsignal/cli"
2
2
 
3
3
  describe Appsignal::CLI::Diagnose do
4
- let(:out_stream) { StringIO.new }
5
- let(:config) { project_fixture_config }
6
- let(:cli) { described_class }
7
- around do |example|
8
- capture_stdout(out_stream) { example.run }
9
- end
10
-
11
4
  describe ".run" do
5
+ let(:out_stream) { StringIO.new }
6
+ let(:config) { project_fixture_config }
7
+ let(:cli) { described_class }
8
+ let(:output) { out_stream.string }
12
9
  before do
13
- Appsignal.config = config
14
- stub_api_request config, 'auth'
15
- end
16
-
17
- it "should output diagnostic information" do
18
- cli.run
19
- output = out_stream.string
20
- expect(output).to include('Gem version')
21
- expect(output).to include('Agent version')
22
- expect(output).to include('Environment')
23
- expect(output).to include('Config')
24
- expect(output).to include('Checking API key')
25
- expect(output).to include('Checking if required paths are writable')
26
- expect(output).to include('Showing last lines of extension install log')
10
+ ENV["APPSIGNAL_APP_ENV"] = "production"
11
+ stub_api_request config, "auth"
12
+ end
13
+ after { Appsignal.config = nil }
14
+ around { |example| capture_stdout(out_stream) { example.run } }
15
+
16
+ def run
17
+ run_within_dir project_fixture_path
18
+ end
19
+
20
+ def run_within_dir(chdir)
21
+ Dir.chdir chdir do
22
+ cli.run
23
+ end
24
+ end
25
+
26
+ it "outputs header and support text" do
27
+ run
28
+ expect(output).to include \
29
+ "AppSignal diagnose",
30
+ "http://docs.appsignal.com/",
31
+ "support@appsignal.com"
32
+ end
33
+
34
+ it "outputs version numbers" do
35
+ run
36
+ gem_path = Bundler::CLI::Common.select_spec("appsignal").full_gem_path.strip
37
+ expect(output).to include \
38
+ "Gem version: #{Appsignal::VERSION}",
39
+ "Agent version: #{Appsignal::Extension.agent_version}",
40
+ "Gem install path: #{gem_path}"
41
+ end
42
+
43
+ describe "host information" do
44
+ it "outputs host information" do
45
+ run
46
+ expect(output).to include \
47
+ "Host information",
48
+ "Architecture: #{RbConfig::CONFIG["host_cpu"]}",
49
+ "Operating System: #{RbConfig::CONFIG["host_os"]}",
50
+ "Ruby version: #{RbConfig::CONFIG["RUBY_VERSION_NAME"]}"
51
+ end
52
+
53
+ describe "Heroku detection" do
54
+ context "when not on Heroku" do
55
+ before { recognize_as_container(:none) { run } }
56
+
57
+ it "does not output Heroku detection" do
58
+ expect(output).to_not include("Heroku:")
59
+ end
60
+ end
61
+
62
+ context "when on Heroku" do
63
+ before { recognize_as_heroku { run } }
64
+
65
+ it "outputs Heroku detection" do
66
+ expect(output).to include("Heroku: true")
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "container detection" do
72
+ context "when not in container" do
73
+ before { recognize_as_container(:none) { run } }
74
+
75
+ it "does not output container detection" do
76
+ expect(output).to_not include("Container id:")
77
+ end
78
+ end
79
+
80
+ context "when in container" do
81
+ before { recognize_as_container(:docker) { run } }
82
+
83
+ it "outputs container information" do
84
+ expect(output).to include \
85
+ "Container id: 0c703b75cdeaad7c933aa68b4678cc5c37a12d5ef5d7cb52c9cefe684d98e575"
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "configuration" do
92
+ context "without extension" do
93
+ before do
94
+ # When the extension isn't loaded the Appsignal.start operation exits
95
+ # early and doesn't load the configuration.
96
+ # Happens when the extension wasn't installed properly.
97
+ Appsignal.extension_loaded = false
98
+ run
99
+ end
100
+ after { Appsignal.extension_loaded = true }
101
+
102
+ it "outputs an error" do
103
+ expect(output).to include \
104
+ "Error: No config found!\nCould not start AppSignal."
105
+ end
106
+
107
+ it "outputs as much as it can" do
108
+ expect(output).to include \
109
+ "AppSignal agent\n Gem version: #{Appsignal::VERSION}",
110
+ "Host information\n Architecture: ",
111
+ %(Extension install log\n Path: "),
112
+ %(Makefile install log\n Path: ")
113
+ end
114
+ end
115
+
116
+ context "without environment" do
117
+ let(:config) { project_fixture_config("") }
118
+ before do
119
+ ENV["APPSIGNAL_APP_ENV"] = ""
120
+ recognize_as_container(:none) { run }
121
+ end
122
+
123
+ it "outputs a warning that no config is loaded" do
124
+ expect(output).to_not include "Error"
125
+ expect(output).to include \
126
+ "Environment: \n Warning: No environment set, no config loaded!",
127
+ " APPSIGNAL_APP_ENV=production appsignal diagnose"
128
+ end
129
+
130
+ it "outputs config defaults" do
131
+ expect(output).to include("Configuration")
132
+ Appsignal::Config::DEFAULT_CONFIG.each do |key, value|
133
+ expect(output).to include("#{key}: #{value}")
134
+ end
135
+ end
136
+ end
137
+
138
+ context "with configured environment" do
139
+ before { run }
140
+
141
+ it "outputs environment" do
142
+ expect(output).to include("Environment: production")
143
+ end
144
+
145
+ it "outputs configuration" do
146
+ expect(output).to include("Configuration")
147
+ expect(output).to_not include "Error"
148
+ Appsignal.config.config_hash.each do |key, value|
149
+ expect(output).to include("#{key}: #{value}")
150
+ end
151
+ end
152
+ end
153
+
154
+ context "with unconfigured environment" do
155
+ let(:config) { project_fixture_config("foobar") }
156
+ before do
157
+ ENV["APPSIGNAL_APP_ENV"] = "foobar"
158
+ recognize_as_container(:none) { run }
159
+ end
160
+
161
+ it "outputs environment" do
162
+ expect(output).to include("Environment: foobar")
163
+ end
164
+
165
+ it "outputs config defaults" do
166
+ expect(output).to include("Configuration")
167
+ expect(output).to_not include "Error"
168
+ Appsignal::Config::DEFAULT_CONFIG.each do |key, value|
169
+ expect(output).to include("#{key}: #{value}")
170
+ end
171
+ end
172
+ end
173
+ end
174
+
175
+ describe "API key validation" do
176
+ context "with valid key" do
177
+ before do
178
+ stub_api_request(config, "auth").to_return(:status => 200)
179
+ run
180
+ end
181
+
182
+ it "outputs valid" do
183
+ expect(output).to include("Validating API key: Valid")
184
+ end
185
+ end
186
+
187
+ context "with invalid key" do
188
+ before do
189
+ stub_api_request(config, "auth").to_return(:status => 401)
190
+ run
191
+ end
192
+
193
+ it "outputs invalid" do
194
+ expect(output).to include("Validating API key: Invalid")
195
+ end
196
+ end
197
+
198
+ context "with invalid key" do
199
+ before do
200
+ stub_api_request(config, "auth").to_return(:status => 500)
201
+ run
202
+ end
203
+
204
+ it "outputs failure with status code" do
205
+ expect(output).to include("Validating API key: Failed with status 500")
206
+ end
207
+ end
208
+ end
209
+
210
+ describe "paths" do
211
+ before { FileUtils.mkdir_p(root_path) }
212
+
213
+ context "when a directory is writable" do
214
+ let(:root_path) { File.join(tmp_dir, "writable_path") }
215
+ let(:log_file) { File.join(root_path, "appsignal.log") }
216
+ let(:config) { Appsignal::Config.new(root_path, "production") }
217
+
218
+ context "without log file" do
219
+ before { run_within_dir root_path }
220
+
221
+ it "outputs writable" do
222
+ expect(output).to include \
223
+ "Required paths",
224
+ %(root_path: "#{root_path}" - Writable),
225
+ %(log_file_path: "#{log_file}" - Does not exist)
226
+ end
227
+ end
228
+
229
+ context "with log file" do
230
+ context "when writable" do
231
+ before do
232
+ FileUtils.touch(log_file)
233
+ run_within_dir root_path
234
+ end
235
+
236
+ it "lists log file as writable" do
237
+ expect(output).to include \
238
+ %(root_path: "#{root_path}" - Writable),
239
+ %(log_file_path: "#{File.join(root_path, "appsignal.log")}" - Writable)
240
+ end
241
+ end
242
+
243
+ context "when not writable" do
244
+ before do
245
+ FileUtils.touch(log_file)
246
+ FileUtils.chmod(0444, log_file)
247
+ run_within_dir root_path
248
+ end
249
+
250
+ it "lists log file as not writable" do
251
+ expect(output).to include \
252
+ %(root_path: "#{root_path}" - Writable),
253
+ %(log_file_path: "#{File.join(root_path, "appsignal.log")}" - Not writable)
254
+ end
255
+ end
256
+ end
257
+ end
258
+
259
+ context "when a directory is not writable" do
260
+ let(:root_path) { File.join(tmp_dir, "not_writable_path") }
261
+ let(:config) { Appsignal::Config.new(root_path, "production") }
262
+ before do
263
+ FileUtils.chmod(0555, root_path)
264
+ run_within_dir root_path
265
+ end
266
+
267
+ it "outputs not writable" do
268
+ expect(output).to include \
269
+ "Required paths",
270
+ %(root_path: "#{root_path}" - Not writable),
271
+ %(log_file_path: "" - Not writable)
272
+ end
273
+ end
274
+
275
+ after { FileUtils.rm_rf(root_path) }
276
+ end
277
+
278
+ describe "logs" do
279
+ shared_examples "ext log file" do |log_file|
280
+ let(:ext_path) { File.join(gem_path, "ext") }
281
+ let(:log_path) { File.join(ext_path, log_file) }
282
+ before do
283
+ allow(cli).to receive(:gem_path).and_return(gem_path)
284
+ end
285
+
286
+ context "when file exists" do
287
+ let(:gem_path) { File.join(tmp_dir, "gem") }
288
+ before do
289
+ FileUtils.mkdir_p ext_path
290
+ File.open log_path, "a" do |f|
291
+ f.write "log line 1"
292
+ f.write "log line 2"
293
+ end
294
+ run
295
+ end
296
+
297
+ it "outputs install.log" do
298
+ expect(output).to include \
299
+ %(Path: "#{log_path}"),
300
+ "log line 1",
301
+ "log line 2"
302
+ end
303
+
304
+ after { FileUtils.rm_rf(gem_path) }
305
+ end
306
+
307
+ context "when file does not exist" do
308
+ let(:gem_path) { File.join(tmp_dir, "non_existent_path") }
309
+ before { run }
310
+
311
+ it "outputs install.log" do
312
+ expect(output).to include %(Path: "#{log_path}"\n File not found.)
313
+ end
314
+ end
315
+ end
316
+
317
+ describe "install.log" do
318
+ it_behaves_like "ext log file", "install.log"
319
+
320
+ it "outputs header" do
321
+ run
322
+ expect(output).to include("Extension install log")
323
+ end
324
+ end
325
+
326
+ describe "mkmf.log" do
327
+ it_behaves_like "ext log file", "mkmf.log"
328
+
329
+ it "outputs header" do
330
+ run
331
+ expect(output).to include("Extension install log")
332
+ end
333
+ end
27
334
  end
28
335
  end
29
336
  end