listen 2.8.4 → 2.8.5
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 +4 -4
- data/README.md +2 -11
- data/lib/listen/adapter/base.rb +8 -4
- data/lib/listen/adapter/bsd.rb +8 -25
- data/lib/listen/adapter/tcp.rb +2 -1
- data/lib/listen/internals/logging.rb +12 -8
- data/lib/listen/listener.rb +1 -1
- data/lib/listen/version.rb +1 -1
- metadata +4 -121
- data/.gitignore +0 -28
- data/.hound.yml +0 -3
- data/.rspec +0 -2
- data/.rubocop.yml +0 -20
- data/.rubocop_todo.yml +0 -33
- data/.travis.yml +0 -15
- data/.yardopts +0 -11
- data/Gemfile +0 -48
- data/Guardfile +0 -16
- data/Rakefile +0 -151
- data/TROUBLESHOOTING.md +0 -139
- data/listen.gemspec +0 -33
- data/spec/acceptance/listen_spec.rb +0 -230
- data/spec/acceptance/tcp_spec.rb +0 -139
- data/spec/lib/listen/adapter/base_spec.rb +0 -31
- data/spec/lib/listen/adapter/bsd_spec.rb +0 -14
- data/spec/lib/listen/adapter/darwin_spec.rb +0 -145
- data/spec/lib/listen/adapter/linux_spec.rb +0 -93
- data/spec/lib/listen/adapter/polling_spec.rb +0 -48
- data/spec/lib/listen/adapter/tcp_spec.rb +0 -129
- data/spec/lib/listen/adapter/windows_spec.rb +0 -14
- data/spec/lib/listen/adapter_spec.rb +0 -75
- data/spec/lib/listen/change_spec.rb +0 -104
- data/spec/lib/listen/directory_spec.rb +0 -180
- data/spec/lib/listen/file_spec.rb +0 -252
- data/spec/lib/listen/listener_spec.rb +0 -482
- data/spec/lib/listen/record_spec.rb +0 -377
- data/spec/lib/listen/silencer_spec.rb +0 -100
- data/spec/lib/listen/tcp/broadcaster_spec.rb +0 -124
- data/spec/lib/listen/tcp/listener_spec.rb +0 -104
- data/spec/lib/listen/tcp/message_spec.rb +0 -138
- data/spec/lib/listen_spec.rb +0 -52
- data/spec/spec_helper.rb +0 -52
- data/spec/support/acceptance_helper.rb +0 -275
- data/spec/support/fixtures_helper.rb +0 -30
- data/spec/support/platform_helper.rb +0 -15
- data/vendor/hound/config/style_guides/ruby.yml +0 -259
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
include Listen
|
|
4
|
-
|
|
5
|
-
describe Directory do
|
|
6
|
-
let(:dir) { double(:dir) }
|
|
7
|
-
let(:file) { double(:file, directory?: false) }
|
|
8
|
-
let(:file2) { double(:file2, directory?: false) }
|
|
9
|
-
let(:subdir) { double(:subdir, directory?: true) }
|
|
10
|
-
|
|
11
|
-
let(:queue) { instance_double(Change, change: nil) }
|
|
12
|
-
|
|
13
|
-
let(:async_record) do
|
|
14
|
-
instance_double(Record, add_dir: true, unset_path: true)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
let(:record) do
|
|
18
|
-
instance_double(Record, async: async_record, dir_entries: record_entries)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
before do
|
|
22
|
-
allow(dir).to receive(:+).with('.') { dir }
|
|
23
|
-
allow(dir).to receive(:+).with('file.rb') { file }
|
|
24
|
-
allow(dir).to receive(:+).with('subdir') { subdir }
|
|
25
|
-
|
|
26
|
-
allow(file).to receive(:relative_path_from).with(dir) { 'file.rb' }
|
|
27
|
-
allow(file2).to receive(:relative_path_from).with(dir) { 'file2.rb' }
|
|
28
|
-
allow(subdir).to receive(:relative_path_from).with(dir) { 'subdir' }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
context '#scan with recursive off' do
|
|
32
|
-
let(:options) { { recursive: false } }
|
|
33
|
-
|
|
34
|
-
context 'with file & subdir in record' do
|
|
35
|
-
let(:record_entries) do
|
|
36
|
-
{ 'file.rb' => { mtime: 1.1 }, 'subdir' => {} }
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
context 'with empty dir' do
|
|
40
|
-
before { allow(dir).to receive(:children) { [] } }
|
|
41
|
-
|
|
42
|
-
it 'sets record dir path' do
|
|
43
|
-
expect(async_record).to receive(:add_dir).with(dir, '.')
|
|
44
|
-
described_class.scan(queue, record, dir, '.', options)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it "queues changes for file path and dir that doesn't exist" do
|
|
48
|
-
expect(queue).to receive(:change).with(:file, dir, 'file.rb')
|
|
49
|
-
|
|
50
|
-
expect(queue).to receive(:change).
|
|
51
|
-
with(:dir, dir, 'subdir', recursive: false)
|
|
52
|
-
|
|
53
|
-
described_class.scan(queue, record, dir, '.', options)
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
context 'with only file2.rb in dir' do
|
|
58
|
-
before { allow(dir).to receive(:children) { [file2] } }
|
|
59
|
-
|
|
60
|
-
it 'notices file & file2 and no longer existing dir' do
|
|
61
|
-
expect(queue).to receive(:change).with(:file, dir, 'file.rb')
|
|
62
|
-
expect(queue).to receive(:change).with(:file, dir, 'file2.rb')
|
|
63
|
-
|
|
64
|
-
expect(queue).to receive(:change).
|
|
65
|
-
with(:dir, dir, 'subdir', recursive: false)
|
|
66
|
-
|
|
67
|
-
described_class.scan(queue, record, dir, '.', options)
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
context 'with empty record' do
|
|
73
|
-
let(:record_entries) { {} }
|
|
74
|
-
|
|
75
|
-
context 'with non-existing dir path' do
|
|
76
|
-
before { allow(dir).to receive(:children) { fail Errno::ENOENT } }
|
|
77
|
-
|
|
78
|
-
it 'reports no changes' do
|
|
79
|
-
expect(queue).to_not receive(:change)
|
|
80
|
-
described_class.scan(queue, record, dir, '.', options)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it 'unsets record dir path' do
|
|
84
|
-
expect(async_record).to receive(:unset_path).with(dir, '.')
|
|
85
|
-
described_class.scan(queue, record, dir, '.', options)
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
context 'with file.rb in dir' do
|
|
90
|
-
before { allow(dir).to receive(:children) { [file] } }
|
|
91
|
-
|
|
92
|
-
it 'queues changes for file & file2 paths' do
|
|
93
|
-
expect(queue).to receive(:change).with(:file, dir, 'file.rb')
|
|
94
|
-
expect(queue).to_not receive(:change).with(:file, dir, 'file2.rb')
|
|
95
|
-
|
|
96
|
-
expect(queue).to_not receive(:change).
|
|
97
|
-
with(:dir, dir, 'subdir', recursive: false)
|
|
98
|
-
|
|
99
|
-
described_class.scan(queue, record, dir, '.', options)
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
context '#scan with recursive on' do
|
|
106
|
-
let(:options) { { recursive: true } }
|
|
107
|
-
|
|
108
|
-
context 'with file.rb & subdir in record' do
|
|
109
|
-
let(:record_entries) do
|
|
110
|
-
{ 'file.rb' => { mtime: 1.1 }, 'subdir' => {} }
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
context 'with empty dir' do
|
|
114
|
-
before do
|
|
115
|
-
allow(dir).to receive(:children) { [] }
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
it 'queues changes for file & subdir path' do
|
|
119
|
-
expect(queue).to receive(:change).with(:file, dir, 'file.rb')
|
|
120
|
-
|
|
121
|
-
expect(queue).to receive(:change).
|
|
122
|
-
with(:dir, dir, 'subdir', recursive: true)
|
|
123
|
-
|
|
124
|
-
described_class.scan(queue, record, dir, '.', options)
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
context 'with subdir2 path present in dir' do
|
|
129
|
-
let(:subdir2) { double(:subdir2, directory?: true, children: []) }
|
|
130
|
-
|
|
131
|
-
before do
|
|
132
|
-
allow(dir).to receive(:children) { [subdir2] }
|
|
133
|
-
allow(subdir2).to receive(:relative_path_from).with(dir) { 'subdir2' }
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
it 'queues changes for file, file2 & subdir paths' do
|
|
137
|
-
expect(queue).to receive(:change).with(:file, dir, 'file.rb')
|
|
138
|
-
|
|
139
|
-
expect(queue).to receive(:change).
|
|
140
|
-
with(:dir, dir, 'subdir', recursive: true)
|
|
141
|
-
|
|
142
|
-
expect(queue).to receive(:change).
|
|
143
|
-
with(:dir, dir, 'subdir2', recursive: true)
|
|
144
|
-
|
|
145
|
-
described_class.scan(queue, record, dir, '.', options)
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
context 'with empty record' do
|
|
151
|
-
let(:record_entries) { {} }
|
|
152
|
-
|
|
153
|
-
context 'with non-existing dir' do
|
|
154
|
-
before do
|
|
155
|
-
allow(dir).to receive(:children) { fail Errno::ENOENT }
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
it 'reports no changes' do
|
|
159
|
-
expect(queue).to_not receive(:change)
|
|
160
|
-
described_class.scan(queue, record, dir, '.', options)
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
context 'with subdir present in dir' do
|
|
165
|
-
|
|
166
|
-
before do
|
|
167
|
-
allow(dir).to receive(:children) { [subdir] }
|
|
168
|
-
allow(subdir).to receive(:children) { [] }
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
it 'queues changes for subdir' do
|
|
172
|
-
expect(queue).to receive(:change).
|
|
173
|
-
with(:dir, dir, 'subdir', recursive: true)
|
|
174
|
-
|
|
175
|
-
described_class.scan(queue, record, dir, '.', options)
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
end
|
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe Listen::File do
|
|
4
|
-
let(:async_record) do
|
|
5
|
-
instance_double(
|
|
6
|
-
Listen::Record,
|
|
7
|
-
add_dir: true,
|
|
8
|
-
update_file: true,
|
|
9
|
-
unset_path: true
|
|
10
|
-
)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
let(:record) do
|
|
14
|
-
instance_double(
|
|
15
|
-
Listen::Record,
|
|
16
|
-
async: async_record,
|
|
17
|
-
file_data: record_data
|
|
18
|
-
)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
let(:path) { Pathname.pwd }
|
|
22
|
-
let(:subject) { described_class.change(record, path, 'file.rb') }
|
|
23
|
-
|
|
24
|
-
around { |example| fixtures { example.run } }
|
|
25
|
-
|
|
26
|
-
before { allow(::File).to receive(:lstat) { fail 'Not stubbed!' } }
|
|
27
|
-
|
|
28
|
-
describe '#change' do
|
|
29
|
-
let(:expected_data) do
|
|
30
|
-
{ mtime: kind_of(Float), mode: kind_of(Integer) }
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
context 'with file record' do
|
|
34
|
-
let(:record_mtime) { nil }
|
|
35
|
-
let(:record_md5) { nil }
|
|
36
|
-
let(:record_mode) { nil }
|
|
37
|
-
|
|
38
|
-
let(:record_data) do
|
|
39
|
-
{ mtime: record_mtime, md5: record_md5, mode: record_mode }
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
context 'with non-existing file' do
|
|
43
|
-
before { allow(::File).to receive(:lstat) { fail Errno::ENOENT } }
|
|
44
|
-
|
|
45
|
-
it { should be :removed }
|
|
46
|
-
|
|
47
|
-
it 'sets path in record' do
|
|
48
|
-
expect(async_record).to receive(:unset_path).with(path, 'file.rb')
|
|
49
|
-
subject
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
context 'with existing file' do
|
|
54
|
-
let(:stat_mtime) { Time.now.to_f - 1234.567 }
|
|
55
|
-
let(:stat_ctime) { Time.now.to_f - 1234.567 }
|
|
56
|
-
let(:stat_atime) { Time.now.to_f - 1234.567 }
|
|
57
|
-
let(:stat_mode) { 0640 }
|
|
58
|
-
let(:md5) { fail 'stub me (md5)' }
|
|
59
|
-
|
|
60
|
-
let(:stat) do
|
|
61
|
-
instance_double(
|
|
62
|
-
File::Stat,
|
|
63
|
-
mtime: stat_mtime,
|
|
64
|
-
atime: stat_atime,
|
|
65
|
-
ctime: stat_ctime,
|
|
66
|
-
mode: stat_mode
|
|
67
|
-
)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
before do
|
|
71
|
-
allow(::File).to receive(:lstat) { stat }
|
|
72
|
-
allow(Digest::MD5).to receive(:file) { double(:md5, digest: md5) }
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
context 'with different mode in record' do
|
|
76
|
-
let(:record_mode) { 0722 }
|
|
77
|
-
|
|
78
|
-
it { should be :modified }
|
|
79
|
-
|
|
80
|
-
it 'sets path in record with expected data' do
|
|
81
|
-
expect(async_record).to receive(:update_file).
|
|
82
|
-
with(path, 'file.rb', expected_data)
|
|
83
|
-
subject
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
context 'with same mode in record' do
|
|
88
|
-
let(:record_mode) { stat_mode }
|
|
89
|
-
|
|
90
|
-
# e.g. file was overwritten by earlier copy
|
|
91
|
-
context 'with earlier mtime than in record' do
|
|
92
|
-
let(:record_mtime) { stat_mtime.to_f - 123.45 }
|
|
93
|
-
|
|
94
|
-
it { should be :modified }
|
|
95
|
-
|
|
96
|
-
it 'sets path in record with expected data' do
|
|
97
|
-
expect(async_record).to receive(:update_file).
|
|
98
|
-
with(path, 'file.rb', expected_data)
|
|
99
|
-
subject
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
context 'with later mtime than in record' do
|
|
104
|
-
let(:record_mtime) { stat_mtime.to_f + 123.45 }
|
|
105
|
-
|
|
106
|
-
it { should be :modified }
|
|
107
|
-
|
|
108
|
-
it 'sets path in record with expected data' do
|
|
109
|
-
expect(async_record).to receive(:update_file).
|
|
110
|
-
with(path, 'file.rb', expected_data)
|
|
111
|
-
subject
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
context 'with indentical mtime in record' do
|
|
116
|
-
let(:record_mtime) { stat_mtime.to_f }
|
|
117
|
-
|
|
118
|
-
context 'with accurate stat times' do
|
|
119
|
-
let(:stat_mtime) { Time.at(1_401_235_714.123) }
|
|
120
|
-
let(:stat_atime) { Time.at(1_401_235_714.123) }
|
|
121
|
-
let(:stat_ctime) { Time.at(1_401_235_714.123) }
|
|
122
|
-
let(:record_mtime) { stat_mtime.to_f }
|
|
123
|
-
it { should be_nil }
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
context 'with inaccurate stat times' do
|
|
127
|
-
let(:stat_mtime) { Time.at(1_401_235_714.0) }
|
|
128
|
-
let(:stat_atime) { Time.at(1_401_235_714.0) }
|
|
129
|
-
let(:stat_ctime) { Time.at(1_401_235_714.0) }
|
|
130
|
-
|
|
131
|
-
let(:record_mtime) { stat_mtime.to_f }
|
|
132
|
-
|
|
133
|
-
context 'with real mtime barely not within last second' do
|
|
134
|
-
before { allow(Time).to receive(:now) { now } }
|
|
135
|
-
|
|
136
|
-
# NOTE: if real mtime is ???14.99, the
|
|
137
|
-
# saved mtime is ???14.0
|
|
138
|
-
let(:now) { Time.at(1_401_235_716.00) }
|
|
139
|
-
it { should be_nil }
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
context 'with real mtime barely within last second' do
|
|
143
|
-
# NOTE: real mtime is in range (???14.0 .. ???14.999),
|
|
144
|
-
# so saved mtime at ???14.0 means it could be
|
|
145
|
-
# ???14.999, so ???15.999 could still be within 1 second
|
|
146
|
-
# range
|
|
147
|
-
let(:now) { Time.at(1_401_235_715.999999) }
|
|
148
|
-
|
|
149
|
-
before { allow(Time).to receive(:now) { now } }
|
|
150
|
-
|
|
151
|
-
context 'without available md5' do
|
|
152
|
-
let(:md5) { fail Errno::ENOENT }
|
|
153
|
-
|
|
154
|
-
# Treat it as a removed file, because chances are ...
|
|
155
|
-
# whatever is listening for changes won't be able to deal
|
|
156
|
-
# with the file either (e.g. because of permissions)
|
|
157
|
-
it { should be :removed }
|
|
158
|
-
|
|
159
|
-
it 'should not unset record' do
|
|
160
|
-
expect(async_record).to_not receive(:unset_path)
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
context 'with available md5' do
|
|
165
|
-
let(:md5) { 'd41d8cd98f00b204e9800998ecf8427e' }
|
|
166
|
-
|
|
167
|
-
context 'with same md5 in record' do
|
|
168
|
-
let(:record_md5) { md5 }
|
|
169
|
-
it { should be_nil }
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
context 'with no md5 in record' do
|
|
173
|
-
let(:record_md5) { nil }
|
|
174
|
-
it { should be_nil }
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
context 'with different md5 in record' do
|
|
178
|
-
let(:record_md5) { 'foo' }
|
|
179
|
-
it { should be :modified }
|
|
180
|
-
|
|
181
|
-
it 'sets path in record with expected data' do
|
|
182
|
-
expect(async_record).to receive(:update_file).
|
|
183
|
-
with(path, 'file.rb', expected_data. merge(md5: md5))
|
|
184
|
-
subject
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
context 'with empty record' do
|
|
196
|
-
let(:record_data) { {} }
|
|
197
|
-
|
|
198
|
-
context 'with existing path' do
|
|
199
|
-
let(:stat) do
|
|
200
|
-
instance_double(
|
|
201
|
-
File::Stat,
|
|
202
|
-
mtime: 1234,
|
|
203
|
-
mode: 0645
|
|
204
|
-
)
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
before do
|
|
208
|
-
allow(::File).to receive(:lstat) { stat }
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
it 'returns added' do
|
|
212
|
-
expect(subject).to eq :added
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
it 'sets path in record with expected data' do
|
|
216
|
-
expect(async_record).to receive(:update_file).
|
|
217
|
-
with(path, 'file.rb', expected_data)
|
|
218
|
-
subject
|
|
219
|
-
end
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
describe '#inaccurate_mac_time?' do
|
|
225
|
-
let(:stat) do
|
|
226
|
-
instance_double(File::Stat, mtime: mtime, atime: atime, ctime: ctime)
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
subject { Listen::File.inaccurate_mac_time?(stat) }
|
|
230
|
-
|
|
231
|
-
context 'with no accurate times' do
|
|
232
|
-
let(:mtime) { Time.at(1_234_567.0) }
|
|
233
|
-
let(:atime) { Time.at(1_234_567.0) }
|
|
234
|
-
let(:ctime) { Time.at(1_234_567.0) }
|
|
235
|
-
it { should be_truthy }
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
context 'with all accurate times' do
|
|
239
|
-
let(:mtime) { Time.at(1_234_567.89) }
|
|
240
|
-
let(:atime) { Time.at(1_234_567.89) }
|
|
241
|
-
let(:ctime) { Time.at(1_234_567.89) }
|
|
242
|
-
it { should be_falsey }
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
context 'with one accurate time' do
|
|
246
|
-
let(:mtime) { Time.at(1_234_567.0) }
|
|
247
|
-
let(:atime) { Time.at(1_234_567.89) }
|
|
248
|
-
let(:ctime) { Time.at(1_234_567.0) }
|
|
249
|
-
it { should be_falsey }
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
end
|
|
@@ -1,482 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
include Listen
|
|
4
|
-
|
|
5
|
-
describe Listener do
|
|
6
|
-
subject { described_class.new(options) }
|
|
7
|
-
let(:options) { {} }
|
|
8
|
-
let(:registry) { instance_double(Celluloid::Registry) }
|
|
9
|
-
|
|
10
|
-
let(:supervisor) do
|
|
11
|
-
instance_double(Celluloid::SupervisionGroup, add: true, pool: true)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
let(:record) { instance_double(Record, terminate: true, build: true) }
|
|
15
|
-
let(:silencer) { instance_double(Silencer, configure: nil) }
|
|
16
|
-
let(:adapter) { instance_double(Adapter::Base, start: nil) }
|
|
17
|
-
|
|
18
|
-
before do
|
|
19
|
-
allow(Listen::Silencer).to receive(:new) { silencer }
|
|
20
|
-
|
|
21
|
-
allow(Celluloid::Registry).to receive(:new) { registry }
|
|
22
|
-
allow(Celluloid::SupervisionGroup).to receive(:run!) { supervisor }
|
|
23
|
-
allow(registry).to receive(:[]).with(:adapter) { adapter }
|
|
24
|
-
allow(registry).to receive(:[]).with(:record) { record }
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
describe 'initialize' do
|
|
28
|
-
it { should_not be_paused }
|
|
29
|
-
|
|
30
|
-
context 'with a block' do
|
|
31
|
-
describe 'block' do
|
|
32
|
-
subject { described_class.new('lib', &(proc {})) }
|
|
33
|
-
specify { expect(subject.block).to_not be_nil }
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
context 'with directories' do
|
|
38
|
-
describe 'directories' do
|
|
39
|
-
subject { described_class.new('lib', 'spec') }
|
|
40
|
-
expected = %w(lib spec).map { |dir| Pathname.pwd + dir }
|
|
41
|
-
specify { expect(subject.directories).to eq expected }
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
describe 'options' do
|
|
47
|
-
context 'default options' do
|
|
48
|
-
it 'sets default options' do
|
|
49
|
-
expect(subject.options).
|
|
50
|
-
to eq(
|
|
51
|
-
debug: false,
|
|
52
|
-
latency: nil,
|
|
53
|
-
wait_for_delay: 0.1,
|
|
54
|
-
force_polling: false,
|
|
55
|
-
polling_fallback_message: nil)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
context 'custom options' do
|
|
60
|
-
subject do
|
|
61
|
-
described_class.new('lib', latency: 1.234, wait_for_delay: 0.85)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it 'sets new options on initialize' do
|
|
65
|
-
expect(subject.options).
|
|
66
|
-
to eq(
|
|
67
|
-
debug: false,
|
|
68
|
-
latency: 1.234,
|
|
69
|
-
wait_for_delay: 0.85,
|
|
70
|
-
force_polling: false,
|
|
71
|
-
polling_fallback_message: nil)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
describe '#start' do
|
|
77
|
-
before do
|
|
78
|
-
allow(subject).to receive(:_start_adapter)
|
|
79
|
-
allow(silencer).to receive(:silenced?) { false }
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
it 'supervises change_pool' do
|
|
83
|
-
expect(supervisor).to receive(:pool).
|
|
84
|
-
with(Change, as: :change_pool, args: subject)
|
|
85
|
-
|
|
86
|
-
subject.start
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it 'supervises adapter' do
|
|
90
|
-
allow(Adapter).to receive(:select) { Adapter::Polling }
|
|
91
|
-
options = [mq: subject, directories: []]
|
|
92
|
-
expect(supervisor).to receive(:add).
|
|
93
|
-
with(Adapter::Polling, as: :adapter, args: options)
|
|
94
|
-
|
|
95
|
-
subject.start
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
it 'supervises record' do
|
|
99
|
-
expect(supervisor).to receive(:add).
|
|
100
|
-
with(Record, as: :record, args: subject)
|
|
101
|
-
|
|
102
|
-
subject.start
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
it 'builds record' do
|
|
106
|
-
expect(record).to receive(:build)
|
|
107
|
-
subject.start
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
it 'sets paused to false' do
|
|
111
|
-
subject.start
|
|
112
|
-
expect(subject).to_not be_paused
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
it 'starts adapter' do
|
|
116
|
-
expect(subject).to receive(:_start_adapter)
|
|
117
|
-
subject.start
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
it 'calls block on changes' do
|
|
121
|
-
foo = instance_double(Pathname, to_s: 'foo', exist?: true)
|
|
122
|
-
|
|
123
|
-
dir = instance_double(Pathname)
|
|
124
|
-
allow(dir).to receive(:+).with('foo') { foo }
|
|
125
|
-
|
|
126
|
-
block_stub = instance_double(Proc)
|
|
127
|
-
subject.block = block_stub
|
|
128
|
-
expect(block_stub).to receive(:call).with(['foo'], [], [])
|
|
129
|
-
subject.start
|
|
130
|
-
subject.queue(:file, :modified, dir, 'foo')
|
|
131
|
-
sleep 0.25
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
describe '#stop' do
|
|
136
|
-
before do
|
|
137
|
-
allow(Celluloid::SupervisionGroup).to receive(:run!) { supervisor }
|
|
138
|
-
subject.start
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
it 'terminates supervisor' do
|
|
142
|
-
expect(supervisor).to receive(:terminate)
|
|
143
|
-
subject.stop
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
describe '#pause' do
|
|
148
|
-
before { subject.start }
|
|
149
|
-
it 'sets paused to true' do
|
|
150
|
-
subject.pause
|
|
151
|
-
expect(subject).to be_paused
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
describe '#unpause' do
|
|
156
|
-
before do
|
|
157
|
-
subject.start
|
|
158
|
-
subject.pause
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
it 'sets paused to false' do
|
|
162
|
-
subject.unpause
|
|
163
|
-
expect(subject).to_not be_paused
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
describe '#paused?' do
|
|
168
|
-
before { subject.start }
|
|
169
|
-
it 'returns true when paused' do
|
|
170
|
-
subject.paused = true
|
|
171
|
-
expect(subject).to be_paused
|
|
172
|
-
end
|
|
173
|
-
it 'returns false when not paused (nil)' do
|
|
174
|
-
subject.paused = nil
|
|
175
|
-
expect(subject).not_to be_paused
|
|
176
|
-
end
|
|
177
|
-
it 'returns false when not paused (false)' do
|
|
178
|
-
subject.paused = false
|
|
179
|
-
expect(subject).not_to be_paused
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
describe '#listen?' do
|
|
184
|
-
context 'when processing' do
|
|
185
|
-
before { subject.start }
|
|
186
|
-
it { should be_processing }
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
context 'when stopped' do
|
|
190
|
-
it { should_not be_processing }
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
context 'when paused' do
|
|
194
|
-
before do
|
|
195
|
-
subject.start
|
|
196
|
-
subject.pause
|
|
197
|
-
end
|
|
198
|
-
it { should_not be_processing }
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
describe '#ignore' do
|
|
203
|
-
context 'with existing ignore options' do
|
|
204
|
-
let(:options) { { ignore: /bar/ } }
|
|
205
|
-
|
|
206
|
-
it 'adds up to existing ignore options' do
|
|
207
|
-
expect(silencer).to receive(:configure).with(options)
|
|
208
|
-
subject.ignore(/foo/)
|
|
209
|
-
expect(subject.options).to include(ignore: [/bar/, /foo/])
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
context 'with existing ignore options (array)' do
|
|
214
|
-
let(:options) { { ignore: [/bar/] } }
|
|
215
|
-
|
|
216
|
-
it 'adds up to existing ignore options' do
|
|
217
|
-
expect(silencer).to receive(:configure).with(options)
|
|
218
|
-
subject.ignore(/foo/)
|
|
219
|
-
expect(subject.options).to include(ignore: [[/bar/], /foo/])
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
describe '#ignore!' do
|
|
225
|
-
context 'with no existing options' do
|
|
226
|
-
let(:options) { {} }
|
|
227
|
-
|
|
228
|
-
it 'sets options' do
|
|
229
|
-
expect(silencer).to receive(:configure).with(options)
|
|
230
|
-
subject
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
context 'with existing ignore! options' do
|
|
235
|
-
let(:options) { { ignore!: /bar/ } }
|
|
236
|
-
|
|
237
|
-
it 'overwrites existing ignore options' do
|
|
238
|
-
expect(silencer).to receive(:configure).with(options)
|
|
239
|
-
subject.ignore!([/foo/])
|
|
240
|
-
expect(subject.options).to include(ignore!: [/foo/])
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
context 'with existing ignore options' do
|
|
245
|
-
let(:options) { { ignore: /bar/ } }
|
|
246
|
-
|
|
247
|
-
it 'deletes ignore options' do
|
|
248
|
-
expect(silencer).to receive(:configure).with(options)
|
|
249
|
-
subject.ignore!([/foo/])
|
|
250
|
-
expect(subject.options).to_not include(ignore: /bar/)
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
describe '#only' do
|
|
256
|
-
context 'with existing only options' do
|
|
257
|
-
let(:options) { { only: /bar/ } }
|
|
258
|
-
|
|
259
|
-
it 'overwrites existing ignore options' do
|
|
260
|
-
expect(silencer).to receive(:configure).with(options)
|
|
261
|
-
subject.only([/foo/])
|
|
262
|
-
expect(subject.options).to include(only: [/foo/])
|
|
263
|
-
end
|
|
264
|
-
end
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
describe '_wait_for_changes' do
|
|
268
|
-
it 'gets two changes and calls the block once' do
|
|
269
|
-
allow(silencer).to receive(:silenced?) { false }
|
|
270
|
-
|
|
271
|
-
subject.block = proc do |modified, added, _|
|
|
272
|
-
expect(modified).to eql(['foo/bar.txt'])
|
|
273
|
-
expect(added).to eql(['foo/baz.txt'])
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
bar = instance_double(
|
|
277
|
-
Pathname,
|
|
278
|
-
to_s: 'foo/bar.txt',
|
|
279
|
-
exist?: true,
|
|
280
|
-
directory?: false)
|
|
281
|
-
|
|
282
|
-
baz = instance_double(
|
|
283
|
-
Pathname,
|
|
284
|
-
to_s: 'foo/baz.txt',
|
|
285
|
-
exist?: true,
|
|
286
|
-
directory?: false)
|
|
287
|
-
|
|
288
|
-
dir = instance_double(Pathname)
|
|
289
|
-
expect(dir).to receive(:+).with('bar.txt') { bar }
|
|
290
|
-
expect(dir).to receive(:+).with('baz.txt') { baz }
|
|
291
|
-
|
|
292
|
-
subject.start
|
|
293
|
-
subject.queue(:file, :modified, dir, 'bar.txt', {})
|
|
294
|
-
subject.queue(:file, :added, dir, 'baz.txt', {})
|
|
295
|
-
sleep 0.25
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
describe '_smoosh_changes' do
|
|
300
|
-
it 'recognizes rename from temp file' do
|
|
301
|
-
bar = instance_double(
|
|
302
|
-
Pathname,
|
|
303
|
-
to_s: 'bar',
|
|
304
|
-
exist?: true,
|
|
305
|
-
directory?: false)
|
|
306
|
-
|
|
307
|
-
foo = instance_double(Pathname, to_s: 'foo')
|
|
308
|
-
allow(foo).to receive(:+).with('bar') { bar }
|
|
309
|
-
|
|
310
|
-
changes = [
|
|
311
|
-
[:file, :modified, foo, 'bar'],
|
|
312
|
-
[:file, :removed, foo, 'bar'],
|
|
313
|
-
[:file, :added, foo, 'bar'],
|
|
314
|
-
[:file, :modified, foo, 'bar']
|
|
315
|
-
]
|
|
316
|
-
allow(silencer).to receive(:silenced?) { false }
|
|
317
|
-
smooshed = subject.send :_smoosh_changes, changes
|
|
318
|
-
expect(smooshed).to eq(modified: ['bar'], added: [], removed: [])
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
it 'ignores deleted temp file' do
|
|
322
|
-
bar = instance_double(
|
|
323
|
-
Pathname,
|
|
324
|
-
to_s: 'bar',
|
|
325
|
-
exist?: false)
|
|
326
|
-
|
|
327
|
-
foo = instance_double(Pathname, to_s: 'foo')
|
|
328
|
-
allow(foo).to receive(:+).with('bar') { bar }
|
|
329
|
-
|
|
330
|
-
changes = [
|
|
331
|
-
[:file, :added, foo, 'bar'],
|
|
332
|
-
[:file, :modified, foo, 'bar'],
|
|
333
|
-
[:file, :removed, foo, 'bar'],
|
|
334
|
-
[:file, :modified, foo, 'bar']
|
|
335
|
-
]
|
|
336
|
-
allow(silencer).to receive(:silenced?) { false }
|
|
337
|
-
smooshed = subject.send :_smoosh_changes, changes
|
|
338
|
-
expect(smooshed).to eq(modified: [], added: [], removed: [])
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
it 'recognizes double move as modification' do
|
|
342
|
-
# e.g. "mv foo x && mv x foo" is like "touch foo"
|
|
343
|
-
bar = instance_double(
|
|
344
|
-
Pathname,
|
|
345
|
-
to_s: 'bar',
|
|
346
|
-
exist?: true)
|
|
347
|
-
|
|
348
|
-
dir = instance_double(Pathname, to_s: 'foo')
|
|
349
|
-
allow(dir).to receive(:+).with('bar') { bar }
|
|
350
|
-
|
|
351
|
-
changes = [
|
|
352
|
-
[:file, :removed, dir, 'bar'],
|
|
353
|
-
[:file, :added, dir, 'bar']
|
|
354
|
-
]
|
|
355
|
-
allow(silencer).to receive(:silenced?) { false }
|
|
356
|
-
smooshed = subject.send :_smoosh_changes, changes
|
|
357
|
-
expect(smooshed).to eq(modified: ['bar'], added: [], removed: [])
|
|
358
|
-
end
|
|
359
|
-
|
|
360
|
-
context 'with cookie' do
|
|
361
|
-
|
|
362
|
-
it 'recognizes single moved_to as add' do
|
|
363
|
-
foo = instance_double(
|
|
364
|
-
Pathname,
|
|
365
|
-
to_s: 'foo',
|
|
366
|
-
exist?: true)
|
|
367
|
-
|
|
368
|
-
dir = instance_double(Pathname, to_s: 'foo')
|
|
369
|
-
allow(dir).to receive(:+).with('foo') { foo }
|
|
370
|
-
|
|
371
|
-
changes = [[:file, :moved_to, dir, 'foo', cookie: 4321]]
|
|
372
|
-
expect(silencer).to receive(:silenced?).
|
|
373
|
-
with(Pathname('foo'), :file) { false }
|
|
374
|
-
|
|
375
|
-
smooshed = subject.send :_smoosh_changes, changes
|
|
376
|
-
expect(smooshed).to eq(modified: [], added: ['foo'], removed: [])
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
it 'recognizes related moved_to as add' do
|
|
380
|
-
foo = instance_double(
|
|
381
|
-
Pathname,
|
|
382
|
-
to_s: 'foo',
|
|
383
|
-
exist?: true,
|
|
384
|
-
directory?: false)
|
|
385
|
-
|
|
386
|
-
bar = instance_double(
|
|
387
|
-
Pathname,
|
|
388
|
-
to_s: 'bar',
|
|
389
|
-
exist?: true,
|
|
390
|
-
directory?: false)
|
|
391
|
-
|
|
392
|
-
dir = instance_double(Pathname)
|
|
393
|
-
allow(dir).to receive(:+).with('foo') { foo }
|
|
394
|
-
allow(dir).to receive(:+).with('bar') { bar }
|
|
395
|
-
|
|
396
|
-
changes = [
|
|
397
|
-
[:file, :moved_from, dir, 'foo', cookie: 4321],
|
|
398
|
-
[:file, :moved_to, dir, 'bar', cookie: 4321]
|
|
399
|
-
]
|
|
400
|
-
|
|
401
|
-
expect(silencer).to receive(:silenced?).
|
|
402
|
-
twice.with(Pathname('foo'), :file) { false }
|
|
403
|
-
|
|
404
|
-
expect(silencer).to receive(:silenced?).
|
|
405
|
-
with(Pathname('bar'), :file) { false }
|
|
406
|
-
|
|
407
|
-
smooshed = subject.send :_smoosh_changes, changes
|
|
408
|
-
expect(smooshed).to eq(modified: [], added: ['bar'], removed: [])
|
|
409
|
-
end
|
|
410
|
-
|
|
411
|
-
# Scenario with workaround for editors using rename()
|
|
412
|
-
it 'recognizes related moved_to with ignored moved_from as modify' do
|
|
413
|
-
|
|
414
|
-
ignored = instance_double(
|
|
415
|
-
Pathname,
|
|
416
|
-
to_s: 'ignored',
|
|
417
|
-
exist?: true,
|
|
418
|
-
directory?: false)
|
|
419
|
-
|
|
420
|
-
foo = instance_double(
|
|
421
|
-
Pathname,
|
|
422
|
-
to_s: 'foo',
|
|
423
|
-
exist?: true,
|
|
424
|
-
directory?: false)
|
|
425
|
-
|
|
426
|
-
dir = instance_double(Pathname)
|
|
427
|
-
allow(dir).to receive(:+).with('foo') { foo }
|
|
428
|
-
allow(dir).to receive(:+).with('ignored') { ignored }
|
|
429
|
-
|
|
430
|
-
changes = [
|
|
431
|
-
[:file, :moved_from, dir, 'ignored', cookie: 4321],
|
|
432
|
-
[:file, :moved_to, dir, 'foo', cookie: 4321]
|
|
433
|
-
]
|
|
434
|
-
|
|
435
|
-
expect(silencer).to receive(:silenced?).
|
|
436
|
-
with(Pathname('ignored'), :file) { true }
|
|
437
|
-
|
|
438
|
-
expect(silencer).to receive(:silenced?).
|
|
439
|
-
with(Pathname('foo'), :file) { false }
|
|
440
|
-
|
|
441
|
-
smooshed = subject.send :_smoosh_changes, changes
|
|
442
|
-
expect(smooshed).to eq(modified: ['foo'], added: [], removed: [])
|
|
443
|
-
end
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
context 'with no cookie' do
|
|
447
|
-
context 'with ignored file' do
|
|
448
|
-
let(:dir) { instance_double(Pathname) }
|
|
449
|
-
let(:ignored) { instance_double(Pathname, to_s: 'foo', exist?: true) }
|
|
450
|
-
|
|
451
|
-
before do
|
|
452
|
-
expect(silencer).to receive(:silenced?).
|
|
453
|
-
with(Pathname('ignored'), :file) { true }
|
|
454
|
-
|
|
455
|
-
allow(dir).to receive(:+).with('ignored') { ignored }
|
|
456
|
-
end
|
|
457
|
-
|
|
458
|
-
it 'recognizes properly ignores files' do
|
|
459
|
-
changes = [[:file, :modified, dir, 'ignored']]
|
|
460
|
-
smooshed = subject.send :_smoosh_changes, changes
|
|
461
|
-
expect(smooshed).to eq(modified: [], added: [], removed: [])
|
|
462
|
-
end
|
|
463
|
-
end
|
|
464
|
-
end
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
context 'when listener is stopped' do
|
|
468
|
-
|
|
469
|
-
before do
|
|
470
|
-
allow(registry).to receive(:[]).with(:change_pool) { nil }
|
|
471
|
-
subject.stop
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
let(:dir) { instance_double(Pathname) }
|
|
475
|
-
|
|
476
|
-
it 'queuing does not crash when no worker is available' do
|
|
477
|
-
expect do
|
|
478
|
-
subject.send(:_queue_raw_change, :dir, dir, 'path', recursive: true)
|
|
479
|
-
end.to_not raise_error
|
|
480
|
-
end
|
|
481
|
-
end
|
|
482
|
-
end
|