appsignal 4.0.5 → 4.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/Rakefile +9 -9
  4. data/appsignal.gemspec +22 -1
  5. data/build_matrix.yml +2 -1
  6. data/ext/agent.rb +27 -27
  7. data/lib/appsignal/check_in/scheduler.rb +3 -4
  8. data/lib/appsignal/check_in.rb +1 -1
  9. data/lib/appsignal/config.rb +1 -3
  10. data/lib/appsignal/integrations/que.rb +8 -2
  11. data/lib/appsignal/integrations/resque.rb +1 -6
  12. data/lib/appsignal/utils/hash_sanitizer.rb +4 -0
  13. data/lib/appsignal/version.rb +1 -1
  14. metadata +2 -191
  15. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -31
  16. data/.github/ISSUE_TEMPLATE/chore.md +0 -14
  17. data/.github/workflows/ci.yml +0 -3150
  18. data/.github/workflows/create_release_from_tag.yml +0 -62
  19. data/.gitignore +0 -35
  20. data/.gitmodules +0 -3
  21. data/.rspec +0 -4
  22. data/.yardopts +0 -8
  23. data/benchmark.rake +0 -139
  24. data/gemfiles/capistrano2.gemfile +0 -6
  25. data/gemfiles/capistrano3.gemfile +0 -7
  26. data/gemfiles/dry-monitor.gemfile +0 -5
  27. data/gemfiles/grape.gemfile +0 -5
  28. data/gemfiles/hanami-2.0.gemfile +0 -7
  29. data/gemfiles/hanami-2.1.gemfile +0 -7
  30. data/gemfiles/http5.gemfile +0 -5
  31. data/gemfiles/no_dependencies.gemfile +0 -10
  32. data/gemfiles/padrino.gemfile +0 -7
  33. data/gemfiles/psych-3.gemfile +0 -5
  34. data/gemfiles/psych-4.gemfile +0 -5
  35. data/gemfiles/que.gemfile +0 -5
  36. data/gemfiles/rails-6.0.gemfile +0 -10
  37. data/gemfiles/rails-6.1.gemfile +0 -11
  38. data/gemfiles/rails-7.0.gemfile +0 -11
  39. data/gemfiles/rails-7.1.gemfile +0 -11
  40. data/gemfiles/rails-7.2.gemfile +0 -11
  41. data/gemfiles/redis-4.gemfile +0 -5
  42. data/gemfiles/redis-5.gemfile +0 -6
  43. data/gemfiles/resque-2.gemfile +0 -6
  44. data/gemfiles/sequel.gemfile +0 -10
  45. data/gemfiles/sinatra.gemfile +0 -5
  46. data/gemfiles/webmachine1.gemfile +0 -7
  47. data/gemfiles/webmachine2.gemfile +0 -6
  48. data/mono.yml +0 -16
  49. data/spec/.rubocop.yml +0 -7
  50. data/spec/lib/appsignal/auth_check_spec.rb +0 -84
  51. data/spec/lib/appsignal/capistrano2_spec.rb +0 -227
  52. data/spec/lib/appsignal/capistrano3_spec.rb +0 -284
  53. data/spec/lib/appsignal/check_in/cron_spec.rb +0 -202
  54. data/spec/lib/appsignal/check_in/scheduler_spec.rb +0 -443
  55. data/spec/lib/appsignal/cli/demo_spec.rb +0 -46
  56. data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +0 -16
  57. data/spec/lib/appsignal/cli/diagnose/utils_spec.rb +0 -86
  58. data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1553
  59. data/spec/lib/appsignal/cli/helpers_spec.rb +0 -179
  60. data/spec/lib/appsignal/cli/install_spec.rb +0 -848
  61. data/spec/lib/appsignal/cli_spec.rb +0 -56
  62. data/spec/lib/appsignal/config_spec.rb +0 -1380
  63. data/spec/lib/appsignal/demo_spec.rb +0 -83
  64. data/spec/lib/appsignal/environment_spec.rb +0 -190
  65. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +0 -60
  66. data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +0 -21
  67. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +0 -21
  68. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +0 -52
  69. data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +0 -21
  70. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +0 -84
  71. data/spec/lib/appsignal/event_formatter/rom/sql_formatter_spec.rb +0 -22
  72. data/spec/lib/appsignal/event_formatter/sequel/sql_formatter_spec.rb +0 -30
  73. data/spec/lib/appsignal/event_formatter/view_component/render_formatter_spec.rb +0 -41
  74. data/spec/lib/appsignal/event_formatter_spec.rb +0 -193
  75. data/spec/lib/appsignal/extension/jruby_spec.rb +0 -46
  76. data/spec/lib/appsignal/extension_install_failure_spec.rb +0 -20
  77. data/spec/lib/appsignal/extension_spec.rb +0 -178
  78. data/spec/lib/appsignal/garbage_collection_spec.rb +0 -98
  79. data/spec/lib/appsignal/hooks/action_cable_spec.rb +0 -345
  80. data/spec/lib/appsignal/hooks/action_mailer_spec.rb +0 -55
  81. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +0 -23
  82. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +0 -99
  83. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +0 -47
  84. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +0 -47
  85. data/spec/lib/appsignal/hooks/activejob_spec.rb +0 -650
  86. data/spec/lib/appsignal/hooks/at_exit_spec.rb +0 -105
  87. data/spec/lib/appsignal/hooks/celluloid_spec.rb +0 -40
  88. data/spec/lib/appsignal/hooks/data_mapper_spec.rb +0 -40
  89. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +0 -38
  90. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +0 -83
  91. data/spec/lib/appsignal/hooks/excon_spec.rb +0 -67
  92. data/spec/lib/appsignal/hooks/gvl_spec.rb +0 -145
  93. data/spec/lib/appsignal/hooks/http_spec.rb +0 -37
  94. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +0 -46
  95. data/spec/lib/appsignal/hooks/mri_spec.rb +0 -23
  96. data/spec/lib/appsignal/hooks/net_http_spec.rb +0 -18
  97. data/spec/lib/appsignal/hooks/passenger_spec.rb +0 -30
  98. data/spec/lib/appsignal/hooks/puma_spec.rb +0 -80
  99. data/spec/lib/appsignal/hooks/que_spec.rb +0 -19
  100. data/spec/lib/appsignal/hooks/rake_spec.rb +0 -144
  101. data/spec/lib/appsignal/hooks/redis_client_spec.rb +0 -218
  102. data/spec/lib/appsignal/hooks/redis_spec.rb +0 -124
  103. data/spec/lib/appsignal/hooks/resque_spec.rb +0 -27
  104. data/spec/lib/appsignal/hooks/sequel_spec.rb +0 -44
  105. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -29
  106. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +0 -115
  107. data/spec/lib/appsignal/hooks/unicorn_spec.rb +0 -63
  108. data/spec/lib/appsignal/hooks/webmachine_spec.rb +0 -24
  109. data/spec/lib/appsignal/hooks_spec.rb +0 -124
  110. data/spec/lib/appsignal/integrations/data_mapper_spec.rb +0 -74
  111. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +0 -454
  112. data/spec/lib/appsignal/integrations/http_spec.rb +0 -111
  113. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +0 -154
  114. data/spec/lib/appsignal/integrations/net_http_spec.rb +0 -33
  115. data/spec/lib/appsignal/integrations/object_spec.rb +0 -347
  116. data/spec/lib/appsignal/integrations/puma_spec.rb +0 -150
  117. data/spec/lib/appsignal/integrations/que_spec.rb +0 -152
  118. data/spec/lib/appsignal/integrations/railtie_spec.rb +0 -457
  119. data/spec/lib/appsignal/integrations/resque_spec.rb +0 -155
  120. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +0 -165
  121. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +0 -640
  122. data/spec/lib/appsignal/integrations/webmachine_spec.rb +0 -136
  123. data/spec/lib/appsignal/loaders/grape_spec.rb +0 -12
  124. data/spec/lib/appsignal/loaders/hanami_spec.rb +0 -92
  125. data/spec/lib/appsignal/loaders/padrino_spec.rb +0 -273
  126. data/spec/lib/appsignal/loaders/sinatra_spec.rb +0 -44
  127. data/spec/lib/appsignal/loaders_spec.rb +0 -144
  128. data/spec/lib/appsignal/logger_spec.rb +0 -205
  129. data/spec/lib/appsignal/marker_spec.rb +0 -51
  130. data/spec/lib/appsignal/probes/gvl_spec.rb +0 -164
  131. data/spec/lib/appsignal/probes/mri_spec.rb +0 -162
  132. data/spec/lib/appsignal/probes/sidekiq_spec.rb +0 -333
  133. data/spec/lib/appsignal/probes_spec.rb +0 -411
  134. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +0 -370
  135. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +0 -319
  136. data/spec/lib/appsignal/rack/event_handler_spec.rb +0 -441
  137. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +0 -201
  138. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +0 -36
  139. data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +0 -38
  140. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +0 -126
  141. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +0 -217
  142. data/spec/lib/appsignal/rack_spec.rb +0 -243
  143. data/spec/lib/appsignal/sample_data_spec.rb +0 -238
  144. data/spec/lib/appsignal/span_spec.rb +0 -141
  145. data/spec/lib/appsignal/system_spec.rb +0 -126
  146. data/spec/lib/appsignal/transaction_spec.rb +0 -2111
  147. data/spec/lib/appsignal/transmitter_spec.rb +0 -198
  148. data/spec/lib/appsignal/utils/data_spec.rb +0 -166
  149. data/spec/lib/appsignal/utils/hash_sanitizer_spec.rb +0 -182
  150. data/spec/lib/appsignal/utils/integration_logger_spec.rb +0 -21
  151. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -153
  152. data/spec/lib/appsignal/utils/json_spec.rb +0 -44
  153. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +0 -192
  154. data/spec/lib/appsignal_spec.rb +0 -1919
  155. data/spec/lib/puma/appsignal_spec.rb +0 -334
  156. data/spec/spec_helper.rb +0 -173
  157. data/spec/support/fixtures/generated_config.yml +0 -24
  158. data/spec/support/fixtures/projects/broken/config/appsignal.yml +0 -1
  159. data/spec/support/fixtures/projects/valid/config/appsignal.yml +0 -57
  160. data/spec/support/fixtures/projects/valid/log/.gitkeep +0 -0
  161. data/spec/support/fixtures/projects/valid_with_rails_app/config/application.rb +0 -16
  162. data/spec/support/fixtures/projects/valid_with_rails_app/config/appsignal.yml +0 -56
  163. data/spec/support/fixtures/projects/valid_with_rails_app/config/environment.rb +0 -10
  164. data/spec/support/fixtures/projects/valid_with_rails_app/log/.gitkeep +0 -0
  165. data/spec/support/fixtures/uploaded_file.txt +0 -0
  166. data/spec/support/hanami/hanami_app.rb +0 -29
  167. data/spec/support/helpers/action_mailer_helpers.rb +0 -25
  168. data/spec/support/helpers/activejob_helpers.rb +0 -27
  169. data/spec/support/helpers/api_request_helper.rb +0 -20
  170. data/spec/support/helpers/cli_helpers.rb +0 -40
  171. data/spec/support/helpers/config_helpers.rb +0 -66
  172. data/spec/support/helpers/dependency_helper.rb +0 -150
  173. data/spec/support/helpers/directory_helper.rb +0 -27
  174. data/spec/support/helpers/env_helpers.rb +0 -41
  175. data/spec/support/helpers/environment_metdata_helper.rb +0 -16
  176. data/spec/support/helpers/example_exception.rb +0 -13
  177. data/spec/support/helpers/example_standard_error.rb +0 -13
  178. data/spec/support/helpers/loader_helper.rb +0 -21
  179. data/spec/support/helpers/log_helpers.rb +0 -36
  180. data/spec/support/helpers/rails_helper.rb +0 -28
  181. data/spec/support/helpers/std_streams_helper.rb +0 -94
  182. data/spec/support/helpers/system_helpers.rb +0 -8
  183. data/spec/support/helpers/take_at_most_helper.rb +0 -21
  184. data/spec/support/helpers/time_helpers.rb +0 -11
  185. data/spec/support/helpers/transaction_helpers.rb +0 -122
  186. data/spec/support/helpers/wait_for_helper.rb +0 -39
  187. data/spec/support/matchers/contains_log.rb +0 -26
  188. data/spec/support/matchers/have_colorized_text.rb +0 -28
  189. data/spec/support/matchers/transaction.rb +0 -200
  190. data/spec/support/mocks/appsignal_mock.rb +0 -18
  191. data/spec/support/mocks/dummy_app.rb +0 -20
  192. data/spec/support/mocks/fake_gc_profiler.rb +0 -19
  193. data/spec/support/mocks/fake_gvl_tools.rb +0 -28
  194. data/spec/support/mocks/hash_like.rb +0 -10
  195. data/spec/support/mocks/mock_probe.rb +0 -13
  196. data/spec/support/mocks/puma_mock.rb +0 -43
  197. data/spec/support/shared_examples/instrument.rb +0 -48
  198. data/spec/support/stubs/appsignal/loaders/loader_stub.rb +0 -7
  199. data/spec/support/stubs/delayed_job.rb +0 -0
  200. data/spec/support/stubs/sidekiq/api.rb +0 -4
  201. data/spec/support/testing.rb +0 -194
  202. data/support/bundler_wrapper +0 -12
  203. data/support/install_deps +0 -33
