This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
require 'spec_helper'
|
||||
require 'tmpdir'
|
||||
require 'concurrent'
|
||||
|
||||
describe INotify::Notifier do
|
||||
describe "instance" do
|
||||
around do |block|
|
||||
Dir.mktmpdir do |dir|
|
||||
@root = Pathname.new(dir)
|
||||
@notifier = INotify::Notifier.new
|
||||
|
||||
begin
|
||||
block.call
|
||||
ensure
|
||||
@notifier.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:dir) do
|
||||
@root.join("foo").tap(&:mkdir)
|
||||
end
|
||||
|
||||
let(:another_dir) do
|
||||
@root.join("bar").tap(&:mkdir)
|
||||
end
|
||||
|
||||
it "stops" do
|
||||
@notifier.stop
|
||||
end
|
||||
|
||||
describe :process do
|
||||
it "gets events" do
|
||||
events = recording(dir, :create)
|
||||
dir.join("test.txt").write("hello world")
|
||||
|
||||
@notifier.process
|
||||
|
||||
expect(events.size).to eq(1)
|
||||
expect(events.first.name).to eq("test.txt")
|
||||
expect(events.first.absolute_name).to eq(dir.join("test.txt").to_s)
|
||||
end
|
||||
|
||||
it "gets simultaneous events" do
|
||||
events = recording(dir, :create)
|
||||
|
||||
dir.join("one.txt").write("hello world")
|
||||
dir.join("two.txt").write("hello world")
|
||||
|
||||
@notifier.process
|
||||
|
||||
expect(events.map(&:name)).to match_array(%w(one.txt two.txt))
|
||||
end
|
||||
|
||||
it "separates events between watches" do
|
||||
bar_events = nil
|
||||
|
||||
foo_events = recording(dir, :create)
|
||||
bar_events = recording(another_dir, :create)
|
||||
|
||||
dir.join("test.txt").write("hello world")
|
||||
another_dir.join("test_two.txt").write("hello world")
|
||||
|
||||
@notifier.process
|
||||
|
||||
expect(foo_events.size).to eq(1)
|
||||
expect(foo_events.first.name).to eq("test.txt")
|
||||
expect(foo_events.first.absolute_name).to eq(dir.join("test.txt").to_s)
|
||||
|
||||
expect(bar_events.size).to eq(1)
|
||||
expect(bar_events.first.name).to eq("test_two.txt")
|
||||
expect(bar_events.first.absolute_name).to eq(another_dir.join("test_two.txt").to_s)
|
||||
end
|
||||
end
|
||||
|
||||
describe :run do
|
||||
it "processes repeatedly until stopped" do
|
||||
barriers = Array.new(3) { Concurrent::Event.new }
|
||||
barrier_queue = barriers.dup
|
||||
events = recording(dir, :create) { barrier_queue.shift.set }
|
||||
|
||||
run_thread = Thread.new { @notifier.run }
|
||||
|
||||
dir.join("one.txt").write("hello world")
|
||||
barriers.shift.wait(1) or raise "timeout"
|
||||
|
||||
expect(events.map(&:name)).to match_array(%w(one.txt))
|
||||
|
||||
dir.join("two.txt").write("hello world")
|
||||
barriers.shift.wait(1) or raise "timeout"
|
||||
|
||||
expect(events.map(&:name)).to match_array(%w(one.txt two.txt))
|
||||
|
||||
@notifier.stop
|
||||
|
||||
dir.join("three.txt").write("hello world")
|
||||
run_thread.join(1) or raise "timeout"
|
||||
|
||||
expect(events.map(&:name)).to match_array(%w(one.txt two.txt))
|
||||
end
|
||||
|
||||
it "can be stopped from within a callback" do
|
||||
recording(dir, :create) { @notifier.stop }
|
||||
|
||||
run_thread = Thread.new { @notifier.run }
|
||||
|
||||
dir.join("one.txt").write("hello world")
|
||||
run_thread.join(1) or raise "timeout"
|
||||
end
|
||||
|
||||
it "can be stopped before it starts processing" do
|
||||
barrier = Concurrent::Event.new
|
||||
|
||||
run_thread = Thread.new do
|
||||
barrier.wait
|
||||
@notifier.run
|
||||
end
|
||||
|
||||
@notifier.stop
|
||||
barrier.set
|
||||
|
||||
run_thread.join(1) or raise "timeout"
|
||||
end
|
||||
end
|
||||
|
||||
describe :fd do
|
||||
it "returns an integer" do
|
||||
expect(@notifier.fd).to be_an(Integer)
|
||||
end
|
||||
end
|
||||
|
||||
describe :to_io do
|
||||
it "returns a ruby IO" do
|
||||
expect(@notifier.to_io).to be_an(::IO)
|
||||
end
|
||||
|
||||
it "matches the fd" do
|
||||
expect(@notifier.to_io.fileno).to eq(@notifier.fd)
|
||||
end
|
||||
|
||||
it "caches its result" do
|
||||
expect(@notifier.to_io).to be(@notifier.to_io)
|
||||
end
|
||||
|
||||
it "is selectable" do
|
||||
events = recording(dir, :create)
|
||||
expect(select([@notifier.to_io], nil, nil, 0.2)).to be_nil
|
||||
|
||||
dir.join("test.txt").write("hello world")
|
||||
expect(select([@notifier.to_io], nil, nil, 0.2)).to eq([[@notifier.to_io], [], []])
|
||||
|
||||
@notifier.process
|
||||
expect(select([@notifier.to_io], nil, nil, 0.2)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def recording(dir, *flags, callback: nil)
|
||||
events = []
|
||||
@notifier.watch(dir.to_s, *flags) do |event|
|
||||
events << event
|
||||
yield if block_given?
|
||||
end
|
||||
|
||||
events
|
||||
end
|
||||
end
|
||||
|
||||
describe "mixed instances" do
|
||||
it "doesn't tangle fds" do
|
||||
notifiers = Array.new(30) { INotify::Notifier.new }
|
||||
notifiers.each(&:to_io)
|
||||
|
||||
one = Array.new(10) { IO.pipe.last }
|
||||
notifiers.each(&:close)
|
||||
|
||||
two = Array.new(10) { IO.pipe.last }
|
||||
|
||||
notifiers = nil
|
||||
GC.start
|
||||
|
||||
_, writable, _ = select(nil, one, nil, 1)
|
||||
expect(writable).to match_array(one)
|
||||
|
||||
_, writable, _ = select(nil, two, nil, 1)
|
||||
expect(writable).to match_array(two)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user