appsignal 2.8.4.beta.1 → 2.9.18.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
  3. data/.github/ISSUE_TEMPLATE/chore.md +14 -0
  4. data/.gitignore +2 -3
  5. data/.rubocop.yml +3 -0
  6. data/.rubocop_todo.yml +7 -16
  7. data/.travis.yml +28 -27
  8. data/CHANGELOG.md +657 -533
  9. data/README.md +31 -3
  10. data/Rakefile +128 -129
  11. data/SUPPORT.md +16 -0
  12. data/appsignal.gemspec +17 -4
  13. data/build_matrix.yml +21 -9
  14. data/ext/Rakefile +23 -17
  15. data/ext/agent.yml +40 -37
  16. data/ext/base.rb +116 -31
  17. data/ext/extconf.rb +34 -28
  18. data/gemfiles/capistrano2.gemfile +5 -0
  19. data/gemfiles/capistrano3.gemfile +5 -0
  20. data/gemfiles/grape.gemfile +5 -0
  21. data/gemfiles/no_dependencies.gemfile +5 -0
  22. data/gemfiles/padrino.gemfile +5 -0
  23. data/gemfiles/que.gemfile +5 -0
  24. data/gemfiles/que_beta.gemfile +10 -0
  25. data/gemfiles/rails-3.2.gemfile +5 -0
  26. data/gemfiles/rails-4.0.gemfile +5 -0
  27. data/gemfiles/rails-4.1.gemfile +5 -0
  28. data/gemfiles/rails-4.2.gemfile +5 -0
  29. data/gemfiles/rails-6.0.gemfile +5 -0
  30. data/gemfiles/resque.gemfile +5 -0
  31. data/lib/appsignal.rb +14 -492
  32. data/lib/appsignal/cli/demo.rb +5 -2
  33. data/lib/appsignal/cli/diagnose.rb +84 -4
  34. data/lib/appsignal/cli/diagnose/paths.rb +0 -5
  35. data/lib/appsignal/cli/diagnose/utils.rb +19 -0
  36. data/lib/appsignal/cli/helpers.rb +6 -0
  37. data/lib/appsignal/cli/install.rb +45 -15
  38. data/lib/appsignal/cli/notify_of_deploy.rb +10 -0
  39. data/lib/appsignal/config.rb +1 -2
  40. data/lib/appsignal/event_formatter.rb +4 -5
  41. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +10 -8
  42. data/lib/appsignal/event_formatter/moped/query_formatter.rb +60 -59
  43. data/lib/appsignal/extension.rb +2 -2
  44. data/lib/appsignal/helpers/instrumentation.rb +494 -0
  45. data/lib/appsignal/helpers/metrics.rb +54 -0
  46. data/lib/appsignal/hooks.rb +11 -8
  47. data/lib/appsignal/hooks/active_support_notifications.rb +2 -5
  48. data/lib/appsignal/hooks/puma.rb +74 -11
  49. data/lib/appsignal/hooks/sequel.rb +1 -1
  50. data/lib/appsignal/hooks/sidekiq.rb +115 -0
  51. data/lib/appsignal/integrations/mongo_ruby_driver.rb +7 -0
  52. data/lib/appsignal/integrations/que.rb +9 -8
  53. data/lib/appsignal/integrations/railtie.rb +2 -1
  54. data/lib/appsignal/marker.rb +2 -3
  55. data/lib/appsignal/minutely.rb +188 -19
  56. data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -1
  57. data/lib/appsignal/system.rb +16 -18
  58. data/lib/appsignal/transaction.rb +8 -0
  59. data/lib/appsignal/utils/rails_helper.rb +20 -0
  60. data/lib/appsignal/version.rb +1 -1
  61. data/lib/puma/plugin/appsignal.rb +26 -0
  62. data/spec/lib/appsignal/cli/diagnose/utils_spec.rb +40 -0
  63. data/spec/lib/appsignal/cli/diagnose_spec.rb +129 -22
  64. data/spec/lib/appsignal/cli/install_spec.rb +57 -8
  65. data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +10 -0
  66. data/spec/lib/appsignal/config_spec.rb +13 -11
  67. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +38 -28
  68. data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +6 -0
  69. data/spec/lib/appsignal/event_formatter_spec.rb +168 -69
  70. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +104 -25
  71. data/spec/lib/appsignal/hooks/puma_spec.rb +251 -34
  72. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +209 -0
  73. data/spec/lib/appsignal/hooks_spec.rb +4 -0
  74. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +24 -1
  75. data/spec/lib/appsignal/minutely_spec.rb +318 -26
  76. data/spec/lib/appsignal/system_spec.rb +0 -35
  77. data/spec/lib/appsignal/transaction_spec.rb +68 -10
  78. data/spec/lib/appsignal/utils/hash_sanitizer_spec.rb +39 -31
  79. data/spec/lib/appsignal/utils/json_spec.rb +7 -3
  80. data/spec/lib/appsignal_spec.rb +98 -22
  81. data/spec/lib/puma/appsignal_spec.rb +91 -0
  82. data/spec/spec_helper.rb +13 -0
  83. data/spec/support/{project_fixture → fixtures/projects/valid}/config/application.rb +0 -0
  84. data/spec/support/{project_fixture → fixtures/projects/valid}/config/appsignal.yml +1 -0
  85. data/spec/support/{project_fixture → fixtures/projects/valid}/config/environments/development.rb +0 -0
  86. data/spec/support/{project_fixture → fixtures/projects/valid}/config/environments/production.rb +0 -0
  87. data/spec/support/{project_fixture → fixtures/projects/valid}/config/environments/test.rb +0 -0
  88. data/spec/support/{project_fixture → fixtures/projects/valid}/log/.gitkeep +0 -0
  89. data/spec/support/helpers/config_helpers.rb +1 -1
  90. data/spec/support/helpers/log_helpers.rb +6 -0
  91. data/spec/support/helpers/wait_for_helper.rb +28 -0
  92. data/spec/support/mocks/mock_probe.rb +11 -0
  93. data/spec/support/stubs/sidekiq/api.rb +4 -0
  94. metadata +43 -31
  95. data/spec/support/fixtures/containers/cgroups/docker +0 -14
  96. data/spec/support/fixtures/containers/cgroups/docker_systemd +0 -8
  97. data/spec/support/fixtures/containers/cgroups/lxc +0 -10
  98. data/spec/support/fixtures/containers/cgroups/no_permission +0 -0
  99. data/spec/support/fixtures/containers/cgroups/none +0 -1
