qu-spec 0.1.2 → 0.2.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.
- data/MIT-LICENSE +1 -1
- data/README.md +182 -1
- data/lib/qu-spec.rb +1 -0
- data/lib/qu-spec/matchers.rb +37 -0
- data/lib/qu-spec/scheduler.rb +33 -0
- data/lib/qu-spec/version.rb +1 -1
- data/lib/qu/backend/memory.rb +24 -0
- data/spec/qu-spec/matchers_spec.rb +16 -0
- metadata +12 -11
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,184 @@
|
|
1
1
|
# QuSpec
|
2
2
|
|
3
|
-
|
3
|
+
## Description
|
4
|
+
|
5
|
+
A QuSpec implements a set of matchers to help testing Qu interaction
|
6
|
+
with RSpec and Cucumber. The code has been inspired by
|
7
|
+
[ResqueSpec](https://leshill/resque_spec) but
|
8
|
+
thanks to the modular architecture of Qu most of the heavy lifting has
|
9
|
+
been implemented as an in-memory Qu::Backend implementation that
|
10
|
+
passes the Qu test suite for backends.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
# Rails 3.x: add it to your Gemfile
|
15
|
+
group :test do
|
16
|
+
gem 'qu-spec'
|
17
|
+
end
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### Configuring QuSpec
|
22
|
+
|
23
|
+
To use QuSpec in your tests you need to setup Qu to use the included
|
24
|
+
Memory Backend. The easiest way to accomplish this is with the
|
25
|
+
`QuSpec.setup!` method:
|
26
|
+
|
27
|
+
RSpec.configure do |config|
|
28
|
+
config.before do
|
29
|
+
QuSpec.setup!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
### Writing tests
|
34
|
+
|
35
|
+
Given this scenario
|
36
|
+
|
37
|
+
Given a person
|
38
|
+
When I recalculate
|
39
|
+
Then the person has calculate queued
|
40
|
+
|
41
|
+
And I write this spec using the `qu-spec` matcher
|
42
|
+
|
43
|
+
describe "#recalculate" do
|
44
|
+
before do
|
45
|
+
QuSpec.reset!
|
46
|
+
end
|
47
|
+
|
48
|
+
it "adds person.calculate to the Person queue" do
|
49
|
+
person.recalculate
|
50
|
+
Person.should have_queued(person.id, :calculate)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
(And I take note of the `before` block that is calling `reset!` for every spec)
|
55
|
+
|
56
|
+
And I might use the `in` statement to specify the queue:
|
57
|
+
|
58
|
+
describe "#recalculate" do
|
59
|
+
before do
|
60
|
+
QuSpec.reset!
|
61
|
+
end
|
62
|
+
|
63
|
+
it "adds person.calculate to the Person queue" do
|
64
|
+
person.recalculate
|
65
|
+
Person.should have_queued(person.id, :calculate).in(:people)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
And I might write this as a Cucumber step
|
70
|
+
|
71
|
+
Then /the (\w?) has (\w?) queued/ do |thing, method|
|
72
|
+
thing_obj = instance_variable_get("@#{thing}")
|
73
|
+
thing_obj.class.should have_queued(thing_obj.id, method.to_sym)
|
74
|
+
end
|
75
|
+
|
76
|
+
Then I write some code to make it pass:
|
77
|
+
|
78
|
+
class Person
|
79
|
+
@queue = :people
|
80
|
+
|
81
|
+
def recalculate
|
82
|
+
Qu.enqueue(Person, id, :calculate)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
You can check the size of the queue in your specs too.
|
87
|
+
|
88
|
+
describe "#recalculate" do
|
89
|
+
before do
|
90
|
+
QuSpec.reset!
|
91
|
+
end
|
92
|
+
|
93
|
+
it "adds an entry to the Person queue" do
|
94
|
+
person.recalculate
|
95
|
+
Person.should have_queue_size_of(1)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
## QuMailer with Specs
|
100
|
+
|
101
|
+
To use with [QuMailer](https://github.com/yabawock/qu-mailer) you should
|
102
|
+
have an initializer that does *not* exclude the `test` (or `cucumber`)
|
103
|
+
environment. Your initializer will probably end up looking like:
|
104
|
+
|
105
|
+
# config/initializers/qu_mailer.rb
|
106
|
+
Qu::Mailer.excluded_environments = []
|
107
|
+
|
108
|
+
## QuScheduler with Specs
|
109
|
+
|
110
|
+
Support for [QuScheduler](https://github.com/yabawock/qu-scheduler) is integrated into QuSpec,
|
111
|
+
no additional setup is needed.
|
112
|
+
|
113
|
+
### Writing tests
|
114
|
+
|
115
|
+
Given this scenario
|
116
|
+
|
117
|
+
Given a person
|
118
|
+
When I schedule a recalculate
|
119
|
+
Then the person has calculate scheduled
|
120
|
+
|
121
|
+
And I write this spec using the `qu-spec` matcher
|
122
|
+
|
123
|
+
describe "#recalculate" do
|
124
|
+
before do
|
125
|
+
QuSpec.reset!
|
126
|
+
end
|
127
|
+
|
128
|
+
it "adds person.calculate to the Person queue" do
|
129
|
+
person.recalculate
|
130
|
+
Person.should have_scheduled(person.id, :calculate)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
(And I take note of the `before` block that is calling `reset!` for every spec)
|
135
|
+
|
136
|
+
*(There is also a **have_scheduled_at** matcher)*
|
137
|
+
|
138
|
+
And I might write this as a Cucumber step
|
139
|
+
|
140
|
+
Then /the (\w?) has (\w?) scheduled/ do |thing, method|
|
141
|
+
thing_obj = instance_variable_get("@#{thing}")
|
142
|
+
thing_obj.class.should have_scheduled(thing_obj.id, method.to_sym)
|
143
|
+
end
|
144
|
+
|
145
|
+
Then I write some code to make it pass:
|
146
|
+
|
147
|
+
class Person
|
148
|
+
@queue = :people
|
149
|
+
|
150
|
+
def recalculate
|
151
|
+
Qu.enqueue_at(Time.now + 3600, Person, id, :calculate)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
## Performing Jobs in Specs
|
156
|
+
|
157
|
+
QuSpec doesn't currently support performing jobs within tests. This is a
|
158
|
+
feature that might get implemented in a future release.
|
159
|
+
|
160
|
+
## Note on Patches / Pull Requests
|
161
|
+
|
162
|
+
* Fork the project.
|
163
|
+
* Make your feature addition or bug fix.
|
164
|
+
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
165
|
+
* Commit, do not mess with rakefile, version, or history.
|
166
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
167
|
+
* Send me a pull request. Bonus points for topic branches.
|
168
|
+
|
169
|
+
## Credits
|
170
|
+
|
171
|
+
This work has been heavily inspired by [ResqueSpec](https://github.com/leshill/resque_spec) by Les Hill.
|
172
|
+
|
173
|
+
## Maintainers
|
174
|
+
|
175
|
+
* [Morton Jonuschat](https://github.com/yabawock)
|
176
|
+
|
177
|
+
## License
|
178
|
+
|
179
|
+
MIT License
|
180
|
+
|
181
|
+
## Copyright
|
182
|
+
|
183
|
+
Copyright 2011 Morton Jonuschat
|
184
|
+
Some parts copyright 2010-2011 Les Hill
|
data/lib/qu-spec.rb
CHANGED
data/lib/qu-spec/matchers.rb
CHANGED
@@ -62,3 +62,40 @@ RSpec::Matchers.define :have_queue_size_of do |size|
|
|
62
62
|
"have a queue size of #{size}"
|
63
63
|
end
|
64
64
|
end
|
65
|
+
|
66
|
+
RSpec::Matchers.define :have_scheduled do |*expected_args|
|
67
|
+
match do |actual|
|
68
|
+
QuSpec.schedule_for(actual).any? { |entry| entry.klass.to_s == actual.to_s && entry.args == expected_args }
|
69
|
+
end
|
70
|
+
|
71
|
+
failure_message_for_should do |actual|
|
72
|
+
"expected that #{actual} would have [#{expected_args.join(', ')}] scheduled"
|
73
|
+
end
|
74
|
+
|
75
|
+
failure_message_for_should_not do |actual|
|
76
|
+
"expected that #{actual} would not have [#{expected_args.join(', ')}] scheduled"
|
77
|
+
end
|
78
|
+
|
79
|
+
description do
|
80
|
+
"have scheduled arguments"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
RSpec::Matchers.define :have_scheduled_at do |*expected_args|
|
85
|
+
match do |actual|
|
86
|
+
time = expected_args.shift
|
87
|
+
QuSpec.schedule_for(actual).any? { |entry| entry.klass.to_s == actual.to_s && entry.time == time && entry.args == expected_args }
|
88
|
+
end
|
89
|
+
|
90
|
+
failure_message_for_should do |actual|
|
91
|
+
"expected that #{actual} would have [#{expected_args.join(', ')}] scheduled"
|
92
|
+
end
|
93
|
+
|
94
|
+
failure_message_for_should_not do |actual|
|
95
|
+
"expected that #{actual} would not have [#{expected_args.join(', ')}] scheduled"
|
96
|
+
end
|
97
|
+
|
98
|
+
description do
|
99
|
+
"have scheduled at the given time the arguments"
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module QuSpec
|
2
|
+
module SchedulerExtension
|
3
|
+
def enqueue_at(time, klass, *args)
|
4
|
+
QuSpec.enqueue_at(time, klass, *args)
|
5
|
+
end
|
6
|
+
|
7
|
+
def enqueue_in(time, klass, *args)
|
8
|
+
QuSpec.enqueue_in(time, klass, *args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def remove_delayed(klass, *args)
|
12
|
+
QuSpec.remove_delayed(klass, *args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.enqueue_at(time, klass, *args)
|
17
|
+
Qu.backend.delayed_push(time, Qu::Payload.new(:klass => klass, :args => args))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.enqueue_in(time, klass, *args)
|
21
|
+
enqueue_at(Time.now + time, klass, *args)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.remove_delayed(klass, *args)
|
25
|
+
Qu.backend.remove_delayed(klass, *args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.schedule_for(klass)
|
29
|
+
Qu.backend.get_schedule_by_klass(klass)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Qu.send :extend, QuSpec::SchedulerExtension
|
data/lib/qu-spec/version.rb
CHANGED
data/lib/qu/backend/memory.rb
CHANGED
@@ -57,6 +57,20 @@ module Qu
|
|
57
57
|
payload
|
58
58
|
end
|
59
59
|
|
60
|
+
def delayed_push(time, payload)
|
61
|
+
payload.id = SimpleUUID::UUID.new.to_guid
|
62
|
+
payload.time = time
|
63
|
+
@queues[scheduled_queue_name(payload.klass)] << payload
|
64
|
+
logger.debug { "Enqueued delayed job #{payload}" }
|
65
|
+
payload
|
66
|
+
end
|
67
|
+
|
68
|
+
def remove_delayed(klass, *args)
|
69
|
+
get_queue_by_name(scheduled_queue_name(klass)).delete_if do |payload|
|
70
|
+
payload.klass.to_s == klass.to_s && payload.args == args
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
60
74
|
def reserve(worker, options = {:block => true})
|
61
75
|
loop do
|
62
76
|
worker.queues.each do |queue|
|
@@ -94,6 +108,16 @@ module Qu
|
|
94
108
|
payload = Payload.new(:klass => klass)
|
95
109
|
get_queue_by_name(payload.queue)
|
96
110
|
end
|
111
|
+
|
112
|
+
def get_schedule_by_klass(klass)
|
113
|
+
get_queue_by_name(scheduled_queue_name(klass))
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def scheduled_queue_name(klass)
|
119
|
+
"#{klass.to_s}_scheduled"
|
120
|
+
end
|
97
121
|
end
|
98
122
|
end
|
99
123
|
end
|
@@ -74,4 +74,20 @@ describe "QuSpec Matchers" do
|
|
74
74
|
it { should_not have_queue_size_of(1).in('other_people') }
|
75
75
|
end
|
76
76
|
end
|
77
|
+
|
78
|
+
describe "#have_scheduled_at" do
|
79
|
+
let(:scheduled_at) { Time.now + 5 * 60 }
|
80
|
+
|
81
|
+
before do
|
82
|
+
Qu.enqueue_at(scheduled_at, Person, first_name, last_name)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "returns true if the arguments are found in the queue" do
|
86
|
+
Person.should have_scheduled_at(scheduled_at, first_name, last_name)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "returns false if the arguments are not found in the queue" do
|
90
|
+
Qu.should_not have_scheduled_at(scheduled_at, last_name, first_name)
|
91
|
+
end
|
92
|
+
end
|
77
93
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qu-spec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2011-12-04 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: qu
|
16
|
-
requirement: &
|
16
|
+
requirement: &70131682168640 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.1.3
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70131682168640
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &70131682167960 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 2.5.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70131682167960
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: simple_uuid
|
38
|
-
requirement: &
|
38
|
+
requirement: &70131682167180 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 0.2.0
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70131682167180
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rake
|
49
|
-
requirement: &
|
49
|
+
requirement: &70131682165160 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70131682165160
|
58
58
|
description: RSpec matchers and an in-memory backend for Qu
|
59
59
|
email:
|
60
60
|
- yabawock@gmail.com
|
@@ -64,6 +64,7 @@ extra_rdoc_files: []
|
|
64
64
|
files:
|
65
65
|
- lib/qu/backend/memory.rb
|
66
66
|
- lib/qu-spec/matchers.rb
|
67
|
+
- lib/qu-spec/scheduler.rb
|
67
68
|
- lib/qu-spec/version.rb
|
68
69
|
- lib/qu-spec.rb
|
69
70
|
- MIT-LICENSE
|
@@ -87,7 +88,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
88
|
version: '0'
|
88
89
|
segments:
|
89
90
|
- 0
|
90
|
-
hash:
|
91
|
+
hash: 1380140734345455011
|
91
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
93
|
none: false
|
93
94
|
requirements:
|
@@ -96,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
97
|
version: '0'
|
97
98
|
segments:
|
98
99
|
- 0
|
99
|
-
hash:
|
100
|
+
hash: 1380140734345455011
|
100
101
|
requirements: []
|
101
102
|
rubyforge_project:
|
102
103
|
rubygems_version: 1.8.10
|