appsignal 2.5.0.alpha.1-java
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 +7 -0
- data/.gitignore +33 -0
- data/.rspec +4 -0
- data/.rubocop.yml +66 -0
- data/.rubocop_todo.yml +124 -0
- data/.travis.yml +72 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +639 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +264 -0
- data/Rakefile +214 -0
- data/appsignal.gemspec +42 -0
- data/benchmark.rake +77 -0
- data/bin/appsignal +13 -0
- data/ext/Rakefile +27 -0
- data/ext/agent.yml +64 -0
- data/ext/appsignal_extension.c +692 -0
- data/ext/base.rb +79 -0
- data/ext/extconf.rb +35 -0
- data/gemfiles/capistrano2.gemfile +7 -0
- data/gemfiles/capistrano3.gemfile +7 -0
- data/gemfiles/grape.gemfile +7 -0
- data/gemfiles/no_dependencies.gemfile +5 -0
- data/gemfiles/padrino.gemfile +7 -0
- data/gemfiles/que.gemfile +5 -0
- data/gemfiles/rails-3.2.gemfile +6 -0
- data/gemfiles/rails-4.0.gemfile +6 -0
- data/gemfiles/rails-4.1.gemfile +6 -0
- data/gemfiles/rails-4.2.gemfile +10 -0
- data/gemfiles/rails-5.0.gemfile +5 -0
- data/gemfiles/rails-5.1.gemfile +5 -0
- data/gemfiles/resque.gemfile +12 -0
- data/gemfiles/sequel-435.gemfile +11 -0
- data/gemfiles/sequel.gemfile +11 -0
- data/gemfiles/sinatra.gemfile +6 -0
- data/gemfiles/webmachine.gemfile +5 -0
- data/lib/appsignal.rb +804 -0
- data/lib/appsignal/auth_check.rb +65 -0
- data/lib/appsignal/capistrano.rb +10 -0
- data/lib/appsignal/cli.rb +108 -0
- data/lib/appsignal/cli/demo.rb +63 -0
- data/lib/appsignal/cli/diagnose.rb +500 -0
- data/lib/appsignal/cli/helpers.rb +72 -0
- data/lib/appsignal/cli/install.rb +277 -0
- data/lib/appsignal/cli/notify_of_deploy.rb +113 -0
- data/lib/appsignal/config.rb +287 -0
- data/lib/appsignal/demo.rb +107 -0
- data/lib/appsignal/event_formatter.rb +74 -0
- data/lib/appsignal/event_formatter/action_view/render_formatter.rb +24 -0
- data/lib/appsignal/event_formatter/active_record/instantiation_formatter.rb +14 -0
- data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +14 -0
- data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +32 -0
- data/lib/appsignal/event_formatter/faraday/request_formatter.rb +19 -0
- data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +89 -0
- data/lib/appsignal/event_formatter/moped/query_formatter.rb +80 -0
- data/lib/appsignal/extension.rb +63 -0
- data/lib/appsignal/extension/jruby.rb +460 -0
- data/lib/appsignal/garbage_collection_profiler.rb +48 -0
- data/lib/appsignal/hooks.rb +105 -0
- data/lib/appsignal/hooks/action_cable.rb +113 -0
- data/lib/appsignal/hooks/active_support_notifications.rb +52 -0
- data/lib/appsignal/hooks/celluloid.rb +30 -0
- data/lib/appsignal/hooks/data_mapper.rb +18 -0
- data/lib/appsignal/hooks/delayed_job.rb +19 -0
- data/lib/appsignal/hooks/mongo_ruby_driver.rb +21 -0
- data/lib/appsignal/hooks/net_http.rb +29 -0
- data/lib/appsignal/hooks/passenger.rb +22 -0
- data/lib/appsignal/hooks/puma.rb +35 -0
- data/lib/appsignal/hooks/que.rb +21 -0
- data/lib/appsignal/hooks/rake.rb +39 -0
- data/lib/appsignal/hooks/redis.rb +30 -0
- data/lib/appsignal/hooks/sequel.rb +60 -0
- data/lib/appsignal/hooks/shoryuken.rb +43 -0
- data/lib/appsignal/hooks/sidekiq.rb +144 -0
- data/lib/appsignal/hooks/unicorn.rb +40 -0
- data/lib/appsignal/hooks/webmachine.rb +23 -0
- data/lib/appsignal/integrations/capistrano/appsignal.cap +39 -0
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +52 -0
- data/lib/appsignal/integrations/data_mapper.rb +33 -0
- data/lib/appsignal/integrations/delayed_job_plugin.rb +54 -0
- data/lib/appsignal/integrations/grape.rb +53 -0
- data/lib/appsignal/integrations/mongo_ruby_driver.rb +55 -0
- data/lib/appsignal/integrations/object.rb +35 -0
- data/lib/appsignal/integrations/padrino.rb +84 -0
- data/lib/appsignal/integrations/que.rb +43 -0
- data/lib/appsignal/integrations/railtie.rb +41 -0
- data/lib/appsignal/integrations/rake.rb +2 -0
- data/lib/appsignal/integrations/resque.rb +20 -0
- data/lib/appsignal/integrations/resque_active_job.rb +30 -0
- data/lib/appsignal/integrations/sinatra.rb +17 -0
- data/lib/appsignal/integrations/webmachine.rb +38 -0
- data/lib/appsignal/js_exception_transaction.rb +54 -0
- data/lib/appsignal/marker.rb +63 -0
- data/lib/appsignal/minutely.rb +42 -0
- data/lib/appsignal/rack/generic_instrumentation.rb +49 -0
- data/lib/appsignal/rack/js_exception_catcher.rb +70 -0
- data/lib/appsignal/rack/rails_instrumentation.rb +51 -0
- data/lib/appsignal/rack/sinatra_instrumentation.rb +99 -0
- data/lib/appsignal/rack/streaming_listener.rb +73 -0
- data/lib/appsignal/system.rb +81 -0
- data/lib/appsignal/transaction.rb +498 -0
- data/lib/appsignal/transmitter.rb +107 -0
- data/lib/appsignal/utils.rb +127 -0
- data/lib/appsignal/utils/params_sanitizer.rb +59 -0
- data/lib/appsignal/utils/query_params_sanitizer.rb +55 -0
- data/lib/appsignal/version.rb +3 -0
- data/lib/sequel/extensions/appsignal_integration.rb +3 -0
- data/resources/appsignal.yml.erb +39 -0
- data/resources/cacert.pem +3866 -0
- data/spec/.rubocop.yml +7 -0
- data/spec/lib/appsignal/auth_check_spec.rb +80 -0
- data/spec/lib/appsignal/capistrano2_spec.rb +224 -0
- data/spec/lib/appsignal/capistrano3_spec.rb +237 -0
- data/spec/lib/appsignal/cli/demo_spec.rb +67 -0
- data/spec/lib/appsignal/cli/diagnose_spec.rb +988 -0
- data/spec/lib/appsignal/cli/helpers_spec.rb +171 -0
- data/spec/lib/appsignal/cli/install_spec.rb +632 -0
- data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +168 -0
- data/spec/lib/appsignal/cli_spec.rb +56 -0
- data/spec/lib/appsignal/config_spec.rb +637 -0
- data/spec/lib/appsignal/demo_spec.rb +87 -0
- data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +44 -0
- data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +21 -0
- data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +21 -0
- data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +52 -0
- data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +21 -0
- data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +113 -0
- data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +112 -0
- data/spec/lib/appsignal/event_formatter_spec.rb +100 -0
- data/spec/lib/appsignal/extension/jruby_spec.rb +43 -0
- data/spec/lib/appsignal/extension_spec.rb +137 -0
- data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +66 -0
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +370 -0
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +92 -0
- data/spec/lib/appsignal/hooks/celluloid_spec.rb +35 -0
- data/spec/lib/appsignal/hooks/data_mapper_spec.rb +39 -0
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +358 -0
- data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +44 -0
- data/spec/lib/appsignal/hooks/net_http_spec.rb +53 -0
- data/spec/lib/appsignal/hooks/passenger_spec.rb +30 -0
- data/spec/lib/appsignal/hooks/puma_spec.rb +80 -0
- data/spec/lib/appsignal/hooks/que_spec.rb +19 -0
- data/spec/lib/appsignal/hooks/rake_spec.rb +73 -0
- data/spec/lib/appsignal/hooks/redis_spec.rb +55 -0
- data/spec/lib/appsignal/hooks/sequel_spec.rb +46 -0
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +192 -0
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +419 -0
- data/spec/lib/appsignal/hooks/unicorn_spec.rb +52 -0
- data/spec/lib/appsignal/hooks/webmachine_spec.rb +35 -0
- data/spec/lib/appsignal/hooks_spec.rb +195 -0
- data/spec/lib/appsignal/integrations/data_mapper_spec.rb +65 -0
- data/spec/lib/appsignal/integrations/grape_spec.rb +225 -0
- data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +127 -0
- data/spec/lib/appsignal/integrations/object_spec.rb +249 -0
- data/spec/lib/appsignal/integrations/padrino_spec.rb +323 -0
- data/spec/lib/appsignal/integrations/que_spec.rb +174 -0
- data/spec/lib/appsignal/integrations/railtie_spec.rb +129 -0
- data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +83 -0
- data/spec/lib/appsignal/integrations/resque_spec.rb +92 -0
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +73 -0
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +69 -0
- data/spec/lib/appsignal/js_exception_transaction_spec.rb +128 -0
- data/spec/lib/appsignal/marker_spec.rb +51 -0
- data/spec/lib/appsignal/minutely_spec.rb +50 -0
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +90 -0
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +147 -0
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +117 -0
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +213 -0
- data/spec/lib/appsignal/rack/streaming_listener_spec.rb +161 -0
- data/spec/lib/appsignal/system_spec.rb +131 -0
- data/spec/lib/appsignal/transaction_spec.rb +1146 -0
- data/spec/lib/appsignal/transmitter_spec.rb +152 -0
- data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +136 -0
- data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +192 -0
- data/spec/lib/appsignal/utils_spec.rb +150 -0
- data/spec/lib/appsignal_spec.rb +1049 -0
- data/spec/spec_helper.rb +116 -0
- data/spec/support/fixtures/containers/cgroups/docker +14 -0
- data/spec/support/fixtures/containers/cgroups/docker_systemd +8 -0
- data/spec/support/fixtures/containers/cgroups/lxc +10 -0
- data/spec/support/fixtures/containers/cgroups/no_permission +0 -0
- data/spec/support/fixtures/containers/cgroups/none +1 -0
- data/spec/support/fixtures/generated_config.yml +24 -0
- data/spec/support/fixtures/uploaded_file.txt +0 -0
- data/spec/support/helpers/api_request_helper.rb +19 -0
- data/spec/support/helpers/cli_helpers.rb +26 -0
- data/spec/support/helpers/config_helpers.rb +21 -0
- data/spec/support/helpers/dependency_helper.rb +73 -0
- data/spec/support/helpers/directory_helper.rb +27 -0
- data/spec/support/helpers/env_helpers.rb +33 -0
- data/spec/support/helpers/example_exception.rb +13 -0
- data/spec/support/helpers/example_standard_error.rb +13 -0
- data/spec/support/helpers/log_helpers.rb +22 -0
- data/spec/support/helpers/std_streams_helper.rb +66 -0
- data/spec/support/helpers/system_helpers.rb +8 -0
- data/spec/support/helpers/time_helpers.rb +11 -0
- data/spec/support/helpers/transaction_helpers.rb +37 -0
- data/spec/support/matchers/contains_log.rb +7 -0
- data/spec/support/mocks/fake_gc_profiler.rb +19 -0
- data/spec/support/mocks/mock_extension.rb +6 -0
- data/spec/support/project_fixture/config/application.rb +0 -0
- data/spec/support/project_fixture/config/appsignal.yml +32 -0
- data/spec/support/project_fixture/config/environments/development.rb +0 -0
- data/spec/support/project_fixture/config/environments/production.rb +0 -0
- data/spec/support/project_fixture/config/environments/test.rb +0 -0
- data/spec/support/project_fixture/log/.gitkeep +0 -0
- data/spec/support/rails/my_app.rb +6 -0
- data/spec/support/shared_examples/instrument.rb +43 -0
- data/spec/support/stubs/delayed_job.rb +0 -0
- metadata +483 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require "appsignal/cli"
|
|
2
|
+
|
|
3
|
+
describe Appsignal::CLI::Demo do
|
|
4
|
+
include CLIHelpers
|
|
5
|
+
|
|
6
|
+
let(:options) { {} }
|
|
7
|
+
let(:out_stream) { std_stream }
|
|
8
|
+
let(:output) { out_stream.read }
|
|
9
|
+
before(:context) { Appsignal.stop }
|
|
10
|
+
before do
|
|
11
|
+
ENV.delete("APPSIGNAL_APP_ENV")
|
|
12
|
+
ENV.delete("RAILS_ENV")
|
|
13
|
+
ENV.delete("RACK_ENV")
|
|
14
|
+
stub_api_request config, "auth"
|
|
15
|
+
end
|
|
16
|
+
after { Appsignal.config = nil }
|
|
17
|
+
|
|
18
|
+
def run
|
|
19
|
+
run_within_dir project_fixture_path
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run_within_dir(chdir)
|
|
23
|
+
Dir.chdir chdir do
|
|
24
|
+
capture_stdout(out_stream) { run_cli("demo", options) }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "without configuration" do
|
|
29
|
+
let(:config) { Appsignal::Config.new("development", tmp_dir) }
|
|
30
|
+
|
|
31
|
+
it "returns an error" do
|
|
32
|
+
expect { run_within_dir tmp_dir }.to raise_error(SystemExit)
|
|
33
|
+
|
|
34
|
+
expect(output).to include("Error: Unable to start the AppSignal agent")
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "with configuration" do
|
|
39
|
+
let(:config) { project_fixture_config }
|
|
40
|
+
before do
|
|
41
|
+
# Ignore sleeps to speed up the test
|
|
42
|
+
allow(Appsignal::Demo).to receive(:sleep)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context "without environment" do
|
|
46
|
+
it "returns an error" do
|
|
47
|
+
expect { run_within_dir tmp_dir }.to raise_error(SystemExit)
|
|
48
|
+
|
|
49
|
+
expect(output).to include("Error: Unable to start the AppSignal agent")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
context "with environment" do
|
|
54
|
+
let(:options) { { :environment => "development" } }
|
|
55
|
+
|
|
56
|
+
it "calls Appsignal::Demo transmitter" do
|
|
57
|
+
expect(Appsignal::Demo).to receive(:transmit).and_return(true)
|
|
58
|
+
run
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "outputs message" do
|
|
62
|
+
run
|
|
63
|
+
expect(output).to include("Demonstration sample data sent!")
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,988 @@
|
|
|
1
|
+
require "appsignal/cli"
|
|
2
|
+
|
|
3
|
+
describe Appsignal::CLI::Diagnose, :api_stub => true, :report => true do
|
|
4
|
+
include CLIHelpers
|
|
5
|
+
|
|
6
|
+
class DiagnosticsReportEndpoint
|
|
7
|
+
class << self
|
|
8
|
+
attr_reader :received_report
|
|
9
|
+
|
|
10
|
+
def clear_report!
|
|
11
|
+
@received_report = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def call(env)
|
|
15
|
+
@received_report = JSON.parse(env["rack.input"].read)["diagnose"]
|
|
16
|
+
[200, {}, [JSON.generate(:token => "my_support_token")]]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe ".run" do
|
|
22
|
+
let(:out_stream) { std_stream }
|
|
23
|
+
let(:output) { out_stream.read }
|
|
24
|
+
let(:config) { project_fixture_config }
|
|
25
|
+
let(:cli) { described_class }
|
|
26
|
+
let(:options) { { :environment => config.env } }
|
|
27
|
+
let(:gem_path) { Bundler::CLI::Common.select_spec("appsignal").full_gem_path.strip }
|
|
28
|
+
let(:received_report) { DiagnosticsReportEndpoint.received_report }
|
|
29
|
+
let(:process_user) { Etc.getpwuid(Process.uid).name }
|
|
30
|
+
before(:context) { Appsignal.stop }
|
|
31
|
+
before do
|
|
32
|
+
# Clear previous reports
|
|
33
|
+
DiagnosticsReportEndpoint.clear_report!
|
|
34
|
+
if cli.instance_variable_defined? :@data
|
|
35
|
+
# Because this is saved on the class rather than an instance of the
|
|
36
|
+
# class we need to clear it like this in case a certain test doesn't
|
|
37
|
+
# generate a report.
|
|
38
|
+
cli.remove_instance_variable :@data
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
if DependencyHelper.rails_present?
|
|
42
|
+
allow(Rails).to receive(:root).and_return(Pathname.new(config.root_path))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
around do |example|
|
|
46
|
+
original_stdin = $stdin
|
|
47
|
+
$stdin = StringIO.new
|
|
48
|
+
example.run
|
|
49
|
+
$stdin = original_stdin
|
|
50
|
+
end
|
|
51
|
+
before :api_stub => true do
|
|
52
|
+
stub_api_request config, "auth"
|
|
53
|
+
end
|
|
54
|
+
before :report => true do
|
|
55
|
+
send_diagnostics_report
|
|
56
|
+
stub_diagnostics_report_request.to_rack(DiagnosticsReportEndpoint)
|
|
57
|
+
end
|
|
58
|
+
before(:report => false) { dont_send_diagnostics_report }
|
|
59
|
+
after { Appsignal.config = nil }
|
|
60
|
+
|
|
61
|
+
def run
|
|
62
|
+
run_within_dir project_fixture_path
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def run_within_dir(chdir)
|
|
66
|
+
prepare_input
|
|
67
|
+
Dir.chdir chdir do
|
|
68
|
+
capture_stdout(out_stream) { cli.run(options) }
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def stub_diagnostics_report_request
|
|
73
|
+
stub_request(:post, "https://appsignal.com/diag").with(
|
|
74
|
+
:query => {
|
|
75
|
+
:api_key => config[:push_api_key],
|
|
76
|
+
:environment => config.env,
|
|
77
|
+
:gem_version => Appsignal::VERSION,
|
|
78
|
+
:hostname => config[:hostname],
|
|
79
|
+
:name => config[:name]
|
|
80
|
+
},
|
|
81
|
+
:headers => { "Content-Type" => "application/json; charset=UTF-8" }
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def send_diagnostics_report
|
|
86
|
+
set_input "y"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def dont_send_diagnostics_report
|
|
90
|
+
set_input "n"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "outputs header and support text" do
|
|
94
|
+
run
|
|
95
|
+
expect(output).to include \
|
|
96
|
+
"AppSignal diagnose",
|
|
97
|
+
"http://docs.appsignal.com/",
|
|
98
|
+
"support@appsignal.com"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe "report" do
|
|
102
|
+
context "when user wants to send report" do
|
|
103
|
+
it "sends report" do
|
|
104
|
+
run
|
|
105
|
+
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."
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "outputs the support token from the server" do
|
|
111
|
+
run
|
|
112
|
+
expect(output).to include "Your support token: my_support_token"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
context "when server response is invalid" do
|
|
116
|
+
before do
|
|
117
|
+
stub_diagnostics_report_request
|
|
118
|
+
.to_return(:status => 200, :body => %({ foo: "Invalid json", a: }))
|
|
119
|
+
run
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "outputs the server response in full" do
|
|
123
|
+
expect(output).to include "Error: Couldn't decode server response.",
|
|
124
|
+
%({ foo: "Invalid json", a: })
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
context "when server returns an error" do
|
|
129
|
+
before do
|
|
130
|
+
stub_diagnostics_report_request
|
|
131
|
+
.to_return(:status => 500, :body => "report: server error")
|
|
132
|
+
run
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "outputs the server response in full" do
|
|
136
|
+
expect(output).to include "report: server error"
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
context "when user doesn't want to send report", :report => false do
|
|
142
|
+
it "does not send report" do
|
|
143
|
+
run
|
|
144
|
+
expect(output).to include "Diagnostics report",
|
|
145
|
+
"Send diagnostics report to AppSignal? (Y/n): ",
|
|
146
|
+
"Not sending diagnostics information to AppSignal."
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
describe "agent information" do
|
|
152
|
+
before { run }
|
|
153
|
+
|
|
154
|
+
it "outputs version numbers" do
|
|
155
|
+
expect(output).to include \
|
|
156
|
+
"Gem version: #{Appsignal::VERSION}",
|
|
157
|
+
"Agent version: #{Appsignal::Extension.agent_version}",
|
|
158
|
+
"Agent architecture: #{Appsignal::System.installed_agent_architecture}",
|
|
159
|
+
"Gem install path: #{gem_path}"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "transmits version numbers in report" do
|
|
163
|
+
expect(received_report).to include(
|
|
164
|
+
"library" => {
|
|
165
|
+
"language" => "ruby",
|
|
166
|
+
"package_version" => Appsignal::VERSION,
|
|
167
|
+
"agent_version" => Appsignal::Extension.agent_version,
|
|
168
|
+
"agent_architecture" => Appsignal::System.installed_agent_architecture,
|
|
169
|
+
"package_install_path" => gem_path,
|
|
170
|
+
"extension_loaded" => true
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
context "with extension" do
|
|
176
|
+
before { run }
|
|
177
|
+
|
|
178
|
+
it "outputs extension is loaded" do
|
|
179
|
+
expect(output).to include "Extension loaded: true"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it "transmits extension_loaded: true in report" do
|
|
183
|
+
expect(received_report["library"]["extension_loaded"]).to eq(true)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
context "without extension" do
|
|
188
|
+
before do
|
|
189
|
+
# When the extension isn't loaded the Appsignal.start operation exits
|
|
190
|
+
# early and doesn't load the configuration.
|
|
191
|
+
# Happens when the extension wasn't installed properly.
|
|
192
|
+
Appsignal.extension_loaded = false
|
|
193
|
+
run
|
|
194
|
+
end
|
|
195
|
+
after { Appsignal.extension_loaded = true }
|
|
196
|
+
|
|
197
|
+
it "outputs extension is not loaded" do
|
|
198
|
+
expect(output).to include "Extension loaded: false"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "transmits extension_loaded: false in report" do
|
|
202
|
+
expect(received_report["library"]["extension_loaded"]).to eq(false)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
describe "agent diagnostics" do
|
|
208
|
+
it "starts the agent in diagnose mode and outputs the report" do
|
|
209
|
+
run
|
|
210
|
+
expect(output).to include \
|
|
211
|
+
"Agent diagnostics",
|
|
212
|
+
" Extension config: valid",
|
|
213
|
+
" Agent config: valid",
|
|
214
|
+
" Agent logger: started",
|
|
215
|
+
" Agent lock path: writable"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
it "adds the agent diagnostics to the report" do
|
|
219
|
+
run
|
|
220
|
+
expect(received_report["agent"]).to eq(
|
|
221
|
+
"extension" => {
|
|
222
|
+
"config" => { "valid" => { "result" => true } }
|
|
223
|
+
},
|
|
224
|
+
"agent" => {
|
|
225
|
+
"boot" => { "started" => { "result" => true } },
|
|
226
|
+
"config" => { "valid" => { "result" => true } },
|
|
227
|
+
"logger" => { "started" => { "result" => true } },
|
|
228
|
+
"lock_path" => { "created" => { "result" => true } }
|
|
229
|
+
}
|
|
230
|
+
)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
context "when user config has active: false" do
|
|
234
|
+
before do
|
|
235
|
+
# ENV is leading so easiest to set in test to force user config with active: false
|
|
236
|
+
ENV["APPSIGNAL_ACTIVE"] = "false"
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it "force starts the agent in diagnose mode and outputs a log" do
|
|
240
|
+
run
|
|
241
|
+
expect(output).to include("active: false")
|
|
242
|
+
expect(output).to include \
|
|
243
|
+
"Agent diagnostics",
|
|
244
|
+
" Extension config: valid",
|
|
245
|
+
" Agent started: started",
|
|
246
|
+
" Agent config: valid",
|
|
247
|
+
" Agent logger: started",
|
|
248
|
+
" Agent lock path: writable"
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
context "when the extention returns invalid JSON" do
|
|
253
|
+
before do
|
|
254
|
+
expect(Appsignal::Extension).to receive(:diagnose).and_return("invalid agent\njson")
|
|
255
|
+
run
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
it "prints a JSON parse error and prints the returned value" do
|
|
259
|
+
expect(output).to include \
|
|
260
|
+
"Agent diagnostics",
|
|
261
|
+
" Error while parsing agent diagnostics report:",
|
|
262
|
+
" Output: invalid agent\njson"
|
|
263
|
+
expect(output).to match(/Error:( \d+:)? unexpected token at 'invalid agent\njson'/)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it "adds the output to the report" do
|
|
267
|
+
expect(received_report["agent"]["error"])
|
|
268
|
+
.to match(/unexpected token at 'invalid agent\njson'/)
|
|
269
|
+
expect(received_report["agent"]["output"]).to eq(["invalid agent", "json"])
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
context "when the extension is not loaded" do
|
|
274
|
+
before do
|
|
275
|
+
DiagnosticsReportEndpoint.clear_report!
|
|
276
|
+
expect(Appsignal).to receive(:extension_loaded?).and_return(false)
|
|
277
|
+
run
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it "prints a warning" do
|
|
281
|
+
expect(output).to include \
|
|
282
|
+
"Agent diagnostics",
|
|
283
|
+
" Extension is not loaded. No agent report created."
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
it "adds the output to the report" do
|
|
287
|
+
expect(received_report["agent"]).to be_nil
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
context "when the report contains an error" do
|
|
292
|
+
let(:agent_report) do
|
|
293
|
+
{ "error" => "fatal error" }
|
|
294
|
+
end
|
|
295
|
+
before do
|
|
296
|
+
expect(Appsignal::Extension).to receive(:diagnose).and_return(JSON.generate(agent_report))
|
|
297
|
+
run
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
it "prints an error for the entire report" do
|
|
301
|
+
expect(output).to include "Agent diagnostics\n Error: fatal error"
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
it "adds the error to the report" do
|
|
305
|
+
expect(received_report["agent"]).to eq(agent_report)
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
context "when the report is incomplete (agent failed to start)" do
|
|
310
|
+
let(:agent_report) do
|
|
311
|
+
{
|
|
312
|
+
"extension" => {
|
|
313
|
+
"config" => { "valid" => { "result" => false } }
|
|
314
|
+
}
|
|
315
|
+
# missing agent section
|
|
316
|
+
}
|
|
317
|
+
end
|
|
318
|
+
before do
|
|
319
|
+
expect(Appsignal::Extension).to receive(:diagnose).and_return(JSON.generate(agent_report))
|
|
320
|
+
run
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it "prints the tests, but shows a dash `-` for missed results" do
|
|
324
|
+
expect(output).to include \
|
|
325
|
+
"Agent diagnostics",
|
|
326
|
+
" Extension config: invalid",
|
|
327
|
+
" Agent started: -",
|
|
328
|
+
" Agent config: -",
|
|
329
|
+
" Agent logger: -",
|
|
330
|
+
" Agent lock path: -"
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it "adds the output to the report" do
|
|
334
|
+
expect(received_report["agent"]).to eq(agent_report)
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
context "when a test contains an error" do
|
|
339
|
+
let(:agent_report) do
|
|
340
|
+
{
|
|
341
|
+
"extension" => {
|
|
342
|
+
"config" => { "valid" => { "result" => true } }
|
|
343
|
+
},
|
|
344
|
+
"agent" => {
|
|
345
|
+
"boot" => {
|
|
346
|
+
"started" => { "result" => false, "error" => "some-error" }
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
end
|
|
351
|
+
before do
|
|
352
|
+
expect(Appsignal::Extension).to receive(:diagnose).and_return(JSON.generate(agent_report))
|
|
353
|
+
run
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
it "prints the error and output" do
|
|
357
|
+
expect(output).to include \
|
|
358
|
+
"Agent diagnostics",
|
|
359
|
+
" Extension config: valid",
|
|
360
|
+
" Agent started: not started\n Error: some-error"
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
it "adds the agent report to the diagnostics report" do
|
|
364
|
+
expect(received_report["agent"]).to eq(agent_report)
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
context "when a test contains command output" do
|
|
369
|
+
let(:agent_report) do
|
|
370
|
+
{
|
|
371
|
+
"extension" => {
|
|
372
|
+
"config" => { "valid" => { "result" => true } }
|
|
373
|
+
},
|
|
374
|
+
"agent" => {
|
|
375
|
+
"config" => { "valid" => { "result" => false, "output" => "some output" } }
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
it "prints the command output" do
|
|
381
|
+
expect(Appsignal::Extension).to receive(:diagnose).and_return(JSON.generate(agent_report))
|
|
382
|
+
run
|
|
383
|
+
expect(output).to include \
|
|
384
|
+
"Agent diagnostics",
|
|
385
|
+
" Extension config: valid",
|
|
386
|
+
" Agent config: invalid\n Output: some output"
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
describe "host information" do
|
|
392
|
+
let(:rbconfig) { RbConfig::CONFIG }
|
|
393
|
+
let(:language_version) { "#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}" }
|
|
394
|
+
|
|
395
|
+
it "outputs host information" do
|
|
396
|
+
run
|
|
397
|
+
expect(output).to include \
|
|
398
|
+
"Host information",
|
|
399
|
+
"Architecture: #{rbconfig["host_cpu"]}",
|
|
400
|
+
"Operating System: #{rbconfig["host_os"]}",
|
|
401
|
+
"Ruby version: #{language_version}"
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
context "when on Microsoft Windows" do
|
|
405
|
+
before do
|
|
406
|
+
expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("mingw32")
|
|
407
|
+
expect(RbConfig::CONFIG).to receive(:[]).at_least(:once).and_call_original
|
|
408
|
+
expect(Gem).to receive(:win_platform?).and_return(true)
|
|
409
|
+
run
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
it "adds the arch to the report" do
|
|
413
|
+
expect(received_report["host"]["os"]).to eq("mingw32")
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it "prints warning that Microsoft Windows is not supported" do
|
|
417
|
+
expect(output).to match(/Operating System: .+ \(Microsoft Windows is not supported\.\)/)
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
it "transmits host information in report" do
|
|
422
|
+
run
|
|
423
|
+
host_report = received_report["host"]
|
|
424
|
+
host_report.delete("running_in_container") # Tested elsewhere
|
|
425
|
+
expect(host_report).to eq(
|
|
426
|
+
"architecture" => rbconfig["host_cpu"],
|
|
427
|
+
"os" => rbconfig["host_os"],
|
|
428
|
+
"language_version" => language_version,
|
|
429
|
+
"heroku" => false,
|
|
430
|
+
"root" => false
|
|
431
|
+
)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
describe "root user detection" do
|
|
435
|
+
context "when not root user" do
|
|
436
|
+
it "outputs false" do
|
|
437
|
+
run
|
|
438
|
+
expect(output).to include "root user: false"
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
it "transmits root: false in report" do
|
|
442
|
+
run
|
|
443
|
+
expect(received_report["host"]["root"]).to eq(false)
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
context "when root user" do
|
|
448
|
+
before do
|
|
449
|
+
allow(Process).to receive(:uid).and_return(0)
|
|
450
|
+
run
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
it "outputs true, with warning" do
|
|
454
|
+
expect(output).to include "root user: true (not recommended)"
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
it "transmits root: true in report" do
|
|
458
|
+
expect(received_report["host"]["root"]).to eq(true)
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
describe "Heroku detection" do
|
|
464
|
+
context "when not on Heroku" do
|
|
465
|
+
before { run }
|
|
466
|
+
|
|
467
|
+
it "does not output Heroku detection" do
|
|
468
|
+
expect(output).to_not include("Heroku:")
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
it "transmits heroku: false in report" do
|
|
472
|
+
expect(received_report["host"]["heroku"]).to eq(false)
|
|
473
|
+
end
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
context "when on Heroku" do
|
|
477
|
+
before { recognize_as_heroku { run } }
|
|
478
|
+
|
|
479
|
+
it "outputs Heroku detection" do
|
|
480
|
+
expect(output).to include("Heroku: true")
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
it "transmits heroku: true in report" do
|
|
484
|
+
expect(received_report["host"]["heroku"]).to eq(true)
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
describe "container detection" do
|
|
490
|
+
context "when not in container" do
|
|
491
|
+
before do
|
|
492
|
+
allow(Appsignal::Extension).to receive(:running_in_container?).and_return(false)
|
|
493
|
+
run
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
it "outputs: false" do
|
|
497
|
+
expect(output).to include("Running in container: false")
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
it "transmits running_in_container: false in report" do
|
|
501
|
+
expect(received_report["host"]["running_in_container"]).to eq(false)
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
context "when in container" do
|
|
506
|
+
before do
|
|
507
|
+
allow(Appsignal::Extension).to receive(:running_in_container?).and_return(true)
|
|
508
|
+
run
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
it "outputs: true" do
|
|
512
|
+
expect(output).to include("Running in container: true")
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
it "transmits running_in_container: true in report" do
|
|
516
|
+
expect(received_report["host"]["running_in_container"]).to eq(true)
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
describe "configuration" do
|
|
523
|
+
context "without environment" do
|
|
524
|
+
let(:config) { project_fixture_config(nil) }
|
|
525
|
+
let(:options) { {} }
|
|
526
|
+
before do
|
|
527
|
+
ENV.delete("RAILS_ENV") # From spec_helper
|
|
528
|
+
ENV.delete("RACK_ENV")
|
|
529
|
+
run_within_dir tmp_dir
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
it "outputs a warning that no config is loaded" do
|
|
533
|
+
expect(output).to include \
|
|
534
|
+
"Environment: \n Warning: No environment set, no config loaded!",
|
|
535
|
+
" appsignal diagnose --environment=production"
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
it "outputs config defaults" do
|
|
539
|
+
expect(output).to include("Configuration")
|
|
540
|
+
Appsignal::Config::DEFAULT_CONFIG.each do |key, value|
|
|
541
|
+
expect(output).to include("#{key}: #{value}")
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
context "with configured environment" do
|
|
547
|
+
before { run }
|
|
548
|
+
|
|
549
|
+
it "outputs environment" do
|
|
550
|
+
expect(output).to include("Environment: production")
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
it "outputs configuration" do
|
|
554
|
+
expect(output).to include("Configuration")
|
|
555
|
+
Appsignal.config.config_hash.each do |key, value|
|
|
556
|
+
expect(output).to include("#{key}: #{value}")
|
|
557
|
+
end
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
context "with unconfigured environment" do
|
|
562
|
+
let(:config) { project_fixture_config("foobar") }
|
|
563
|
+
before { run_within_dir tmp_dir }
|
|
564
|
+
|
|
565
|
+
it "outputs environment" do
|
|
566
|
+
expect(output).to include("Environment: foobar")
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
it "outputs config defaults" do
|
|
570
|
+
expect(output).to include("Configuration")
|
|
571
|
+
Appsignal::Config::DEFAULT_CONFIG.each do |key, value|
|
|
572
|
+
expect(output).to include("#{key}: #{value}")
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
describe "API key validation", :api_stub => false do
|
|
579
|
+
context "with valid key" do
|
|
580
|
+
before do
|
|
581
|
+
stub_api_request(config, "auth").to_return(:status => 200)
|
|
582
|
+
run
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
it "outputs valid" do
|
|
586
|
+
expect(output).to include "Validation",
|
|
587
|
+
"Validating Push API key: valid"
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
it "transmits validation in report" do
|
|
591
|
+
expect(received_report).to include(
|
|
592
|
+
"validation" => {
|
|
593
|
+
"push_api_key" => "valid"
|
|
594
|
+
}
|
|
595
|
+
)
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
context "with invalid key" do
|
|
600
|
+
before do
|
|
601
|
+
stub_api_request(config, "auth").to_return(:status => 401)
|
|
602
|
+
run
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
it "outputs invalid" do
|
|
606
|
+
expect(output).to include "Validation",
|
|
607
|
+
"Validating Push API key: invalid"
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
it "transmits validation in report" do
|
|
611
|
+
expect(received_report).to include(
|
|
612
|
+
"validation" => {
|
|
613
|
+
"push_api_key" => "invalid"
|
|
614
|
+
}
|
|
615
|
+
)
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
context "with invalid key" do
|
|
620
|
+
before do
|
|
621
|
+
stub_api_request(config, "auth").to_return(:status => 500)
|
|
622
|
+
run
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
it "outputs failure with status code" do
|
|
626
|
+
expect(output).to include "Validation",
|
|
627
|
+
"Validating Push API key: Failed with status 500\n" +
|
|
628
|
+
%("Could not confirm authorization: 500")
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
it "transmits validation in report" do
|
|
632
|
+
expect(received_report).to include(
|
|
633
|
+
"validation" => {
|
|
634
|
+
"push_api_key" => %(Failed with status 500\n\"Could not confirm authorization: 500")
|
|
635
|
+
}
|
|
636
|
+
)
|
|
637
|
+
end
|
|
638
|
+
end
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
describe "paths" do
|
|
642
|
+
let(:system_tmp_dir) { Appsignal::Config.system_tmp_dir }
|
|
643
|
+
before do
|
|
644
|
+
FileUtils.mkdir_p(root_path)
|
|
645
|
+
FileUtils.mkdir_p(system_tmp_dir)
|
|
646
|
+
end
|
|
647
|
+
after { FileUtils.rm_rf([root_path, system_tmp_dir]) }
|
|
648
|
+
|
|
649
|
+
describe "report" do
|
|
650
|
+
let(:root_path) { tmp_dir }
|
|
651
|
+
|
|
652
|
+
it "adds paths to the report" do
|
|
653
|
+
run
|
|
654
|
+
expect(received_report["paths"].keys)
|
|
655
|
+
.to match_array(%w[root_path working_dir log_dir_path log_file_path])
|
|
656
|
+
end
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
context "when a directory is not configured" do
|
|
660
|
+
let(:root_path) { File.join(tmp_dir, "writable_path") }
|
|
661
|
+
let(:config) { Appsignal::Config.new(root_path, "production", :log_file => nil) }
|
|
662
|
+
before do
|
|
663
|
+
FileUtils.mkdir_p(File.join(root_path, "log"), :mode => 0o555)
|
|
664
|
+
FileUtils.chmod(0o555, system_tmp_dir)
|
|
665
|
+
run_within_dir root_path
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
it "outputs unconfigured directory" do
|
|
669
|
+
expect(output).to include %(log_file_path: ""\n Configured?: false)
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
it "transmits path data in report" do
|
|
673
|
+
expect(received_report["paths"]["log_file_path"]).to eq(
|
|
674
|
+
"path" => nil,
|
|
675
|
+
"configured" => false,
|
|
676
|
+
"exists" => false,
|
|
677
|
+
"writable" => false
|
|
678
|
+
)
|
|
679
|
+
end
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
context "when a directory does not exist" do
|
|
683
|
+
let(:root_path) { tmp_dir }
|
|
684
|
+
let(:execution_path) { File.join(tmp_dir, "not_existing_dir") }
|
|
685
|
+
let(:config) { Appsignal::Config.new(execution_path, "production") }
|
|
686
|
+
before do
|
|
687
|
+
allow(Dir).to receive(:pwd).and_return(execution_path)
|
|
688
|
+
run_within_dir tmp_dir
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
it "outputs not existing path" do
|
|
692
|
+
expect(output).to include %(root_path: "#{execution_path}"\n Exists?: false)
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
it "transmits path data in report" do
|
|
696
|
+
expect(received_report["paths"]["root_path"]).to eq(
|
|
697
|
+
"path" => execution_path,
|
|
698
|
+
"configured" => true,
|
|
699
|
+
"exists" => false,
|
|
700
|
+
"writable" => false
|
|
701
|
+
)
|
|
702
|
+
end
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
describe "ownership" do
|
|
706
|
+
let(:config) { Appsignal::Config.new(root_path, "production") }
|
|
707
|
+
|
|
708
|
+
context "when a directory is owned by the current user" do
|
|
709
|
+
let(:root_path) { File.join(tmp_dir, "owned_path") }
|
|
710
|
+
before { run_within_dir root_path }
|
|
711
|
+
|
|
712
|
+
it "outputs ownership" do
|
|
713
|
+
expect(output).to include \
|
|
714
|
+
%(root_path: "#{root_path}"\n Writable?: true\n ) \
|
|
715
|
+
"Ownership?: true (file: #{process_user}:#{Process.uid}, "\
|
|
716
|
+
"process: #{process_user}:#{Process.uid})"
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
it "transmits path data in report" do
|
|
720
|
+
expect(received_report["paths"]["root_path"]).to eq(
|
|
721
|
+
"path" => root_path,
|
|
722
|
+
"configured" => true,
|
|
723
|
+
"exists" => true,
|
|
724
|
+
"writable" => true,
|
|
725
|
+
"ownership" => { "uid" => Process.uid, "user" => process_user }
|
|
726
|
+
)
|
|
727
|
+
end
|
|
728
|
+
end
|
|
729
|
+
|
|
730
|
+
context "when a directory is not owned by the current user" do
|
|
731
|
+
let(:root_path) { File.join(tmp_dir, "not_owned_path") }
|
|
732
|
+
before do
|
|
733
|
+
stat = File.stat(root_path)
|
|
734
|
+
allow(stat).to receive(:uid).and_return(0)
|
|
735
|
+
allow(File).to receive(:stat).and_return(stat)
|
|
736
|
+
run_within_dir root_path
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
it "outputs no ownership" do
|
|
740
|
+
expect(output).to include \
|
|
741
|
+
%(root_path: "#{root_path}"\n Writable?: true\n ) \
|
|
742
|
+
"Ownership?: false (file: root:0, process: #{process_user}:#{Process.uid})"
|
|
743
|
+
end
|
|
744
|
+
end
|
|
745
|
+
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
|
+
end
|
|
908
|
+
|
|
909
|
+
describe "logs" do
|
|
910
|
+
shared_examples "ext log file" do |log_file|
|
|
911
|
+
let(:ext_path) { File.join(gem_path, "ext") }
|
|
912
|
+
let(:log_path) { File.join(ext_path, log_file) }
|
|
913
|
+
before do
|
|
914
|
+
FileUtils.mkdir_p ext_path
|
|
915
|
+
allow(cli).to receive(:gem_path).and_return(gem_path)
|
|
916
|
+
end
|
|
917
|
+
after { FileUtils.rm_rf ext_path }
|
|
918
|
+
|
|
919
|
+
context "when file exists" do
|
|
920
|
+
let(:gem_path) { File.join(tmp_dir, "gem") }
|
|
921
|
+
let(:log_content) do
|
|
922
|
+
[
|
|
923
|
+
"log line 1",
|
|
924
|
+
"log line 2"
|
|
925
|
+
]
|
|
926
|
+
end
|
|
927
|
+
before do
|
|
928
|
+
File.open log_path, "a" do |f|
|
|
929
|
+
log_content.each do |line|
|
|
930
|
+
f.puts line
|
|
931
|
+
end
|
|
932
|
+
end
|
|
933
|
+
run
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
it "outputs install.log" do
|
|
937
|
+
expect(output).to include(%(Path: "#{log_path}"))
|
|
938
|
+
expect(output).to include(*log_content)
|
|
939
|
+
end
|
|
940
|
+
|
|
941
|
+
it "transmits log data in report" do
|
|
942
|
+
expect(received_report["logs"][File.join("ext", log_file)]).to eq(
|
|
943
|
+
"path" => log_path,
|
|
944
|
+
"exists" => true,
|
|
945
|
+
"content" => log_content
|
|
946
|
+
)
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
after { FileUtils.rm_rf(gem_path) }
|
|
950
|
+
end
|
|
951
|
+
|
|
952
|
+
context "when file does not exist" do
|
|
953
|
+
let(:gem_path) { File.join(tmp_dir, "gem_without_log_files") }
|
|
954
|
+
before { run }
|
|
955
|
+
|
|
956
|
+
it "outputs install.log" do
|
|
957
|
+
expect(output).to include %(Path: "#{log_path}"\n File not found.)
|
|
958
|
+
end
|
|
959
|
+
|
|
960
|
+
it "transmits log data in report" do
|
|
961
|
+
expect(received_report["logs"][File.join("ext", log_file)]).to eq(
|
|
962
|
+
"path" => log_path,
|
|
963
|
+
"exists" => false
|
|
964
|
+
)
|
|
965
|
+
end
|
|
966
|
+
end
|
|
967
|
+
end
|
|
968
|
+
|
|
969
|
+
describe "install.log" do
|
|
970
|
+
it_behaves_like "ext log file", "install.log"
|
|
971
|
+
|
|
972
|
+
it "outputs header" do
|
|
973
|
+
run
|
|
974
|
+
expect(output).to include("Extension install log")
|
|
975
|
+
end
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
describe "mkmf.log" do
|
|
979
|
+
it_behaves_like "ext log file", "mkmf.log"
|
|
980
|
+
|
|
981
|
+
it "outputs header" do
|
|
982
|
+
run
|
|
983
|
+
expect(output).to include("Makefile install log")
|
|
984
|
+
end
|
|
985
|
+
end
|
|
986
|
+
end
|
|
987
|
+
end
|
|
988
|
+
end
|