@@ -32,7 +32,7 @@ module Appsignal
32
32
  attr_reader :raise_errors_on
33
33
 
34
34
  def initialize(app, options = {})
35
- Appsignal.logger.debug "Initializing Appsignal::Rack::SinatraInstrumentation"
35
+ Appsignal.logger.debug "Initializing Appsignal::Rack::SinatraBaseInstrumentation"
36
36
  @app = app
37
37
  @options = options
38
38
  @raise_errors_on = raise_errors?(@app)
@@ -16,21 +16,6 @@ module Appsignal
16
16
  ENV.key? "DYNO".freeze
17
17
  end
18
18
 
19
- # Returns the architecture for which the agent was installed.
20
- #
21
- # This value is saved when the gem is installed in `ext/extconf.rb`.
22
- # We use this value to build the diagnose report with the installed
23
- # CPU type and platform, rather than the detected architecture in
24
- # {.agent_platform} during the diagnose run.
25
- #
26
- # @api private
27
- # @return [String]
28
- def self.installed_agent_architecture
29
- architecture_file = File.join(GEM_EXT_PATH, "appsignal.architecture")
30
- return unless File.exist?(architecture_file)
31
- File.read(architecture_file)
32
- end
33
-
34
19
  # Detect agent and extension platform build
35
20
  #
36
21
  # Used by `ext/extconf.rb` to select which build it should download and
@@ -42,7 +27,7 @@ module Appsignal
42
27
  # @api private
43
28
  # @return [String]
44
29
  def self.agent_platform
45
- return MUSL_TARGET if ENV["APPSIGNAL_BUILD_FOR_MUSL"]
30
+ return MUSL_TARGET if force_musl_build?
46
31
 
47
32
  host_os = RbConfig::CONFIG["host_os"].downcase
48
33
  local_os =
@@ -59,8 +44,8 @@ module Appsignal
59
44
  if local_os =~ /linux/
60
45
  ldd_output = ldd_version_output
61
46
  return MUSL_TARGET if ldd_output.include? "musl"
