2017-07-09 08:06:36 -04:00
|
|
|
# frozen_string_literal: true
|
2017-07-10 09:39:13 -04:00
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
require "abstract_unit"
|
|
|
|
require "pathname"
|
|
|
|
require "file_update_checker_shared_tests"
|
2015-10-12 14:41:14 -04:00
|
|
|
|
2015-12-08 21:07:49 -05:00
|
|
|
class EventedFileUpdateCheckerTest < ActiveSupport::TestCase
|
2015-11-10 10:21:33 -05:00
|
|
|
include FileUpdateCheckerSharedTests
|
2015-10-12 14:41:14 -04:00
|
|
|
|
2015-11-27 04:29:53 -05:00
|
|
|
def setup
|
2016-08-06 12:03:25 -04:00
|
|
|
skip if ENV["LISTEN"] == "0"
|
2017-01-31 18:37:28 -05:00
|
|
|
require "listen"
|
2015-11-27 04:29:53 -05:00
|
|
|
super
|
|
|
|
end
|
|
|
|
|
2015-11-11 00:38:18 -05:00
|
|
|
def new_checker(files = [], dirs = {}, &block)
|
2016-06-06 12:26:22 -04:00
|
|
|
ActiveSupport::EventedFileUpdateChecker.new(files, dirs, &block).tap do |c|
|
2015-11-09 01:32:46 -05:00
|
|
|
wait
|
|
|
|
end
|
2015-10-12 14:41:14 -04:00
|
|
|
end
|
2015-11-08 21:14:08 -05:00
|
|
|
|
|
|
|
def teardown
|
|
|
|
super
|
|
|
|
Listen.stop
|
|
|
|
end
|
2015-11-09 00:01:38 -05:00
|
|
|
|
|
|
|
def wait
|
2015-11-09 01:32:46 -05:00
|
|
|
sleep 1
|
2015-11-09 00:01:38 -05:00
|
|
|
end
|
2015-11-09 12:24:41 -05:00
|
|
|
|
|
|
|
def touch(files)
|
|
|
|
super
|
|
|
|
wait # wait for the events to fire
|
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "notifies forked processes" do
|
2019-09-26 18:27:00 -04:00
|
|
|
skip "Forking not available" unless Process.respond_to?(:fork)
|
2016-10-20 09:32:25 -04:00
|
|
|
|
2016-06-08 16:52:02 -04:00
|
|
|
FileUtils.touch(tmpfiles)
|
|
|
|
|
2018-09-25 13:18:20 -04:00
|
|
|
checker = new_checker(tmpfiles) { }
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_not_predicate checker, :updated?
|
2016-06-08 16:52:02 -04:00
|
|
|
|
2017-02-05 20:00:18 -05:00
|
|
|
# Pipes used for flow control across fork.
|
2016-06-08 16:52:02 -04:00
|
|
|
boot_reader, boot_writer = IO.pipe
|
|
|
|
touch_reader, touch_writer = IO.pipe
|
|
|
|
|
|
|
|
pid = fork do
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate checker, :updated?
|
2016-06-08 16:52:02 -04:00
|
|
|
|
|
|
|
# Clear previous check value.
|
|
|
|
checker.execute
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_not_predicate checker, :updated?
|
2016-06-08 16:52:02 -04:00
|
|
|
|
|
|
|
# Fork is booted, ready for file to be touched
|
|
|
|
# notify parent process.
|
|
|
|
boot_writer.write("booted")
|
|
|
|
|
|
|
|
# Wait for parent process to signal that file
|
|
|
|
# has been touched.
|
|
|
|
IO.select([touch_reader])
|
|
|
|
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate checker, :updated?
|
2016-06-08 16:52:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
assert pid
|
|
|
|
|
|
|
|
# Wait for fork to be booted before touching files.
|
|
|
|
IO.select([boot_reader])
|
|
|
|
touch(tmpfiles)
|
|
|
|
|
|
|
|
# Notify fork that files have been touched.
|
|
|
|
touch_writer.write("touched")
|
|
|
|
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate checker, :updated?
|
2016-06-08 16:52:02 -04:00
|
|
|
|
|
|
|
Process.wait(pid)
|
|
|
|
end
|
2018-09-07 08:54:23 -04:00
|
|
|
|
2019-05-22 19:42:34 -04:00
|
|
|
test "should detect changes through symlink" do
|
|
|
|
actual_dir = File.join(tmpdir, "actual")
|
|
|
|
linked_dir = File.join(tmpdir, "linked")
|
|
|
|
|
|
|
|
Dir.mkdir(actual_dir)
|
|
|
|
FileUtils.ln_s(actual_dir, linked_dir)
|
|
|
|
|
|
|
|
checker = new_checker([], linked_dir => ".rb") { }
|
|
|
|
|
|
|
|
assert_not_predicate checker, :updated?
|
|
|
|
|
|
|
|
FileUtils.touch(File.join(actual_dir, "a.rb"))
|
|
|
|
wait
|
|
|
|
|
|
|
|
assert_predicate checker, :updated?
|
|
|
|
assert checker.execute_if_updated
|
|
|
|
end
|
|
|
|
|
2018-09-07 08:54:23 -04:00
|
|
|
test "updated should become true when nonexistent directory is added later" do
|
2019-05-22 19:58:01 -04:00
|
|
|
watched_dir = File.join(tmpdir, "app")
|
|
|
|
unwatched_dir = File.join(tmpdir, "node_modules")
|
|
|
|
not_exist_watched_dir = File.join(tmpdir, "test")
|
2018-09-07 08:54:23 -04:00
|
|
|
|
2019-05-22 19:58:01 -04:00
|
|
|
Dir.mkdir(watched_dir)
|
|
|
|
Dir.mkdir(unwatched_dir)
|
2018-09-07 08:54:23 -04:00
|
|
|
|
2019-05-22 19:58:01 -04:00
|
|
|
checker = new_checker([], watched_dir => ".rb", not_exist_watched_dir => ".rb") { }
|
2018-09-07 08:54:23 -04:00
|
|
|
|
2019-05-22 19:58:01 -04:00
|
|
|
FileUtils.touch(File.join(watched_dir, "a.rb"))
|
|
|
|
wait
|
|
|
|
assert_predicate checker, :updated?
|
|
|
|
assert checker.execute_if_updated
|
2018-09-07 08:54:23 -04:00
|
|
|
|
2019-05-22 19:58:01 -04:00
|
|
|
Dir.mkdir(not_exist_watched_dir)
|
|
|
|
wait
|
|
|
|
assert_predicate checker, :updated?
|
|
|
|
assert checker.execute_if_updated
|
2018-09-07 08:54:23 -04:00
|
|
|
|
2019-05-22 19:58:01 -04:00
|
|
|
FileUtils.touch(File.join(unwatched_dir, "a.rb"))
|
|
|
|
wait
|
|
|
|
assert_not_predicate checker, :updated?
|
|
|
|
assert_not checker.execute_if_updated
|
2018-09-07 08:54:23 -04:00
|
|
|
end
|
2015-10-12 14:41:14 -04:00
|
|
|
end
|
2015-11-08 17:29:26 -05:00
|
|
|
|
2015-12-08 21:07:49 -05:00
|
|
|
class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase
|
2015-11-08 17:29:26 -05:00
|
|
|
def pn(path)
|
|
|
|
Pathname.new(path)
|
|
|
|
end
|
|
|
|
|
|
|
|
setup do
|
2015-12-08 21:07:49 -05:00
|
|
|
@ph = ActiveSupport::EventedFileUpdateChecker::PathHelper.new
|
2015-11-08 17:29:26 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#xpath returns the expanded path as a Pathname object" do
|
2015-11-08 17:29:26 -05:00
|
|
|
assert_equal pn(__FILE__).expand_path, @ph.xpath(__FILE__)
|
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#normalize_extension returns a bare extension as is" do
|
|
|
|
assert_equal "rb", @ph.normalize_extension("rb")
|
2015-11-08 17:29:26 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#normalize_extension removes a leading dot" do
|
|
|
|
assert_equal "rb", @ph.normalize_extension(".rb")
|
2015-11-08 17:29:26 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#normalize_extension supports symbols" do
|
|
|
|
assert_equal "rb", @ph.normalize_extension(:rb)
|
2015-11-08 17:29:26 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#longest_common_subpath finds the longest common subpath, if there is one" do
|
2015-11-08 17:29:26 -05:00
|
|
|
paths = %w(
|
|
|
|
/foo/bar
|
|
|
|
/foo/baz
|
|
|
|
/foo/bar/baz/woo/zoo
|
2015-11-11 00:38:18 -05:00
|
|
|
).map { |path| pn(path) }
|
2015-11-08 17:29:26 -05:00
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
assert_equal pn("/foo"), @ph.longest_common_subpath(paths)
|
2015-11-08 17:29:26 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#longest_common_subpath returns the root directory as an edge case" do
|
2015-11-08 17:29:26 -05:00
|
|
|
paths = %w(
|
|
|
|
/foo/bar
|
|
|
|
/foo/baz
|
|
|
|
/foo/bar/baz/woo/zoo
|
|
|
|
/wadus
|
2015-11-11 00:38:18 -05:00
|
|
|
).map { |path| pn(path) }
|
2015-11-08 17:29:26 -05:00
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
assert_equal pn("/"), @ph.longest_common_subpath(paths)
|
2015-11-08 17:29:26 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#longest_common_subpath returns nil for an empty collection" do
|
2015-11-08 17:29:26 -05:00
|
|
|
assert_nil @ph.longest_common_subpath([])
|
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#filter_out_descendants returns the same collection if there are no descendants (empty)" do
|
2015-11-10 05:28:14 -05:00
|
|
|
assert_equal [], @ph.filter_out_descendants([])
|
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#filter_out_descendants returns the same collection if there are no descendants (one)" do
|
|
|
|
assert_equal ["/foo"], @ph.filter_out_descendants(["/foo"])
|
2015-11-10 05:28:14 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#filter_out_descendants returns the same collection if there are no descendants (several)" do
|
2015-11-10 05:28:14 -05:00
|
|
|
paths = %w(
|
|
|
|
/Rails.root/app/controllers
|
|
|
|
/Rails.root/app/models
|
|
|
|
/Rails.root/app/helpers
|
2015-11-11 00:38:18 -05:00
|
|
|
).map { |path| pn(path) }
|
2015-11-10 05:28:14 -05:00
|
|
|
|
|
|
|
assert_equal paths, @ph.filter_out_descendants(paths)
|
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#filter_out_descendants filters out descendants preserving order" do
|
2015-11-10 05:28:14 -05:00
|
|
|
paths = %w(
|
|
|
|
/Rails.root/app/controllers
|
|
|
|
/Rails.root/app/controllers/concerns
|
|
|
|
/Rails.root/app/models
|
|
|
|
/Rails.root/app/models/concerns
|
|
|
|
/Rails.root/app/helpers
|
2015-11-11 00:38:18 -05:00
|
|
|
).map { |path| pn(path) }
|
2015-11-10 05:28:14 -05:00
|
|
|
|
|
|
|
assert_equal paths.values_at(0, 2, 4), @ph.filter_out_descendants(paths)
|
|
|
|
end
|
2015-11-11 04:18:43 -05:00
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#filter_out_descendants works on path units" do
|
2015-11-11 04:18:43 -05:00
|
|
|
paths = %w(
|
|
|
|
/foo/bar
|
|
|
|
/foo/barrrr
|
|
|
|
).map { |path| pn(path) }
|
|
|
|
|
|
|
|
assert_equal paths, @ph.filter_out_descendants(paths)
|
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#filter_out_descendants deals correctly with the root directory" do
|
2015-11-11 04:18:43 -05:00
|
|
|
paths = %w(
|
|
|
|
/
|
|
|
|
/foo
|
|
|
|
/foo/bar
|
|
|
|
).map { |path| pn(path) }
|
|
|
|
|
|
|
|
assert_equal paths.values_at(0), @ph.filter_out_descendants(paths)
|
|
|
|
end
|
|
|
|
|
2016-08-06 12:03:25 -04:00
|
|
|
test "#filter_out_descendants preserves duplicates" do
|
2015-11-11 04:18:43 -05:00
|
|
|
paths = %w(
|
|
|
|
/foo
|
|
|
|
/foo/bar
|
|
|
|
/foo
|
|
|
|
).map { |path| pn(path) }
|
|
|
|
|
|
|
|
assert_equal paths.values_at(0, 2), @ph.filter_out_descendants(paths)
|
|
|
|
end
|
2015-11-08 17:29:26 -05:00
|
|
|
end
|