observr 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,142 @@
1
+ require 'test/test_helper'
2
+
3
+ class Observr::EventHandler::Portable
4
+ attr_accessor :monitored_paths
5
+ end
6
+
7
+ class PortableEventHandlerTest < MiniTest::Unit::TestCase
8
+ include Observr
9
+
10
+ def setup
11
+ @handler = EventHandler::Portable.new
12
+ @handler.stubs(:loop)
13
+
14
+ @foo = Pathname('foo').expand_path
15
+ @bar = Pathname('bar').expand_path
16
+ @baz = Pathname('baz').expand_path
17
+ @bax = Pathname('bax').expand_path
18
+
19
+ @now = Time.now
20
+ [@foo, @bar, @baz, @bax].each do |path|
21
+ path.stubs(:mtime ).returns(@now - 100)
22
+ path.stubs(:atime ).returns(@now - 100)
23
+ path.stubs(:ctime ).returns(@now - 100)
24
+ path.stubs(:exist?).returns(true)
25
+ end
26
+ end
27
+
28
+ test "triggers listening state" do
29
+ @handler.expects(:loop)
30
+ @handler.listen([])
31
+ end
32
+
33
+ ## monitoring file events
34
+
35
+ test "listens for events on monitored files" do
36
+ @handler.listen [ @foo, @bar ]
37
+ assert_includes @handler.monitored_paths, @foo
38
+ assert_includes @handler.monitored_paths, @bar
39
+ end
40
+
41
+ test "doesn't trigger on start" do
42
+ end
43
+
44
+ ## event types
45
+
46
+ test "deleted file event" do
47
+ @foo.stubs(:exist?).returns(false)
48
+
49
+ @handler.listen [ @foo, @bar ]
50
+ @handler.expects(:notify).with(@foo, :deleted)
51
+ @handler.trigger
52
+ end
53
+
54
+ test "modified file event" do
55
+ @foo.stubs(:mtime).returns(@now + 100)
56
+
57
+ @handler.listen [ @foo, @bar ]
58
+ @handler.expects(:notify).with(@foo, :modified)
59
+ @handler.trigger
60
+ end
61
+
62
+ test "accessed file event" do
63
+ @foo.stubs(:atime).returns(@now + 100)
64
+
65
+ @handler.listen [ @foo, @bar ]
66
+ @handler.expects(:notify).with(@foo, :accessed)
67
+ @handler.trigger
68
+ end
69
+
70
+ test "changed file event" do
71
+ @foo.stubs(:ctime).returns(@now + 100)
72
+
73
+ @handler.listen [ @foo, @bar ]
74
+ @handler.expects(:notify).with(@foo, :changed)
75
+ @handler.trigger
76
+ end
77
+
78
+ ## event type priorities
79
+
80
+ test "mtime > atime" do
81
+ @foo.stubs(:mtime).returns(@now + 100)
82
+ @foo.stubs(:atime).returns(@now + 100)
83
+ @foo.stubs(:ctime).returns(@now + 100)
84
+
85
+ @handler.listen [ @foo, @bar ]
86
+ @handler.expects(:notify).with(@foo, :modified)
87
+ @handler.trigger
88
+ end
89
+
90
+ test "mtime > ctime" do
91
+ @foo.stubs(:mtime).returns(@now + 100)
92
+ @foo.stubs(:ctime).returns(@now + 100)
93
+
94
+ @handler.listen [ @foo, @bar ]
95
+ @handler.expects(:notify).with(@foo, :modified)
96
+ @handler.trigger
97
+ end
98
+
99
+ test "atime > ctime" do
100
+ @foo.stubs(:atime).returns(@now + 100)
101
+ @foo.stubs(:ctime).returns(@now + 100)
102
+
103
+ @handler.listen [ @foo, @bar ]
104
+ @handler.expects(:notify).with(@foo, :accessed)
105
+ @handler.trigger
106
+ end
107
+
108
+ test "deleted > mtime" do
109
+ @foo.stubs(:exist?).returns(false)
110
+ @foo.stubs(:mtime ).returns(@now + 100)
111
+
112
+ @handler.listen [ @foo, @bar ]
113
+ @handler.expects(:notify).with(@foo, :deleted)
114
+ @handler.trigger
115
+ end
116
+
117
+ ## on the fly updates of monitored files list
118
+
119
+ test "reattaches to new monitored files" do
120
+ @handler.listen [ @foo, @bar ]
121
+ assert_includes @handler.monitored_paths, @foo
122
+ assert_includes @handler.monitored_paths, @bar
123
+
124
+ @handler.refresh [ @baz, @bax ]
125
+ assert_includes @handler.monitored_paths, @baz
126
+ assert_includes @handler.monitored_paths, @bax
127
+ refute_includes @handler.monitored_paths, @foo
128
+ refute_includes @handler.monitored_paths, @bar
129
+ end
130
+
131
+ test "retries on ENOENT errors" do
132
+ @oops = Pathname('oops').expand_path
133
+ @oops.stubs(:exist?).returns(true)
134
+ @oops.stubs(:mtime).raises(Errno::ENOENT).
135
+ then.returns(Time.now + 100)
136
+
137
+ @handler.listen [ @oops ]
138
+
139
+ @handler.expects(:notify).with(@oops, :modified)
140
+ @handler.trigger
141
+ end
142
+ end
@@ -0,0 +1,162 @@
1
+ require 'test/test_helper'
2
+
3
+ if Observr::HAVE_REV
4
+
5
+ class Observr::EventHandler::Unix::SingleFileWatcher
6
+ public :type
7
+ end
8
+
9
+ class UnixEventHandlerTest < MiniTest::Unit::TestCase
10
+ include Observr
11
+
12
+ SingleFileWatcher = EventHandler::Unix::SingleFileWatcher
13
+
14
+ def setup
15
+ @now = Time.now
16
+ pathname = Pathname.new('foo/bar')
17
+ pathname.stubs(:atime ).returns(@now)
18
+ pathname.stubs(:mtime ).returns(@now)
19
+ pathname.stubs(:ctime ).returns(@now)
20
+ pathname.stubs(:exist?).returns(true)
21
+ SingleFileWatcher.any_instance.stubs(:pathname).returns(pathname)
22
+
23
+ @loop = Rev::Loop.default
24
+ @handler = EventHandler::Unix.new
25
+ @watcher = SingleFileWatcher.new('foo/bar')
26
+ @loop.stubs(:run)
27
+ end
28
+
29
+ def teardown
30
+ SingleFileWatcher.handler = nil
31
+ Rev::Loop.default.watchers.every.detach
32
+ end
33
+
34
+ test "triggers listening state" do
35
+ @loop.expects(:run)
36
+ @handler.listen([])
37
+ end
38
+
39
+ ## SingleFileWatcher
40
+
41
+ test "watcher pathname" do
42
+ assert_instance_of Pathname, @watcher.pathname
43
+ assert_equal @watcher.path, @watcher.pathname.to_s
44
+ end
45
+
46
+ test "stores reference times" do
47
+ @watcher.pathname.stubs(:atime).returns(:time)
48
+ @watcher.pathname.stubs(:mtime).returns(:time)
49
+ @watcher.pathname.stubs(:ctime).returns(:time)
50
+
51
+ @watcher.send(:update_reference_times)
52
+ assert_equal :time, @watcher.instance_variable_get(:@reference_atime)
53
+ assert_equal :time, @watcher.instance_variable_get(:@reference_mtime)
54
+ assert_equal :time, @watcher.instance_variable_get(:@reference_ctime)
55
+ end
56
+
57
+ test "stores initial reference times" do
58
+ SingleFileWatcher.any_instance.expects(:update_reference_times)
59
+ SingleFileWatcher.new('foo')
60
+ end
61
+
62
+ test "updates reference times on change" do
63
+ @watcher.expects(:update_reference_times)
64
+ @watcher.on_change
65
+ end
66
+
67
+ test "detects event type" do
68
+ trigger_event @watcher, @now, :atime
69
+ assert_equal :accessed, @watcher.type
70
+
71
+ trigger_event @watcher, @now, :mtime
72
+ assert_equal :modified, @watcher.type
73
+
74
+ trigger_event @watcher, @now, :ctime
75
+ assert_equal :changed, @watcher.type
76
+
77
+ trigger_event @watcher, @now, :atime, :mtime
78
+ assert_equal :modified, @watcher.type
79
+
80
+ trigger_event @watcher, @now, :mtime, :ctime
81
+ assert_equal :modified, @watcher.type
82
+
83
+ trigger_event @watcher, @now, :atime, :ctime
84
+ assert_equal :accessed, @watcher.type
85
+
86
+ trigger_event @watcher, @now, :atime, :mtime, :ctime
87
+ assert_equal :modified, @watcher.type
88
+
89
+ @watcher.pathname.stubs(:exist?).returns(false)
90
+ assert_equal :deleted, @watcher.type
91
+ end
92
+
93
+ ## monitoring file events
94
+
95
+ test "listens for events on monitored files" do
96
+ @handler.listen %w( foo bar )
97
+ assert_equal 2, @loop.watchers.size
98
+ assert_equal %w( foo bar ).to_set, @loop.watchers.every.path.to_set
99
+ assert_equal [SingleFileWatcher], @loop.watchers.every.class.uniq
100
+ end
101
+
102
+ test "notifies observers on file event" do
103
+ @watcher.stubs(:path).returns('foo')
104
+ @handler.expects(:notify).with('foo', anything)
105
+ @watcher.on_change
106
+ end
107
+
108
+ test "notifies observers of event type" do
109
+ trigger_event @watcher, @now, :atime
110
+ @handler.expects(:notify).with('foo/bar', :accessed)
111
+ @watcher.on_change
112
+
113
+ trigger_event @watcher, @now, :mtime
114
+ @handler.expects(:notify).with('foo/bar', :modified)
115
+ @watcher.on_change
116
+
117
+ trigger_event @watcher, @now, :ctime
118
+ @handler.expects(:notify).with('foo/bar', :changed)
119
+ @watcher.on_change
120
+
121
+ trigger_event @watcher, @now, :atime, :mtime, :ctime
122
+ @handler.expects(:notify).with('foo/bar', :modified)
123
+ @watcher.on_change
124
+
125
+ @watcher.pathname.stubs(:exist?).returns(false)
126
+ @handler.expects(:notify).with('foo/bar', :deleted)
127
+ @watcher.on_change
128
+ end
129
+
130
+ ## on the fly updates of monitored files list
131
+
132
+ test "reattaches to new monitored files" do
133
+ @handler.listen %w( foo bar )
134
+ assert_equal 2, @loop.watchers.size
135
+ assert_includes @loop.watchers.every.path, 'foo'
136
+ assert_includes @loop.watchers.every.path, 'bar'
137
+
138
+ @handler.refresh %w( baz bax )
139
+ assert_equal 2, @loop.watchers.size
140
+ assert_includes @loop.watchers.every.path, 'baz'
141
+ assert_includes @loop.watchers.every.path, 'bax'
142
+ refute_includes @loop.watchers.every.path, 'foo'
143
+ refute_includes @loop.watchers.every.path, 'bar'
144
+ end
145
+
146
+ private
147
+
148
+ def trigger_event(watcher, now, *types)
149
+ watcher.pathname.stubs(:atime).returns(now)
150
+ watcher.pathname.stubs(:mtime).returns(now)
151
+ watcher.pathname.stubs(:ctime).returns(now)
152
+ watcher.instance_variable_set(:@reference_atime, now)
153
+ watcher.instance_variable_set(:@reference_mtime, now)
154
+ watcher.instance_variable_set(:@reference_ctime, now)
155
+
156
+ types.each do |type|
157
+ watcher.pathname.stubs(type).returns(now+10)
158
+ end
159
+ end
160
+ end
161
+
162
+ end # if Observr::HAVE_REV
@@ -0,0 +1,121 @@
1
+ require 'test/test_helper'
2
+ require 'observer'
3
+
4
+ class MockHandler
5
+ include Observable
6
+ def listen(paths) end
7
+ def refresh(paths) end
8
+ end
9
+
10
+ class TestController < MiniTest::Unit::TestCase
11
+ include Observr
12
+
13
+ def to_p(str)
14
+ Pathname(str).expand_path
15
+ end
16
+
17
+ def setup
18
+ tmpfile = Tempfile.new('foo')
19
+ @script = Script.new( Pathname.new( tmpfile.path ) )
20
+ @handler = MockHandler.new
21
+ @controller = Controller.new(@script, @handler)
22
+ end
23
+
24
+ test "triggers listening state on run" do
25
+ @controller.stubs(:monitored_paths).returns %w( foo bar )
26
+ @handler.expects(:listen).with %w( foo bar )
27
+ @controller.run
28
+ end
29
+
30
+ test "parses the script on #run" do
31
+ @script.expects(:parse!)
32
+ @controller.run
33
+ end
34
+
35
+ test "adds itself as handler observer" do
36
+ assert_equal 1, @handler.count_observers
37
+ @handler.delete_observer(@controller)
38
+ assert_equal 0, @handler.count_observers
39
+ end
40
+
41
+ ## monitored paths list
42
+
43
+ test "fetches monitored paths" do
44
+ Dir.expects(:[]).at_least_once.with('**/*').returns(%w(
45
+ a
46
+ b/x.z
47
+ b/c
48
+ b/c/y.z
49
+ ))
50
+ @script.watch('.\.z') { :x }
51
+
52
+ contrl = Controller.new(@script, MockHandler.new)
53
+ assert_includes contrl.monitored_paths, to_p('b/x.z')
54
+ assert_includes contrl.monitored_paths, to_p('b/c/y.z')
55
+ end
56
+
57
+ test "doesn't fetch unmonitored paths" do
58
+ Dir.expects(:[]).at_least_once.with('**/*').returns(%w(
59
+ a
60
+ b/x.z
61
+ b/c
62
+ b/c/y.z
63
+ ))
64
+ @script.watch('.\.z') { :x }
65
+
66
+ contrl = Controller.new(@script, MockHandler.new)
67
+ refute_includes contrl.monitored_paths, to_p('a')
68
+ refute_includes contrl.monitored_paths, to_p('b/c')
69
+ refute_includes contrl.monitored_paths, to_p('p/q.z')
70
+ end
71
+
72
+ test "monitored paths include script" do
73
+ Dir.expects(:[]).at_least_once.with('**/*').returns(%w( a ))
74
+ Script.any_instance.stubs(:parse!)
75
+
76
+ path = to_p('some/file')
77
+ script = Script.new(path)
78
+ contrl = Controller.new(script, MockHandler.new)
79
+ assert_includes contrl.monitored_paths, path
80
+ end
81
+
82
+ ## on update
83
+
84
+ test "calls action for path" do
85
+ path = to_p('abc')
86
+ @script.expects(:action_for).with(path, :modified).returns(lambda {})
87
+
88
+ @controller.update('abc', :modified)
89
+ end
90
+
91
+ test "parses script on script file update" do
92
+ path = to_p('abc')
93
+ @script.stubs(:path).returns(path)
94
+ @script.expects(:parse!)
95
+
96
+ @controller.update('abc')
97
+ end
98
+
99
+ test "refreshes handler on script file update" do
100
+ path = to_p('abc')
101
+ @script.stubs(:path).returns(path)
102
+ @controller.stubs(:monitored_paths).returns %w( foo bar )
103
+
104
+ @handler.expects(:refresh).with %w( foo bar )
105
+ @controller.update(path)
106
+ end
107
+
108
+ test "exits gracefully when Interrupted" do
109
+ @handler.stubs(:listen).raises(Interrupt)
110
+ @controller.run
111
+ end
112
+
113
+ test "does not parse script on mere script file access" do
114
+ path = to_p('abc')
115
+ @script.stubs(:path).returns(path)
116
+ @script.expects(:parse!).never
117
+
118
+ @controller.update('abc', :accessed)
119
+ end
120
+ end
121
+
@@ -0,0 +1,37 @@
1
+ require 'pathname'
2
+ require 'tmpdir'
3
+ require 'tempfile'
4
+ require 'fileutils'
5
+
6
+ require 'minitest/autorun'
7
+ require 'mocha'
8
+ require 'every'
9
+ begin
10
+ require 'redgreen' #http://gemcutter.org/gems/mynyml-redgreen
11
+ require 'phocus'
12
+ require 'ruby-debug'
13
+ rescue LoadError, RuntimeError
14
+ end
15
+
16
+ require 'observr'
17
+
18
+ class MiniTest::Unit::TestCase
19
+ class << self
20
+ def test(name, &block)
21
+ define_method("test_#{name.gsub(/\s/,'_')}", &block)
22
+ end
23
+ alias :should :test
24
+
25
+ # noop
26
+ def xtest(*args) end
27
+ end
28
+ end
29
+
30
+ unless Observr::HAVE_REV
31
+ puts "Skipping Unix handler tests. Install Rev (gem install rev) to properly test full suite"
32
+ end
33
+
34
+ unless Observr::HAVE_FSE
35
+ puts "Skipping Darwin handler tests. Install FSEvent (gem install ruby-fsevent) to properly test full suite (osx only)"
36
+ end
37
+