62
- ldd_version = ldd_output.match(/\d+\.\d+/)
63
- if ldd_version && versionify(ldd_version[0]) < versionify("2.15")
47
+ ldd_version = extract_ldd_version(ldd_output)
48
+ if ldd_version && versionify(ldd_version) < versionify("2.15")
64
49
  return MUSL_TARGET
65
50
  end
66
51
  end
@@ -68,6 +53,13 @@ module Appsignal
68
53
  local_os
69
54
  end
70
55
 
56
+ # Returns whether or not the musl build was forced by the user.
57
+ #
58
+ # @api private
59
+ def self.force_musl_build?
60
+ %w[true 1].include?(ENV["APPSIGNAL_BUILD_FOR_MUSL"])
61
+ end
62
+
71
63
  # @api private
72
64
  def self.versionify(version)
73
65
  Gem::Version.new(version)
@@ -78,6 +70,12 @@ module Appsignal
78
70
  `ldd --version 2>&1`
79
71
  end
80
72
 
73
+ # @api private
74
+ def self.extract_ldd_version(string)
75
+ ldd_version = string.match(/\d+\.\d+/)
76
+ ldd_version && ldd_version[0]
77
+ end
78
+
81
79
  def self.jruby?
82
80
  RUBY_PLATFORM == "java"
83
81
  end
@@ -264,6 +264,11 @@ module Appsignal
264
264
  end
265
265
 
266
266
  def set_error(error)
267
+ unless error.is_a?(Exception)
268
+ Appsignal.logger.error "Appsignal::Transaction#set_error: Cannot set error. " \
269
+ "The given value is not an exception: #{error.inspect}"
270
+ return
271
+ end
267
272
  return unless error
268
273
  return unless Appsignal.active?
269
274
 
@@ -277,10 +282,12 @@ module Appsignal
277
282
  alias_method :add_exception, :set_error
278
283
 
279
284
  def start_event
285
+ return if paused?
280
286
  @ext.start_event(self.class.garbage_collection_profiler.total_time)
281
287
  end
282
288
 
283
289
  def finish_event(name, title, body, body_format = Appsignal::EventFormatter::DEFAULT)
