em-ventually 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +59 -16
- data/Rakefile +49 -34
- data/lib/em-ventually.rb +4 -0
- data/lib/em-ventually/emify.rb +3 -1
- data/lib/em-ventually/version.rb +1 -1
- metadata +25 -25
data/README.md
CHANGED
@@ -5,11 +5,28 @@
|
|
5
5
|
Your tests will eventually pass. You're not sure when, but you know it'll be quick. This is where EM::Ventually can help you!
|
6
6
|
|
7
7
|
Take this trivial example. (It's in Minitest, but you can use whatever test suite you'd like*)
|
8
|
+
Without em-ventually, testing your EM code requires a lot of boilerplate such as:
|
8
9
|
|
9
10
|
~~~~~ {ruby}
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
# Without em-ventually
|
12
|
+
def test_em
|
13
|
+
# Start EM loop.
|
14
|
+
EM.run do
|
15
|
+
# The only two lines you actually care about.
|
16
|
+
val = nil
|
17
|
+
EM.add_timer(0.5) { val = 'test' }
|
18
|
+
|
19
|
+
# Test that work happens in the future.
|
20
|
+
EM.add_periodic_timer(0.1) do
|
21
|
+
if val == 'test'
|
22
|
+
pass # Increment assertion count.
|
23
|
+
EM.stop # Manually stop EM loop.
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Guard against infinite loops.
|
28
|
+
EM.add_timer(1) { raise "Potential infinite loop averted!" }
|
29
|
+
end
|
13
30
|
end
|
14
31
|
~~~~~
|
15
32
|
|
@@ -22,17 +39,27 @@ So, you want to test that val is 'test', and as well, you want EM to start on th
|
|
22
39
|
Taking the example above you can enqueue a test.
|
23
40
|
|
24
41
|
~~~~~ {ruby}
|
25
|
-
def
|
26
|
-
val =
|
42
|
+
def test_em
|
43
|
+
val = 'not test'
|
27
44
|
EM.add_timer(0.5) { val = 'test' }
|
28
45
|
eventually('test') { val }
|
29
46
|
end
|
30
47
|
~~~~~
|
31
48
|
|
32
|
-
This will poll
|
49
|
+
This will poll the block passed to eventually every 0.1 seconds to see if the condition is equal to the argument you passed in to eventually, in this case 'test'. After one second, if it's still not equal, it will fail. If you do not pass in a value for testing, it will evaluate what you return against ruby's notion of truth (not nil and not false). An exmaple:
|
50
|
+
|
51
|
+
~~~~~ {ruby}
|
52
|
+
def test_em
|
53
|
+
count = 0
|
54
|
+
EM.add_periodic_timer(0.01) { count += 0.5 }
|
55
|
+
eventually { count >= 3 }
|
56
|
+
end
|
57
|
+
~~~~~
|
58
|
+
|
59
|
+
As well, you can change both the polling interval as well as the maximum execution time by passing in `:every` and `:total`. Here is an example:
|
33
60
|
|
34
61
|
~~~~~ {ruby}
|
35
|
-
def
|
62
|
+
def test_em
|
36
63
|
val = nil
|
37
64
|
EM.add_timer(0.5) { val = 'test' }
|
38
65
|
eventually('test', :every => 0.2, :total => 10) { val } # check every 0.2 seconds
|
@@ -43,7 +70,7 @@ This will poll your block every 0.1 seconds to see if the condition is true. Aft
|
|
43
70
|
You can also parallelize tests if you don't want them to run serially.
|
44
71
|
|
45
72
|
~~~~~ {ruby}
|
46
|
-
def
|
73
|
+
def test_em
|
47
74
|
val1, val2 = nil, nil
|
48
75
|
EM.add_timer(0.5) { val1 = 'test1' }
|
49
76
|
EM.add_timer(0.5) { val2 = 'test2' }
|
@@ -54,14 +81,21 @@ You can also parallelize tests if you don't want them to run serially.
|
|
54
81
|
end
|
55
82
|
~~~~~
|
56
83
|
|
57
|
-
|
84
|
+
Simply returning from your block doesn't always cover your test. Say for instance, you need to do a call against some sort of async client that will return your value in a callback. You can pass values back for equality by doing the following.
|
58
85
|
|
59
86
|
~~~~~ {ruby}
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
87
|
+
class AsyncClient
|
88
|
+
def status(&blk)
|
89
|
+
EM.add_timer(0.5) do
|
90
|
+
blk.call(:ok)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_em
|
96
|
+
client = AsyncClient.new
|
97
|
+
eventually(:ok) { |with| client.status {|status| with[status]} }
|
98
|
+
# The secret sauce is in the arity of the block passed to `eventually`
|
65
99
|
end
|
66
100
|
~~~~~
|
67
101
|
|
@@ -74,7 +108,7 @@ There are a couple of global options you can mess with too. `EM::Ventually.every
|
|
74
108
|
If you don't pass a value to eventually, it will test that your value is true (in the ruby sense). Optionally, you can call `.test` to pass a custom tester.
|
75
109
|
|
76
110
|
~~~~~ {ruby}
|
77
|
-
def
|
111
|
+
def test_em
|
78
112
|
count = 0
|
79
113
|
EM.add_periodic_timer(0.01) { count += 0.5 }
|
80
114
|
eventually { count }.test{ |v| v >= 3 }
|
@@ -84,9 +118,18 @@ If you don't pass a value to eventually, it will test that your value is true (i
|
|
84
118
|
of course, you're gonna be writing so many of these we've aliased it to make your tests stylish and classy.
|
85
119
|
|
86
120
|
~~~~~ {ruby}
|
87
|
-
def
|
121
|
+
def test_em
|
88
122
|
count = 0
|
89
123
|
EM.add_periodic_timer(0.01) { count += 0.5 }
|
90
124
|
ly { count }.test{ |v| v >= 3 }
|
91
125
|
end
|
92
126
|
~~~~~
|
127
|
+
|
128
|
+
If you want to manually manage stopping and starting EM within a test, you can call `manually_stop_em!` within your test. An example:
|
129
|
+
|
130
|
+
~~~~~ {ruby}
|
131
|
+
def test_em
|
132
|
+
manually_stop_em!
|
133
|
+
EM.add_timer(0.5) { assert "Hey!"; EM.stop }
|
134
|
+
end
|
135
|
+
~~~~~
|
data/Rakefile
CHANGED
@@ -1,45 +1,60 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
2
|
|
3
3
|
task :default => :test
|
4
|
+
task :test => [:'test:readme', :'test:suites']
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
namespace :test do
|
7
|
+
task :suites do
|
8
|
+
matchers = {
|
9
|
+
'minitest-2.0' => [/6 tests, 9 assertions, 1 failures, 0 errors/m],
|
10
|
+
'rspec-2.6' => [/\n\.\.\.\.F\.\.\.\n/m],
|
11
|
+
'test-unit' => [/\n\.\.\.F\.\.\n/m, /test_out_of_order\(TestEMVentually\)/m]
|
12
|
+
}
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
14
|
+
matchers.each do |type, matcher|
|
15
|
+
STDOUT.sync = true
|
16
|
+
Dir.chdir("./test/#{type}") do
|
17
|
+
print "Testing #{type}#{' ' * (22 - type.size )}"
|
18
|
+
fork {
|
19
|
+
ENV['BUNDLE_GEMFILE'] = File.expand_path("./Gemfile")
|
20
|
+
out = `bundle && bundle exec rake 2>&1`
|
21
|
+
if matcher.all?{|m|out[m]}
|
22
|
+
exit
|
23
|
+
else
|
24
|
+
puts out
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
}
|
28
|
+
_, status = Process.wait2
|
29
|
+
puts status.success? ? "PASSED" : "FAILED"
|
30
|
+
end
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
require 'em-ventually'
|
36
|
-
class ReadmeTest < MiniTest::Unit::TestCase
|
37
|
-
include EM::Ventually
|
38
|
-
|
34
|
+
task :readme do
|
35
|
+
# test README.md
|
36
|
+
puts "Testing README.md"
|
37
|
+
STDOUT.sync = true
|
39
38
|
readme = File.read('./README.md')
|
40
|
-
readme.scan(/~~~~~ \{ruby\}\n(.*?)~~~~~/m).
|
41
|
-
|
39
|
+
passes = readme.scan(/~~~~~ \{ruby\}\n(.*?)~~~~~/m).map do |block|
|
40
|
+
fork {
|
41
|
+
require 'minitest/autorun'
|
42
|
+
require 'eventmachine'
|
43
|
+
$LOAD_PATH << 'lib'
|
44
|
+
STDOUT.reopen('/dev/null')
|
45
|
+
require 'em-ventually'
|
46
|
+
code = block.join
|
47
|
+
cls = Class.new(MiniTest::Unit::TestCase)
|
48
|
+
cls.class_eval "include EM::Ventually" unless code[/# Without em-ventually/]
|
49
|
+
cls.class_eval(code)
|
50
|
+
cls
|
51
|
+
}
|
52
|
+
_, status = Process.wait2
|
53
|
+
print status.success? ? '.' : 'F'
|
54
|
+
status.success? ? :pass : :fail
|
42
55
|
end
|
56
|
+
puts
|
57
|
+
pass_count = passes.inject(0){|m, s| m += (s == :pass ? 1 : 0)}
|
58
|
+
raise "README tests failed" unless pass_count == passes.size
|
43
59
|
end
|
44
|
-
end
|
45
|
-
|
60
|
+
end
|
data/lib/em-ventually.rb
CHANGED
data/lib/em-ventually/emify.rb
CHANGED
@@ -10,7 +10,9 @@ module EventMachine
|
|
10
10
|
begin
|
11
11
|
result = yield
|
12
12
|
ensure
|
13
|
-
|
13
|
+
unless instance_variable_defined?(:@_manually_stop_em) && @_manually_stop_em
|
14
|
+
EM.stop if (!instance_variable_defined?(:@_pool) || @_pool.nil? || @_pool.empty?) && EM.reactor_running?
|
15
|
+
end
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
data/lib/em-ventually/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-ventually
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Josh Hull
|
@@ -15,13 +15,12 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-08-
|
18
|
+
date: 2011-08-17 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
name: eventmachine
|
23
22
|
prerelease: false
|
24
|
-
|
23
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
25
24
|
none: false
|
26
25
|
requirements:
|
27
26
|
- - ">="
|
@@ -30,12 +29,12 @@ dependencies:
|
|
30
29
|
segments:
|
31
30
|
- 0
|
32
31
|
version: "0"
|
32
|
+
requirement: *id001
|
33
|
+
name: eventmachine
|
33
34
|
type: :runtime
|
34
|
-
version_requirements: *id001
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
|
-
name: callsite
|
37
36
|
prerelease: false
|
38
|
-
|
37
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
39
38
|
none: false
|
40
39
|
requirements:
|
41
40
|
- - ~>
|
@@ -46,12 +45,12 @@ dependencies:
|
|
46
45
|
- 0
|
47
46
|
- 5
|
48
47
|
version: 0.0.5
|
48
|
+
requirement: *id002
|
49
|
+
name: callsite
|
49
50
|
type: :runtime
|
50
|
-
version_requirements: *id002
|
51
51
|
- !ruby/object:Gem::Dependency
|
52
|
-
name: code_stats
|
53
52
|
prerelease: false
|
54
|
-
|
53
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
55
54
|
none: false
|
56
55
|
requirements:
|
57
56
|
- - ">="
|
@@ -60,12 +59,12 @@ dependencies:
|
|
60
59
|
segments:
|
61
60
|
- 0
|
62
61
|
version: "0"
|
62
|
+
requirement: *id003
|
63
|
+
name: code_stats
|
63
64
|
type: :development
|
64
|
-
version_requirements: *id003
|
65
65
|
- !ruby/object:Gem::Dependency
|
66
|
-
name: rake
|
67
66
|
prerelease: false
|
68
|
-
|
67
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
69
68
|
none: false
|
70
69
|
requirements:
|
71
70
|
- - ~>
|
@@ -76,12 +75,12 @@ dependencies:
|
|
76
75
|
- 8
|
77
76
|
- 7
|
78
77
|
version: 0.8.7
|
78
|
+
requirement: *id004
|
79
|
+
name: rake
|
79
80
|
type: :development
|
80
|
-
version_requirements: *id004
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
|
-
name: phocus
|
83
82
|
prerelease: false
|
84
|
-
|
83
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
85
84
|
none: false
|
86
85
|
requirements:
|
87
86
|
- - ">="
|
@@ -90,12 +89,12 @@ dependencies:
|
|
90
89
|
segments:
|
91
90
|
- 0
|
92
91
|
version: "0"
|
92
|
+
requirement: *id005
|
93
|
+
name: phocus
|
93
94
|
type: :development
|
94
|
-
version_requirements: *id005
|
95
95
|
- !ruby/object:Gem::Dependency
|
96
|
-
name: bundler
|
97
96
|
prerelease: false
|
98
|
-
|
97
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
99
98
|
none: false
|
100
99
|
requirements:
|
101
100
|
- - ~>
|
@@ -106,12 +105,12 @@ dependencies:
|
|
106
105
|
- 0
|
107
106
|
- 0
|
108
107
|
version: 1.0.0
|
108
|
+
requirement: *id006
|
109
|
+
name: bundler
|
109
110
|
type: :development
|
110
|
-
version_requirements: *id006
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name: minitest
|
113
112
|
prerelease: false
|
114
|
-
|
113
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
115
114
|
none: false
|
116
115
|
requirements:
|
117
116
|
- - ~>
|
@@ -122,8 +121,9 @@ dependencies:
|
|
122
121
|
- 0
|
123
122
|
- 0
|
124
123
|
version: 2.0.0
|
124
|
+
requirement: *id007
|
125
|
+
name: minitest
|
125
126
|
type: :development
|
126
|
-
version_requirements: *id007
|
127
127
|
description: Eventually, your tests should pass in EventMachine.
|
128
128
|
email:
|
129
129
|
- joshbuddy@gmail.com
|