appsignal 4.0.5 → 4.0.7

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.
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