forked from guard/listen
/
thread_spec.rb
133 lines (115 loc) · 3.6 KB
/
thread_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# frozen_string_literal: true
require 'listen/thread'
RSpec.describe Listen::Thread do
let(:raise_nested_exception_block) do
-> do
begin
begin
raise ArgumentError, 'boom!'
rescue
raise 'nested inner'
end
rescue
raise 'nested outer'
end
end
end
let(:raise_script_error_block) do
-> do
raise ScriptError, "ruby typo!"
end
end
describe '.new' do
let(:name) { "worker_thread" }
let(:block) { -> { } }
subject { described_class.new(name, &block) }
it "calls Thread.new" do
expect(Thread).to receive(:new) do
thread = instance_double(Thread, "thread")
expect(thread).to receive(:name=).with("listen-#{name}")
thread
end
subject
end
context "when exception raised" do
let(:block) do
-> { raise ArgumentError, 'boom!' }
end
it "rescues and logs exceptions" do
pattern = <<~EOS.strip
Exception rescued in listen-worker_thread:
ArgumentError: boom!
.*\\/listen\\/thread_spec\\.rb
EOS
expect(Listen.logger).to receive(:error).with(/#{pattern}/)
subject.join
end
it "rescues and logs backtrace + exception backtrace" do
pattern = <<~EOS.strip
Exception rescued in listen-worker_thread:
ArgumentError: boom!
.*\\/listen\\/thread\\.rb.*--- Thread.new ---.*\\/listen\\/thread_spec\\.rb
EOS
expect(Listen.logger).to receive(:error).with(/#{pattern}/m)
subject.join
end
end
class TestExceptionDerivedFromException < Exception; end # rubocop:disable Lint/InheritException
context "when exception raised that is not derived from StandardError" do
[SystemExit, SystemStackError, NoMemoryError, SecurityError, TestExceptionDerivedFromException].each do |exception|
context exception.name do
let(:block) do
-> { raise exception, 'boom!' }
end
it "does not rescue" do
expect(Thread).to receive(:new) do |&block|
expect do
block.call
end.to raise_exception(exception, 'boom!')
thread = instance_double(Thread, "thread")
allow(thread).to receive(:name=).with(any_args)
thread
end
subject
end
end
end
end
context "when nested exceptions raised" do
let(:block) { raise_nested_exception_block }
it "details exception causes" do
pattern = <<~EOS
RuntimeError: nested outer
--- Caused by: ---
RuntimeError: nested inner
--- Caused by: ---
ArgumentError: boom!
EOS
expect(Listen.logger).to receive(:error).with(/#{pattern}/)
subject.join
end
end
end
describe '.rescue_and_log' do
it 'rescues and logs nested exceptions' do
pattern = <<~EOS
Exception rescued in method:
RuntimeError: nested outer
--- Caused by: ---
RuntimeError: nested inner
--- Caused by: ---
ArgumentError: boom!
EOS
expect(Listen.logger).to receive(:error).with(/#{pattern}/)
described_class.rescue_and_log("method", &raise_nested_exception_block)
end
context 'when exception raised that is not derived from StandardError' do
let(:block) { raise_script_error_block }
it "raises out" do
expect do
described_class.rescue_and_log("method", &raise_script_error_block)
end.to raise_exception(ScriptError, "ruby typo!")
end
end
end
end