bean_counter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,227 @@
1
+ module BeanCounter::TestAssertions
2
+
3
+ # :call-seq:
4
+ # assert_enqueued(options = {Symbol,String => Numeric,Proc,Range,Regexp,String})
5
+ #
6
+ # Asserts that some number of jobs are enqueued that match the given Hash of
7
+ # +options+. If no +options+ are given, asserts that at least one job exists.
8
+ #
9
+ # Each _key_ in +options+ is a String or a Symbol that identifies an attribute
10
+ # of a job that the corresponding _value_ should be compared against. All attribute
11
+ # comparisons are performed using the triple equal (===) operator/method of
12
+ # the given _value_.
13
+ #
14
+ # +options+ may additionally include a _count_ key of 'count' or :count that
15
+ # can be used to assert that a particular number of matching jobs are found.
16
+ #
17
+ # If no _count_ option is provided, the assertion succeeds if any job is found
18
+ # that matches all of the +options+ given. If no jobs are found that match the
19
+ # +options+ given, the assertion fails.
20
+ #
21
+ # If a _count_ option is provided the assertion only succeeds if the triple equal
22
+ # (===) operator/method of the value of _count_ evaluates to true when given the
23
+ # total number of matching jobs. Otherwise the assertion fails. The use of ===
24
+ # allows for more advanced comparisons using Procs, Ranges, Regexps, etc.
25
+ #
26
+ # See Strategy#job_matches? and/or the #job_matches? method of the strategy
27
+ # in use for more detailed information on how it is determined whether or not
28
+ # a job matches the given +options+.
29
+ #
30
+ # assert_enqueued
31
+ #
32
+ # assert_enqueued(:body => /test/, :count => 5)
33
+ #
34
+ # assert_enqueued('state' => 'buried', 'count' => 3)
35
+ def assert_enqueued(options = {})
36
+ enqueue_expectation(:assert, options)
37
+ end
38
+
39
+
40
+ # :call-seq:
41
+ # assert_enqueues(options = {Symbol,String => Numeric,Proc,Range,Regexp,String}) { block }
42
+ #
43
+ # Asserts that the given +block+ enqueues some number of jobs that match the
44
+ # given Hash of +options+. If no +options+ are given, asserts that at least
45
+ # one job is enqueued during the execution of the +block+.
46
+ #
47
+ # Unlike #assert_enqueued, which will evaluate all jobs in the beanstalkd pool,
48
+ # this method will only evaluate jobs that were enqueued during the
49
+ # execution of the given +block+. This can be useful for performance and for
50
+ # making assertions that could return false positives if all jobs were
51
+ # evaluated.
52
+ #
53
+ # Each _key_ in +options+ is a String or a Symbol that identifies an attribute
54
+ # of a job that the corresponding _value_ should be compared against. All attribute
55
+ # comparisons are performed using the triple equal (===) operator/method of
56
+ # the given _value_.
57
+ #
58
+ # +options+ may additionally include a _count_ key of 'count' or :count that
59
+ # can be used to assert that a particular number of matching jobs are found.
60
+ #
61
+ # If no _count_ option is provided, the assertion succeeds if any job is found
62
+ # that matches all of the +options+ given. If no jobs are found that match the
63
+ # +options+ given, the assertion fails.
64
+ #
65
+ # If a _count_ option is provided the assertion only succeeds if the triple equal
66
+ # (===) operator/method of the value of _count_ evaluates to true when given the
67
+ # total number of matching jobs. Otherwise the assertion fails. The use of ===
68
+ # allows for more advanced comparisons using Procs, Ranges, Regexps, etc.
69
+ #
70
+ # See Strategy#job_matches? and/or the #job_matches? method of the strategy
71
+ # in use for more detailed information on how it is determined whether or not
72
+ # a job matches the given +options+.
73
+ #
74
+ # assert_enqueues(:body => /test/) do
75
+ # enqueue_some_jobs
76
+ # end
77
+ def assert_enqueues(options = {})
78
+ raise ArgumentError, 'Block required' unless block_given?
79
+
80
+ enqueue_expectation(:assert, options, &Proc.new)
81
+ end
82
+
83
+
84
+ # :call-seq:
85
+ # assert_tube(options = {Symbol,String => Numeric,Proc,Range,Regexp,String})
86
+ #
87
+ # Asserts that at least one tube exist that matches the given Hash of
88
+ # +options+. If no +options+ are given, asserts that at least one tube exists,
89
+ # which will always succeed.
90
+ #
91
+ # Each _key_ in +options+ is a String or a Symbol that identifies an attribute
92
+ # of a tube that the corresponding _value_ should be compared against. All attribute
93
+ # comparisons are performed using the triple equal (===) operator/method of
94
+ # the given _value_.
95
+ #
96
+ # The assertion succeeds if any tube exists that matches all of the given
97
+ # +options+. If no tube exists matching all of the given +options+, the assertion
98
+ # fails.
99
+ #
100
+ # See Strategy#tube_matches? and/or the #tube_matches? method of the strategy
101
+ # in use for more detailed information on how it is determined whether or not
102
+ # a tube matches the given +options+.
103
+ #
104
+ # assert_tube
105
+ #
106
+ # assert_tube(:name => /test/)
107
+ #
108
+ # assert_tube('current-jobs-ready' => 1..10)
109
+ def assert_tube(options = {})
110
+ tube_expectation(:assert, :failure_message, options)
111
+ end
112
+
113
+
114
+ # :call-seq:
115
+ # refute_enqueued(options = {Symbol,String => Numeric,Proc,Range,Regexp,String})
116
+ #
117
+ # Asserts that no jobs are enqueued that match the given Hash of +options+.
118
+ # If no +options+ are given, asserts that no jobs exist.
119
+ #
120
+ # Each _key_ in +options+ is a String or a Symbol that identifies an attribute
121
+ # of a job that the corresponding _value_ should be compared against. All attribute
122
+ # comparisons are performed using the triple equal (===) operator/method of
123
+ # the given _value_.
124
+ #
125
+ # The refutation succeeds if no jobs are found that match all of the +options+
126
+ # given. If any matching jobs are found, the refutation fails.
127
+ #
128
+ # See Strategy#job_matches? and/or the #job_matches? method of the strategy
129
+ # in use for more detailed information on how it is determined whether or not
130
+ # a job matches the given +options+.
131
+ #
132
+ # refute_enqueued
133
+ #
134
+ # refute_enqueued(:body => lambda {|body| body.length > 50})
135
+ #
136
+ # refute_enqueued('state' => 'buried')
137
+ def refute_enqueued(options = {})
138
+ enqueue_expectation(:refute, options)
139
+ end
140
+
141
+
142
+ # :call-seq:
143
+ # refute_enqueues(options = {Symbol,String => Numeric,Proc,Range,Regexp,String}) { block }
144
+ #
145
+ # Asserts that the given +block+ enqueues no jobs that match the given Hash
146
+ # of +options+. If no +options+ are given, asserts that no job are enqueued
147
+ # by the given +block+.
148
+ #
149
+ # Unlike #refute_enqueued, which will evaluate all jobs in the beanstalkd pool,
150
+ # this method will only evaluate jobs that were enqueued during the
151
+ # execution of the given +block+. This can be useful for performance and for
152
+ # making assertions that could return false positives if all jobs were
153
+ # evaluated.
154
+ #
155
+ # Each _key_ in +options+ is a String or a Symbol that identifies an attribute
156
+ # of a job that the corresponding _value_ should be compared against. All attribute
157
+ # comparisons are performed using the triple equal (===) operator/method of
158
+ # the given _value_.
159
+ #
160
+ # The refutation succeeds if no jobs are found that match all of the +options+
161
+ # given. If any matching jobs are found, the refutation fails.
162
+ #
163
+ # See Strategy#job_matches? and/or the #job_matches? method of the strategy
164
+ # in use for more detailed information on how it is determined whether or not
165
+ # a job matches the given +options+.
166
+ #
167
+ # refute_enqueues do
168
+ # do_some_work_that_should_not_enqueue_any_jobs
169
+ # end
170
+ def refute_enqueues(options = {})
171
+ raise ArgumentError, 'Block required' unless block_given?
172
+
173
+ enqueue_expectation(:refute, options, &Proc.new)
174
+ end
175
+
176
+
177
+ # :call-seq:
178
+ # refute_tube(options = {Symbol,String => Numeric,Proc,Range,Regexp,String})
179
+ #
180
+ # Asserts that no tube exist that matches the given Hash of +options+.
181
+ # If no options are given, asserts that no tubes exist which will always fail.
182
+ #
183
+ # Each _key_ in +options+ is a String or a Symbol that identifies an attribute
184
+ # of a tube that the corresponding _value_ should be compared against. All attribute
185
+ # comparisons are performed using the triple equal (===) operator/method of
186
+ # the given _value_.
187
+ #
188
+ # The refutation succeeds if no tube exists that matches all of the given
189
+ # +options+. If any tubes exist that match all of the given +options+, the
190
+ # refutation fails.
191
+ #
192
+ # See Strategy#tube_matches? and/or the #tube_matches? method of the strategy
193
+ # in use for more detailed information on how it is determined whether or not
194
+ # a tube matches the given +options+.
195
+ #
196
+ # refute_tube
197
+ # #=> always fails
198
+ #
199
+ # refute_tube(:name => /production/)
200
+ #
201
+ # refute_tube('current-jobs-ready' => 0)
202
+ def refute_tube(options = {})
203
+ tube_expectation(:refute, :negative_failure_message, options)
204
+ end
205
+
206
+ private
207
+
208
+
209
+ # Builds job expectation object, evaluates and makes appropriate assertion
210
+ # with appropriate failure message
211
+ def enqueue_expectation(assertion_method, options, &block)
212
+ message_type = assertion_method == :assert ? :failure_message : :negative_failure_message
213
+ expectation = BeanCounter::EnqueuedExpectation.new(options)
214
+ match = expectation.matches?(block_given? ? block : nil)
215
+ send(assertion_method, match, expectation.send(message_type))
216
+ end
217
+
218
+
219
+ # Builds tube expectation object, evaluates and makes appropriate assertion
220
+ # with appropriate failure message
221
+ def tube_expectation(assertion_method, message_type, options)
222
+ expectation = BeanCounter::TubeExpectation.new(options)
223
+ match = expectation.matches?
224
+ send(assertion_method, match, expectation.send(message_type))
225
+ end
226
+
227
+ end
@@ -0,0 +1,3 @@
1
+ require 'bean_counter/mini_test'
2
+
3
+ Test::Unit::TestCase.send(:include, BeanCounter::MiniTest)
@@ -0,0 +1,66 @@
1
+ class BeanCounter::TubeExpectation
2
+
3
+ extend Forwardable
4
+
5
+ def_delegators BeanCounter, :strategy
6
+
7
+ # The value that the expectation expects
8
+ attr_reader :expected
9
+
10
+ # The tube found by the expecation during matching
11
+ attr_reader :found
12
+
13
+
14
+ # Builds the failure message used in the event of a positive expectation
15
+ # failure
16
+ def failure_message
17
+ return '' unless found.nil?
18
+ return "expected tube matching #{expected.to_s}, found none."
19
+ end
20
+
21
+
22
+ # Create a new tube expectation. Uses the given +expected+ Hash to determine
23
+ # if any tubes exist that match the expected options.
24
+ #
25
+ # Each _key_ in the +expected+ Hash is a String or a Symbol that identifies
26
+ # an attribute of a tube that the corresponding _value_ should be compared
27
+ # against. All attribute comparisons are performed using the triple equal
28
+ # (===) operator/method of the given _value_.
29
+ #
30
+ # See BeanCounter::MiniTest and/or BeanCounter::SpecMatchers for more information.
31
+ def initialize(expected)
32
+ @expected = expected
33
+ end
34
+
35
+
36
+ # Checks all tubes in the beanstalkd pool for a tube matching the expected
37
+ # options hash given at instantiation. The expectation succeeds if any tube
38
+ # exists that matches all of the expected options. If no tube exists
39
+ # matching all of the given options, the expectation fails.
40
+ #
41
+ # See Strategy#tube_matches? and/or the #tube_matches? method of the strategy
42
+ # in use for more detailed information on how it is determined whether or not
43
+ # a tube matches the options expected.
44
+ #
45
+ # See also BeanCounter::MiniTest and/or BeanCounter::SpecMatchers for additional
46
+ # information.
47
+ def matches?(given = nil)
48
+ @found = strategy.tubes.detect do |tube|
49
+ strategy.tube_matches?(tube, expected)
50
+ end
51
+
52
+ return !found.nil?
53
+ end
54
+
55
+
56
+ # Builds the failure message used in the event of a negative expectation
57
+ # failure
58
+ def negative_failure_message
59
+ return '' if found.nil?
60
+ return [
61
+ "expected no tubes matching #{expected.to_s},",
62
+ "found #{strategy.pretty_print_tube(found)}",
63
+ ].join(' ')
64
+ end
65
+
66
+ end
@@ -0,0 +1,4 @@
1
+ module BeanCounter
2
+ # BeanCounter version number
3
+ VERSION = '0.0.1'
4
+ end
@@ -0,0 +1,16 @@
1
+ require 'coveralls'
2
+ Coveralls.wear_merged!
3
+
4
+ lib = File.expand_path('../../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+
7
+ require 'rspec'
8
+ require 'mocha/api'
9
+ require 'bean_counter'
10
+ require 'bean_counter/spec'
11
+
12
+ BeanCounter.beanstalkd_url = 'beanstalk://localhost'
13
+
14
+ def client
15
+ return @client ||= Beaneater::Connection.new('localhost:11300')
16
+ end
@@ -0,0 +1,224 @@
1
+ require 'spec_helper'
2
+ require 'securerandom'
3
+
4
+ # Fuller testing of matchers handled by strategy and matcher tests. Just make
5
+ # sure matchers work as expected at high level
6
+ describe BeanCounter::SpecMatchers do
7
+
8
+ before(:each) do
9
+ BeanCounter.reset!
10
+ @tube_name = SecureRandom.uuid
11
+ client.transmit("use #{@tube_name}")
12
+ @message = SecureRandom.uuid
13
+ end
14
+
15
+
16
+ describe 'enqueued job matcher' do
17
+
18
+ describe 'positive match' do
19
+
20
+ it 'should match any matching job when not given a count' do
21
+ should_not have_enqueued(:body => @message)
22
+ proc do
23
+ 2.times do
24
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
25
+ end
26
+ end.should have_enqueued(:body => @message)
27
+ should have_enqueued(:body => @message)
28
+ end
29
+
30
+
31
+ it 'should match count exactly when given integer count' do
32
+ should_not have_enqueued(:body => @message)
33
+ proc do
34
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
35
+ end.should have_enqueued(:body => @message, :count => 1)
36
+ should have_enqueued(:body => @message, :count => 1)
37
+ end
38
+
39
+
40
+ it 'should match count to range when given range' do
41
+ should_not have_enqueued(:body => @message)
42
+ proc do
43
+ 2.times do
44
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
45
+ end
46
+ end.should have_enqueued(:body => @message, :count => 1..3)
47
+ should have_enqueued(:body => @message, :count => 1..3)
48
+ end
49
+
50
+
51
+ it 'should not match when no matching jobs are found' do
52
+ message = SecureRandom.uuid
53
+ ::RSpec::Expectations.expects(:fail_with)
54
+ proc do
55
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
56
+ end.should have_enqueued(:body => message)
57
+ should have_enqueued(:body => @message)
58
+ should_not have_enqueued(:body => message)
59
+ end
60
+
61
+
62
+ it 'should not match with exact count when given integer count' do
63
+ should_not have_enqueued(:body => @message)
64
+ ::RSpec::Expectations.expects(:fail_with)
65
+ proc do
66
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
67
+ end.should have_enqueued(:body => @message, :count => 2)
68
+ should have_enqueued(:body => @message, :count => 1)
69
+ end
70
+
71
+
72
+ it 'should not match when no matching jobs are enqueued during block' do
73
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
74
+ ::RSpec::Expectations.expects(:fail_with)
75
+ (proc {}).should have_enqueued(:body => @message)
76
+ should have_enqueued(:body => @message)
77
+ end
78
+
79
+ end
80
+
81
+
82
+ describe 'negative match' do
83
+
84
+ it 'should match when no matching jobs are found' do
85
+ message = SecureRandom.uuid
86
+ proc do
87
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
88
+ end.should_not have_enqueued(:body => message)
89
+ should have_enqueued(:body => @message)
90
+ should_not have_enqueued(:body => message)
91
+ end
92
+
93
+
94
+ it 'should match with exact count when given integer count' do
95
+ should_not have_enqueued(:body => @message)
96
+ proc do
97
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
98
+ end.should_not have_enqueued(:body => @message, :count => 2)
99
+ should have_enqueued(:body => @message, :count => 1)
100
+ end
101
+
102
+
103
+ it 'should match when no matching jobs are enqueued during block' do
104
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
105
+ (proc {}).should_not have_enqueued(:body => @message)
106
+ should have_enqueued(:body => @message)
107
+ end
108
+
109
+
110
+ it 'should not match when not given a count and job found' do
111
+ should_not have_enqueued(:body => @message)
112
+ ::RSpec::Expectations.expects(:fail_with)
113
+ proc do
114
+ 2.times do
115
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
116
+ end
117
+ end.should_not have_enqueued(:body => @message)
118
+ should have_enqueued(:body => @message)
119
+ end
120
+
121
+
122
+ it 'should not match when found count matches expected count' do
123
+ should_not have_enqueued(:body => @message)
124
+ ::RSpec::Expectations.expects(:fail_with)
125
+ proc do
126
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
127
+ end.should_not have_enqueued(:body => @message, :count => 1)
128
+ should have_enqueued(:body => @message, :count => 1)
129
+ end
130
+
131
+
132
+ it 'should not match when found count falls in expected range' do
133
+ should_not have_enqueued(:body => @message)
134
+ ::RSpec::Expectations.expects(:fail_with)
135
+ proc do
136
+ 2.times do
137
+ client.transmit("put 0 0 120 #{@message.bytesize}\r\n#{@message}")
138
+ end
139
+ end.should_not have_enqueued(:body => @message, :count => 1..3)
140
+ should have_enqueued(:body => @message, :count => 1..3)
141
+ end
142
+ end
143
+
144
+ end
145
+
146
+
147
+ describe 'tube matcher' do
148
+
149
+ describe 'positive match' do
150
+
151
+ it 'should match when matching tube found' do
152
+ client.transmit("put 0 0 120 2\r\nxx")
153
+ client.transmit("put 0 120 120 2\r\nxx")
154
+ client.transmit("pause-tube #{@tube_name} 0")
155
+
156
+ should have_tube({
157
+ 'name' => @tube_name,
158
+ 'cmd-pause' => 1..3,
159
+ 'current-jobs-ready' => 1,
160
+ 'current-jobs-delayed' => 1,
161
+ 'current-using' => 1,
162
+ })
163
+ end
164
+
165
+
166
+ it 'should not match when no matching tubes are found' do
167
+ should_not have_tube(:name => SecureRandom.uuid)
168
+
169
+ default_stats = client.transmit('stats-tube default')[:body]
170
+ urgent = default_stats['current-jobs-urgent']
171
+ should_not have_tube({
172
+ 'name' => 'default',
173
+ 'current-jobs-urgent' => (urgent + 5)..(urgent + 10),
174
+ })
175
+ watching = default_stats['current-watching']
176
+ ::RSpec::Expectations.expects(:fail_with)
177
+ should have_tube({
178
+ 'name' => 'default',
179
+ 'current-watching' => watching + 10,
180
+ })
181
+ end
182
+
183
+ end
184
+
185
+
186
+ describe 'negative match' do
187
+
188
+ it 'should match when no matching tubes are found' do
189
+ should_not have_tube(:name => SecureRandom.uuid)
190
+
191
+ default_stats = client.transmit('stats-tube default')[:body]
192
+ urgent = default_stats['current-jobs-urgent']
193
+ should_not have_tube({
194
+ 'name' => 'default',
195
+ 'current-jobs-urgent' => (urgent + 5)..(urgent + 10),
196
+ })
197
+ watching = default_stats['current-watching']
198
+ should_not have_tube({
199
+ 'name' => 'default',
200
+ 'current-watching' => watching + 10,
201
+ })
202
+ end
203
+
204
+
205
+ it 'should not match when matching tube found' do
206
+ client.transmit("put 0 0 120 2\r\nxx")
207
+ client.transmit("put 0 120 120 2\r\nxx")
208
+ client.transmit("pause-tube #{@tube_name} 0")
209
+
210
+ ::RSpec::Expectations.expects(:fail_with)
211
+ should_not have_tube({
212
+ 'name' => @tube_name,
213
+ 'cmd-pause' => 1..3,
214
+ 'current-jobs-ready' => 1,
215
+ 'current-jobs-delayed' => 1,
216
+ 'current-using' => 1,
217
+ })
218
+ end
219
+
220
+ end
221
+
222
+ end
223
+
224
+ end