290
+ return if paused?
284
291
  @ext.finish_event(
285
292
  name,
286
293
  title || BLANK,
@@ -291,6 +298,7 @@ module Appsignal
291
298
  end
292
299
 
293
300
  def record_event(name, title, body, duration, body_format = Appsignal::EventFormatter::DEFAULT)
301
+ return if paused?
294
302
  @ext.record_event(
295
303
  name,
296
304
  title || BLANK,
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Utils
5
+ module RailsHelper
6
+ def self.detected_rails_app_name
7
+ rails_class = Rails.application.class
8
+ if rails_class.respond_to? :module_parent_name # Rails 6
9
+ rails_class.module_parent_name
10
+ else # Older Rails versions
11
+ rails_class.parent_name
12
+ end
13
+ end
14
+
15
+ def self.application_config_path
16
+ File.expand_path(File.join(Dir.pwd, "config/application.rb"))
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "2.8.4.beta.1".freeze
4
+ VERSION = "2.9.18.beta.1".freeze
5
5
  end
@@ -0,0 +1,26 @@
1
+ APPSIGNAL_PUMA_PLUGIN_LOADED = true
2
+
3
+ # AppSignal Puma plugin
4
+ #
5
+ # This plugin ensures the minutely probe thread is started with the Puma
6
+ # minutely probe in the Puma master process.
7
+ #
8
+ # The constant {APPSIGNAL_PUMA_PLUGIN_LOADED} is here to mark the Plugin as
9
+ # loaded by the rest of the AppSignal gem. This ensures that the Puma minutely
10
+ # probe is not also started in every Puma workers, which was the old behavior.
11
+ # See {Appsignal::Hooks::PumaHook#install} for more information.
12
+ #
13
+ # For even more information:
14
+ # https://docs.appsignal.com/ruby/integrations/puma.html
15
+ Puma::Plugin.create do
16
+ def start(launcher = nil)
17
+ launcher.events.on_booted do
18
+ require "appsignal"
19
+ if ::Puma.respond_to?(:stats)
20
+ Appsignal::Minutely.probes.register :puma, Appsignal::Hooks::PumaProbe
21
+ end
22
+ Appsignal.start
23
+ Appsignal.start_logger
24
+ end
25
+ end
26
+ end
@@ -1,6 +1,46 @@
1
1
  require "appsignal/cli/diagnose/utils"
2
2
 
3
3
  describe Appsignal::CLI::Diagnose::Utils do
4
+ describe ".username_for_uid" do
5
+ subject { described_class.username_for_uid(uid) }
6
+
7
+ context "when user with id exists" do
8
+ let(:uid) { 0 }
9
+
10
+ it "returns username" do
11
+ is_expected.to be_kind_of(String)
12
+ end
13
+ end
14
+
15
+ context "when user with id does not exist" do
16
+ let(:uid) { -1 }
17
+
18
+ it "returns nil" do
19
+ is_expected.to be_nil
20
+ end
21
+ end
22
+ end
23
+
24
+ describe ".group_for_gid" do
25
+ subject { described_class.group_for_gid(uid) }
26
+
27
+ context "when group with id exists" do
28
+ let(:uid) { 0 }
29
+
30
+ it "returns group name" do
31
+ is_expected.to be_kind_of(String)
32
+ end
33
+ end
34
+
35
+ context "when group with id does not exist" do
36
+ let(:uid) { -3 }
37
+
38
+ it "returns nil" do
39
+ is_expected.to be_nil
40
+ end
41
+ end
42
+ end
43
+
4
44
  describe ".read_file_content" do
5
45
  let(:path) { File.join(spec_system_tmp_dir, "test_file.txt") }
6
46
  let(:bytes_to_read) { 100 }
@@ -190,8 +190,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
190
190
  it "outputs version numbers" do
191
191
  expect(output).to include \
192
192
  "Gem version: #{Appsignal::VERSION}",
193
- "Agent version: #{Appsignal::Extension.agent_version}",
194
- "Agent architecture: #{Appsignal::System.installed_agent_architecture}"
193
+ "Agent version: #{Appsignal::Extension.agent_version}"
195
194
  end
196
195
 
197
196
  it "transmits version numbers in report" do
@@ -200,7 +199,6 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
200
199
  "language" => "ruby",
201
200
  "package_version" => Appsignal::VERSION,
202
201
  "agent_version" => Appsignal::Extension.agent_version,
203
- "agent_architecture" => Appsignal::System.installed_agent_architecture,
204
202
  "extension_loaded" => true
205
203
  }
206
204
  )
@@ -238,6 +236,131 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
238
236
  end
239
237
  end
240
238
 
