aboutsummaryrefslogblamecommitdiffstats
path: root/activesupport/test/evented_file_update_checker_test.rb
blob: 4d5a9bed7a7e30a13066a4a99915a83aa04385ab (plain) (tree)
1
2
3
4
5
6
7
8
9
                             
 


                                          
 
                                                            
                                      
 
           
                                
                    


         
                                                
                                                                               

          
     




               

          
           
     





                                      
                                     

                                               

                             
                                       
                                           
 
                                              



                                        
                                         


                                   
                                             








                                                    
                                         










                                                       
                                       


                     
 

















                                                      
                                                                                


                                                     
 

                            
 
                                                                                       
 



                                                   
 



                                       
 



                                                     
     
   
 
                                                                      




                      
                                                                 

     
                                                                 


                                                              

                                                               

     

                                                      

     

                                                   

     
                                                                                     



                          
                             
 
                                                              

     
                                                                              




                          
                             
 
                                                           

     
                                                                       


                                             
                                                                                                   


                                                   

                                                                                                 

     
                                                                                                     



                                 
                             



                                                         
                                                                            





                                          
                             


                                                                            
 
                                                       







                                                         
                                                                           








                                                                      
                                                        







                                                                         
   
# frozen_string_literal: true

require "abstract_unit"
require "pathname"
require "file_update_checker_shared_tests"

class EventedFileUpdateCheckerTest < ActiveSupport::TestCase
  include FileUpdateCheckerSharedTests

  def setup
    skip if ENV["LISTEN"] == "0"
    require "listen"
    super
  end

  def new_checker(files = [], dirs = {}, &block)
    ActiveSupport::EventedFileUpdateChecker.new(files, dirs, &block).tap do |c|
      wait
    end
  end

  def teardown
    super
    Listen.stop
  end

  def wait
    sleep 1
  end

  def touch(files)
    super
    wait # wait for the events to fire
  end

  test "notifies forked processes" do
    jruby_skip "Forking not available on JRuby"

    FileUtils.touch(tmpfiles)

    checker = new_checker(tmpfiles) { }
    assert_not_predicate checker, :updated?

    # Pipes used for flow control across fork.
    boot_reader,  boot_writer  = IO.pipe
    touch_reader, touch_writer = IO.pipe

    pid = fork do
      assert_predicate checker, :updated?

      # Clear previous check value.
      checker.execute
      assert_not_predicate checker, :updated?

      # 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])

      assert_predicate checker, :updated?
    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")

    assert_predicate checker, :updated?

    Process.wait(pid)
  end

  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

  test "updated should become true when nonexistent directory is added later" do
    watched_dir = File.join(tmpdir, "app")
    unwatched_dir = File.join(tmpdir, "node_modules")
    not_exist_watched_dir = File.join(tmpdir, "test")

    Dir.mkdir(watched_dir)
    Dir.mkdir(unwatched_dir)

    checker = new_checker([], watched_dir => ".rb", not_exist_watched_dir => ".rb") { }

    FileUtils.touch(File.join(watched_dir, "a.rb"))
    wait
    assert_predicate checker, :updated?
    assert checker.execute_if_updated

    Dir.mkdir(not_exist_watched_dir)
    wait
    assert_predicate checker, :updated?
    assert checker.execute_if_updated

    FileUtils.touch(File.join(unwatched_dir, "a.rb"))
    wait
    assert_not_predicate checker, :updated?
    assert_not checker.execute_if_updated
  end
end

class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase
  def pn(path)
    Pathname.new(path)
  end

  setup do
    @ph = ActiveSupport::EventedFileUpdateChecker::PathHelper.new
  end

  test "#xpath returns the expanded path as a Pathname object" do
    assert_equal pn(__FILE__).expand_path, @ph.xpath(__FILE__)
  end

  test "#normalize_extension returns a bare extension as is" do
    assert_equal "rb", @ph.normalize_extension("rb")
  end

  test "#normalize_extension removes a leading dot" do
    assert_equal "rb", @ph.normalize_extension(".rb")
  end

  test "#normalize_extension supports symbols" do
    assert_equal "rb", @ph.normalize_extension(:rb)
  end

  test "#longest_common_subpath finds the longest common subpath, if there is one" do
    paths = %w(
      /foo/bar
      /foo/baz
      /foo/bar/baz/woo/zoo
    ).map { |path| pn(path) }

    assert_equal pn("/foo"), @ph.longest_common_subpath(paths)
  end

  test "#longest_common_subpath returns the root directory as an edge case" do
    paths = %w(
      /foo/bar
      /foo/baz
      /foo/bar/baz/woo/zoo
      /wadus
    ).map { |path| pn(path) }

    assert_equal pn("/"), @ph.longest_common_subpath(paths)
  end

  test "#longest_common_subpath returns nil for an empty collection" do
    assert_nil @ph.longest_common_subpath([])
  end

  test "#filter_out_descendants returns the same collection if there are no descendants (empty)" do
    assert_equal [], @ph.filter_out_descendants([])
  end

  test "#filter_out_descendants returns the same collection if there are no descendants (one)" do
    assert_equal ["/foo"], @ph.filter_out_descendants(["/foo"])
  end

  test "#filter_out_descendants returns the same collection if there are no descendants (several)" do
    paths = %w(
      /Rails.root/app/controllers
      /Rails.root/app/models
      /Rails.root/app/helpers
    ).map { |path| pn(path) }

    assert_equal paths, @ph.filter_out_descendants(paths)
  end

  test "#filter_out_descendants filters out descendants preserving order" do
    paths = %w(
      /Rails.root/app/controllers
      /Rails.root/app/controllers/concerns
      /Rails.root/app/models
      /Rails.root/app/models/concerns
      /Rails.root/app/helpers
    ).map { |path| pn(path) }

    assert_equal paths.values_at(0, 2, 4), @ph.filter_out_descendants(paths)
  end

  test "#filter_out_descendants works on path units" do
    paths = %w(
      /foo/bar
      /foo/barrrr
    ).map { |path| pn(path) }

    assert_equal paths, @ph.filter_out_descendants(paths)
  end

  test "#filter_out_descendants deals correctly with the root directory" do
    paths = %w(
      /
      /foo
      /foo/bar
    ).map { |path| pn(path) }

    assert_equal paths.values_at(0), @ph.filter_out_descendants(paths)
  end

  test "#filter_out_descendants preserves duplicates" do
    paths = %w(
      /foo
      /foo/bar
      /foo
    ).map { |path| pn(path) }

    assert_equal paths.values_at(0, 2), @ph.filter_out_descendants(paths)
  end
end