File: watcher_test.rb

package info (click to toggle)
ruby-spring 2.1.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 428 kB
  • sloc: ruby: 3,373; sh: 9; makefile: 7
file content (194 lines) | stat: -rw-r--r-- 4,460 bytes parent folder | download
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
require "tmpdir"
require "fileutils"
require "timeout"
require "active_support/core_ext/numeric/time"

module Spring
  module Test
    class WatcherTest < ActiveSupport::TestCase
      runnables.delete self # prevent Minitest running this class

      LATENCY = 0.001
      TIMEOUT = 1

      attr_accessor :dir

      def watcher_class
        raise NotImplementedError
      end

      def watcher
        @watcher ||= watcher_class.new(dir, LATENCY)
      end

      def setup
        @dir = File.realpath(Dir.mktmpdir)
      end

      def teardown
        FileUtils.remove_entry_secure @dir
        watcher.stop
      end

      def touch(file, mtime = nil)
        options = {}
        options[:mtime] = mtime if mtime
        FileUtils.touch(file, **options)
      end

      def assert_stale
        timeout = Time.now + TIMEOUT
        sleep LATENCY until watcher.stale? || Time.now > timeout
        assert watcher.stale?
      end

      def assert_not_stale
        sleep LATENCY * 10
        assert !watcher.stale?
      end

      test "starting with no file" do
        file = "#{@dir}/omg"
        touch file, Time.now - 2.seconds

        watcher.start
        watcher.add file

        assert_not_stale
        touch file, Time.now
        assert_stale
      end

      test "is stale when a watched file is updated" do
        file = "#{@dir}/omg"
        touch file, Time.now - 2.seconds

        watcher.add file
        watcher.start

        assert_not_stale
        touch file, Time.now
        assert_stale
      end

      test "is stale when removing files" do
        file = "#{@dir}/omg"
        touch file, Time.now

        watcher.add file
        watcher.start

        assert_not_stale
        FileUtils.rm(file)
        assert_stale
      end

      test "is stale when files are added to a watched directory" do
        subdir = "#{@dir}/subdir"
        FileUtils.mkdir(subdir)

        watcher.add subdir
        watcher.start

        assert_not_stale
        touch "#{subdir}/foo", Time.now - 1.minute
        assert_stale
      end

      test "is stale when a file is changed in a watched directory" do
        subdir = "#{@dir}/subdir"
        FileUtils.mkdir(subdir)
        touch "#{subdir}/foo", Time.now - 1.minute

        watcher.add subdir
        watcher.start

        assert_not_stale
        touch "#{subdir}/foo", Time.now
        assert_stale
      end

      test "adding doesn't wipe stale state" do
        file = "#{@dir}/omg"
        file2 = "#{@dir}/foo"
        touch file, Time.now - 2.seconds
        touch file2, Time.now - 2.seconds

        watcher.add file
        watcher.start

        assert_not_stale

        touch file, Time.now
        watcher.add file2

        assert_stale
      end

      test "on stale" do
        file = "#{@dir}/omg"
        touch file, Time.now - 2.seconds

        stale = false
        watcher.on_stale { stale = true }

        watcher.add file
        watcher.start

        touch file, Time.now

        Timeout.timeout(1) { sleep 0.01 until stale }
        assert stale

        # Check that we only get notified once
        stale = false
        sleep LATENCY * 3
        assert !stale
      end

      test "add relative path" do
        File.write("#{dir}/foo", "foo")
        watcher.add "foo"
        assert_equal ["#{dir}/foo"], watcher.files.to_a
      end

      test "add dot relative path" do
        File.write("#{dir}/foo", "foo")
        watcher.add "./foo"
        assert_equal ["#{dir}/foo"], watcher.files.to_a
      end

      test "add non existent file" do
        watcher.add './foobar'
        assert watcher.files.empty?
      end

      test "add symlink" do
        File.write("#{dir}/bar", "bar")
        File.symlink("#{dir}/bar", "#{dir}/foo")
        watcher.add './foo'
        assert_equal ["#{dir}/bar"], watcher.files.to_a
      end

      test "add dangling symlink" do
        File.symlink("#{dir}/bar", "#{dir}/foo")
        watcher.add './foo'
        assert watcher.files.empty?
      end

      test "add directory with dangling symlink" do
        subdir = "#{@dir}/subdir"
        FileUtils.mkdir(subdir)
        File.symlink("dangling", "#{subdir}/foo")

        watcher.add subdir
        assert_not_stale

        # Adding a new file should mark as stale despite the dangling symlink.
        File.write("#{subdir}/new-file", "new")
        watcher.check_stale
        assert_stale
      end
    end
  end
end