airbrake-ruby 3.2.2-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/airbrake-ruby.rb +554 -0
- data/lib/airbrake-ruby/async_sender.rb +119 -0
- data/lib/airbrake-ruby/backtrace.rb +194 -0
- data/lib/airbrake-ruby/code_hunk.rb +53 -0
- data/lib/airbrake-ruby/config.rb +238 -0
- data/lib/airbrake-ruby/config/validator.rb +63 -0
- data/lib/airbrake-ruby/deploy_notifier.rb +47 -0
- data/lib/airbrake-ruby/file_cache.rb +48 -0
- data/lib/airbrake-ruby/filter_chain.rb +95 -0
- data/lib/airbrake-ruby/filters/context_filter.rb +29 -0
- data/lib/airbrake-ruby/filters/dependency_filter.rb +31 -0
- data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +45 -0
- data/lib/airbrake-ruby/filters/gem_root_filter.rb +33 -0
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +90 -0
- data/lib/airbrake-ruby/filters/git_repository_filter.rb +42 -0
- data/lib/airbrake-ruby/filters/git_revision_filter.rb +66 -0
- data/lib/airbrake-ruby/filters/keys_blacklist.rb +50 -0
- data/lib/airbrake-ruby/filters/keys_filter.rb +140 -0
- data/lib/airbrake-ruby/filters/keys_whitelist.rb +49 -0
- data/lib/airbrake-ruby/filters/root_directory_filter.rb +28 -0
- data/lib/airbrake-ruby/filters/sql_filter.rb +104 -0
- data/lib/airbrake-ruby/filters/system_exit_filter.rb +23 -0
- data/lib/airbrake-ruby/filters/thread_filter.rb +92 -0
- data/lib/airbrake-ruby/hash_keyable.rb +37 -0
- data/lib/airbrake-ruby/ignorable.rb +44 -0
- data/lib/airbrake-ruby/nested_exception.rb +39 -0
- data/lib/airbrake-ruby/notice.rb +165 -0
- data/lib/airbrake-ruby/notice_notifier.rb +228 -0
- data/lib/airbrake-ruby/performance_notifier.rb +161 -0
- data/lib/airbrake-ruby/promise.rb +99 -0
- data/lib/airbrake-ruby/response.rb +71 -0
- data/lib/airbrake-ruby/stat.rb +56 -0
- data/lib/airbrake-ruby/sync_sender.rb +111 -0
- data/lib/airbrake-ruby/tdigest.rb +393 -0
- data/lib/airbrake-ruby/time_truncate.rb +17 -0
- data/lib/airbrake-ruby/truncator.rb +115 -0
- data/lib/airbrake-ruby/version.rb +6 -0
- data/spec/airbrake_spec.rb +171 -0
- data/spec/async_sender_spec.rb +154 -0
- data/spec/backtrace_spec.rb +438 -0
- data/spec/code_hunk_spec.rb +118 -0
- data/spec/config/validator_spec.rb +189 -0
- data/spec/config_spec.rb +281 -0
- data/spec/deploy_notifier_spec.rb +41 -0
- data/spec/file_cache.rb +36 -0
- data/spec/filter_chain_spec.rb +83 -0
- data/spec/filters/context_filter_spec.rb +25 -0
- data/spec/filters/dependency_filter_spec.rb +14 -0
- data/spec/filters/exception_attributes_filter_spec.rb +63 -0
- data/spec/filters/gem_root_filter_spec.rb +44 -0
- data/spec/filters/git_last_checkout_filter_spec.rb +48 -0
- data/spec/filters/git_repository_filter.rb +53 -0
- data/spec/filters/git_revision_filter_spec.rb +126 -0
- data/spec/filters/keys_blacklist_spec.rb +236 -0
- data/spec/filters/keys_whitelist_spec.rb +205 -0
- data/spec/filters/root_directory_filter_spec.rb +42 -0
- data/spec/filters/sql_filter_spec.rb +219 -0
- data/spec/filters/system_exit_filter_spec.rb +14 -0
- data/spec/filters/thread_filter_spec.rb +279 -0
- data/spec/fixtures/notroot.txt +7 -0
- data/spec/fixtures/project_root/code.rb +221 -0
- data/spec/fixtures/project_root/empty_file.rb +0 -0
- data/spec/fixtures/project_root/long_line.txt +1 -0
- data/spec/fixtures/project_root/short_file.rb +3 -0
- data/spec/fixtures/project_root/vendor/bundle/ignored_file.rb +5 -0
- data/spec/helpers.rb +9 -0
- data/spec/ignorable_spec.rb +14 -0
- data/spec/nested_exception_spec.rb +75 -0
- data/spec/notice_notifier_spec.rb +436 -0
- data/spec/notice_notifier_spec/options_spec.rb +266 -0
- data/spec/notice_spec.rb +297 -0
- data/spec/performance_notifier_spec.rb +287 -0
- data/spec/promise_spec.rb +165 -0
- data/spec/response_spec.rb +82 -0
- data/spec/spec_helper.rb +102 -0
- data/spec/stat_spec.rb +35 -0
- data/spec/sync_sender_spec.rb +140 -0
- data/spec/tdigest_spec.rb +230 -0
- data/spec/time_truncate_spec.rb +13 -0
- data/spec/truncator_spec.rb +238 -0
- metadata +278 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
RSpec.describe Airbrake::DeployNotifier do
|
2
|
+
let(:user_params) { { project_id: 1, project_key: 'banana' } }
|
3
|
+
let(:params) { {} }
|
4
|
+
let(:config) { Airbrake::Config.new(user_params.merge(params)) }
|
5
|
+
|
6
|
+
subject { described_class.new(config) }
|
7
|
+
|
8
|
+
describe "#notify" do
|
9
|
+
it "returns a promise" do
|
10
|
+
stub_request(:post, 'https://api.airbrake.io/api/v4/projects/1/deploys').
|
11
|
+
to_return(status: 201, body: '{}')
|
12
|
+
expect(subject.notify({})).to be_an(Airbrake::Promise)
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when environment is configured" do
|
16
|
+
let(:params) { { environment: 'fooenv' } }
|
17
|
+
|
18
|
+
it "prefers the passed environment to the config env" do
|
19
|
+
expect_any_instance_of(Airbrake::SyncSender).to receive(:send).with(
|
20
|
+
{ environment: 'barenv' },
|
21
|
+
instance_of(Airbrake::Promise),
|
22
|
+
URI('https://api.airbrake.io/api/v4/projects/1/deploys')
|
23
|
+
)
|
24
|
+
subject.notify(environment: 'barenv')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when environment is not configured" do
|
29
|
+
let(:params) { { environment: 'fooenv' } }
|
30
|
+
|
31
|
+
it "sets the environment from the config" do
|
32
|
+
expect_any_instance_of(Airbrake::SyncSender).to receive(:send).with(
|
33
|
+
{ environment: 'fooenv' },
|
34
|
+
instance_of(Airbrake::Promise),
|
35
|
+
URI('https://api.airbrake.io/api/v4/projects/1/deploys')
|
36
|
+
)
|
37
|
+
subject.notify({})
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/file_cache.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
RSpec.describe Airbrake::FileCache do
|
2
|
+
after do
|
3
|
+
%i[banana mango].each { |k| described_class.delete(k) }
|
4
|
+
expect(described_class).to be_empty
|
5
|
+
end
|
6
|
+
|
7
|
+
describe ".[]=" do
|
8
|
+
context "when cache limit isn't reached" do
|
9
|
+
before do
|
10
|
+
stub_const("#{described_class.name}::MAX_SIZE", 10)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "adds objects" do
|
14
|
+
described_class[:banana] = 1
|
15
|
+
described_class[:mango] = 2
|
16
|
+
|
17
|
+
expect(described_class[:banana]).to eq(1)
|
18
|
+
expect(described_class[:mango]).to eq(2)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when cache limit is reached" do
|
23
|
+
before do
|
24
|
+
stub_const("#{described_class.name}::MAX_SIZE", 1)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "replaces old objects with new ones" do
|
28
|
+
described_class[:banana] = 1
|
29
|
+
described_class[:mango] = 2
|
30
|
+
|
31
|
+
expect(described_class[:banana]).to be_nil
|
32
|
+
expect(described_class[:mango]).to eq(2)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
RSpec.describe Airbrake::FilterChain do
|
2
|
+
let(:notice) do
|
3
|
+
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
4
|
+
end
|
5
|
+
|
6
|
+
describe "#refine" do
|
7
|
+
let(:filter) do
|
8
|
+
Class.new do
|
9
|
+
attr_reader :weight
|
10
|
+
|
11
|
+
def initialize(weight)
|
12
|
+
@weight = weight
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(notice)
|
16
|
+
notice[:params][:bingo] << @weight
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "executes filters from heaviest to lightest" do
|
22
|
+
notice[:params][:bingo] = []
|
23
|
+
|
24
|
+
(0...3).reverse_each { |i| subject.add_filter(filter.new(i)) }
|
25
|
+
subject.refine(notice)
|
26
|
+
|
27
|
+
expect(notice[:params][:bingo]).to eq([2, 1, 0])
|
28
|
+
end
|
29
|
+
|
30
|
+
it "stops execution once a notice was ignored" do
|
31
|
+
f2 = filter.new(2)
|
32
|
+
expect(f2).to receive(:call)
|
33
|
+
|
34
|
+
f1 = proc { |notice| notice.ignore! }
|
35
|
+
|
36
|
+
f0 = filter.new(-1)
|
37
|
+
expect(f0).not_to receive(:call)
|
38
|
+
|
39
|
+
[f2, f1, f0].each { |f| subject.add_filter(f) }
|
40
|
+
|
41
|
+
subject.refine(notice)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#delete_filter" do
|
46
|
+
let(:filter) do
|
47
|
+
Class.new do
|
48
|
+
class << self
|
49
|
+
def name
|
50
|
+
'FooFilter'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(foo)
|
55
|
+
@foo = foo
|
56
|
+
end
|
57
|
+
|
58
|
+
def call(notice)
|
59
|
+
notice[:params][:foo] << @foo
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it "deletes a class filter" do
|
65
|
+
notice[:params][:foo] = []
|
66
|
+
|
67
|
+
f1 = filter.new(1)
|
68
|
+
subject.add_filter(f1)
|
69
|
+
|
70
|
+
foo_filter_mock = double
|
71
|
+
expect(foo_filter_mock).to(
|
72
|
+
receive(:name).at_least(:once).and_return('FooFilter')
|
73
|
+
)
|
74
|
+
subject.delete_filter(foo_filter_mock)
|
75
|
+
|
76
|
+
f2 = filter.new(2)
|
77
|
+
subject.add_filter(f2)
|
78
|
+
|
79
|
+
subject.refine(notice)
|
80
|
+
expect(notice[:params][:foo]).to eq([2])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
RSpec.describe Airbrake::Filters::ContextFilter do
|
2
|
+
let(:notice) do
|
3
|
+
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
4
|
+
end
|
5
|
+
|
6
|
+
context "when the current context is empty" do
|
7
|
+
it "doesn't merge anything with params" do
|
8
|
+
described_class.new({}).call(notice)
|
9
|
+
expect(notice[:params]).to be_empty
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "when the current context has some data" do
|
14
|
+
it "merges the data with params" do
|
15
|
+
described_class.new(apples: 'oranges').call(notice)
|
16
|
+
expect(notice[:params]).to eq(airbrake_context: { apples: 'oranges' })
|
17
|
+
end
|
18
|
+
|
19
|
+
it "clears the data from the provided context" do
|
20
|
+
context = { apples: 'oranges' }
|
21
|
+
described_class.new(context).call(notice)
|
22
|
+
expect(context).to be_empty
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
RSpec.describe Airbrake::Filters::DependencyFilter do
|
2
|
+
let(:notice) do
|
3
|
+
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
4
|
+
end
|
5
|
+
|
6
|
+
describe "#call" do
|
7
|
+
it "attaches loaded dependencies to context/versions/dependencies" do
|
8
|
+
subject.call(notice)
|
9
|
+
expect(notice[:context][:versions][:dependencies]).to include(
|
10
|
+
'airbrake-ruby' => Airbrake::AIRBRAKE_RUBY_VERSION
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
RSpec.describe Airbrake::Filters::ExceptionAttributesFilter do
|
2
|
+
describe "#call" do
|
3
|
+
let(:out) { StringIO.new }
|
4
|
+
let(:notice) { Airbrake::Notice.new(Airbrake::Config.new, ex) }
|
5
|
+
|
6
|
+
subject { described_class.new(Logger.new(out)) }
|
7
|
+
|
8
|
+
context "when #to_airbrake returns a non-Hash object" do
|
9
|
+
let(:ex) do
|
10
|
+
Class.new(AirbrakeTestError) do
|
11
|
+
def to_airbrake
|
12
|
+
Object.new
|
13
|
+
end
|
14
|
+
end.new
|
15
|
+
end
|
16
|
+
|
17
|
+
it "doesn't raise" do
|
18
|
+
expect { subject.call(notice) }.not_to raise_error
|
19
|
+
expect(notice[:params]).to be_empty
|
20
|
+
end
|
21
|
+
|
22
|
+
it "logs the error" do
|
23
|
+
expect { subject.call(notice) }.not_to raise_error
|
24
|
+
expect(out.string).to match(/wanted Hash, got Object/)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when #to_airbrake errors out" do
|
29
|
+
let(:ex) do
|
30
|
+
Class.new(AirbrakeTestError) do
|
31
|
+
def to_airbrake
|
32
|
+
1 / 0
|
33
|
+
end
|
34
|
+
end.new
|
35
|
+
end
|
36
|
+
|
37
|
+
it "doesn't raise" do
|
38
|
+
expect { subject.call(notice) }.not_to raise_error
|
39
|
+
expect(notice[:params]).to be_empty
|
40
|
+
end
|
41
|
+
|
42
|
+
it "logs the error" do
|
43
|
+
expect { subject.call(notice) }.not_to raise_error
|
44
|
+
expect(out.string).to match(/#to_airbrake failed.+ZeroDivisionError/)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when #to_airbrake returns a hash" do
|
49
|
+
let(:ex) do
|
50
|
+
Class.new(AirbrakeTestError) do
|
51
|
+
def to_airbrake
|
52
|
+
{ params: { foo: '1' } }
|
53
|
+
end
|
54
|
+
end.new
|
55
|
+
end
|
56
|
+
|
57
|
+
it "merges parameters with the notice" do
|
58
|
+
subject.call(notice)
|
59
|
+
expect(notice[:params]).to eq(foo: '1')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
RSpec.describe Airbrake::Filters::GemRootFilter do
|
2
|
+
let(:notice) do
|
3
|
+
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
4
|
+
end
|
5
|
+
|
6
|
+
let(:root1) { '/my/gem/root' }
|
7
|
+
let(:root2) { '/my/other/gem/root' }
|
8
|
+
|
9
|
+
before { Gem.path << root1 << root2 }
|
10
|
+
after { 2.times { Gem.path.pop } }
|
11
|
+
|
12
|
+
it "replaces gem root in the backtrace with a label" do
|
13
|
+
# rubocop:disable Metrics/LineLength
|
14
|
+
notice[:errors].first[:backtrace] = [
|
15
|
+
{ file: "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb" },
|
16
|
+
{ file: "#{root1}/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb" },
|
17
|
+
{ file: "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb" },
|
18
|
+
{ file: "#{root2}/gems/rspec-core-3.3.2/exe/rspec" }
|
19
|
+
]
|
20
|
+
# rubocop:enable Metrics/LineLength
|
21
|
+
|
22
|
+
subject.call(notice)
|
23
|
+
|
24
|
+
# rubocop:disable Metrics/LineLength
|
25
|
+
expect(notice[:errors].first[:backtrace]).to(
|
26
|
+
eq(
|
27
|
+
[
|
28
|
+
{ file: "/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb" },
|
29
|
+
{ file: "/GEM_ROOT/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb" },
|
30
|
+
{ file: "/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb" },
|
31
|
+
{ file: "/GEM_ROOT/gems/rspec-core-3.3.2/exe/rspec" }
|
32
|
+
]
|
33
|
+
)
|
34
|
+
)
|
35
|
+
# rubocop:enable Metrics/LineLength
|
36
|
+
end
|
37
|
+
|
38
|
+
it "does not filter file when it is nil" do
|
39
|
+
expect(notice[:errors].first[:file]).to be_nil
|
40
|
+
expect { subject.call(notice) }.not_to(
|
41
|
+
change { notice[:errors].first[:file] }
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
RSpec.describe Airbrake::Filters::GitLastCheckoutFilter do
|
2
|
+
subject { described_class.new(Logger.new(STDOUT), '.') }
|
3
|
+
|
4
|
+
let(:notice) do
|
5
|
+
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when context/lastCheckout is defined" do
|
9
|
+
it "doesn't attach anything to context/lastCheckout" do
|
10
|
+
notice[:context][:lastCheckout] = '123'
|
11
|
+
subject.call(notice)
|
12
|
+
expect(notice[:context][:lastCheckout]).to eq('123')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when .git directory doesn't exist" do
|
17
|
+
subject { described_class.new(Logger.new(STDOUT), 'root/dir') }
|
18
|
+
|
19
|
+
it "doesn't attach anything to context/lastCheckout" do
|
20
|
+
subject.call(notice)
|
21
|
+
expect(notice[:context][:lastCheckout]).to be_nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when .git directory exists" do
|
26
|
+
before { subject.call(notice) }
|
27
|
+
|
28
|
+
it "attaches last checkouted username" do
|
29
|
+
expect(notice[:context][:lastCheckout][:username]).not_to be_empty
|
30
|
+
end
|
31
|
+
|
32
|
+
it "attaches last checkouted email" do
|
33
|
+
expect(notice[:context][:lastCheckout][:email]).to(
|
34
|
+
match(/\A\w+[\w.-]*@\w+\.?\w+?\z/)
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "attaches last checkouted revision" do
|
39
|
+
expect(notice[:context][:lastCheckout][:revision]).not_to be_empty
|
40
|
+
expect(notice[:context][:lastCheckout][:revision].size).to eq(40)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "attaches last checkouted time" do
|
44
|
+
expect(notice[:context][:lastCheckout][:time]).not_to be_empty
|
45
|
+
expect(notice[:context][:lastCheckout][:time].size).to eq(25)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
RSpec.describe Airbrake::Filters::GitRepositoryFilter do
|
2
|
+
subject { described_class.new('.') }
|
3
|
+
|
4
|
+
let(:notice) do
|
5
|
+
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#initialize" do
|
9
|
+
it "parses standard git version" do
|
10
|
+
allow_any_instance_of(Kernel).
|
11
|
+
to receive(:`).and_return('git version 2.18.0')
|
12
|
+
expect { subject }.not_to raise_error
|
13
|
+
end
|
14
|
+
|
15
|
+
it "parses release candidate git version" do
|
16
|
+
allow_any_instance_of(Kernel).
|
17
|
+
to receive(:`).and_return('git version 2.21.0-rc0')
|
18
|
+
expect { subject }.not_to raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it "parses git version with brackets" do
|
22
|
+
allow_any_instance_of(Kernel).
|
23
|
+
to receive(:`).and_return('git version 2.17.2 (Apple Git-113)')
|
24
|
+
expect { subject }.not_to raise_error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when context/repository is defined" do
|
29
|
+
it "doesn't attach anything to context/repository" do
|
30
|
+
notice[:context][:repository] = 'git@github.com:kyrylo/test.git'
|
31
|
+
subject.call(notice)
|
32
|
+
expect(notice[:context][:repository]).to eq('git@github.com:kyrylo/test.git')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when .git directory doesn't exist" do
|
37
|
+
subject { described_class.new('root/dir') }
|
38
|
+
|
39
|
+
it "doesn't attach anything to context/repository" do
|
40
|
+
subject.call(notice)
|
41
|
+
expect(notice[:context][:repository]).to be_nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when .git directory exists" do
|
46
|
+
it "attaches context/repository" do
|
47
|
+
subject.call(notice)
|
48
|
+
expect(notice[:context][:repository]).to eq(
|
49
|
+
'ssh://git@github.com/airbrake/airbrake-ruby.git'
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
RSpec.describe Airbrake::Filters::GitRevisionFilter do
|
2
|
+
subject { described_class.new('root/dir') }
|
3
|
+
|
4
|
+
let(:notice) do
|
5
|
+
Airbrake::Notice.new(Airbrake::Config.new, AirbrakeTestError.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when context/revision is defined" do
|
9
|
+
it "doesn't attach anything to context/revision" do
|
10
|
+
notice[:context][:revision] = '1.2.3'
|
11
|
+
subject.call(notice)
|
12
|
+
expect(notice[:context][:revision]).to eq('1.2.3')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when .git directory doesn't exist" do
|
17
|
+
it "doesn't attach anything to context/revision" do
|
18
|
+
subject.call(notice)
|
19
|
+
expect(notice[:context][:revision]).to be_nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when .git directory exists" do
|
24
|
+
before do
|
25
|
+
expect(File).to receive(:exist?).with('root/dir/.git').and_return(true)
|
26
|
+
end
|
27
|
+
|
28
|
+
context "and when HEAD doesn't exist" do
|
29
|
+
before do
|
30
|
+
expect(File).to receive(:exist?).with('root/dir/.git/HEAD').and_return(false)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "doesn't attach anything to context/revision" do
|
34
|
+
subject.call(notice)
|
35
|
+
expect(notice[:context][:revision]).to be_nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "and when HEAD exists" do
|
40
|
+
before do
|
41
|
+
expect(File).to receive(:exist?).with('root/dir/.git/HEAD').and_return(true)
|
42
|
+
end
|
43
|
+
|
44
|
+
context "and also when HEAD doesn't start with 'ref: '" do
|
45
|
+
before do
|
46
|
+
expect(File).to(
|
47
|
+
receive(:read).with('root/dir/.git/HEAD').and_return('refs/foo')
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "attaches the content of HEAD to context/revision" do
|
52
|
+
subject.call(notice)
|
53
|
+
expect(notice[:context][:revision]).to eq('refs/foo')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "and also when HEAD starts with 'ref: " do
|
58
|
+
before do
|
59
|
+
expect(File).to(
|
60
|
+
receive(:read).with('root/dir/.git/HEAD').and_return("ref: refs/foo\n")
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when the ref exists" do
|
65
|
+
before do
|
66
|
+
expect(File).to(
|
67
|
+
receive(:exist?).with('root/dir/.git/refs/foo').and_return(true)
|
68
|
+
)
|
69
|
+
expect(File).to(
|
70
|
+
receive(:read).with('root/dir/.git/refs/foo').and_return("d34db33f\n")
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "attaches the revision from the ref to context/revision" do
|
75
|
+
subject.call(notice)
|
76
|
+
expect(notice[:context][:revision]).to eq('d34db33f')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when the ref doesn't exist" do
|
81
|
+
before do
|
82
|
+
expect(File).to(
|
83
|
+
receive(:exist?).with('root/dir/.git/refs/foo').and_return(false)
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
context "and when '.git/packed-refs' exists" do
|
88
|
+
before do
|
89
|
+
expect(File).to(
|
90
|
+
receive(:exist?).with('root/dir/.git/packed-refs').and_return(true)
|
91
|
+
)
|
92
|
+
expect(File).to(
|
93
|
+
receive(:readlines).with('root/dir/.git/packed-refs').and_return(
|
94
|
+
[
|
95
|
+
"# pack-refs with: peeled fully-peeled\n",
|
96
|
+
"ccb316eecff79c7528d1ad43e5fa165f7a44d52e refs/tags/v3.0.30\n",
|
97
|
+
"^d358900f73ee5bfd6ca3a592cf23ac6e82df83c1",
|
98
|
+
"d34db33f refs/foo\n"
|
99
|
+
]
|
100
|
+
)
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "attaches the revision from 'packed-refs' to context/revision" do
|
105
|
+
subject.call(notice)
|
106
|
+
expect(notice[:context][:revision]).to eq('d34db33f')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "and when '.git/packed-refs' doesn't exist" do
|
111
|
+
before do
|
112
|
+
expect(File).to(
|
113
|
+
receive(:exist?).with('root/dir/.git/packed-refs').and_return(false)
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "attaches the content of HEAD to context/revision" do
|
118
|
+
subject.call(notice)
|
119
|
+
expect(notice[:context][:revision]).to eq('refs/foo')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|