appsignal 2.0.3 → 2.0.4
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 +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +22 -0
- data/README.md +9 -5
- data/appsignal.gemspec +1 -1
- data/ext/agent.yml +11 -11
- data/lib/appsignal.rb +8 -9
- data/lib/appsignal/cli.rb +12 -14
- data/lib/appsignal/cli/diagnose.rb +82 -31
- data/lib/appsignal/cli/helpers.rb +67 -0
- data/lib/appsignal/cli/install.rb +22 -69
- data/lib/appsignal/config.rb +3 -3
- data/lib/appsignal/integrations/padrino.rb +1 -1
- data/lib/appsignal/integrations/railtie.rb +1 -1
- data/lib/appsignal/integrations/sinatra.rb +1 -1
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/capistrano2_spec.rb +18 -19
- data/spec/lib/appsignal/capistrano3_spec.rb +16 -17
- data/spec/lib/appsignal/cli/demo_spec.rb +4 -4
- data/spec/lib/appsignal/cli/diagnose_spec.rb +237 -88
- data/spec/lib/appsignal/cli/helpers_spec.rb +99 -0
- data/spec/lib/appsignal/cli/install_spec.rb +486 -352
- data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +5 -6
- data/spec/lib/appsignal/cli_spec.rb +24 -44
- data/spec/lib/appsignal/config_spec.rb +39 -8
- data/spec/lib/appsignal/demo_spec.rb +13 -8
- data/spec/lib/appsignal/hooks_spec.rb +3 -0
- data/spec/lib/appsignal/integrations/object_spec.rb +35 -26
- data/spec/lib/appsignal/marker_spec.rb +10 -14
- data/spec/lib/appsignal_spec.rb +83 -60
- data/spec/spec_helper.rb +8 -7
- data/spec/support/helpers/cli_helpers.rb +9 -0
- data/spec/support/helpers/std_streams_helper.rb +44 -13
- data/spec/support/helpers/transaction_helpers.rb +2 -2
- metadata +9 -6
@@ -1,17 +1,22 @@
|
|
1
1
|
require "appsignal/cli"
|
2
2
|
|
3
|
-
describe Appsignal::CLI::Diagnose do
|
3
|
+
describe Appsignal::CLI::Diagnose, :api_stub => true do
|
4
4
|
describe ".run" do
|
5
|
-
let(:out_stream) {
|
5
|
+
let(:out_stream) { std_stream }
|
6
|
+
let(:output) { out_stream.read }
|
6
7
|
let(:config) { project_fixture_config }
|
7
8
|
let(:cli) { described_class }
|
8
|
-
let(:
|
9
|
+
let(:options) { { :environment => config.env } }
|
10
|
+
before(:all) { Appsignal.stop }
|
9
11
|
before do
|
10
|
-
|
12
|
+
if DependencyHelper.rails_present?
|
13
|
+
allow(Rails).to receive(:root).and_return(Pathname.new(config.root_path))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
before :api_stub => true do
|
11
17
|
stub_api_request config, "auth"
|
12
18
|
end
|
13
19
|
after { Appsignal.config = nil }
|
14
|
-
around { |example| capture_stdout(out_stream) { example.run } }
|
15
20
|
|
16
21
|
def run
|
17
22
|
run_within_dir project_fixture_path
|
@@ -19,7 +24,7 @@ describe Appsignal::CLI::Diagnose do
|
|
19
24
|
|
20
25
|
def run_within_dir(chdir)
|
21
26
|
Dir.chdir chdir do
|
22
|
-
cli.run
|
27
|
+
capture_stdout(out_stream) { cli.run(options) }
|
23
28
|
end
|
24
29
|
end
|
25
30
|
|
@@ -31,13 +36,48 @@ describe Appsignal::CLI::Diagnose do
|
|
31
36
|
"support@appsignal.com"
|
32
37
|
end
|
33
38
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
describe "agent information" do
|
40
|
+
it "outputs version numbers" do
|
41
|
+
run
|
42
|
+
gem_path = Bundler::CLI::Common.select_spec("appsignal").full_gem_path.strip
|
43
|
+
expect(output).to include \
|
44
|
+
"Gem version: #{Appsignal::VERSION}",
|
45
|
+
"Agent version: #{Appsignal::Extension.agent_version}",
|
46
|
+
"Gem install path: #{gem_path}"
|
47
|
+
end
|
48
|
+
|
49
|
+
context "with extension" do
|
50
|
+
it "outputs extension is loaded" do
|
51
|
+
run
|
52
|
+
expect(output).to include "Extension loaded: yes"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "starts the agent in diagnose mode and outputs a log" do
|
56
|
+
run
|
57
|
+
expect(output).to include \
|
58
|
+
"Agent diagnostics:",
|
59
|
+
"Running agent in diagnose mode",
|
60
|
+
"Valid config present",
|
61
|
+
"Logger initialized successfully",
|
62
|
+
"Lock path is writable",
|
63
|
+
"Agent diagnose finished"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "without extension" do
|
68
|
+
before do
|
69
|
+
# When the extension isn't loaded the Appsignal.start operation exits
|
70
|
+
# early and doesn't load the configuration.
|
71
|
+
# Happens when the extension wasn't installed properly.
|
72
|
+
Appsignal.extension_loaded = false
|
73
|
+
run
|
74
|
+
end
|
75
|
+
after { Appsignal.extension_loaded = true }
|
76
|
+
|
77
|
+
it "outputs extension is not loaded" do
|
78
|
+
expect(output).to include "Extension loaded: no"
|
79
|
+
end
|
80
|
+
end
|
41
81
|
end
|
42
82
|
|
43
83
|
describe "host information" do
|
@@ -50,6 +90,26 @@ describe Appsignal::CLI::Diagnose do
|
|
50
90
|
"Ruby version: #{RbConfig::CONFIG["RUBY_VERSION_NAME"]}"
|
51
91
|
end
|
52
92
|
|
93
|
+
describe "root user detection" do
|
94
|
+
context "when not root user" do
|
95
|
+
it "prints no" do
|
96
|
+
run
|
97
|
+
expect(output).to include "root user: no"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when root user" do
|
102
|
+
before do
|
103
|
+
allow(Process).to receive(:uid).and_return(0)
|
104
|
+
run
|
105
|
+
end
|
106
|
+
|
107
|
+
it "prints yes, with warning" do
|
108
|
+
expect(output).to include "root user: yes (not recommended)"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
53
113
|
describe "Heroku detection" do
|
54
114
|
context "when not on Heroku" do
|
55
115
|
before { recognize_as_container(:none) { run } }
|
@@ -89,42 +149,20 @@ describe Appsignal::CLI::Diagnose do
|
|
89
149
|
end
|
90
150
|
|
91
151
|
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
152
|
context "without environment" do
|
117
|
-
let(:config) { project_fixture_config(
|
153
|
+
let(:config) { project_fixture_config(nil) }
|
154
|
+
let(:options) { {} }
|
118
155
|
before do
|
119
|
-
ENV
|
120
|
-
|
156
|
+
ENV.delete("RAILS_ENV") # From spec_helper
|
157
|
+
ENV.delete("RACK_ENV")
|
158
|
+
recognize_as_container(:none) { run_within_dir tmp_dir }
|
121
159
|
end
|
122
160
|
|
123
161
|
it "outputs a warning that no config is loaded" do
|
124
162
|
expect(output).to_not include "Error"
|
125
163
|
expect(output).to include \
|
126
164
|
"Environment: \n Warning: No environment set, no config loaded!",
|
127
|
-
"
|
165
|
+
" appsignal diagnose --environment=production"
|
128
166
|
end
|
129
167
|
|
130
168
|
it "outputs config defaults" do
|
@@ -153,10 +191,7 @@ describe Appsignal::CLI::Diagnose do
|
|
153
191
|
|
154
192
|
context "with unconfigured environment" do
|
155
193
|
let(:config) { project_fixture_config("foobar") }
|
156
|
-
before
|
157
|
-
ENV["APPSIGNAL_APP_ENV"] = "foobar"
|
158
|
-
recognize_as_container(:none) { run }
|
159
|
-
end
|
194
|
+
before { recognize_as_container(:none) { run_within_dir tmp_dir } }
|
160
195
|
|
161
196
|
it "outputs environment" do
|
162
197
|
expect(output).to include("Environment: foobar")
|
@@ -172,7 +207,7 @@ describe Appsignal::CLI::Diagnose do
|
|
172
207
|
end
|
173
208
|
end
|
174
209
|
|
175
|
-
describe "API key validation" do
|
210
|
+
describe "API key validation", :api_stub => false do
|
176
211
|
context "with valid key" do
|
177
212
|
before do
|
178
213
|
stub_api_request(config, "auth").to_return(:status => 200)
|
@@ -208,71 +243,185 @@ describe Appsignal::CLI::Diagnose do
|
|
208
243
|
end
|
209
244
|
|
210
245
|
describe "paths" do
|
211
|
-
|
246
|
+
let(:system_tmp_dir) { Appsignal::Config::SYSTEM_TMP_DIR }
|
247
|
+
before do
|
248
|
+
FileUtils.mkdir_p(root_path)
|
249
|
+
FileUtils.mkdir_p(system_tmp_dir)
|
250
|
+
end
|
251
|
+
after { FileUtils.rm_rf([root_path, system_tmp_dir]) }
|
212
252
|
|
213
|
-
context "when a directory is
|
253
|
+
context "when a directory is not configured" do
|
214
254
|
let(:root_path) { File.join(tmp_dir, "writable_path") }
|
215
|
-
let(:
|
216
|
-
|
255
|
+
let(:config) { Appsignal::Config.new(root_path, "production", :log_file => nil) }
|
256
|
+
before do
|
257
|
+
FileUtils.mkdir_p(File.join(root_path, "log"), :mode => 0555)
|
258
|
+
FileUtils.chmod(0555, system_tmp_dir)
|
259
|
+
run_within_dir root_path
|
260
|
+
end
|
261
|
+
|
262
|
+
it "outputs unconfigured directory" do
|
263
|
+
expect(output).to include %(log_file_path: ""\n - Configured?: no)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
context "when a directory does not exist" do
|
268
|
+
let(:root_path) { tmp_dir }
|
269
|
+
let(:execution_path) { File.join(tmp_dir, "not_existing_dir") }
|
270
|
+
let(:config) { Appsignal::Config.new(execution_path, "production") }
|
271
|
+
before do
|
272
|
+
allow(Dir).to receive(:pwd).and_return(execution_path)
|
273
|
+
run_within_dir tmp_dir
|
274
|
+
end
|
217
275
|
|
218
|
-
|
276
|
+
it "outputs not existing path" do
|
277
|
+
expect(output).to include %(root_path: "#{execution_path}"\n - Exists?: no)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
describe "ownership" do
|
282
|
+
context "when a directory is owned by the current user" do
|
283
|
+
let(:root_path) { File.join(tmp_dir, "owned_path") }
|
284
|
+
let(:config) { Appsignal::Config.new(root_path, "production") }
|
285
|
+
let(:process_user) { Etc.getpwuid(Process.uid).name }
|
219
286
|
before { run_within_dir root_path }
|
220
287
|
|
221
|
-
it "outputs
|
288
|
+
it "outputs ownership" do
|
222
289
|
expect(output).to include \
|
223
|
-
"
|
224
|
-
|
225
|
-
|
290
|
+
%(root_path: "#{root_path}"\n - Writable?: yes\n ) \
|
291
|
+
"- Ownership?: yes (file: #{process_user}:#{Process.uid}, "\
|
292
|
+
"process: #{process_user}:#{Process.uid})"
|
226
293
|
end
|
227
294
|
end
|
228
295
|
|
229
|
-
context "
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
296
|
+
context "when a directory is not owned by the current user" do
|
297
|
+
let(:root_path) { File.join(tmp_dir, "not_owned_path") }
|
298
|
+
let(:config) { Appsignal::Config.new(root_path, "production") }
|
299
|
+
let(:process_user) { Etc.getpwuid(Process.uid).name }
|
300
|
+
before do
|
301
|
+
stat = File.stat(root_path)
|
302
|
+
allow(stat).to receive(:uid).and_return(0)
|
303
|
+
allow(File).to receive(:stat).and_return(stat)
|
304
|
+
run_within_dir root_path
|
305
|
+
end
|
235
306
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
end
|
307
|
+
it "outputs no ownership" do
|
308
|
+
expect(output).to include \
|
309
|
+
%(root_path: "#{root_path}"\n - Writable?: yes\n ) \
|
310
|
+
"- Ownership?: no (file: root:0, process: #{process_user}:#{Process.uid})"
|
241
311
|
end
|
312
|
+
end
|
313
|
+
end
|
242
314
|
|
243
|
-
|
315
|
+
describe "current_path" do
|
316
|
+
let(:root_path) { tmp_dir }
|
317
|
+
let(:config) { Appsignal::Config.new(root_path, "production") }
|
318
|
+
before { run_within_dir root_path }
|
319
|
+
|
320
|
+
it "outputs current path" do
|
321
|
+
expect(output).to include %(current_path: "#{tmp_dir}"\n - Writable?: yes)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
describe "root_path" do
|
326
|
+
let(:system_tmp_log_file) { File.join(system_tmp_dir, "appsignal.log") }
|
327
|
+
context "when not writable" do
|
328
|
+
let(:root_path) { File.join(tmp_dir, "not_writable_path") }
|
329
|
+
let(:config) { Appsignal::Config.new(root_path, "production") }
|
330
|
+
before do
|
331
|
+
FileUtils.chmod(0555, root_path)
|
332
|
+
run_within_dir root_path
|
333
|
+
end
|
334
|
+
|
335
|
+
it "outputs not writable root path" do
|
336
|
+
expect(output).to include %(root_path: "#{root_path}"\n - Writable?: no)
|
337
|
+
end
|
338
|
+
|
339
|
+
it "log files fall back on system tmp directory" do
|
340
|
+
expect(output).to include \
|
341
|
+
%(log_dir_path: "#{system_tmp_dir}"\n - Writable?: yes)
|
342
|
+
%(log_file_path: "#{system_tmp_log_file}"\n - Exist?: false)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
context "when writable" do
|
347
|
+
let(:root_path) { File.join(tmp_dir, "writable_path") }
|
348
|
+
let(:config) { Appsignal::Config.new(root_path, "production") }
|
349
|
+
|
350
|
+
context "without log dir" do
|
244
351
|
before do
|
245
|
-
FileUtils.
|
246
|
-
FileUtils.chmod(0444, log_file)
|
352
|
+
FileUtils.chmod(0777, root_path)
|
247
353
|
run_within_dir root_path
|
248
354
|
end
|
249
355
|
|
250
|
-
it "
|
356
|
+
it "outputs writable root path" do
|
357
|
+
expect(output).to include %(root_path: "#{root_path}"\n - Writable?: yes)
|
358
|
+
end
|
359
|
+
|
360
|
+
it "log files fall back on system tmp directory" do
|
251
361
|
expect(output).to include \
|
252
|
-
%(
|
253
|
-
%(log_file_path: "#{
|
362
|
+
%(log_dir_path: "#{system_tmp_dir}"\n - Writable?: yes),
|
363
|
+
%(log_file_path: "#{system_tmp_log_file}"\n - Exists?: no)
|
254
364
|
end
|
255
365
|
end
|
256
|
-
end
|
257
|
-
end
|
258
366
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
367
|
+
context "with log dir" do
|
368
|
+
let(:log_dir) { File.join(root_path, "log") }
|
369
|
+
let(:log_file) { File.join(log_dir, "appsignal.log") }
|
370
|
+
before { FileUtils.mkdir_p(log_dir) }
|
371
|
+
|
372
|
+
context "when not writable" do
|
373
|
+
before do
|
374
|
+
FileUtils.chmod(0444, log_dir)
|
375
|
+
run_within_dir root_path
|
376
|
+
end
|
377
|
+
|
378
|
+
it "log files fall back on system tmp directory" do
|
379
|
+
expect(output).to include \
|
380
|
+
%(log_dir_path: "#{system_tmp_dir}"\n - Writable?: yes),
|
381
|
+
%(log_file_path: "#{system_tmp_log_file}"\n - Exists?: no)
|
382
|
+
end
|
383
|
+
end
|
266
384
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
385
|
+
context "when writable" do
|
386
|
+
context "without log file" do
|
387
|
+
before { run_within_dir root_path }
|
388
|
+
|
389
|
+
it "outputs writable but without log file" do
|
390
|
+
expect(output).to include \
|
391
|
+
%(root_path: "#{root_path}"\n - Writable?: yes),
|
392
|
+
%(log_dir_path: "#{log_dir}"\n - Writable?: yes),
|
393
|
+
%(log_file_path: "#{log_file}"\n - Exists?: no)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
context "with log file" do
|
398
|
+
context "when writable" do
|
399
|
+
before do
|
400
|
+
FileUtils.touch(log_file)
|
401
|
+
run_within_dir root_path
|
402
|
+
end
|
403
|
+
|
404
|
+
it "lists log file as writable" do
|
405
|
+
expect(output).to include %(log_file_path: "#{log_file}"\n - Writable?: yes)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
context "when not writable" do
|
410
|
+
before do
|
411
|
+
FileUtils.touch(log_file)
|
412
|
+
FileUtils.chmod(0444, log_file)
|
413
|
+
run_within_dir root_path
|
414
|
+
end
|
415
|
+
|
416
|
+
it "lists log file as not writable" do
|
417
|
+
expect(output).to include %(log_file_path: "#{log_file}"\n - Writable?: no)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
272
423
|
end
|
273
424
|
end
|
274
|
-
|
275
|
-
after { FileUtils.rm_rf(root_path) }
|
276
425
|
end
|
277
426
|
|
278
427
|
describe "logs" do
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "appsignal/cli/helpers"
|
2
|
+
|
3
|
+
describe Appsignal::CLI::Helpers do
|
4
|
+
include CLIHelpers
|
5
|
+
|
6
|
+
let(:out_stream) { std_stream }
|
7
|
+
let(:output) { out_stream.read }
|
8
|
+
let(:cli) do
|
9
|
+
Class.new do
|
10
|
+
extend Appsignal::CLI::Helpers
|
11
|
+
end
|
12
|
+
end
|
13
|
+
before do
|
14
|
+
# Speed up tests
|
15
|
+
allow(cli).to receive(:sleep)
|
16
|
+
end
|
17
|
+
around do |example|
|
18
|
+
original_stdin = $stdin
|
19
|
+
$stdin = StringIO.new
|
20
|
+
example.run
|
21
|
+
$stdin = original_stdin
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".colorize" do
|
25
|
+
subject { cli.send(:colorize, "text", :green) }
|
26
|
+
|
27
|
+
context "on windows" do
|
28
|
+
before { allow(Gem).to receive(:win_platform?).and_return(true) }
|
29
|
+
|
30
|
+
it "outputs plain string" do
|
31
|
+
expect(subject).to eq "text"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "not on windows" do
|
36
|
+
before { allow(Gem).to receive(:win_platform?).and_return(false) }
|
37
|
+
|
38
|
+
it "wraps text in color tags" do
|
39
|
+
expect(subject).to eq "\e[32mtext\e[0m"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".periods" do
|
45
|
+
it "prints three periods" do
|
46
|
+
capture_stdout(out_stream) { cli.send :periods }
|
47
|
+
expect(output).to include("...")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe ".press_any_key" do
|
52
|
+
before do
|
53
|
+
set_input "a" # a as in any
|
54
|
+
end
|
55
|
+
|
56
|
+
it "continues after press" do
|
57
|
+
capture_stdout(out_stream) { cli.send :press_any_key }
|
58
|
+
expect(output).to include("Press any key")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe ".yes_or_no" do
|
63
|
+
def yes_or_no
|
64
|
+
capture_stdout(out_stream) { cli.send(:yes_or_no, "yes or no?: ") }
|
65
|
+
end
|
66
|
+
|
67
|
+
it "takes yes for an answer" do
|
68
|
+
set_input ""
|
69
|
+
set_input "nonsense"
|
70
|
+
set_input "y"
|
71
|
+
prepare_input
|
72
|
+
|
73
|
+
expect(yes_or_no).to be_true
|
74
|
+
end
|
75
|
+
|
76
|
+
it "takes no for an answer" do
|
77
|
+
set_input ""
|
78
|
+
set_input "nonsense"
|
79
|
+
set_input "n"
|
80
|
+
prepare_input
|
81
|
+
|
82
|
+
expect(yes_or_no).to be_false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe ".required_input" do
|
87
|
+
def required_input
|
88
|
+
capture_stdout(out_stream) { cli.send(:required_input, "provide: ") }
|
89
|
+
end
|
90
|
+
|
91
|
+
it "collects required input" do
|
92
|
+
set_input ""
|
93
|
+
set_input "value"
|
94
|
+
prepare_input
|
95
|
+
|
96
|
+
expect(required_input).to eq("value")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|