239
+ describe "installation report" do
240
+ let(:rbconfig) { RbConfig::CONFIG }
241
+
242
+ it "adds the installation report to the diagnostics report" do
243
+ run
244
+ jruby = DependencyHelper.running_jruby?
245
+ expect(received_report["installation"]).to match(
246
+ "result" => {
247
+ "status" => "success"
248
+ },
249
+ "language" => {
250
+ "name" => "ruby",
251
+ "version" => "#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}",
252
+ "implementation" => jruby ? "jruby" : "ruby"
253
+ },
254
+ "download" => {
255
+ "download_url" => kind_of(String),
256
+ "checksum" => "verified"
257
+ },
258
+ "build" => {
259
+ "time" => kind_of(String),
260
+ "package_path" => File.expand_path("../../../../../", __FILE__),
261
+ "architecture" => rbconfig["host_cpu"],
262
+ "target" => Appsignal::System.agent_platform,
263
+ "musl_override" => false,
264
+ "library_type" => jruby ? "dynamic" : "static",
265
+ "source" => "remote",
266
+ "dependencies" => kind_of(Hash),
267
+ "flags" => kind_of(Hash),
268
+ "agent_version" => Appsignal::Extension.agent_version
269
+ },
270
+ "host" => {
271
+ "root_user" => false,
272
+ "dependencies" => kind_of(Hash)
273
+ }
274
+ )
275
+ end
276
+
277
+ it "prints the extension installation report" do
278
+ run
279
+ jruby = Appsignal::System.jruby?
280
+ expect(output).to include(
281
+ "Extension installation report",
282
+ "Language details",
283
+ " Implementation: #{jruby ? "jruby" : "ruby"}",
284
+ " Ruby version: #{"#{rbconfig["ruby_version"]}-p#{rbconfig["PATCHLEVEL"]}"}",
285
+ "Download details",
286
+ " Download URL: https://",
287
+ " Checksum: verified",
288
+ "Build details",
289
+ " Install time: 20",
290
+ " Architecture: #{rbconfig["host_cpu"]}",
291
+ " Target: #{Appsignal::System.agent_platform}",
292
+ " Musl override: false",
293
+ " Library type: #{jruby ? "dynamic" : "static"}",
294
+ " Dependencies: {",
295
+ " Flags: {",
296
+ "Host details",
297
+ " Root user: false",
298
+ " Dependencies: {"
299
+ )
300
+ end
301
+
302
+ context "without install report" do
303
+ let(:error) { RuntimeError.new("foo") }
304
+ before do
305
+ allow(File).to receive(:read).and_call_original
306
+ expect(File).to receive(:read)
307
+ .with(File.expand_path("../../../../../ext/install.report", __FILE__))
308
+ .and_raise(error)
309
+ end
310
+
311
+ it "sends an error" do
312
+ run
313
+ expect(received_report["installation"]).to match(
314
+ "parsing_error" => {
315
+ "error" => "RuntimeError: foo",
316
+ "backtrace" => error.backtrace
317
+ }
318
+ )
319
+ end
320
+
321
+ it "prints the error" do
322
+ run
323
+ expect(output).to include(
324
+ "Extension installation report",
325
+ " Error found while parsing the report.",
326
+ " Error: RuntimeError: foo"
327
+ )
328
+ expect(output).to_not include("Raw report:")
329
+ end
330
+ end
331
+
332
+ context "when report is invalid YAML" do
333
+ let(:raw_report) { "foo:\nbar" }
334
+ before do
335
+ allow(File).to receive(:read).and_call_original
336
+ expect(File).to receive(:read)
337
+ .with(File.expand_path("../../../../../ext/install.report", __FILE__))
338
+ .and_return(raw_report)
339
+ end
340
+
341
+ it "sends an error" do
342
+ run
343
+ expect(received_report["installation"]).to match(
344
+ "parsing_error" => {
345
+ "error" => kind_of(String),
346
+ "backtrace" => kind_of(Array),
347
+ "raw" => raw_report
348
+ }
349
+ )
350
+ end
351
+
352
+ it "prints the error" do
353
+ run
354
+ expect(output).to include(
355
+ "Extension installation report",
356
+ " Error found while parsing the report.",
357
+ " Error: ",
358
+ " Raw report:\n#{raw_report}"
359
+ )
360
+ end
361
+ end
362
+ end
363
+
241
364
  describe "agent diagnostics" do
242
365
  let(:working_directory_stat) { File.stat("/tmp/appsignal") }
243
366
 
@@ -471,7 +594,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
471
594
  context "when not root user" do
472
595
  it "outputs false" do
473
596
  run
474
- expect(output).to include "root user: false"
597
+ expect(output).to include "Root user: false"
475
598
  end
476
599
 
477
600
  it "transmits root: false in report" do
@@ -487,7 +610,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
487
610
  end
488
611
 
489
612
  it "outputs true, with warning" do
490
- expect(output).to include "root user: true (not recommended)"
613
+ expect(output).to include "Root user: true (not recommended)"
491
614
  end
492
615
 
493
616
  it "transmits root: true in report" do
@@ -834,7 +957,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
834
957
  expect(received_report["paths"].keys).to match_array(
835
958
  %w[
836
959
  package_install_path root_path working_dir log_dir_path
837
- ext/install.log ext/mkmf.log appsignal.log
960
+ ext/mkmf.log appsignal.log
838
961
  ]
839
962
  )
840
963
  end
@@ -1138,22 +1261,6 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1138
1261
  end
1139
1262
  end
1140
1263
 
1141
- describe "install.log" do
1142
- it_behaves_like "diagnose file" do
1143
- let(:filename) { File.join("ext", "install.log") }
1144
- before do
1145
- expect_any_instance_of(Appsignal::CLI::Diagnose::Paths).to receive(:gem_path)
1146
- .at_least(:once)
1147
- .and_return(parent_directory)
1148
- end
1149
- end
1150
-
1151
- it "outputs header" do
1152
- run
1153
- expect(output).to include("Extension install log")
1154
- end
1155
- end
1156
-
1157
1264
  describe "mkmf.log" do
1158
1265
  it_behaves_like "diagnose file" do
