observr 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+