@@ -1,1553 +0,0 @@
1
- require "bundler/cli"
2
- require "bundler/cli/common"
3
- require "appsignal/cli"
4
-
5
- describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_input,
6
- :color => false do
7
- include CLIHelpers
8
-
9
- class DiagnosticsReportEndpoint
10
- class << self
11
- attr_reader :received_report
12
-
13
- def clear_report!
14
- @received_report = nil
15
- end
16
-
17
- def call(env)
18
- @received_report = JSON.parse(env["rack.input"].read)["diagnose"]
19
- [200, {}, [JSON.generate(:token => "my_support_token")]]
20
- end
21
- end
22
- end
23
-
24
- describe ".run" do
25
- let(:out_stream) { std_stream }
26
- let(:output) { out_stream.read }
27
- let(:root_path) { project_fixture_path }
28
- let(:app_name) { "TestApp" }
29
- let(:push_api_key) { "abc" }
30
- let(:environment) { "production" }
31
- let(:config) do
32
- {
33
- :root_path => root_path,
34
- :environment => environment.to_s,
35
- :name => app_name,
36
- :endpoint => Appsignal::Config::DEFAULT_CONFIG[:endpoint],
37
- :push_api_key => push_api_key,
38
- :hostname => nil
39
- }
40
- end
41
- let(:cli_class) { described_class }
42
- let(:options) { { :environment => environment } }
43
- let(:gem_path) { Bundler::CLI::Common.select_spec("appsignal").full_gem_path.strip }
44
- let(:received_report) { DiagnosticsReportEndpoint.received_report }
45
- let(:process_user) { Etc.getpwuid(Process.uid).name }
46
- let(:process_group) { Etc.getgrgid(Process.gid).name }
47
- before(:context) { Appsignal.stop }
48
- before do
49
- # Clear previous reports
50
- DiagnosticsReportEndpoint.clear_report!
51
- if cli_class.instance_variable_defined? :@data
52
- # Because this is saved on the class rather than an instance of the
53
- # class we need to clear it like this in case a certain test doesn't
54
- # generate a report.
55
- cli_class.send :remove_instance_variable, :@data
56
- end
57
-
58
- if DependencyHelper.rails_present?
59
- allow(Rails).to receive(:root).and_return(Pathname.new(config[:root_path]))
60
- end
61
- end
62
- around do |example|
63
- original_stdin = $stdin
64
- $stdin = StringIO.new
65
- example.run
66
- $stdin = original_stdin
67
- end
68
- before { clear_integration_env_vars! }
69
- before :api_stub => true do
70
- stub_api_request config, "auth"
71
- end
72
- before(:color => false) { options["no-color"] = nil }
73
- before(:color => true) { options["color"] = nil }
74
- before(:send_report => :yes_cli_input) do
75
- accept_prompt_to_send_diagnostics_report
76
- capture_diagnatics_report_request
77
- end
78
- before(:send_report => :no_cli_input) { dont_accept_prompt_to_send_diagnostics_report }
79
- before(:send_report => :yes_cli_option) do
80
- options["send-report"] = nil
81
- capture_diagnatics_report_request
82
- end
83
- before(:send_report => :no_cli_option) { options["no-send-report"] = nil }
84
-
85
- def capture_diagnatics_report_request
86
- stub_diagnostics_report_request.to_rack(DiagnosticsReportEndpoint)
87
- end
88
-
89
- def run
90
- run_within_dir project_fixture_path
91
- end
92
-
93
- def run_within_dir(chdir)
94
- prepare_cli_input
95
- Dir.chdir chdir do
96
- capture_stdout(out_stream) { run_cli("diagnose", options) }
97
- end
98
- end
99
-
100
- def stub_diagnostics_report_request
101
- stub_request(:post, "https://appsignal.com/diag").with(
102
- :query => {
103
- :api_key => config[:push_api_key],
104
- :environment => config[:environment],
105
- :gem_version => Appsignal::VERSION,
106
- :hostname => config[:hostname],
107
- :name => config[:name]
108
- },
109
- :headers => { "Content-Type" => "application/json; charset=UTF-8" }
110
- )
111
- end
112
-
113
- def accept_prompt_to_send_diagnostics_report
114
- add_cli_input "y"
115
- end
116
-
117
- def dont_accept_prompt_to_send_diagnostics_report
118
- add_cli_input "n"
119
- end
120
-
121
- it "outputs header and support text" do
122
- run
123
- expect(output).to include \
124
- "AppSignal diagnose",
125
- "https://docs.appsignal.com/",
126
- "support@appsignal.com"
127
- end
128
-
129
- it "logs to the log file" do
130
- run
131
- log_contents = File.read(Appsignal.config.log_file_path)
132
- expect(log_contents).to contains_log :info, "Starting AppSignal diagnose"
133
- end
134
-
135
- describe "report" do
136
- context "when user wants to send report" do
137
- it "sends report" do
138
- run
139
- expect(output).to include "Diagnostics report",
140
- "Send diagnostics report to AppSignal? (Y/n): "
141
- end
142
-
143
- it "outputs the support token from the server" do
144
- run
145
- expect(output).to include "Your support token: my_support_token"
146
- expect(output).to include "View this report: https://appsignal.com/diagnose/my_support_token"
147
- end
148
-
149
- context "when server response is invalid" do
150
- before do
151
- stub_diagnostics_report_request
152
- .to_return(:status => 200, :body => %({ foo: "Invalid json", a: }))
153
- run
154
- end
155
-
156
- it "outputs the server response in full" do
157
- expect(output).to include "Error: Couldn't decode server response.",
158
- %({ foo: "Invalid json", a: })
159
- end
160
- end
161
-
162
- context "when server returns an error" do
163
- before do
164
- stub_diagnostics_report_request
165
- .to_return(:status => 500, :body => "report: server error")
166
- run
167
- end
168
-
169
- it "outputs the server response in full" do
170
- expect(output).to include "report: server error"
171
- end
172
- end
173
- end
174
-
175
- context "when user uses the --send-report option", :send_report => :yes_cli_option do
176
- it "sends the report without prompting" do
177
- run
178
- expect(output).to include "Diagnostics report",
179
- "Confirmed sending report using --send-report option.",
180
- "Transmitting diagnostics report"
181
- end
182
- end
183
-
184
- context "when user uses the --no-send-report option", :send_report => :no_cli_option do
185
- it "does not send the report" do
186
- run
187
- expect(output).to include "Diagnostics report",
188
- "Not sending report. (Specified with the --no-send-report option.)",
189
- "Not sending diagnostics information to AppSignal."
190
- end
191
- end
192
-
193
- context "when user doesn't want to send report", :send_report => :no_cli_input do
194
- it "does not send report" do
195
- run
196
- expect(output).to include "Diagnostics report",
197
- "Send diagnostics report to AppSignal? (Y/n): ",
198
- "Not sending diagnostics information to AppSignal."
199
- end
200
- end
201
- end
202
-
203
- describe "agent information" do
204
- before { run }
205
-
206
- it "outputs version numbers" do
207
- expect(output).to include \
208
- "Gem version: \"#{Appsignal::VERSION}\"",
209
- "Agent version: \"#{Appsignal::Extension.agent_version}\""
210
- end
211
-
212
- it "transmits version numbers in report" do
213
- expect(received_report).to include(
214
- "library" => {
215
- "language" => "ruby",
216
- "package_version" => Appsignal::VERSION,
217
- "agent_version" => Appsignal::Extension.agent_version,
218
- "extension_loaded" => true
219
- }
220
- )
221
- end
222
-
223
- context "with extension" do
224
- before { run }
225
-
226
- it "outputs extension is loaded" do
227
- expect(output).to include "Extension loaded: true"
228
- end
229
-
230
- it "transmits extension_loaded: true in report" do
231
- expect(received_report["library"]["extension_loaded"]).to eq(true)
232
- end
233
- end
234
-
235
- context "without extension" do
236
- before do
237
- # When the extension isn't loaded the Appsignal.start operation exits
238
- # early and doesn't load the configuration.
239
- # Happens when the extension wasn't installed properly.
240
- Appsignal.extension_loaded = false
241
- run
242
- end
243
- after { Appsignal.extension_loaded = true }
244
-
245
- it "outputs extension is not loaded" do
246
- expect(output).to include "Extension loaded: false"
247
- expect(output).to include "Extension is not loaded. No agent report created."
248
- end
249
-
250
- context "with color", :color => true do
251
- it "outputs extension is not loaded in color" do
252
- expect(output).to have_colorized_text :red,
253
- " Extension is not loaded. No agent report created."
254
- end
255
- end
256
-
257
- it "transmits extension_loaded: false in report" do
258
- expect(received_report["library"]["extension_loaded"]).to eq(false)
259
- end
260
- end
261
- end
262
-
263
- describe "installation report" do
264
- let(:rbconfig) { RbConfig::CONFIG }
265
-
266
- it "adds the installation report to the diagnostics report" do
267
- run
268
- jruby = Appsignal::System.jruby?
269
- language = {
270
- "name" => "ruby",
271
- "version" => "#{RUBY_VERSION}#{"-p#{rbconfig["PATCHLEVEL"]}" unless jruby}",
272
- "implementation" => jruby ? "jruby" : "ruby"
273
- }
274
- language["implementation_version"] = JRUBY_VERSION if jruby
275
- expect(received_report["installation"]).to match(
276
- "result" => {
277
- "status" => "success"
278
- },
279
- "language" => language,
280
- "download" => {
281
- "download_url" => kind_of(String),
282
- "checksum" => "verified",
283
- "http_proxy" => nil
284
- },
285
- "build" => {
286
- "time" => kind_of(String),
287
- "package_path" => File.expand_path("../../../..", __dir__),
288
- "architecture" => Appsignal::System.agent_architecture,
289
- "target" => Appsignal::System.agent_platform,
290
- "musl_override" => false,
291
- "linux_arm_override" => false,
292
- "library_type" => jruby ? "dynamic" : "static",
293
- "source" => "remote",
294
- "dependencies" => kind_of(Hash),
295
- "flags" => kind_of(Hash),
296
- "agent_version" => Appsignal::Extension.agent_version
297
- },
298
- "host" => {
299
- "root_user" => false,
300
- "dependencies" => kind_of(Hash)
301
- }
302
- )
303
- end
304
-
305
- it "prints the extension installation report" do
306
- run
307
- jruby = Appsignal::System.jruby?
308
- expect(output).to include(
309
- "Extension installation report",
310
- "Installation result",
311
- " Status: success",
312
- "Language details",
313
- " Implementation: \"#{jruby ? "jruby" : "ruby"}\"",
314
- " Ruby version: \"#{"#{rbconfig["RUBY_PROGRAM_VERSION"]}-p#{rbconfig["PATCHLEVEL"]}"}\"",
315
- "Download details",
316
- " Download URL: \"https://",
317
- " Checksum: \"verified\"",
318
- "Build details",
319
- " Install time: \"20",
320
- " Architecture: \"#{Appsignal::System.agent_architecture}\"",
321
- " Target: \"#{Appsignal::System.agent_platform}\"",
322
- " Musl override: false",
323
- " Linux ARM override: false",
324
- " Library type: \"#{jruby ? "dynamic" : "static"}\"",
325
- " Dependencies: {",
326
- " Flags: {",
327
- "Host details",
328
- " Root user: false",
329
- " Dependencies: {"
330
- )
331
- end
332
-
333
- context "with error in install report" do
334
- let(:error) { RuntimeError.new("some error") }
335
- before do
336
- allow(File).to receive(:read).and_call_original
337
- expect(File).to receive(:read)
338
- .with(File.expand_path("../../../../ext/install.report", __dir__))
339
- .and_return(
340
- JSON.generate(
341
- "result" => {
342
- "status" => "error",
343
- "error" => "RuntimeError: some error",
344
- "backtrace" => error.backtrace
345
- }
346
- )
347
- )
348
- end
349
-
350
- it "sends an error" do
351
- run
352
- expect(received_report["installation"]).to match(
353
- "result" => {
354
- "status" => "error",
355
- "error" => "RuntimeError: some error",
356
- "backtrace" => error.backtrace
357
- }
358
- )
359
- end
360
-
361
- it "prints the error" do
362
- run
363
-
364
- expect(output).to include(
365
- "Extension installation report",
366
- "Installation result",
367
- "Status: error\n Error: RuntimeError: some error"
368
- )
369
- expect(output).to_not include("Raw report:")
370
- end
371
- end
372
-
373
- context "without install report" do
374
- let(:error) { RuntimeError.new("foo") }
375
- before do
376
- allow(File).to receive(:read).and_call_original
377
- expect(File).to receive(:read)
378
- .with(File.expand_path("../../../../ext/install.report", __dir__))
379
- .and_raise(error)
380
- end
381
-
382
- it "sends an error" do
383
- run
384
- expect(received_report["installation"]).to match(
385
- "parsing_error" => {
386
- "error" => "RuntimeError: foo",
387
- "backtrace" => error.backtrace
388
- }
389
- )
390
- end
391
-
392
- it "prints the error" do
393
- run
394
- expect(output).to include(
395
- "Extension installation report",
396
- " Error found while parsing the report.",
397
- " Error: RuntimeError: foo"
398
- )
399
- expect(output).to_not include("Raw report:")
400
- end
401
- end
402
-
403
- context "when report is invalid JSON" do
404
- let(:raw_report) { "{}-" }
405
- before do
406
- allow(File).to receive(:read).and_call_original
407
- expect(File).to receive(:read)
408
- .with(File.expand_path("../../../../ext/install.report", __dir__))
409
- .and_return(raw_report)
410
- end
411
-
412
- it "sends an error" do
413
- run
414
- expect(received_report["installation"]).to match(
415
- "parsing_error" => {
416
- "error" => kind_of(String),
417
- "backtrace" => kind_of(Array),
418
- "raw" => raw_report
419
- }
420
- )
421
- end
422
-
423
- it "prints the error" do
424
- run
425
- expect(output).to include(
426
- "Extension installation report",
427
- " Error found while parsing the report.",
428
- " Error: ",
429
- " Raw report:\n#{raw_report}"
430
- )
431
- end
432
- end
433
- end
434
-
435
- describe "agent diagnostics" do
436
- let(:working_directory_stat) { File.stat("/tmp/appsignal") }
437
-
438
- it "starts the agent in diagnose mode and outputs the report" do
439
- run
440
- working_directory_stat = File.stat("/tmp/appsignal")
441
- expect_valid_agent_diagnostics_report(output, working_directory_stat)
442
- end
443
-
444
- it "adds the agent diagnostics to the report" do
445
- run
446
- expect(received_report["agent"]).to eq(
447
- "extension" => {
448
- "config" => { "valid" => { "result" => true } }
449
- },
450
- "agent" => {
451
- "boot" => { "started" => { "result" => true } },
452
- "host" => {
453
- "uid" => { "result" => Process.uid },
454
- "gid" => { "result" => Process.gid },
455
- "running_in_container" => { "result" => Appsignal::Extension.running_in_container? }
456
- },
457
- "config" => { "valid" => { "result" => true } },
458
- "logger" => { "started" => { "result" => true } },
459
- "working_directory_stat" => {
460
- "uid" => { "result" => working_directory_stat.uid },
461
- "gid" => { "result" => working_directory_stat.gid },
462
- "mode" => { "result" => working_directory_stat.mode }
463
- },
464
- "lock_path" => { "created" => { "result" => true } }
465
- }
466
- )
467
- end
468
-
469
- context "when user config has active: false" do
470
- before do
471
- # ENV is leading so easiest to set in test to force user config with active: false
472
- ENV["APPSIGNAL_ACTIVE"] = "false"
473
- end
474
-
475
- it "force starts the agent in diagnose mode and outputs a log" do
476
- run
477
- expect(output).to include("active: false")
478
- expect_valid_agent_diagnostics_report(output, working_directory_stat)
479
- end
480
- end
481
-
482
- context "when the extension returns invalid JSON" do
483
- before do
484
- expect(Appsignal::Extension).to receive(:diagnose).and_return("invalid agent\njson")
485
- run
486
- end
487
-
488
- it "prints a JSON parse error and prints the returned value" do
489
- expect(output).to include \
490
- "Agent diagnostics",
491
- " Error while parsing agent diagnostics report:",
492
- " Output: invalid agent\njson"
493
- expect(output).to match(/Error:( \d+:)? unexpected token at 'invalid agent\njson'/)
494
- end
495
-
496
- it "adds the output to the report" do
497
- expect(received_report["agent"]["error"])
498
- .to match(/unexpected token at 'invalid agent\njson'/)
499
- expect(received_report["agent"]["output"]).to eq(["invalid agent", "json"])
500
- end
501
- end
502
-
503
- context "when the extension is not loaded" do
504
- before do
505
- DiagnosticsReportEndpoint.clear_report!
506
- expect(Appsignal).to receive(:extension_loaded?).and_return(false)
507
- run
508
- end
509
-
510
- it "prints a warning" do
511
- expect(output).to include \
512
- "Agent diagnostics",
513
- " Extension is not loaded. No agent report created."
514
- end
515
-
516
- it "adds the output to the report" do
517
- expect(received_report["agent"]).to be_nil
518
- end
519
- end
520
-
521
- context "when the report contains an error" do
522
- let(:agent_report) do
523
- { "error" => "fatal error" }
524
- end
525
- before do
526
- expect(Appsignal::Extension).to receive(:diagnose).and_return(JSON.generate(agent_report))
527
- run
528
- end
529
-
530
- it "prints an error for the entire report" do
531
- expect(output).to include "Agent diagnostics\n Error: fatal error"
532
- end
533
-
534
- it "adds the error to the report" do
535
- expect(received_report["agent"]).to eq(agent_report)
536
- end
537
- end
538
-
539
- context "when the report is incomplete (agent failed to start)" do
540
- let(:agent_report) do
541
- {
542
- "extension" => {
543
- "config" => { "valid" => { "result" => false } }
544
- }
545
- # missing agent section
546
- }
547
- end
548
- before do
549
- expect(Appsignal::Extension).to receive(:diagnose).and_return(JSON.generate(agent_report))
550
- run
551
- end
552
-
553
- it "prints the tests, but shows a dash `-` for missed results" do
554
- expect(output).to include \
555
- "Agent diagnostics",
556
- " Extension tests\n Configuration: invalid",
557
- " Agent tests",
558
- " Started: -",
559
- " Configuration: -",
560
- " Logger: -",
561
- " Lock path: -"
562
- end
563
-
564
- it "adds the output to the report" do
565
- expect(received_report["agent"]).to eq(agent_report)
566
- end
567
- end
568
-
569
- context "when a test contains an error" do
570
- let(:agent_report) do
571
- {
572
- "extension" => {
573
- "config" => { "valid" => { "result" => true } }
574
- },
575
- "agent" => {
576
- "boot" => {
577
- "started" => { "result" => false, "error" => "some-error" }
578
- }
579
- }
580
- }
581
- end
582
- before do
583
- expect(Appsignal::Extension).to receive(:diagnose).and_return(JSON.generate(agent_report))
584
- run
585
- end
586
-
587
- it "prints the error and output" do
588
- expect(output).to include \
589
- "Agent diagnostics",
590
- " Extension tests\n Configuration: valid",
591
- " Agent tests\n Started: not started\n Error: some-error"
592
- end
593
-
594
- it "adds the agent report to the diagnostics report" do
595
- expect(received_report["agent"]).to eq(agent_report)
596
- end
597
- end
598
-
599
- context "when a test contains command output" do
600
- let(:agent_report) do
601
- {
602
- "extension" => {
603
- "config" => { "valid" => { "result" => true } }
604
- },
605
- "agent" => {
606
- "config" => { "valid" => { "result" => false, "output" => "some output" } }
607
- }
608
- }
609
- end
610
-
611
- it "prints the command output" do
612
- expect(Appsignal::Extension).to receive(:diagnose).and_return(JSON.generate(agent_report))
613
- run
614
- expect(output).to include \
615
- "Agent diagnostics",
616
- " Extension tests\n Configuration: valid",
617
- " Configuration: invalid\n Output: some output"
618
- end
619
- end
620
- end
621
-
622
- describe "host information" do
623
- let(:rbconfig) { RbConfig::CONFIG }
624
- let(:language_version) { "#{rbconfig["RUBY_PROGRAM_VERSION"]}-p#{rbconfig["PATCHLEVEL"]}" }
625
-
626
- it "outputs host information" do
627
- run
628
- expect(output).to include \
629
- "Host information",
630
- "Architecture: \"#{rbconfig["host_cpu"]}\"",
631
- "Operating System: \"#{rbconfig["host_os"]}\"",
632
- "Ruby version: \"#{language_version}\""
633
- end
634
-
635
- context "when on Microsoft Windows" do
636
- before do
637
- expect(RbConfig::CONFIG).to receive(:[]).with("host_os").and_return("mingw32")
638
- expect(RbConfig::CONFIG).to receive(:[]).at_least(:once).and_call_original
639
- expect(Gem).to receive(:win_platform?).and_return(true)
640
- run
641
- end
642
-
643
- it "adds the arch to the report" do
644
- expect(received_report["host"]["os"]).to eq("mingw32")
645
- end
646
-
647
- it "prints warning that Microsoft Windows is not supported" do
648
- expect(output).to match(/Operating System: .+ \(Microsoft Windows is not supported\.\)/)
649
- end
650
- end
651
-
652
- it "transmits host information in report" do
653
- run
654
- host_report = received_report["host"]
655
- host_report.delete("running_in_container") # Tested elsewhere
656
- distribution_file = "/etc/os-release"
657
- os_distribution = File.exist?(distribution_file) ? File.read(distribution_file) : ""
658
- expect(host_report).to eq(
659
- "architecture" => rbconfig["host_cpu"],
660
- "os" => rbconfig["host_os"],
661
- "os_distribution" => os_distribution,
662
- "language_version" => language_version,
663
- "heroku" => false,
664
- "root" => false
665
- )
666
- end
667
-
668
- describe "root user detection" do
669
- context "when not root user" do
670
- it "outputs false" do
671
- run
672
- expect(output).to include "Root user: false"
673
- end
674
-
675
- it "transmits root: false in report" do
676
- run
677
- expect(received_report["host"]["root"]).to eq(false)
678
- end
679
- end
680
-
681
- context "when root user" do
682
- before do
683
- allow(Process).to receive(:uid).and_return(0)
684
- run
685
- end
686
-
687
- it "outputs true, with warning" do
688
- expect(output).to include "Root user: true (not recommended)"
689
- end
690
-
691
- it "transmits root: true in report" do
692
- expect(received_report["host"]["root"]).to eq(true)
693
- end
694
- end
695
- end
696
-
697
- describe "Heroku detection" do
698
- context "when not on Heroku" do
699
- before { run }
700
-
701
- it "does not output Heroku detection" do
702
- expect(output).to_not include("Heroku:")
703
- end
704
-
705
- it "transmits heroku: false in report" do
706
- expect(received_report["host"]["heroku"]).to eq(false)
707
- end
708
- end
709
-
710
- context "when on Heroku" do
711
- before { recognize_as_heroku { run } }
712
-
713
- it "outputs Heroku detection" do
714
- expect(output).to include("Heroku: true")
715
- end
716
-
717
- it "transmits heroku: true in report" do
718
- expect(received_report["host"]["heroku"]).to eq(true)
719
- end
720
- end
721
- end
722
-
723
- describe "container detection" do
724
- context "when not in container" do
725
- before do
726
- allow(Appsignal::Extension).to receive(:running_in_container?).and_return(false)
727
- run
728
- end
729
-
730
- it "outputs: false" do
731
- expect(output).to include("Running in container: false")
732
- end
733
-
734
- it "transmits running_in_container: false in report" do
735
- expect(received_report["host"]["running_in_container"]).to eq(false)
736
- end
737
- end
738
-
739
- context "when in container" do
740
- before do
741
- allow(Appsignal::Extension).to receive(:running_in_container?).and_return(true)
742
- run
743
- end
744
-
745
- it "outputs: true" do
746
- expect(output).to include("Running in container: true")
747
- end
748
-
749
- it "transmits running_in_container: true in report" do
750
- expect(received_report["host"]["running_in_container"]).to eq(true)
751
- end
752
- end
753
- end
754
- end
755
-
756
- describe "configuration" do
757
- context "without environment" do
758
- let(:app_name) { nil }
759
- let(:environment) { nil }
760
- let(:push_api_key) { nil }
761
- let(:options) { {} }
762
- let(:warning_message) do
763
- " Warning: No environment set, no config loaded!\n" \
764
- " Please make sure appsignal diagnose is run within your\n" \
765
- " project directory with an environment.\n" \
766
- " appsignal diagnose --environment=production"
767
- end
768
- before do
769
- ENV.delete("RAILS_ENV") # From spec_helper
770
- ENV.delete("RACK_ENV")
771
- run_within_dir tmp_dir
772
- end
773
-
774
- it "outputs a warning that no config is loaded" do
775
- expect(output).to include "environment: \"\"\n#{warning_message}"
776
- expect(output).to_not have_color_markers
777
- end
778
-
779
- context "with color", :color => true do
780
- it "outputs a warning that no config is loaded in color" do
781
- expect(output).to include "environment: \"\"\n"
782
- expect(output).to have_colorized_text :red, warning_message
783
- end
784
- end
785
-
786
- it "outputs config defaults" do
787
- expect(output).to include("Configuration")
788
- expect_config_to_be_printed(Appsignal::Config::DEFAULT_CONFIG)
789
- end
790
-
791
- it "transmits validation in report" do
792
- default_config = hash_with_string_keys(Appsignal::Config::DEFAULT_CONFIG)
793
- expect(received_report["config"]).to eq(
794
- "options" => default_config.merge("env" => "", "send_session_data" => true),
795
- "sources" => {
796
- "default" => default_config,
797
- "system" => {},
798
- "loaders" => {},
799
- "initial" => { "env" => "" },
800
- "file" => {},
801
- "env" => {},
802
- "override" => {},
803
- "dsl" => {}
804
- }
805
- )
806
- end
807
- end
808
-
809
- context "with configured environment" do
810
- describe "environment" do
811
- it "outputs environment" do
812
- run
813
- expect(output).to include(%(environment: "production"))
814
- end
815
-
816
- context "when the source is a single source" do
817
- before { run }
818
-
819
- it "outputs the label source after the value" do
820
- expect(output).to include(
821
- %(environment: "#{environment}" (Loaded from: initial)\n)
822
- )
823
- end
824
- end
825
-
826
- context "when the source is the RACK_ENV env variable", :send_report => :no_cli_option do
827
- let(:environment) { "rack_env" }
828
- let(:options) { {} }
829
- before do
830
- ENV["RACK_ENV"] = "rack_env"
831
- run
832
- end
833
- after { ENV.delete("RACK_ENV") }
834
-
835
- it "outputs the RACK_ENV variable value" do
836
- expect(output).to include(
837
- %(environment: "rack_env" (Loaded from: initial)\n)
838
- )
839
- end
840
- end
841
-
842
- context "when the source is the RAILS_ENV env variable", :send_report => :no_cli_option do
843
- let(:environment) { "rails_env" }
844
- let(:options) { {} }
845
- before do
846
- ENV["RAILS_ENV"] = "rails_env"
847
- run
848
- end
849
- after { ENV.delete("RAILS_ENV") }
850
-
851
- it "outputs the RAILS_ENV variable value" do
852
- expect(output).to include(
853
- %(environment: "rails_env" (Loaded from: initial)\n)
854
- )
855
- end
856
- end
857
-
858
- context "when the source is multiple sources" do
859
- let(:options) { { :environment => "production" } }
860
- before do
861
- ENV["APPSIGNAL_APP_ENV"] = "development"
862
- stub_api_request(config, "auth").to_return(:status => 200)
863
- capture_diagnatics_report_request
864
- run
865
- end
866
-
867
- it "outputs a list of sources with their values" do
868
- expect(output).to include(
869
- " environment: \"production\"\n" \
870
- " Sources:\n" \
871
- " initial: \"production\"\n" \
872
- " env: \"development\"\n"
873
- )
874
- end
875
- end
876
- end
877
-
878
- it "outputs configuration" do
879
- run
880
- expect(output).to include("Configuration")
881
- expect_config_to_be_printed(Appsignal.config.config_hash)
882
- end
883
-
884
- describe "option sources" do
885
- context "when the source is a single source" do
886
- before { run }
887
-
888
- it "outputs the label source after the value" do
889
- expect(output).to include(
890
- %(push_api_key: "#{Appsignal.config[:push_api_key]}" (Loaded from: file)\n)
891
- )
892
- end
893
-
894
- context "when the source is only default" do
895
- it "does not print a source" do
896
- expect(output)
897
- .to include("enable_host_metrics: #{Appsignal.config[:enable_host_metrics]}\n")
898
- end
899
- end
900
- end
901
-
902
- context "when the source is multiple sources" do
903
- let(:app_name) { "MyApp" }
904
- before do
905
- ENV["APPSIGNAL_APP_NAME"] = app_name
906
- run
907
- end
908
-
909
- it "outputs a list of sources with their values" do
910
- expect(output).to include(
911
- " name: \"MyApp\"\n" \
912
- " Sources:\n" \
913
- " file: \"TestApp\"\n" \
914
- " env: \"MyApp\"\n"
915
- )
916
- end
917
- end
918
-
919
- if DependencyHelper.rails_present?
920
- context "when is a Rails app" do
921
- let(:root_path) { rails_project_fixture_path }
922
- let(:app_name) { "TestApp" }
923
- let(:environment) { "test" }
924
- let(:options) { {} }
925
- before do
926
- # Workaround to not being able to require the railtie file
927
- # multiple times and triggering the Rails initialization process.
928
- # This will be used whtn the MyApp app has already been loaded.
929
- Appsignal::Integrations::Railtie.load_default_config if defined?(MyApp)
930
- run_within_dir(root_path)
931
- end
932
-
933
- it "includes the Rails default config in the output and transmitted report" do
934
- expect(output).to include(
935
- " name: \"TestApp\"\n" \
936
- " Sources:\n" \
937
- " loaders: \"MyApp\"\n" \
938
- " file: \"TestApp\"\n"
939
- )
940
- # Outputs values from the DSL
941
- expect(output).to include(
942
- " ignore_actions: [\"Action from DSL\"]\n" \
943
- " Sources:\n" \
944
- " default: []\n" \
945
- " dsl: [\"Action from DSL\"]\n"
946
- )
947
-
948
- expect(received_report["app"]["rails"]).to be(true)
949
- expect(received_report["config"]["sources"]).to include(
950
- "loaders" => {
951
- "root_path" => root_path,
952
- "env" => "test",
953
- "log_path" => File.join(rails_project_fixture_path, "log"),
954
- "name" => "MyApp"
955
- }
956
- )
957
- # Includes values from the DSL
958
- expect(received_report["config"]["sources"]).to include(
959
- "dsl" => {
960
- "ignore_actions" => ["Action from DSL"]
961
- }
962
- )
963
- end
964
-
965
- context "when there's a problem loading the app" do
966
- before do
967
- # A spot where we can mock an error raise
968
- expect(Appsignal::Utils::RailsHelper).to receive(:environment_config_path)
969
- .and_raise(ExampleStandardError, "error message", ["line 1", "line 2"])
970
- run_within_dir(root_path)
971
- end
972
-
973
- it "includes a load error" do
974
- expect(output).to include(
975
- "ERROR: Error encountered while loading the Rails app\n" \
976
- "ExampleStandardError: error message"
977
- )
978
-
979
- expect(received_report["app"]["load_error"])
980
- .to eq("ExampleStandardError: error message\nline 1\nline 2")
981
- end
982
- end
983
- end
984
- end
985
- end
986
-
987
- it "transmits config in report" do
988
- run
989
- final_config = Appsignal.config.config_hash
990
- .merge(:env => "production")
991
- expect(received_report["config"]).to match(
992
- "options" => hash_with_string_keys(final_config),
993
- "sources" => {
994
- "default" => hash_with_string_keys(Appsignal::Config::DEFAULT_CONFIG),
995
- "system" => {},
996
- "loaders" => {},
997
- "initial" => hash_with_string_keys(Appsignal.config.initial_config),
998
- "file" => hash_with_string_keys(Appsignal.config.file_config),
999
- "env" => {},
1000
- "override" => {},
1001
- "dsl" => {}
1002
- }
1003
- )
1004
- end
1005
- end
1006
-
1007
- context "with unconfigured environment" do
1008
- let(:app_name) { nil }
1009
- let(:push_api_key) { nil }
1010
- let(:environment) { "foobar" }
1011
- before { run_within_dir tmp_dir }
1012
-
1013
- it "outputs environment" do
1014
- expect(output).to include(%(environment: "foobar"))
1015
- end
1016
-
1017
- it "outputs config defaults" do
1018
- expect(output).to include("Configuration")
1019
- expect_config_to_be_printed(Appsignal::Config::DEFAULT_CONFIG)
1020
- end
1021
-
1022
- it "transmits config in report" do
1023
- expect(received_report["config"]).to match(
1024
- "options" => hash_with_string_keys(
1025
- Appsignal.config.config_hash.merge("env" => "foobar")
1026
- ),
1027
- "sources" => {
1028
- "default" => hash_with_string_keys(Appsignal::Config::DEFAULT_CONFIG),
1029
- "system" => {},
1030
- "loaders" => {},
1031
- "initial" => hash_with_string_keys(Appsignal.config.initial_config),
1032
- "file" => hash_with_string_keys(Appsignal.config.file_config),
1033
- "env" => {},
1034
- "override" => {},
1035
- "dsl" => {}
1036
- }
1037
- )
1038
- end
1039
- end
1040
-
1041
- def expect_config_to_be_printed(config)
1042
- nil_options = config.select { |_, v| v.nil? }
1043
- nil_options.each_key do |key|
1044
- expect(output).to include(%(#{key}: nil))
1045
- end
1046
- string_options = config.select { |_, v| v.is_a?(String) }
1047
- string_options.each do |key, value|
1048
- expect(output).to include(%(#{key}: "#{value}"))
1049
- end
1050
- other_options = config.select do |k, _|
1051
- !string_options.key?(k) && !nil_options.key?(k)
1052
- end
1053
- other_options.each do |key, value|
1054
- expect(output).to include(%(#{key}: #{value}))
1055
- end
1056
- end
1057
- end
1058
-
1059
- describe "API key validation", :api_stub => false do
1060
- context "with valid key" do
1061
- before do
1062
- stub_api_request(config, "auth").to_return(:status => 200)
1063
- run
1064
- end
1065
-
1066
- it "outputs valid" do
1067
- expect(output).to include "Validation",
1068
- "Validating Push API key: valid"
1069
- end
1070
-
1071
- context "with color", :color => true do
1072
- it "outputs valid in color" do
1073
- expect(output).to include "Validation",
1074
- "Validating Push API key: #{colorize("valid", :green)}"
1075
- end
1076
- end
1077
-
1078
- it "transmits validation in report" do
1079
- expect(received_report).to include(
1080
- "validation" => {
1081
- "push_api_key" => "valid"
1082
- }
1083
- )
1084
- end
1085
- end
1086
-
1087
- context "with invalid key" do
1088
- before do
1089
- stub_api_request(config, "auth").to_return(:status => 401)
1090
- run
1091
- end
1092
-
1093
- it "outputs invalid" do
1094
- expect(output).to include "Validation",
1095
- "Validating Push API key: invalid"
1096
- end
1097
-
1098
- context "with color", :color => true do
1099
- it "outputs invalid in color" do
1100
- expect(output).to include "Validation",
1101
- "Validating Push API key: #{colorize("invalid", :red)}"
1102
- end
1103
- end
1104
-
1105
- it "transmits validation in report" do
1106
- expect(received_report).to include(
1107
- "validation" => {
1108
- "push_api_key" => "invalid"
1109
- }
1110
- )
1111
- end
1112
- end
1113
-
1114
- context "with invalid key" do
1115
- before do
1116
- stub_api_request(config, "auth").to_return(:status => 500)
1117
- run
1118
- end
1119
-
1120
- it "outputs failure with status code" do
1121
- expect(output).to include "Validation",
1122
- "Validating Push API key: Failed to validate: status 500\n" +
1123
- %("Could not confirm authorization: 500")
1124
- end
1125
-
1126
- context "with color", :color => true do
1127
- it "outputs error in color" do
1128
- expect(output).to include "Validation",
1129
- "Validating Push API key: #{colorize(
1130
- %(Failed to validate: status 500\n"Could not confirm authorization: 500"),
1131
- :red
1132
- )}"
1133
- end
1134
- end
1135
-
1136
- it "transmits validation in report" do
1137
- expect(received_report).to include(
1138
- "validation" => {
1139
- "push_api_key" => "Failed to validate: status 500\n" +
1140
- %("Could not confirm authorization: 500")
1141
- }
1142
- )
1143
- end
1144
- end
1145
- end
1146
-
1147
- describe "paths" do
1148
- describe "report" do
1149
- it "adds paths to the report" do
1150
- run
1151
- expect(received_report["paths"].keys).to match_array(
1152
- %w[
1153
- package_install_path root_path working_dir log_dir_path
1154
- ext/mkmf.log appsignal.log
1155
- ]
1156
- )
1157
- end
1158
-
1159
- describe "working_dir" do
1160
- before { run }
1161
-
1162
- it "outputs current path" do
1163
- expect(output).to include %(Current working directory\n Path: "#{root_path}")
1164
- end
1165
-
1166
- it "transmits path data in report" do
1167
- expect(received_report["paths"]["working_dir"]).to match(
1168
- "path" => root_path,
1169
- "exists" => true,
1170
- "type" => "directory",
1171
- "mode" => kind_of(String),
1172
- "writable" => boolean,
1173
- "ownership" => {
1174
- "uid" => kind_of(Integer),
1175
- "user" => kind_of(String),
1176
- "gid" => kind_of(Integer),
1177
- "group" => kind_of(String)
1178
- }
1179
- )
1180
- end
1181
- end
1182
-
1183
- describe "root_path" do
1184
- before { run }
1185
-
1186
- it "outputs root path" do
1187
- expect(output).to include %(Root path\n Path: "#{root_path}")
1188
- end
1189
-
1190
- it "transmits path data in report" do
1191
- expect(received_report["paths"]["root_path"]).to match(
1192
- "path" => root_path,
1193
- "exists" => true,
1194
- "type" => "directory",
1195
- "mode" => kind_of(String),
1196
- "writable" => boolean,
1197
- "ownership" => {
1198
- "uid" => kind_of(Integer),
1199
- "user" => kind_of(String),
1200
- "gid" => kind_of(Integer),
1201
- "group" => kind_of(String)
1202
- }
1203
- )
1204
- end
1205
- end
1206
-
1207
- describe "package_install_path" do
1208
- before { run }
1209
-
1210
- it "outputs gem install path" do
1211
- expect(output).to match %(AppSignal gem path\n Path: "#{gem_path}")
1212
- end
1213
-
1214
- it "transmits path data in report" do
1215
- expect(received_report["paths"]["package_install_path"]).to match(
1216
- "path" => gem_path,
1217
- "exists" => true,
1218
- "type" => "directory",
1219
- "mode" => kind_of(String),
1220
- "writable" => boolean,
1221
- "ownership" => {
1222
- "uid" => kind_of(Integer),
1223
- "user" => kind_of(String),
1224
- "gid" => kind_of(Integer),
1225
- "group" => kind_of(String)
1226
- }
1227
- )
1228
- end
1229
- end
1230
-
1231
- describe "log_dir_path" do
1232
- let(:log_path) { File.dirname(Appsignal.config.log_file_path) }
1233
- before { run }
1234
-
1235
- it "outputs log directory path" do
1236
- expect(output).to match %(Log directory\n Path: "#{log_path}")
1237
- end
1238
-
1239
- it "transmits path data in report" do
1240
- expect(received_report["paths"]["log_dir_path"]).to match(
1241
- "path" => log_path,
1242
- "exists" => true,
1243
- "type" => "directory",
1244
- "mode" => kind_of(String),
1245
- "writable" => boolean,
1246
- "ownership" => {
1247
- "uid" => kind_of(Integer),
1248
- "user" => kind_of(String),
1249
- "gid" => kind_of(Integer),
1250
- "group" => kind_of(String)
1251
- }
1252
- )
1253
- end
1254
- end
1255
- end
1256
-
1257
- context "when a directory does not exist" do
1258
- let(:root_path) { tmp_dir }
1259
- let(:environment) { nil }
1260
- let(:push_api_key) { nil }
1261
- let(:app_name) { nil }
1262
- let(:options) { {} }
1263
- let(:execution_path) { File.join(tmp_dir, "not_existing_dir") }
1264
- before do
1265
- allow(Dir).to receive(:pwd).and_return(execution_path)
1266
- FileUtils.rm_rf(execution_path)
1267
- run_within_dir root_path
1268
- end
1269
-
1270
- it "outputs not existing path" do
1271
- expect(output).to include %(Root path\n Path: "#{execution_path}"\n Exists?: false)
1272
- end
1273
-
1274
- it "transmits path data in report" do
1275
- expect(received_report["paths"]["root_path"]).to eq(
1276
- "path" => execution_path,
1277
- "exists" => false
1278
- )
1279
- end
1280
- end
1281
-
1282
- context "when not writable" do
1283
- let(:root_path) { File.join(tmp_dir, "not_writable_path") }
1284
- let(:environment) { nil }
1285
- let(:push_api_key) { nil }
1286
- let(:app_name) { nil }
1287
- let(:options) { {} }
1288
- before do
1289
- FileUtils.mkdir_p(root_path)
1290
- FileUtils.chmod(0o555, root_path)
1291
- run_within_dir root_path
1292
- end
1293
-
1294
- it "outputs not writable root path" do
1295
- expect(output).to include %(Root path\n Path: "#{root_path}"\n Writable?: false)
1296
- end
1297
-
1298
- it "transmits path data in report" do
1299
- expect(received_report["paths"]["root_path"]).to eq(
1300
- "path" => root_path,
1301
- "exists" => true,
1302
- "type" => "directory",
1303
- "mode" => "40555",
1304
- "writable" => false,
1305
- "ownership" => {
1306
- "uid" => Process.uid,
1307
- "user" => process_user,
1308
- "gid" => Process.gid,
1309
- "group" => process_group
1310
- }
1311
- )
1312
- end
1313
- end
1314
-
1315
- context "when writable" do
1316
- let(:root_path) { File.join(tmp_dir, "writable_path") }
1317
- let(:environment) { nil }
1318
- let(:push_api_key) { nil }
1319
- let(:app_name) { nil }
1320
- let(:options) { {} }
1321
- before do
1322
- FileUtils.mkdir_p(root_path)
1323
- FileUtils.chmod(0o755, root_path)
1324
- run_within_dir root_path
1325
- end
1326
-
1327
- it "outputs writable root path" do
1328
- expect(output).to include %(Root path\n Path: "#{root_path}"\n Writable?: true)
1329
- end
1330
-
1331
- it "transmits path data in report" do
1332
- expect(received_report["paths"]["root_path"]).to eq(
1333
- "path" => root_path,
1334
- "exists" => true,
1335
- "type" => "directory",
1336
- "mode" => "40755",
1337
- "writable" => true,
1338
- "ownership" => {
1339
- "uid" => Process.uid,
1340
- "user" => process_user,
1341
- "gid" => Process.gid,
1342
- "group" => process_group
1343
- }
1344
- )
1345
- end
1346
- end
1347
-
1348
- describe "ownership" do
1349
- let(:environment) { nil }
1350
- let(:push_api_key) { nil }
1351
- let(:app_name) { nil }
1352
- let(:options) { {} }
1353
- before do
1354
- FileUtils.mkdir_p(root_path)
1355
- end
1356
-
1357
- context "when a directory is owned by the current user" do
1358
- let(:root_path) { File.join(tmp_dir, "owned_path") }
1359
- before { run_within_dir root_path }
1360
-
1361
- it "outputs ownership" do
1362
- expect(output).to include \
1363
- %(Root path\n Path: "#{root_path}"\n Writable?: true\n ) \
1364
- "Ownership?: true (file: #{process_user}:#{Process.uid}, " \
1365
- "process: #{process_user}:#{Process.uid})"
1366
- end
1367
-
1368
- it "transmits path data in report" do
1369
- mode = "40755"
1370
- expect(received_report["paths"]["root_path"]).to eq(
1371
- "path" => root_path,
1372
- "exists" => true,
1373
- "type" => "directory",
1374
- "mode" => mode,
1375
- "writable" => true,
1376
- "ownership" => {
1377
- "uid" => Process.uid,
1378
- "user" => process_user,
1379
- "gid" => Process.gid,
1380
- "group" => process_group
1381
- }
1382
- )
1383
- end
1384
- end
1385
-
1386
- context "when a directory is not owned by the current user" do
1387
- let(:root_path) { File.join(tmp_dir, "not_owned_path") }
1388
- before do
1389
- stat = File.stat(root_path)
1390
- allow(stat).to receive(:uid).and_return(0)
1391
- allow(File).to receive(:stat).and_return(stat)
1392
- run_within_dir root_path
1393
- end
1394
-
1395
- it "outputs no ownership" do
1396
- expect(output).to include \
1397
- %(Root path\n Path: "#{root_path}"\n Writable?: true\n ) \
1398
- "Ownership?: false (file: root:0, process: #{process_user}:#{Process.uid})"
1399
- end
1400
- end
1401
- end
1402
- end
1403
-
1404
- describe "files" do
1405
- shared_examples "diagnose file" do |shared_example_options|
1406
- let(:parent_directory) { File.join(tmp_dir, "diagnose_files") }
1407
- let(:file_path) { File.join(parent_directory, filename) }
1408
- let(:path_key) { filename }
1409
- before { FileUtils.mkdir_p File.dirname(file_path) }
1410
- after { FileUtils.rm_rf parent_directory }
1411
-
1412
- context "when file exists" do
1413
- let(:contents) do
1414
- [].tap do |lines|
1415
- (1..12).each do |i|
1416
- lines << "log line #{i}"
1417
- end
1418
- end
1419
- end
1420
- before do
1421
- File.open file_path, "a" do |f|
1422
- contents.each do |line|
1423
- f.puts line
1424
- end
1425
- end
1426
- run
1427
- end
1428
-
1429
- it "outputs file location and content" do
1430
- expect(output).to include(
1431
- %(Path: "#{file_path}"),
1432
- "Contents (last 10 lines):"
1433
- )
1434
- expect(output).to include(*contents.last(10).join("\n"))
1435
- expect(output).to_not include(*contents.first(2).join("\n"))
1436
- end
1437
-
1438
- it "transmits file data in report" do
1439
- expect(received_report["paths"][path_key]).to match(
1440
- "path" => file_path,
1441
- "exists" => true,
1442
- "type" => "file",
1443
- "mode" => kind_of(String),
1444
- "writable" => boolean,
1445
- "ownership" => {
1446
- "uid" => kind_of(Integer),
1447
- "user" => kind_of(String),
1448
- "gid" => kind_of(Integer),
1449
- "group" => kind_of(String)
1450
- },
1451
- "content" => contents
1452
- )
1453
- end
1454
- end
1455
-
1456
- context "when file does not exist" do
1457
- before do
1458
- if shared_example_options && shared_example_options[:stub_not_exists]
1459
- allow(File).to receive(:exist?).and_call_original
1460
- expect(File).to receive(:exist?).with(file_path).and_return(false)
1461
- end
1462
- run
1463
- end
1464
-
1465
- it "outputs file does not exists" do
1466
- expect(output).to include %(Path: "#{file_path}"\n Exists?: false)
1467
- end
1468
-
1469
- it "transmits file data in report" do
1470
- expect(received_report["paths"][path_key]).to eq(
1471
- "path" => file_path,
1472
- "exists" => false
1473
- )
1474
- end
1475
- end
1476
-
1477
- context "when reading the file returns a illegal seek error" do
1478
- before do
1479
- File.write(file_path, "Some content")
1480
- allow(File).to receive(:binread).and_call_original
1481
- expect(File).to receive(:binread).with(file_path, anything,
1482
- anything).and_raise(Errno::ESPIPE)
1483
- run
1484
- end
1485
-
1486
- it "outputs file does not exists" do
1487
- expect(output).to include %(Read error: Errno::ESPIPE: Illegal seek)
1488
- end
1489
-
1490
- it "transmits file data in report" do
1491
- expect(received_report["paths"][path_key]).to include(
1492
- "read_error" => "Errno::ESPIPE: Illegal seek"
1493
- )
1494
- end
1495
- end
1496
- end
1497
-
1498
- describe "ext/mkmf.log" do
1499
- it_behaves_like "diagnose file" do
1500
- let(:filename) { "mkmf.log" }
1501
- let(:path_key) { "ext/mkmf.log" }
1502
- before do
1503
- expect_any_instance_of(Appsignal::CLI::Diagnose::Paths)
1504
- .to receive(:makefile_install_log_path)
1505
- .at_least(:once)
1506
- .and_return(File.join(parent_directory, filename))
1507
- end
1508
- end
1509
-
1510
- it "outputs header" do
1511
- run
1512
- expect(output).to include("Makefile install log")
1513
- end
1514
- end
1515
-
1516
- describe "appsignal.log" do
1517
- it_behaves_like "diagnose file", :stub_not_exists => true do
1518
- let(:filename) { "appsignal.log" }
1519
- before do
1520
- ENV["APPSIGNAL_LOG"] = "stdout"
1521
- expect_any_instance_of(Appsignal::Config).to receive(:log_file_path)
1522
- .at_least(:once)
1523
- .and_return(file_path)
1524
- end
1525
- end
1526
-
1527
- it "outputs header" do
1528
- run
1529
- expect(output).to include("AppSignal log")
1530
- end
1531
- end
1532
- end
1533
- end
1534
-
1535
- def expect_valid_agent_diagnostics_report(output, working_directory_stat)
1536
- expect(output).to include \
1537
- "Agent diagnostics",
1538
- " Extension tests\n Configuration: valid",
1539
- " Started: started",
1540
- " Process user id: #{Process.uid}",
1541
- " Process user group id: #{Process.gid}\n" \
1542
- " Configuration: valid",
1543
- " Logger: started",
1544
- " Working directory user id: #{working_directory_stat.uid}",
1545
- " Working directory user group id: #{working_directory_stat.gid}",
1546
- " Working directory permissions: #{working_directory_stat.mode}",
1547
- " Lock path: writable"
1548
- end
1549
-
1550
- def hash_with_string_keys(hash)
1551
- hash.transform_keys(&:to_s)
1552
- end
1553
- end