File: file_system_watcher_spec.rb

package info (click to toggle)
ruby-passenger 3.0.13debian-1%2Bdeb7u2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 15,920 kB
  • sloc: cpp: 99,104; ruby: 18,098; ansic: 9,846; sh: 8,632; python: 141; makefile: 30
file content (221 lines) | stat: -rw-r--r-- 5,880 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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require 'phusion_passenger/utils/file_system_watcher'

module PhusionPassenger

describe Utils::FileSystemWatcher do
	before :each do
		@tmpdir = "tmp.fs_watcher"
		@tmpdir2 = "tmp.fs_watcher2"
		@tmpdir3 = "tmp.fs_watcher3"
		@term_pipe = IO.pipe
		[@tmpdir, @tmpdir2, @tmpdir3].each do |dir|
			remove_dir_tree(dir)
			Dir.mkdir(dir)
		end
	end
	
	after :each do
		if @thread
			@term_pipe[1].write("x")
			@thread.join
		end
		@watcher.close if @watcher
		@term_pipe[0].close
		@term_pipe[1].close
		[@tmpdir, @tmpdir2, @tmpdir3].each do |dir|
			remove_dir_tree(dir)
		end
	end
	
	def create(*args)
		@watcher = Utils::FileSystemWatcher.new(*args)
		@watcher.poll_interval = 0.1 if @watcher.respond_to?(:poll_interval=)
		return @watcher
	end
	
	describe "#wait_for_change blocks until" do
		def test_block(filenames)
			create(filenames, @term_pipe[0])
			result = nil
			thread = Thread.new do
				result = @watcher.wait_for_change
			end
			yield if block_given?
			eventually do
				!thread.alive?
			end
			return result
		ensure
			if thread
				@term_pipe[1].write("x")
				thread.join
			end
			@watcher.close
		end
		
		specify "a subdirectory has been created in one of the watched directories" do
			result = test_block([@tmpdir, @tmpdir2]) do
				Dir.mkdir("#{@tmpdir}/foo")
			end
			result.should be_true
		end
		
		specify "a subdirectory has been removed in one of the watched directories" do
			Dir.mkdir("#{@tmpdir2}/foo")
			result = test_block([@tmpdir, @tmpdir2]) do
				Dir.rmdir("#{@tmpdir2}/foo")
			end
			result.should be_true
		end
		
		specify "a subdirectory has been renamed in one of the watched directories" do
			Dir.mkdir("#{@tmpdir}/foo")
			result = test_block([@tmpdir, @tmpdir2]) do
				File.rename("#{@tmpdir}/foo", "#{@tmpdir3}/bar")
			end
			result.should be_true
		end
		
		specify "a file has been created in one of the watched directories" do
			result = test_block([@tmpdir, @tmpdir2]) do
				File.touch("#{@tmpdir}/foo")
			end
			result.should be_true
		end
		
		specify "a file has been removed in one of the watched directories" do
			File.touch("#{@tmpdir2}/foo")
			result = test_block([@tmpdir, @tmpdir2]) do
				File.unlink("#{@tmpdir2}/foo")
			end
			result.should be_true
		end
		
		specify "a file has been renamed in one of the watched directories" do
			File.touch("#{@tmpdir}/foo")
			result = test_block([@tmpdir, @tmpdir2]) do
				File.rename("#{@tmpdir}/foo", "#{@tmpdir3}/bar")
			end
			result.should be_true
		end
		
		specify "a watched file has been written to" do
			File.touch("#{@tmpdir}/foo")
			result = test_block(["#{@tmpdir}/foo"]) do
				File.write("#{@tmpdir}/foo", "bar")
			end
		end
		
		specify "a watched file has been truncated" do
			File.write("#{@tmpdir}/foo", "contents")
			result = test_block(["#{@tmpdir}/foo"]) do
				File.open("#{@tmpdir}/foo", "w").close
			end
		end
		
		specify "a watched file has been removed" do
			File.touch("#{@tmpdir}/foo")
			result = test_block(["#{@tmpdir}/foo"]) do
				File.unlink("#{@tmpdir}/foo")
			end
		end
		
		specify "a watched file has been renamed" do
			File.touch("#{@tmpdir}/foo")
			result = test_block(["#{@tmpdir}/foo"]) do
				File.rename("#{@tmpdir}/foo", "#{@tmpdir}/bar")
			end
		end
		
		specify "the termination pipe became readable" do
			result = test_block([@tmpdir]) do
				@term_pipe[1].write("x")
			end
			result.should be_nil
		end
		
		specify "one of the watched files or directories could not be statted while constructing the object" do
			test_block([@tmpdir, "#{@tmpdir}/foo"]).should be_false
			
			when_not_running_as_root do
				Dir.mkdir("#{@tmpdir}/foo")
				File.touch("#{@tmpdir}/foo/file")
				Dir.mkdir("#{@tmpdir}/foo/dir")
				File.chmod(0000, "#{@tmpdir}/foo")
				
				test_block([@tmpdir, "#{@tmpdir}/foo/file"]).should be_false
				test_block([@tmpdir, "#{@tmpdir}/foo/dir"]).should be_false
			end
		end
		
		if Utils::FileSystemWatcher.opens_files?
		when_not_running_as_root do
			specify "one of the watched files or directories could not be opened while constructing the object" do
				File.touch("#{@tmpdir}/file")
				File.chmod(0000, "#{@tmpdir}/file")
				test_block([@tmpdir, "#{@tmpdir}/file"]).should be_false
				
				Dir.mkdir("#{@tmpdir}/dir")
				File.chmod(0000, "#{@tmpdir}/dir")
				test_block([@tmpdir, "#{@tmpdir}/dir"]).should be_false
			end
		end
		end # if
	end
	
	describe "#wait_for_change does not return if" do
		def test_block(filenames)
			create(filenames, @term_pipe[0])
			@thread = Thread.new do
				@watcher.wait_for_change
			end
			yield
			should_never_happen(0.4) do
				!@thread.alive?
			end
		end
		
		specify "nothing happened in one of its watched files or directories" do
			test_block([@tmpdir, @tmpdir2]) do
				File.touch("#{@tmpdir3}/file")
				Dir.mkdir("#{@tmpdir3}/dir")
			end
		end
		
		specify "something happened in a subdirectory that isn't on the watch list" do
			# In other words it does not watch subdirectories recursively.
			Dir.mkdir("#{@tmpdir}/subdir")
			test_block([@tmpdir, @tmpdir2]) do
				File.touch("#{@tmpdir}/subdir/file")
			end
		end
		
		specify "a file in a watched directory is merely modified" do
			File.touch("#{@tmpdir}/hello", 10)
			test_block([@tmpdir, @tmpdir2]) do
				File.touch("#{@tmpdir}/hello", 4567)
				File.write("#{@tmpdir}/hello", "foobar")
			end
		end
	end
	
	specify "#wait_for_change notices events that have occurred after object construction but before #wait_for_change has been called" do
		create([@tmpdir, @tmpdir2], @term_pipe[0])
		@thread = Thread.new do
			@watcher.wait_for_change
		end
		File.touch("#{@tmpdir}/foo", Time.now - 10)
		eventually do
			!@thread.alive?
		end
	end
	
	it "can be closed multiple times" do
		create([@tmpdir])
		@watcher.close
		@watcher.close
	end
end

end # module PhusionPassenger