appsignal 2.8.0.alpha.1 → 2.8.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 +4 -4
- data/.travis.yml +13 -14
- data/CHANGELOG.md +27 -5
- data/ext/agent.yml +38 -35
- data/ext/extconf.rb +12 -0
- data/lib/appsignal/cli.rb +3 -0
- data/lib/appsignal/cli/diagnose.rb +191 -177
- data/lib/appsignal/cli/diagnose/paths.rb +91 -0
- data/lib/appsignal/cli/diagnose/utils.rb +36 -0
- data/lib/appsignal/cli/install.rb +2 -2
- data/lib/appsignal/config.rb +71 -23
- data/lib/appsignal/event_formatter.rb +11 -5
- data/lib/appsignal/garbage_collection_profiler.rb +11 -0
- data/lib/appsignal/system.rb +6 -4
- data/lib/appsignal/transaction.rb +2 -1
- data/lib/appsignal/utils.rb +1 -0
- data/lib/appsignal/utils/deprecation_message.rb +10 -0
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/cli/diagnose/utils_spec.rb +37 -0
- data/spec/lib/appsignal/cli/diagnose_spec.rb +498 -278
- data/spec/lib/appsignal/config_spec.rb +93 -36
- data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +1 -1
- data/spec/lib/appsignal/event_formatter_spec.rb +12 -7
- data/spec/lib/appsignal/extension_spec.rb +5 -2
- data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +10 -0
- data/spec/lib/appsignal/system_spec.rb +1 -1
- data/spec/lib/appsignal/transaction_spec.rb +24 -7
- data/spec/support/helpers/std_streams_helper.rb +31 -8
- metadata +9 -4
@@ -1,6 +1,6 @@
|
|
1
1
|
require "appsignal/cli"
|
2
2
|
|
3
|
-
describe Appsignal::CLI::Diagnose, :api_stub => true, :
|
3
|
+
describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_input do
|
4
4
|
include CLIHelpers
|
5
5
|
|
6
6
|
class DiagnosticsReportEndpoint
|
@@ -27,6 +27,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
27
27
|
let(:gem_path) { Bundler::CLI::Common.select_spec("appsignal").full_gem_path.strip }
|
28
28
|
let(:received_report) { DiagnosticsReportEndpoint.received_report }
|
29
29
|
let(:process_user) { Etc.getpwuid(Process.uid).name }
|
30
|
+
let(:process_group) { Etc.getgrgid(Process.gid).name }
|
30
31
|
before(:context) { Appsignal.stop }
|
31
32
|
before do
|
32
33
|
# Clear previous reports
|
@@ -51,13 +52,22 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
51
52
|
before :api_stub => true do
|
52
53
|
stub_api_request config, "auth"
|
53
54
|
end
|
54
|
-
before
|
55
|
-
|
56
|
-
|
55
|
+
before(:send_report => :yes_cli_input) do
|
56
|
+
accept_prompt_to_send_diagnostics_report
|
57
|
+
capture_diagnatics_report_request
|
58
|
+
end
|
59
|
+
before(:send_report => :no_cli_input) { dont_accept_prompt_to_send_diagnostics_report }
|
60
|
+
before(:send_report => :yes_cli_option) do
|
61
|
+
options[:send_report] = true
|
62
|
+
capture_diagnatics_report_request
|
57
63
|
end
|
58
|
-
before(:
|
64
|
+
before(:send_report => :no_cli_option) { options[:send_report] = false }
|
59
65
|
after { Appsignal.config = nil }
|
60
66
|
|
67
|
+
def capture_diagnatics_report_request
|
68
|
+
stub_diagnostics_report_request.to_rack(DiagnosticsReportEndpoint)
|
69
|
+
end
|
70
|
+
|
61
71
|
def run
|
62
72
|
run_within_dir project_fixture_path
|
63
73
|
end
|
@@ -82,11 +92,11 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
82
92
|
)
|
83
93
|
end
|
84
94
|
|
85
|
-
def
|
95
|
+
def accept_prompt_to_send_diagnostics_report
|
86
96
|
add_cli_input "y"
|
87
97
|
end
|
88
98
|
|
89
|
-
def
|
99
|
+
def dont_accept_prompt_to_send_diagnostics_report
|
90
100
|
add_cli_input "n"
|
91
101
|
end
|
92
102
|
|
@@ -94,22 +104,28 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
94
104
|
run
|
95
105
|
expect(output).to include \
|
96
106
|
"AppSignal diagnose",
|
97
|
-
"
|
107
|
+
"https://docs.appsignal.com/",
|
98
108
|
"support@appsignal.com"
|
99
109
|
end
|
100
110
|
|
111
|
+
it "logs to the log file" do
|
112
|
+
run
|
113
|
+
log_contents = File.read(config.log_file_path)
|
114
|
+
expect(log_contents).to contains_log :info, "Starting AppSignal diagnose"
|
115
|
+
end
|
116
|
+
|
101
117
|
describe "report" do
|
102
118
|
context "when user wants to send report" do
|
103
119
|
it "sends report" do
|
104
120
|
run
|
105
121
|
expect(output).to include "Diagnostics report",
|
106
|
-
"Send diagnostics report to AppSignal? (Y/n): "
|
107
|
-
"Please email us at support@appsignal.com with the following\n support token."
|
122
|
+
"Send diagnostics report to AppSignal? (Y/n): "
|
108
123
|
end
|
109
124
|
|
110
125
|
it "outputs the support token from the server" do
|
111
126
|
run
|
112
127
|
expect(output).to include "Your support token: my_support_token"
|
128
|
+
expect(output).to include "View this report: https://appsignal.com/diagnose/my_support_token"
|
113
129
|
end
|
114
130
|
|
115
131
|
context "when server response is invalid" do
|
@@ -138,7 +154,25 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
138
154
|
end
|
139
155
|
end
|
140
156
|
|
141
|
-
context "when user
|
157
|
+
context "when user uses the --send-report option", :send_report => :yes_cli_option do
|
158
|
+
it "sends the report without prompting" do
|
159
|
+
run
|
160
|
+
expect(output).to include "Diagnostics report",
|
161
|
+
"Confirmed sending report using --send-report option.",
|
162
|
+
"Transmitting diagnostics report"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "when user uses the --no-send-report option", :send_report => :no_cli_option do
|
167
|
+
it "does not send the report" do
|
168
|
+
run
|
169
|
+
expect(output).to include "Diagnostics report",
|
170
|
+
"Not sending report. (Specified with the --no-send-report option.)",
|
171
|
+
"Not sending diagnostics information to AppSignal."
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context "when user doesn't want to send report", :send_report => :no_cli_input do
|
142
176
|
it "does not send report" do
|
143
177
|
run
|
144
178
|
expect(output).to include "Diagnostics report",
|
@@ -155,8 +189,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
155
189
|
expect(output).to include \
|
156
190
|
"Gem version: #{Appsignal::VERSION}",
|
157
191
|
"Agent version: #{Appsignal::Extension.agent_version}",
|
158
|
-
"Agent architecture: #{Appsignal::System.installed_agent_architecture}"
|
159
|
-
"Gem install path: #{gem_path}"
|
192
|
+
"Agent architecture: #{Appsignal::System.installed_agent_architecture}"
|
160
193
|
end
|
161
194
|
|
162
195
|
it "transmits version numbers in report" do
|
@@ -166,7 +199,6 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
166
199
|
"package_version" => Appsignal::VERSION,
|
167
200
|
"agent_version" => Appsignal::Extension.agent_version,
|
168
201
|
"agent_architecture" => Appsignal::System.installed_agent_architecture,
|
169
|
-
"package_install_path" => gem_path,
|
170
202
|
"extension_loaded" => true
|
171
203
|
}
|
172
204
|
)
|
@@ -205,14 +237,12 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
205
237
|
end
|
206
238
|
|
207
239
|
describe "agent diagnostics" do
|
240
|
+
let(:working_directory_stat) { File.stat("/tmp/appsignal") }
|
241
|
+
|
208
242
|
it "starts the agent in diagnose mode and outputs the report" do
|
209
243
|
run
|
210
|
-
|
211
|
-
|
212
|
-
" Extension config: valid",
|
213
|
-
" Agent config: valid",
|
214
|
-
" Agent logger: started",
|
215
|
-
" Agent lock path: writable"
|
244
|
+
working_directory_stat = File.stat("/tmp/appsignal")
|
245
|
+
expect_valid_agent_diagnostics_report(output, working_directory_stat)
|
216
246
|
end
|
217
247
|
|
218
248
|
it "adds the agent diagnostics to the report" do
|
@@ -223,8 +253,17 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
223
253
|
},
|
224
254
|
"agent" => {
|
225
255
|
"boot" => { "started" => { "result" => true } },
|
256
|
+
"host" => {
|
257
|
+
"uid" => { "result" => Process.uid },
|
258
|
+
"gid" => { "result" => Process.gid }
|
259
|
+
},
|
226
260
|
"config" => { "valid" => { "result" => true } },
|
227
261
|
"logger" => { "started" => { "result" => true } },
|
262
|
+
"working_directory_stat" => {
|
263
|
+
"uid" => { "result" => working_directory_stat.uid },
|
264
|
+
"gid" => { "result" => working_directory_stat.gid },
|
265
|
+
"mode" => { "result" => working_directory_stat.mode }
|
266
|
+
},
|
228
267
|
"lock_path" => { "created" => { "result" => true } }
|
229
268
|
}
|
230
269
|
)
|
@@ -239,13 +278,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
239
278
|
it "force starts the agent in diagnose mode and outputs a log" do
|
240
279
|
run
|
241
280
|
expect(output).to include("active: false")
|
242
|
-
|
243
|
-
"Agent diagnostics",
|
244
|
-
" Extension config: valid",
|
245
|
-
" Agent started: started",
|
246
|
-
" Agent config: valid",
|
247
|
-
" Agent logger: started",
|
248
|
-
" Agent lock path: writable"
|
281
|
+
expect_valid_agent_diagnostics_report(output, working_directory_stat)
|
249
282
|
end
|
250
283
|
end
|
251
284
|
|
@@ -323,11 +356,12 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
323
356
|
it "prints the tests, but shows a dash `-` for missed results" do
|
324
357
|
expect(output).to include \
|
325
358
|
"Agent diagnostics",
|
326
|
-
" Extension
|
327
|
-
" Agent
|
328
|
-
"
|
329
|
-
"
|
330
|
-
"
|
359
|
+
" Extension tests\n Configuration: invalid",
|
360
|
+
" Agent tests",
|
361
|
+
" Started: -",
|
362
|
+
" Configuration: -",
|
363
|
+
" Logger: -",
|
364
|
+
" Lock path: -"
|
331
365
|
end
|
332
366
|
|
333
367
|
it "adds the output to the report" do
|
@@ -356,8 +390,8 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
356
390
|
it "prints the error and output" do
|
357
391
|
expect(output).to include \
|
358
392
|
"Agent diagnostics",
|
359
|
-
" Extension
|
360
|
-
" Agent
|
393
|
+
" Extension tests\n Configuration: valid",
|
394
|
+
" Agent tests\n Started: not started\n Error: some-error"
|
361
395
|
end
|
362
396
|
|
363
397
|
it "adds the agent report to the diagnostics report" do
|
@@ -382,8 +416,8 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
382
416
|
run
|
383
417
|
expect(output).to include \
|
384
418
|
"Agent diagnostics",
|
385
|
-
" Extension
|
386
|
-
"
|
419
|
+
" Extension tests\n Configuration: valid",
|
420
|
+
" Configuration: invalid\n Output: some output"
|
387
421
|
end
|
388
422
|
end
|
389
423
|
end
|
@@ -531,31 +565,147 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
531
565
|
|
532
566
|
it "outputs a warning that no config is loaded" do
|
533
567
|
expect(output).to include \
|
534
|
-
"Environment: \n
|
568
|
+
"Environment: \"\"\n",
|
569
|
+
" Warning: No environment set, no config loaded!",
|
535
570
|
" appsignal diagnose --environment=production"
|
536
571
|
end
|
537
572
|
|
538
573
|
it "outputs config defaults" do
|
539
574
|
expect(output).to include("Configuration")
|
540
|
-
Appsignal::Config::DEFAULT_CONFIG
|
541
|
-
|
542
|
-
|
575
|
+
expect_config_to_be_printed(Appsignal::Config::DEFAULT_CONFIG)
|
576
|
+
end
|
577
|
+
|
578
|
+
it "transmits validation in report" do
|
579
|
+
default_config = hash_with_string_keys(Appsignal::Config::DEFAULT_CONFIG)
|
580
|
+
expect(received_report["config"]).to eq(
|
581
|
+
"options" => default_config.merge("env" => ""),
|
582
|
+
"sources" => {
|
583
|
+
"default" => default_config,
|
584
|
+
"system" => {},
|
585
|
+
"initial" => { "env" => "" },
|
586
|
+
"file" => {},
|
587
|
+
"env" => {}
|
588
|
+
}
|
589
|
+
)
|
543
590
|
end
|
544
591
|
end
|
545
592
|
|
546
593
|
context "with configured environment" do
|
547
|
-
|
594
|
+
describe "environment" do
|
595
|
+
it "outputs environment" do
|
596
|
+
run
|
597
|
+
expect(output).to include(%(Environment: "production"))
|
598
|
+
end
|
548
599
|
|
549
|
-
|
550
|
-
|
600
|
+
context "when the source is a single source" do
|
601
|
+
before { run }
|
602
|
+
|
603
|
+
it "outputs the label source after the value" do
|
604
|
+
expect(output).to include(
|
605
|
+
%(Environment: "#{Appsignal.config.env}" (Loaded from: initial)\n)
|
606
|
+
)
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
context "when the source is multiple sources" do
|
611
|
+
let(:options) { { :environment => "development" } }
|
612
|
+
before do
|
613
|
+
ENV["APPSIGNAL_APP_ENV"] = "production"
|
614
|
+
config.instance_variable_set(:@env, ENV["APPSIGNAL_APP_ENV"])
|
615
|
+
stub_api_request(config, "auth").to_return(:status => 200)
|
616
|
+
capture_diagnatics_report_request
|
617
|
+
run
|
618
|
+
end
|
619
|
+
|
620
|
+
it "outputs a list of sources with their values" do
|
621
|
+
expect(output).to include(
|
622
|
+
%( Environment: "production"\n) +
|
623
|
+
%( Sources:\n) +
|
624
|
+
%( initial: "development"\n) +
|
625
|
+
%( env: "production"\n)
|
626
|
+
)
|
627
|
+
end
|
628
|
+
end
|
551
629
|
end
|
552
630
|
|
553
631
|
it "outputs configuration" do
|
632
|
+
run
|
554
633
|
expect(output).to include("Configuration")
|
555
|
-
Appsignal.config.config_hash
|
556
|
-
|
634
|
+
expect_config_to_be_printed(Appsignal.config.config_hash)
|
635
|
+
end
|
636
|
+
|
637
|
+
describe "option sources" do
|
638
|
+
context "when the source is a single source" do
|
639
|
+
before { run }
|
640
|
+
|
641
|
+
it "outputs the label source after the value" do
|
642
|
+
expect(output).to include(
|
643
|
+
%(push_api_key: "#{Appsignal.config[:push_api_key]}" (Loaded from: file)\n)
|
644
|
+
)
|
645
|
+
end
|
646
|
+
|
647
|
+
context "when the source is only default" do
|
648
|
+
it "does not print a source" do
|
649
|
+
expect(output).to include("debug: #{Appsignal.config[:debug]}\n")
|
650
|
+
end
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
context "when the source is multiple sources" do
|
655
|
+
before do
|
656
|
+
ENV["APPSIGNAL_APP_NAME"] = "MyApp"
|
657
|
+
config[:name] = ENV["APPSIGNAL_APP_NAME"]
|
658
|
+
stub_api_request(config, "auth").to_return(:status => 200)
|
659
|
+
capture_diagnatics_report_request
|
660
|
+
run
|
661
|
+
end
|
662
|
+
|
663
|
+
if DependencyHelper.rails_present?
|
664
|
+
it "outputs a list of sources with their values" do
|
665
|
+
expect(output).to include(
|
666
|
+
%( name: "MyApp"\n) +
|
667
|
+
%( Sources:\n) +
|
668
|
+
%( initial: "MyApp"\n) +
|
669
|
+
%( file: "TestApp"\n) +
|
670
|
+
%( env: "MyApp"\n)
|
671
|
+
)
|
672
|
+
end
|
673
|
+
else
|
674
|
+
it "outputs a list of sources with their values" do
|
675
|
+
expect(output).to include(
|
676
|
+
%( name: "MyApp"\n) +
|
677
|
+
%( Sources:\n) +
|
678
|
+
%( file: "TestApp"\n) +
|
679
|
+
%( env: "MyApp"\n)
|
680
|
+
)
|
681
|
+
end
|
682
|
+
end
|
557
683
|
end
|
558
684
|
end
|
685
|
+
|
686
|
+
it "transmits config in report" do
|
687
|
+
run
|
688
|
+
additional_initial_config = {}
|
689
|
+
if DependencyHelper.rails_present?
|
690
|
+
additional_initial_config = {
|
691
|
+
:name => "MyApp",
|
692
|
+
:log_path => File.join(Rails.root, "log")
|
693
|
+
}
|
694
|
+
end
|
695
|
+
final_config = { "env" => "production" }
|
696
|
+
.merge(additional_initial_config)
|
697
|
+
.merge(config.config_hash)
|
698
|
+
expect(received_report["config"]).to match(
|
699
|
+
"options" => hash_with_string_keys(final_config),
|
700
|
+
"sources" => {
|
701
|
+
"default" => hash_with_string_keys(Appsignal::Config::DEFAULT_CONFIG),
|
702
|
+
"system" => {},
|
703
|
+
"initial" => hash_with_string_keys(config.initial_config.merge(additional_initial_config)),
|
704
|
+
"file" => hash_with_string_keys(config.file_config),
|
705
|
+
"env" => {}
|
706
|
+
}
|
707
|
+
)
|
708
|
+
end
|
559
709
|
end
|
560
710
|
|
561
711
|
context "with unconfigured environment" do
|
@@ -563,14 +713,42 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
563
713
|
before { run_within_dir tmp_dir }
|
564
714
|
|
565
715
|
it "outputs environment" do
|
566
|
-
expect(output).to include(
|
716
|
+
expect(output).to include(%(Environment: "foobar"))
|
567
717
|
end
|
568
718
|
|
569
719
|
it "outputs config defaults" do
|
570
720
|
expect(output).to include("Configuration")
|
571
|
-
Appsignal::Config::DEFAULT_CONFIG
|
572
|
-
|
573
|
-
|
721
|
+
expect_config_to_be_printed(Appsignal::Config::DEFAULT_CONFIG)
|
722
|
+
end
|
723
|
+
|
724
|
+
it "transmits config in report" do
|
725
|
+
expect(received_report["config"]).to match(
|
726
|
+
"options" => hash_with_string_keys(config.config_hash).merge("env" => "foobar"),
|
727
|
+
"sources" => {
|
728
|
+
"default" => hash_with_string_keys(Appsignal::Config::DEFAULT_CONFIG),
|
729
|
+
"system" => {},
|
730
|
+
"initial" => hash_with_string_keys(config.initial_config),
|
731
|
+
"file" => hash_with_string_keys(config.file_config),
|
732
|
+
"env" => {}
|
733
|
+
}
|
734
|
+
)
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
738
|
+
def expect_config_to_be_printed(config)
|
739
|
+
nil_options = config.select { |_, v| v.nil? }
|
740
|
+
nil_options.each_key do |key|
|
741
|
+
expect(output).to include(%(#{key}: nil))
|
742
|
+
end
|
743
|
+
string_options = config.select { |_, v| v.is_a?(String) }
|
744
|
+
string_options.each do |key, value|
|
745
|
+
expect(output).to include(%(#{key}: "#{value}"))
|
746
|
+
end
|
747
|
+
other_options = config.select do |k, _|
|
748
|
+
!string_options.key?(k) && !nil_options.key?(k)
|
749
|
+
end
|
750
|
+
other_options.each do |key, value|
|
751
|
+
expect(output).to include(%(#{key}: #{value}))
|
574
752
|
end
|
575
753
|
end
|
576
754
|
end
|
@@ -639,6 +817,8 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
639
817
|
end
|
640
818
|
|
641
819
|
describe "paths" do
|
820
|
+
let(:config) { Appsignal::Config.new(root_path, "production") }
|
821
|
+
let(:root_path) { tmp_dir }
|
642
822
|
let(:system_tmp_dir) { Appsignal::Config.system_tmp_dir }
|
643
823
|
before do
|
644
824
|
FileUtils.mkdir_p(root_path)
|
@@ -647,82 +827,220 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
647
827
|
after { FileUtils.rm_rf([root_path, system_tmp_dir]) }
|
648
828
|
|
649
829
|
describe "report" do
|
650
|
-
let(:root_path) { tmp_dir }
|
651
|
-
|
652
830
|
it "adds paths to the report" do
|
653
|
-
|
654
|
-
expect(received_report["paths"].keys)
|
655
|
-
|
831
|
+
run_within_dir root_path
|
832
|
+
expect(received_report["paths"].keys).to match_array(
|
833
|
+
%w[
|
834
|
+
package_install_path root_path working_dir log_dir_path
|
835
|
+
ext/install.log ext/mkmf.log appsignal.log
|
836
|
+
]
|
837
|
+
)
|
656
838
|
end
|
657
|
-
end
|
658
839
|
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
840
|
+
describe "working_dir" do
|
841
|
+
before { run_within_dir root_path }
|
842
|
+
|
843
|
+
it "outputs current path" do
|
844
|
+
expect(output).to include %(Current working directory\n Path: "#{tmp_dir}")
|
845
|
+
end
|
846
|
+
|
847
|
+
it "transmits path data in report" do
|
848
|
+
expect(received_report["paths"]["working_dir"]).to match(
|
849
|
+
"path" => tmp_dir,
|
850
|
+
"exists" => true,
|
851
|
+
"type" => "directory",
|
852
|
+
"mode" => kind_of(String),
|
853
|
+
"writable" => boolean,
|
854
|
+
"ownership" => {
|
855
|
+
"uid" => kind_of(Integer),
|
856
|
+
"user" => kind_of(String),
|
857
|
+
"gid" => kind_of(Integer),
|
858
|
+
"group" => kind_of(String)
|
859
|
+
}
|
860
|
+
)
|
861
|
+
end
|
666
862
|
end
|
667
863
|
|
668
|
-
|
669
|
-
|
864
|
+
describe "root_path" do
|
865
|
+
before { run_within_dir root_path }
|
866
|
+
|
867
|
+
it "outputs root path" do
|
868
|
+
expect(output).to include %(Root path\n Path: "#{root_path}")
|
869
|
+
end
|
870
|
+
|
871
|
+
it "transmits path data in report" do
|
872
|
+
expect(received_report["paths"]["root_path"]).to match(
|
873
|
+
"path" => root_path,
|
874
|
+
"exists" => true,
|
875
|
+
"type" => "directory",
|
876
|
+
"mode" => kind_of(String),
|
877
|
+
"writable" => boolean,
|
878
|
+
"ownership" => {
|
879
|
+
"uid" => kind_of(Integer),
|
880
|
+
"user" => kind_of(String),
|
881
|
+
"gid" => kind_of(Integer),
|
882
|
+
"group" => kind_of(String)
|
883
|
+
}
|
884
|
+
)
|
885
|
+
end
|
670
886
|
end
|
671
887
|
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
"
|
677
|
-
|
678
|
-
|
888
|
+
describe "package_install_path" do
|
889
|
+
before { run_within_dir root_path }
|
890
|
+
|
891
|
+
it "outputs gem install path" do
|
892
|
+
expect(output).to match %(AppSignal gem path\n Path: "#{gem_path}")
|
893
|
+
end
|
894
|
+
|
895
|
+
it "transmits path data in report" do
|
896
|
+
expect(received_report["paths"]["package_install_path"]).to match(
|
897
|
+
"path" => gem_path,
|
898
|
+
"exists" => true,
|
899
|
+
"type" => "directory",
|
900
|
+
"mode" => kind_of(String),
|
901
|
+
"writable" => boolean,
|
902
|
+
"ownership" => {
|
903
|
+
"uid" => kind_of(Integer),
|
904
|
+
"user" => kind_of(String),
|
905
|
+
"gid" => kind_of(Integer),
|
906
|
+
"group" => kind_of(String)
|
907
|
+
}
|
908
|
+
)
|
909
|
+
end
|
910
|
+
end
|
911
|
+
|
912
|
+
describe "log_dir_path" do
|
913
|
+
before { run_within_dir root_path }
|
914
|
+
|
915
|
+
it "outputs log directory path" do
|
916
|
+
expect(output).to match %(Log directory\n Path: "#{system_tmp_dir}")
|
917
|
+
end
|
918
|
+
|
919
|
+
it "transmits path data in report" do
|
920
|
+
expect(received_report["paths"]["log_dir_path"]).to match(
|
921
|
+
"path" => system_tmp_dir,
|
922
|
+
"exists" => true,
|
923
|
+
"type" => "directory",
|
924
|
+
"mode" => kind_of(String),
|
925
|
+
"writable" => boolean,
|
926
|
+
"ownership" => {
|
927
|
+
"uid" => kind_of(Integer),
|
928
|
+
"user" => kind_of(String),
|
929
|
+
"gid" => kind_of(Integer),
|
930
|
+
"group" => kind_of(String)
|
931
|
+
}
|
932
|
+
)
|
933
|
+
end
|
679
934
|
end
|
680
935
|
end
|
681
936
|
|
682
937
|
context "when a directory does not exist" do
|
683
938
|
let(:root_path) { tmp_dir }
|
684
939
|
let(:execution_path) { File.join(tmp_dir, "not_existing_dir") }
|
685
|
-
let(:config)
|
940
|
+
let(:config) do
|
941
|
+
silence(:allowed => ["Push api key not set after loading config"]) do
|
942
|
+
Appsignal::Config.new(execution_path, "production")
|
943
|
+
end
|
944
|
+
end
|
686
945
|
before do
|
687
946
|
allow(Dir).to receive(:pwd).and_return(execution_path)
|
688
947
|
run_within_dir tmp_dir
|
689
948
|
end
|
690
949
|
|
691
950
|
it "outputs not existing path" do
|
692
|
-
expect(output).to include %(
|
951
|
+
expect(output).to include %(Root path\n Path: "#{execution_path}"\n Exists?: false)
|
693
952
|
end
|
694
953
|
|
695
954
|
it "transmits path data in report" do
|
696
955
|
expect(received_report["paths"]["root_path"]).to eq(
|
697
956
|
"path" => execution_path,
|
698
|
-
"
|
699
|
-
"exists" => false,
|
700
|
-
"writable" => false
|
957
|
+
"exists" => false
|
701
958
|
)
|
702
959
|
end
|
703
960
|
end
|
704
961
|
|
705
|
-
|
706
|
-
let(:
|
962
|
+
context "when not writable" do
|
963
|
+
let(:root_path) { File.join(tmp_dir, "not_writable_path") }
|
964
|
+
before do
|
965
|
+
FileUtils.chmod(0o555, root_path)
|
966
|
+
run_within_dir root_path
|
967
|
+
end
|
968
|
+
|
969
|
+
it "outputs not writable root path" do
|
970
|
+
expect(output).to include %(Root path\n Path: "#{root_path}"\n Writable?: false)
|
971
|
+
end
|
972
|
+
|
973
|
+
it "transmits path data in report" do
|
974
|
+
expect(received_report["paths"]["root_path"]).to eq(
|
975
|
+
"path" => root_path,
|
976
|
+
"exists" => true,
|
977
|
+
"type" => "directory",
|
978
|
+
"mode" => "40555",
|
979
|
+
"writable" => false,
|
980
|
+
"ownership" => {
|
981
|
+
"uid" => Process.uid,
|
982
|
+
"user" => process_user,
|
983
|
+
"gid" => Process.gid,
|
984
|
+
"group" => process_group
|
985
|
+
}
|
986
|
+
)
|
987
|
+
end
|
988
|
+
end
|
989
|
+
|
990
|
+
context "when writable" do
|
991
|
+
let(:root_path) { File.join(tmp_dir, "writable_path") }
|
992
|
+
before do
|
993
|
+
FileUtils.chmod(0o755, root_path)
|
994
|
+
run_within_dir root_path
|
995
|
+
end
|
996
|
+
|
997
|
+
it "outputs writable root path" do
|
998
|
+
expect(output).to include %(Root path\n Path: "#{root_path}"\n Writable?: true)
|
999
|
+
end
|
707
1000
|
|
1001
|
+
it "transmits path data in report" do
|
1002
|
+
expect(received_report["paths"]["root_path"]).to eq(
|
1003
|
+
"path" => root_path,
|
1004
|
+
"exists" => true,
|
1005
|
+
"type" => "directory",
|
1006
|
+
"mode" => "40755",
|
1007
|
+
"writable" => true,
|
1008
|
+
"ownership" => {
|
1009
|
+
"uid" => Process.uid,
|
1010
|
+
"user" => process_user,
|
1011
|
+
"gid" => Process.gid,
|
1012
|
+
"group" => process_group
|
1013
|
+
}
|
1014
|
+
)
|
1015
|
+
end
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
describe "ownership" do
|
708
1019
|
context "when a directory is owned by the current user" do
|
709
1020
|
let(:root_path) { File.join(tmp_dir, "owned_path") }
|
710
1021
|
before { run_within_dir root_path }
|
711
1022
|
|
712
1023
|
it "outputs ownership" do
|
713
1024
|
expect(output).to include \
|
714
|
-
%(
|
1025
|
+
%(Root path\n Path: "#{root_path}"\n Writable?: true\n ) \
|
715
1026
|
"Ownership?: true (file: #{process_user}:#{Process.uid}, "\
|
716
1027
|
"process: #{process_user}:#{Process.uid})"
|
717
1028
|
end
|
718
1029
|
|
719
1030
|
it "transmits path data in report" do
|
1031
|
+
mode = ENV["RUNNING_IN_CI"] ? "40775" : "40755"
|
720
1032
|
expect(received_report["paths"]["root_path"]).to eq(
|
721
1033
|
"path" => root_path,
|
722
|
-
"configured" => true,
|
723
1034
|
"exists" => true,
|
1035
|
+
"type" => "directory",
|
1036
|
+
"mode" => mode,
|
724
1037
|
"writable" => true,
|
725
|
-
"ownership" => {
|
1038
|
+
"ownership" => {
|
1039
|
+
"uid" => Process.uid,
|
1040
|
+
"user" => process_user,
|
1041
|
+
"gid" => Process.gid,
|
1042
|
+
"group" => process_group
|
1043
|
+
}
|
726
1044
|
)
|
727
1045
|
end
|
728
1046
|
end
|
@@ -738,228 +1056,80 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
738
1056
|
|
739
1057
|
it "outputs no ownership" do
|
740
1058
|
expect(output).to include \
|
741
|
-
%(
|
1059
|
+
%(Root path\n Path: "#{root_path}"\n Writable?: true\n ) \
|
742
1060
|
"Ownership?: false (file: root:0, process: #{process_user}:#{Process.uid})"
|
743
1061
|
end
|
744
1062
|
end
|
745
1063
|
end
|
746
|
-
|
747
|
-
describe "working_dir" do
|
748
|
-
let(:root_path) { tmp_dir }
|
749
|
-
let(:config) { Appsignal::Config.new(root_path, "production") }
|
750
|
-
before { run_within_dir root_path }
|
751
|
-
|
752
|
-
it "outputs current path" do
|
753
|
-
expect(output).to include %(working_dir: "#{tmp_dir}"\n Writable?: true)
|
754
|
-
end
|
755
|
-
|
756
|
-
it "transmits path data in report" do
|
757
|
-
expect(received_report["paths"]["working_dir"]).to eq(
|
758
|
-
"path" => tmp_dir,
|
759
|
-
"configured" => true,
|
760
|
-
"exists" => true,
|
761
|
-
"writable" => true,
|
762
|
-
"ownership" => { "uid" => Process.uid, "user" => process_user }
|
763
|
-
)
|
764
|
-
end
|
765
|
-
end
|
766
|
-
|
767
|
-
describe "root_path" do
|
768
|
-
let(:system_tmp_log_file) { File.join(system_tmp_dir, "appsignal.log") }
|
769
|
-
let(:config) { Appsignal::Config.new(root_path, "production") }
|
770
|
-
|
771
|
-
context "when not writable" do
|
772
|
-
let(:root_path) { File.join(tmp_dir, "not_writable_path") }
|
773
|
-
before do
|
774
|
-
FileUtils.chmod(0o555, root_path)
|
775
|
-
run_within_dir root_path
|
776
|
-
end
|
777
|
-
|
778
|
-
it "outputs not writable root path" do
|
779
|
-
expect(output).to include %(root_path: "#{root_path}"\n Writable?: false)
|
780
|
-
end
|
781
|
-
|
782
|
-
it "log files fall back on system tmp directory" do
|
783
|
-
expect(output).to include \
|
784
|
-
%(log_dir_path: "#{system_tmp_dir}"\n Writable?: true),
|
785
|
-
%(log_file_path: "#{system_tmp_log_file}"\n Exists?: false)
|
786
|
-
end
|
787
|
-
|
788
|
-
it "transmits path data in report" do
|
789
|
-
expect(received_report["paths"]["root_path"]).to eq(
|
790
|
-
"path" => root_path,
|
791
|
-
"configured" => true,
|
792
|
-
"exists" => true,
|
793
|
-
"writable" => false,
|
794
|
-
"ownership" => { "uid" => Process.uid, "user" => process_user }
|
795
|
-
)
|
796
|
-
end
|
797
|
-
end
|
798
|
-
|
799
|
-
context "when writable" do
|
800
|
-
let(:root_path) { File.join(tmp_dir, "writable_path") }
|
801
|
-
|
802
|
-
context "without log dir" do
|
803
|
-
before do
|
804
|
-
FileUtils.chmod(0o777, root_path)
|
805
|
-
run_within_dir root_path
|
806
|
-
end
|
807
|
-
|
808
|
-
it "outputs writable root path" do
|
809
|
-
expect(output).to include %(root_path: "#{root_path}"\n Writable?: true)
|
810
|
-
end
|
811
|
-
|
812
|
-
it "log files fall back on system tmp directory" do
|
813
|
-
expect(output).to include \
|
814
|
-
%(log_dir_path: "#{system_tmp_dir}"\n Writable?: true),
|
815
|
-
%(log_file_path: "#{system_tmp_log_file}"\n Exists?: false)
|
816
|
-
end
|
817
|
-
|
818
|
-
it "transmits path data in report" do
|
819
|
-
expect(received_report["paths"]["root_path"]).to eq(
|
820
|
-
"path" => root_path,
|
821
|
-
"configured" => true,
|
822
|
-
"exists" => true,
|
823
|
-
"writable" => true,
|
824
|
-
"ownership" => { "uid" => Process.uid, "user" => process_user }
|
825
|
-
)
|
826
|
-
end
|
827
|
-
end
|
828
|
-
|
829
|
-
context "with log dir" do
|
830
|
-
let(:log_dir) { File.join(root_path, "log") }
|
831
|
-
let(:log_file) { File.join(log_dir, "appsignal.log") }
|
832
|
-
before { FileUtils.mkdir_p(log_dir) }
|
833
|
-
|
834
|
-
context "when not writable" do
|
835
|
-
before do
|
836
|
-
FileUtils.chmod(0o444, log_dir)
|
837
|
-
run_within_dir root_path
|
838
|
-
end
|
839
|
-
|
840
|
-
it "log files fall back on system tmp directory" do
|
841
|
-
expect(output).to include \
|
842
|
-
%(log_dir_path: "#{system_tmp_dir}"\n Writable?: true),
|
843
|
-
%(log_file_path: "#{system_tmp_log_file}"\n Exists?: false)
|
844
|
-
end
|
845
|
-
|
846
|
-
it "transmits path data in report" do
|
847
|
-
expect(received_report["paths"]["log_dir_path"]).to be_kind_of(Hash)
|
848
|
-
expect(received_report["paths"]["log_file_path"]).to be_kind_of(Hash)
|
849
|
-
end
|
850
|
-
end
|
851
|
-
|
852
|
-
context "when writable" do
|
853
|
-
context "without log file" do
|
854
|
-
before { run_within_dir root_path }
|
855
|
-
|
856
|
-
it "outputs writable but without log file" do
|
857
|
-
expect(output).to include \
|
858
|
-
%(root_path: "#{root_path}"\n Writable?: true),
|
859
|
-
%(log_dir_path: "#{log_dir}"\n Writable?: true),
|
860
|
-
%(log_file_path: "#{log_file}"\n Exists?: false)
|
861
|
-
end
|
862
|
-
|
863
|
-
it "transmits path data in report" do
|
864
|
-
expect(received_report["paths"]["log_dir_path"]).to be_kind_of(Hash)
|
865
|
-
expect(received_report["paths"]["log_file_path"]).to be_kind_of(Hash)
|
866
|
-
end
|
867
|
-
end
|
868
|
-
|
869
|
-
context "with log file" do
|
870
|
-
context "when writable" do
|
871
|
-
before do
|
872
|
-
FileUtils.touch(log_file)
|
873
|
-
run_within_dir root_path
|
874
|
-
end
|
875
|
-
|
876
|
-
it "lists log file as writable" do
|
877
|
-
expect(output).to include %(log_file_path: "#{log_file}"\n Writable?: true)
|
878
|
-
end
|
879
|
-
|
880
|
-
it "transmits path data in report" do
|
881
|
-
expect(received_report["paths"]["log_dir_path"]).to be_kind_of(Hash)
|
882
|
-
expect(received_report["paths"]["log_file_path"]).to be_kind_of(Hash)
|
883
|
-
end
|
884
|
-
end
|
885
|
-
|
886
|
-
context "when not writable" do
|
887
|
-
before do
|
888
|
-
FileUtils.touch(log_file)
|
889
|
-
FileUtils.chmod(0o444, log_file)
|
890
|
-
run_within_dir root_path
|
891
|
-
end
|
892
|
-
|
893
|
-
it "lists log file as not writable" do
|
894
|
-
expect(output).to include %(log_file_path: "#{log_file}"\n Writable?: false)
|
895
|
-
end
|
896
|
-
|
897
|
-
it "transmits path data in report" do
|
898
|
-
expect(received_report["paths"]["log_dir_path"]).to be_kind_of(Hash)
|
899
|
-
expect(received_report["paths"]["log_file_path"]).to be_kind_of(Hash)
|
900
|
-
end
|
901
|
-
end
|
902
|
-
end
|
903
|
-
end
|
904
|
-
end
|
905
|
-
end
|
906
|
-
end
|
907
1064
|
end
|
908
1065
|
|
909
|
-
describe "
|
910
|
-
shared_examples "
|
911
|
-
let(:
|
912
|
-
let(:
|
913
|
-
before
|
914
|
-
|
915
|
-
allow(cli).to receive(:gem_path).and_return(gem_path)
|
916
|
-
end
|
917
|
-
after { FileUtils.rm_rf ext_path }
|
1066
|
+
describe "files" do
|
1067
|
+
shared_examples "diagnose file" do |shared_example_options|
|
1068
|
+
let(:parent_directory) { File.join(tmp_dir, "diagnose_files") }
|
1069
|
+
let(:file_path) { File.join(parent_directory, filename) }
|
1070
|
+
before { FileUtils.mkdir_p File.dirname(file_path) }
|
1071
|
+
after { FileUtils.rm_rf parent_directory }
|
918
1072
|
|
919
1073
|
context "when file exists" do
|
920
|
-
let(:
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
1074
|
+
let(:contents) do
|
1075
|
+
[].tap do |lines|
|
1076
|
+
(1..12).each do |i|
|
1077
|
+
lines << "log line #{i}"
|
1078
|
+
end
|
1079
|
+
end
|
926
1080
|
end
|
927
1081
|
before do
|
928
|
-
File.open
|
929
|
-
|
1082
|
+
File.open file_path, "a" do |f|
|
1083
|
+
contents.each do |line|
|
930
1084
|
f.puts line
|
931
1085
|
end
|
932
1086
|
end
|
933
1087
|
run
|
934
1088
|
end
|
935
1089
|
|
936
|
-
it "outputs
|
937
|
-
expect(output).to include(
|
938
|
-
|
1090
|
+
it "outputs file location and content" do
|
1091
|
+
expect(output).to include(
|
1092
|
+
%(Path: "#{file_path}"),
|
1093
|
+
"Contents (last 10 lines):"
|
1094
|
+
)
|
1095
|
+
expect(output).to include(*contents.last(10).join("\n"))
|
1096
|
+
expect(output).to_not include(*contents.first(2).join("\n"))
|
939
1097
|
end
|
940
1098
|
|
941
|
-
it "transmits
|
942
|
-
expect(received_report["
|
943
|
-
"path" =>
|
1099
|
+
it "transmits file data in report" do
|
1100
|
+
expect(received_report["paths"][filename]).to match(
|
1101
|
+
"path" => file_path,
|
944
1102
|
"exists" => true,
|
945
|
-
"
|
1103
|
+
"type" => "file",
|
1104
|
+
"mode" => kind_of(String),
|
1105
|
+
"writable" => boolean,
|
1106
|
+
"ownership" => {
|
1107
|
+
"uid" => kind_of(Integer),
|
1108
|
+
"user" => kind_of(String),
|
1109
|
+
"gid" => kind_of(Integer),
|
1110
|
+
"group" => kind_of(String)
|
1111
|
+
},
|
1112
|
+
"content" => contents
|
946
1113
|
)
|
947
1114
|
end
|
948
|
-
|
949
|
-
after { FileUtils.rm_rf(gem_path) }
|
950
1115
|
end
|
951
1116
|
|
952
1117
|
context "when file does not exist" do
|
953
|
-
|
954
|
-
|
1118
|
+
before do
|
1119
|
+
if shared_example_options && shared_example_options[:stub_not_exists]
|
1120
|
+
allow(File).to receive(:exist?).and_call_original
|
1121
|
+
expect(File).to receive(:exist?).with(file_path).and_return(false)
|
1122
|
+
end
|
1123
|
+
run
|
1124
|
+
end
|
955
1125
|
|
956
|
-
it "outputs
|
957
|
-
expect(output).to include %(Path: "#{
|
1126
|
+
it "outputs file does not exists" do
|
1127
|
+
expect(output).to include %(Path: "#{file_path}"\n Exists?: false)
|
958
1128
|
end
|
959
1129
|
|
960
|
-
it "transmits
|
961
|
-
expect(received_report["
|
962
|
-
"path" =>
|
1130
|
+
it "transmits file data in report" do
|
1131
|
+
expect(received_report["paths"][filename]).to eq(
|
1132
|
+
"path" => file_path,
|
963
1133
|
"exists" => false
|
964
1134
|
)
|
965
1135
|
end
|
@@ -967,7 +1137,15 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
967
1137
|
end
|
968
1138
|
|
969
1139
|
describe "install.log" do
|
970
|
-
it_behaves_like "
|
1140
|
+
it_behaves_like "diagnose file" do
|
1141
|
+
let(:filename) { File.join("ext", "install.log") }
|
1142
|
+
before do
|
1143
|
+
expect(Bundler::CLI::Common).to receive(:select_spec)
|
1144
|
+
.with("appsignal")
|
1145
|
+
.at_least(:once)
|
1146
|
+
.and_return(double(:full_gem_path => parent_directory))
|
1147
|
+
end
|
1148
|
+
end
|
971
1149
|
|
972
1150
|
it "outputs header" do
|
973
1151
|
run
|
@@ -976,13 +1154,55 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
976
1154
|
end
|
977
1155
|
|
978
1156
|
describe "mkmf.log" do
|
979
|
-
it_behaves_like "
|
1157
|
+
it_behaves_like "diagnose file" do
|
1158
|
+
let(:filename) { File.join("ext", "mkmf.log") }
|
1159
|
+
before do
|
1160
|
+
expect(Bundler::CLI::Common).to receive(:select_spec)
|
1161
|
+
.with("appsignal")
|
1162
|
+
.at_least(:once)
|
1163
|
+
.and_return(double(:full_gem_path => parent_directory))
|
1164
|
+
end
|
1165
|
+
end
|
980
1166
|
|
981
1167
|
it "outputs header" do
|
982
1168
|
run
|
983
1169
|
expect(output).to include("Makefile install log")
|
984
1170
|
end
|
985
1171
|
end
|
1172
|
+
|
1173
|
+
describe "appsignal.log" do
|
1174
|
+
it_behaves_like "diagnose file", :stub_not_exists => true do
|
1175
|
+
let(:filename) { "appsignal.log" }
|
1176
|
+
before do
|
1177
|
+
ENV["APPSIGNAL_LOG"] = "stdout"
|
1178
|
+
expect_any_instance_of(Appsignal::Config).to receive(:log_file_path).at_least(:once).and_return(file_path)
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
it "outputs header" do
|
1183
|
+
run
|
1184
|
+
expect(output).to include("AppSignal log")
|
1185
|
+
end
|
1186
|
+
end
|
986
1187
|
end
|
987
1188
|
end
|
1189
|
+
|
1190
|
+
def expect_valid_agent_diagnostics_report(output, working_directory_stat)
|
1191
|
+
expect(output).to include \
|
1192
|
+
"Agent diagnostics",
|
1193
|
+
" Extension tests\n Configuration: valid",
|
1194
|
+
" Started: started",
|
1195
|
+
" Process user id: #{Process.uid}",
|
1196
|
+
" Process user group id: #{Process.gid}\n" \
|
1197
|
+
" Configuration: valid",
|
1198
|
+
" Logger: started",
|
1199
|
+
" Working directory user id: #{working_directory_stat.uid}",
|
1200
|
+
" Working directory user group id: #{working_directory_stat.gid}",
|
1201
|
+
" Working directory permissions: #{working_directory_stat.mode}",
|
1202
|
+
" Lock path: writable"
|
1203
|
+
end
|
1204
|
+
|
1205
|
+
def hash_with_string_keys(hash)
|
1206
|
+
Hash[hash.map { |key, value| [key.to_s, value] }]
|
1207
|
+
end
|
988
1208
|
end
|