1159
1266
  let(:filename) { File.join("ext", "mkmf.log") }
@@ -16,6 +16,10 @@ describe Appsignal::CLI::Install do
16
16
  allow(described_class).to receive(:press_any_key)
17
17
  allow(Appsignal::Demo).to receive(:transmit).and_return(true)
18
18
  end
19
+ after do
20
+ FileUtils.rm_rf(tmp_dir)
21
+ FileUtils.mkdir_p(tmp_dir)
22
+ end
19
23
  around do |example|
20
24
  original_stdin = $stdin
21
25
  $stdin = StringIO.new
@@ -157,16 +161,10 @@ describe Appsignal::CLI::Install do
157
161
  shared_examples "capistrano install" do
158
162
  let(:capfile) { File.join(tmp_dir, "Capfile") }
159
163
  before do
160
- FileUtils.mkdir_p(tmp_dir)
161
-
162
164
  enter_app_name "foo"
163
165
  add_cli_input "n"
164
166
  choose_environment_config
165
167
  end
166
- after do
167
- FileUtils.rm_rf(tmp_dir)
168
- FileUtils.mkdir_p(tmp_dir)
169
- end
170
168
 
171
169
  context "without Capfile" do
172
170
  it "does nothing" do
@@ -243,7 +241,12 @@ describe Appsignal::CLI::Install do
243
241
 
244
242
  if rails_present?
245
243
  context "with rails" do
246
- let(:installation_instructions) { ["Installing for Ruby on Rails"] }
244
+ let(:installation_instructions) do
245
+ [
246
+ "Installing for Ruby on Rails",
247
+ "Your app's name is: 'MyApp'"
248
+ ]
249
+ end
247
250
  let(:app_name) { "MyApp" }
248
251
  let(:config_dir) { File.join(tmp_dir, "config") }
249
252
  let(:environments_dir) { File.join(config_dir, "environments") }
@@ -255,7 +258,6 @@ describe Appsignal::CLI::Install do
255
258
  FileUtils.touch(File.join(environments_dir, "development.rb"))
256
259
  FileUtils.touch(File.join(environments_dir, "staging.rb"))
257
260
  FileUtils.touch(File.join(environments_dir, "production.rb"))
258
- enter_app_name app_name
259
261
  end
260
262
 
261
263
  describe "environments" do
@@ -405,6 +407,53 @@ describe Appsignal::CLI::Install do
405
407
  end
406
408
  end
407
409
  end
410
+
411
+ context "when there is no Rails application.rb file" do
412
+ before do
413
+ # Do not detect it as another framework for testing
414
+ allow(described_class).to receive(:framework_available?).and_call_original
415
+ allow(described_class).to receive(:framework_available?).with("sinatra").and_return(false)
416
+
417
+ File.delete(File.join(config_dir, "application.rb"))
418
+ expect(File.exist?(File.join(config_dir, "application.rb"))).to eql(false)
419
+ end
420
+
421
+ it "fails the installation" do
422
+ run
423
+
424
+ expect(output).to include("We could not detect which framework you are using.")
425
+ expect(output).to_not include("Installing for Ruby on Rails")
426
+ expect(output).to include_complete_install
427
+
428
+ expect(File.exist?(config_file_path)).to be(false)
429
+ end
430
+ end
431
+
432
+ context "when failed to load the Rails application.rb file" do
433
+ before do
434
+ File.open(File.join(config_dir, "application.rb"), "w") do |file|
435
+ file.write("I am invalid code")
436
+ end
437
+ end
438
+
439
+ it "prompts the user to fill in an app name" do
440
+ enter_app_name app_name
441
+ choose_config_file
442
+ run
443
+
444
+ expect(output).to include("Installing for Ruby on Rails")
445
+ expect(output).to include("Unable to automatically detect your Rails app's name.")
446
+ expect(output).to include("Choose your app's display name for AppSignal.com:")
447
+ expect(output).to include_file_config
448
+ expect(output).to include_complete_install
449
+
450
+ expect(config_file).to configure_app_name(app_name)
451
+ expect(config_file).to configure_push_api_key(push_api_key)
452
+ expect(config_file).to configure_environment("development")
453
+ expect(config_file).to configure_environment("staging")
454
+ expect(config_file).to configure_environment("production")
455
+ end
456
+ end
408
457
  end
409
458
  end
410
459