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.
@@ -1,4 +1,4 @@
1
- Copyright 2011 YOURNAME
1
+ Copyright 2011 Morton Jonuschat <yabawock@gmail.com>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,3 +1,184 @@
1
1
  # QuSpec
2
2
 
3
- This project rocks and uses MIT-LICENSE.
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
@@ -1,5 +1,6 @@
1
1
  require 'qu/backend/memory'
2
2
  require 'qu-spec/matchers'
3
+ require 'qu-spec/scheduler'
3
4
 
4
5
  module QuSpec
5
6
  def self.setup!
@@ -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
@@ -1,3 +1,3 @@
1
1
  module QuSpec
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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.1.2
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: &70160136907080 !ruby/object:Gem::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: *70160136907080
24
+ version_requirements: *70131682168640
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &70160136906420 !ruby/object:Gem::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: *70160136906420
35
+ version_requirements: *70131682167960
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: simple_uuid
38
- requirement: &70160136905640 !ruby/object:Gem::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: *70160136905640
46
+ version_requirements: *70131682167180
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake
49
- requirement: &70160136904880 !ruby/object:Gem::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: *70160136904880
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: 4087639463335953036
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: 4087639463335953036
100
+ hash: 1380140734345455011
100
101
  requirements: []
101
102
  rubyforge_project:
102
103
  rubygems_version: 1.8.10