amqp-spec 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/HISTORY +19 -0
- data/LICENSE +20 -0
- data/README.rdoc +169 -0
- data/Rakefile +24 -0
- data/VERSION +1 -0
- data/lib/amqp-spec.rb +27 -0
- data/lib/amqp-spec/rspec.rb +195 -0
- data/lib/version.rb +10 -0
- data/spec/amqp.yml +28 -0
- data/spec/failing_rspec_spec.rb +62 -0
- data/spec/rspec_amqp_spec.rb +273 -0
- data/spec/rspec_em_spec.rb +67 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +35 -0
- data/tasks/common.rake +18 -0
- data/tasks/doc.rake +14 -0
- data/tasks/gem.rake +40 -0
- data/tasks/git.rake +34 -0
- data/tasks/spec.rake +19 -0
- data/tasks/version.rake +71 -0
- metadata +114 -0
data/.gitignore
ADDED
data/HISTORY
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
== 0.0.0 / 2010-10-13
|
2
|
+
|
3
|
+
* Birthday!
|
4
|
+
|
5
|
+
== 0.0.1 / 2010-10-13
|
6
|
+
|
7
|
+
* Initial code import from EM-Spec and AMQPHelper
|
8
|
+
|
9
|
+
== 0.0.2 / 2010-10-13
|
10
|
+
|
11
|
+
* Minimal functionality implemented
|
12
|
+
|
13
|
+
== 0.0.3 / 2010-10-13
|
14
|
+
|
15
|
+
* Bunch of non-working specs added
|
16
|
+
|
17
|
+
== 0.0.4 / 2010-10-14
|
18
|
+
|
19
|
+
* Problems with default_options resolved
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Arvicco
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
= amqp-spec
|
2
|
+
by: Arvicco
|
3
|
+
url: http://github.com/arvicco/amqp-spec
|
4
|
+
|
5
|
+
== Summary
|
6
|
+
|
7
|
+
Simple API for testing asynchronous EventMachine/AMQP code.
|
8
|
+
|
9
|
+
== Description
|
10
|
+
|
11
|
+
EventMachine-based code, including synchronous {AMQP library}[http://github.com/tmm1/amqp] is
|
12
|
+
notoriously difficult to test. To the point that many people recommend using either
|
13
|
+
Mocks[http://github.com/danielsdeleo/moqueue] or {synchronous libraries}[http://github.com/celldee/bunny]
|
14
|
+
instead of EM-based libraries in unit tests. This is not always an option, however - sometimes your code
|
15
|
+
is supposed to run inside event loop, and you want to test a real thing, not mocks.
|
16
|
+
|
17
|
+
EM-Spec[http://github.com/tmm1/em-spec] gem made it easier to write evented specs, but it has several drawbacks.
|
18
|
+
First, it is not easy to manage both EM.run and AMQP.start loops at the same time. Second, AMQP is not
|
19
|
+
properly stopped and deactivated upon exceptions and timeouts, resulting in AMQP library state leak
|
20
|
+
between examples and multiple mystereous failures.
|
21
|
+
|
22
|
+
AMQP-Spec is built upon EM-Spec code but makes it easier to test AMQP event loops specifically. API is
|
23
|
+
very similar to EM-Spec, only a bit extended. The final goal is to make writing AMQP specs reasonably
|
24
|
+
pleasant experience and dispel the notion that evented AMQP-based libs are impossible to unit-test.
|
25
|
+
|
26
|
+
Mind you, you still have to properly manage your AMQP broker in order to prevent broker state from leaking
|
27
|
+
between examples. You can try to combine AMQP-Spec and Moqueue[http://github.com/danielsdeleo/moqueue]
|
28
|
+
if you want to abstract away actual broker interactions, but still specify some event-based expectations.
|
29
|
+
|
30
|
+
==Rspec
|
31
|
+
There are several ways to use amqp-spec. To use it as a helper, include AMQP::SpecHelper in your describe block.
|
32
|
+
You then use either 'amqp' or 'em' methods to wrap your evented test code. Inside the amqp/em block, you must call
|
33
|
+
#done after your expectations. Everything works normally otherwise. You can use default_timeout and default_options
|
34
|
+
macros to avoid manually setting AMQP options in each example. However, if you DO manually set options inside
|
35
|
+
the example, they override the defaults. Only one set of default options and default timeout is used across groups,
|
36
|
+
it is not possible to have separate defaults for separate groups.
|
37
|
+
|
38
|
+
require "amqp-spec/rspec"
|
39
|
+
describe AMQP do
|
40
|
+
include AMQP::SpecHelper
|
41
|
+
|
42
|
+
before(:each) do
|
43
|
+
puts EM.reactor_running?
|
44
|
+
end
|
45
|
+
|
46
|
+
it "works normally when not using #amqp or #em" do
|
47
|
+
1.should == 1
|
48
|
+
end
|
49
|
+
|
50
|
+
it "makes testing evented code easy with #em" do
|
51
|
+
em do
|
52
|
+
start = Time.now
|
53
|
+
|
54
|
+
EM.add_timer(0.5){
|
55
|
+
(Time.now-start).should be_close( 0.5, 0.1 )
|
56
|
+
done
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "runs AMQP.start loop with options given to #amqp" do
|
62
|
+
amqp(:host => 'my.amqp.broker.org', :port => '21118')do
|
63
|
+
AMQP.conn.should be_connected
|
64
|
+
done
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "optionally raises timeout exception if your loop hangs for some reason" do
|
69
|
+
proc {
|
70
|
+
amqp(:spec_timeout => 3){}
|
71
|
+
}.should raise_error SpecTimeoutExceededError
|
72
|
+
end
|
73
|
+
|
74
|
+
default_timeout 1 # Can be used to set default :spec_timeout for all your amqp-based specs
|
75
|
+
end
|
76
|
+
|
77
|
+
Another option is to include AMQP::Spec in your describe block. This will patch Rspec so that all of your
|
78
|
+
examples run inside an amqp block automatically. A word of caution about before{} and after{} hooks in your example
|
79
|
+
groups including AMQP::Spec. Each of these hooks will run in its separate EM loop that you'll need to shut down
|
80
|
+
either manually (done) or via default_timeout. Essentially, this means that any EM-related state that you'd like
|
81
|
+
to setup/teardown using these hooks will be lost as each example will run in a separate thread. In order to
|
82
|
+
run setup/teardown hooks inside the EM loop, you'll need to use before_amqp{} and after_amqp{} hooks that run
|
83
|
+
inside the EM loop but before/after AMQP loop (these hooks are currently not implemented)
|
84
|
+
|
85
|
+
require "amqp-spec/rspec"
|
86
|
+
describe AMQP do
|
87
|
+
include AMQP::Spec
|
88
|
+
|
89
|
+
before(:each) do
|
90
|
+
puts EM.reactor_running?
|
91
|
+
done
|
92
|
+
end
|
93
|
+
|
94
|
+
default_options :host => 'my.amqp.broker.org', :port => '21118'
|
95
|
+
# Can be used to set default options for all your (implied) amqp{} event loops
|
96
|
+
|
97
|
+
it "requires a call to #done in every example" do
|
98
|
+
1.should == 1
|
99
|
+
done
|
100
|
+
end
|
101
|
+
|
102
|
+
it "runs test code in an amqp block automatically" do
|
103
|
+
start = Time.now
|
104
|
+
|
105
|
+
EM.add_timer(0.5){
|
106
|
+
(Time.now-start).should be_close( 0.5, 0.1 )
|
107
|
+
done
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
it "runs AMQP.start loop with default_options" do
|
112
|
+
AMQP.conn.should be_connected
|
113
|
+
done
|
114
|
+
end
|
115
|
+
|
116
|
+
it "raises timeout exception ONLY if default_timeout was set" do
|
117
|
+
proc{}.should raise_error SpecTimeoutExceededError
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
Finally, you can include AMQP::EMSpec in your describe block. This will run all the group examples
|
122
|
+
inside em block instead of amqp. before{} and after{} hooks should be finished with 'done', same as
|
123
|
+
when including AMQP::Spec, and same caution about using them applies.
|
124
|
+
|
125
|
+
require "amqp-spec/rspec"
|
126
|
+
describe AMQP do
|
127
|
+
include AMQP::EMSpec
|
128
|
+
|
129
|
+
it "requires a call to #done in every example" do
|
130
|
+
1.should == 1
|
131
|
+
done
|
132
|
+
end
|
133
|
+
|
134
|
+
it "runs test code in an amqp block automatically" do
|
135
|
+
start = Time.now
|
136
|
+
|
137
|
+
EM.add_timer(0.5){
|
138
|
+
(Time.now-start).should be_close( 0.5, 0.1 )
|
139
|
+
done
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
default_timeout 1
|
144
|
+
# Default spec timeouts can be used same as with AMQP::Spec, default_options (if defined) are not used
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
==Bacon
|
149
|
+
|
150
|
+
...
|
151
|
+
|
152
|
+
==Test::Unit
|
153
|
+
|
154
|
+
...
|
155
|
+
|
156
|
+
==Limitations
|
157
|
+
|
158
|
+
AMQP-Spec can be currently used with rspec only. I suppose, there is nothing special in extending EM-Spec's
|
159
|
+
test unit and bacon support, I just do not have experience dealing with these platforms. Another limitation,
|
160
|
+
it uses native Fibers and therefore not compatible with Ruby 1.8. Again, it seems possible to rewrite it in
|
161
|
+
1.8-compatible style, with string evals and Fiber backport, but I'd rather leave this work to someone else.
|
162
|
+
|
163
|
+
Any help improving this library is greatly appreciated...
|
164
|
+
|
165
|
+
== LICENSE:
|
166
|
+
Copyright (c) 2010 Arvicco.
|
167
|
+
Original EM-Spec code copyright (c) 2008 Aman Gupta (tmm1)
|
168
|
+
|
169
|
+
See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
NAME = 'amqp-spec'
|
3
|
+
BASE_PATH = Pathname.new(__FILE__).dirname
|
4
|
+
LIB_PATH = BASE_PATH + 'lib'
|
5
|
+
PKG_PATH = BASE_PATH + 'pkg'
|
6
|
+
DOC_PATH = BASE_PATH + 'rdoc'
|
7
|
+
|
8
|
+
$LOAD_PATH.unshift LIB_PATH.to_s
|
9
|
+
require 'version'
|
10
|
+
|
11
|
+
CLASS_NAME = AMQP::Spec
|
12
|
+
VERSION = CLASS_NAME::VERSION
|
13
|
+
|
14
|
+
begin
|
15
|
+
require 'rake'
|
16
|
+
rescue LoadError
|
17
|
+
require 'rubygems'
|
18
|
+
gem 'rake', '~> 0.8.3.1'
|
19
|
+
require 'rake'
|
20
|
+
end
|
21
|
+
|
22
|
+
# Load rakefile tasks
|
23
|
+
Dir['tasks/*.rake'].sort.each { |file| load file }
|
24
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.4
|
data/lib/amqp-spec.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'version'
|
2
|
+
|
3
|
+
module AMQP
|
4
|
+
module Spec
|
5
|
+
|
6
|
+
# require "bundler"
|
7
|
+
# Bundler.setup
|
8
|
+
|
9
|
+
# Requires ruby source file(s). Accepts either single filename/glob or Array of filenames/globs.
|
10
|
+
# Accepts following options:
|
11
|
+
# :*file*:: Lib(s) required relative to this file - defaults to __FILE__
|
12
|
+
# :*dir*:: Required lib(s) located under this dir name - defaults to gem name
|
13
|
+
#
|
14
|
+
def self.require_libs(libs, opts={})
|
15
|
+
file = Pathname.new(opts[:file] || __FILE__)
|
16
|
+
[libs].flatten.each do |lib|
|
17
|
+
name = file.dirname + (opts[:dir] || file.basename('.*')) + lib.gsub(/(?<!.rb)$/, '.rb')
|
18
|
+
Pathname.glob(name.to_s).sort.each { |rb| require rb }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Require all ruby source files located under directory lib/amqp-spec
|
25
|
+
# If you need files in specific order, you should specify it here before the glob
|
26
|
+
AMQP::Spec.require_libs %W[**/*]
|
27
|
+
|
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'mq'
|
2
|
+
require 'fiber' unless Fiber.respond_to?(:current)
|
3
|
+
|
4
|
+
# You can include one of the following modules into your example groups:
|
5
|
+
# AMQP::SpecHelper
|
6
|
+
# AMQP::Spec
|
7
|
+
#
|
8
|
+
# AMQP::SpecHelper module defines 'ampq' method that can be safely used inside your specs(examples)
|
9
|
+
# to test expectations inside running AMQP.start loop. Each loop is running in a separate Fiber,
|
10
|
+
# and you can control for timeouts using either :spec_timeout option given to amqp method,
|
11
|
+
# or setting default timeout with class method default_timeout(timeout).
|
12
|
+
#
|
13
|
+
# If you include AMQP::Spec module into your example group, each example of this group will run
|
14
|
+
# inside AMQP.start loop without the need to explicitly call 'amqp'. In order to provide options
|
15
|
+
# to AMQP loop, default_options class method is defined. Remember, when using AMQP::Specs, you
|
16
|
+
# will have a single set of AMQP.start options for all your examples.
|
17
|
+
#
|
18
|
+
# In order to stop AMQP loop, you should call 'done' AFTER you are sure that your example is finished.
|
19
|
+
# For example, if you are using subscribe block that tests expectations on messages, 'done' should be
|
20
|
+
# probably called at the end of this block.
|
21
|
+
#
|
22
|
+
# TODO: Define 'async' method wrapping async requests and returning results... 'async_loop' too for subscribe?
|
23
|
+
# TODO: 'evented_before', 'evented_after' that will be run inside EM before the example
|
24
|
+
module AMQP
|
25
|
+
module SpecHelper
|
26
|
+
|
27
|
+
SpecTimeoutExceededError = Class.new(RuntimeError)
|
28
|
+
|
29
|
+
def self.included(example_group)
|
30
|
+
::Spec::Example::ExampleGroup.instance_exec do
|
31
|
+
unless defined? default_spec_timeout
|
32
|
+
|
33
|
+
@@_em_default_options = {}
|
34
|
+
@@_em_default_timeout = nil
|
35
|
+
|
36
|
+
def self.default_spec_timeout(spec_timeout=nil)
|
37
|
+
if spec_timeout
|
38
|
+
@@_em_default_timeout = spec_timeout
|
39
|
+
else
|
40
|
+
@@_em_default_timeout
|
41
|
+
end
|
42
|
+
end
|
43
|
+
alias default_timeout default_spec_timeout
|
44
|
+
|
45
|
+
def self.default_options(opts=nil)
|
46
|
+
if opts
|
47
|
+
@@_em_default_options = opts
|
48
|
+
else
|
49
|
+
@@_em_default_options
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Yields to given block inside EM.run and AMQP.start loops. This method takes any option that is
|
57
|
+
# also accepted by EventMachine::connect. Also, options for AMQP.start include:
|
58
|
+
# * :user => String (default ‘guest’) - The username as defined by the AMQP server.
|
59
|
+
# * :pass => String (default ‘guest’) - The password for the associated :user as defined by the AMQP server.
|
60
|
+
# * :vhost => String (default ’/’) - The virtual host as defined by the AMQP server.
|
61
|
+
# * :timeout => Numeric (default nil) - *Connection* timeout, measured in seconds.
|
62
|
+
# * :logging => true | false (default false) - Toggle the extremely verbose AMQP logging.
|
63
|
+
#
|
64
|
+
# In addition to EM and AMQP options, :spec_timeout option (in seconds) is used to force spec to timeout
|
65
|
+
# if something goes wrong and EM/AMQP loop hangs for some reason. SpecTimeoutExceededError is raised.
|
66
|
+
|
67
|
+
def amqp opts={}, &block
|
68
|
+
opts = @@_em_default_options.merge opts
|
69
|
+
EM.run do
|
70
|
+
# begin ?
|
71
|
+
@_em_spec_with_amqp = true
|
72
|
+
@_em_spec_exception = nil
|
73
|
+
spec_timeout = opts.delete(:spec_timeout) || @@_em_default_timeout
|
74
|
+
timeout(spec_timeout) if spec_timeout
|
75
|
+
@_em_spec_fiber = Fiber.new do
|
76
|
+
begin
|
77
|
+
amqp_start opts, &block
|
78
|
+
rescue Exception => @_em_spec_exception
|
79
|
+
p @_em_spec_exception
|
80
|
+
done
|
81
|
+
end
|
82
|
+
Fiber.yield
|
83
|
+
end
|
84
|
+
|
85
|
+
@_em_spec_fiber.resume
|
86
|
+
# raise @_em_spec_exception if @_em_spec_exception
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Yields to block inside EM loop, :spec_timeout option (in seconds) is used to force spec to timeout
|
91
|
+
# if something goes wrong and EM/AMQP loop hangs for some reason. SpecTimeoutExceededError is raised.
|
92
|
+
# TODO: accept :spec_timeout =>1 as a Hash for compatibility with amqp interface
|
93
|
+
def em(spec_timeout = @@_em_default_timeout, &block)
|
94
|
+
EM.run do
|
95
|
+
@_em_spec_with_amqp = false
|
96
|
+
@_em_spec_exception = nil
|
97
|
+
timeout(spec_timeout) if spec_timeout
|
98
|
+
@_em_spec_fiber = Fiber.new do
|
99
|
+
begin
|
100
|
+
block.call
|
101
|
+
rescue Exception => @_em_spec_exception
|
102
|
+
done
|
103
|
+
end
|
104
|
+
Fiber.yield
|
105
|
+
end
|
106
|
+
|
107
|
+
@_em_spec_fiber.resume
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Sets timeout for current spec
|
112
|
+
def timeout(spec_timeout)
|
113
|
+
EM.cancel_timer(@_em_timer) if @_em_timer
|
114
|
+
@_em_timer = EM.add_timer(spec_timeout) do
|
115
|
+
@_em_spec_exception = SpecTimeoutExceededError.new
|
116
|
+
done
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Stops AMQP and EM event loop
|
121
|
+
def done
|
122
|
+
EM.next_tick do
|
123
|
+
if @_em_spec_with_amqp
|
124
|
+
amqp_stop(@_em_spec_exception) do
|
125
|
+
finish_em_spec_fiber
|
126
|
+
end
|
127
|
+
else
|
128
|
+
finish_em_spec_fiber
|
129
|
+
raise @_em_spec_exception if @_em_spec_exception
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def finish_em_spec_fiber
|
137
|
+
EM.stop_event_loop if EM.reactor_running?
|
138
|
+
# p Thread.current, Thread.current[:mq], __LINE__
|
139
|
+
@_em_spec_fiber.resume if @_em_spec_fiber.alive?
|
140
|
+
end
|
141
|
+
|
142
|
+
# Private method that initializes AMQP client/connection without starting another EM loop
|
143
|
+
def amqp_start opts={}, &block
|
144
|
+
AMQP.instance_exec do
|
145
|
+
# p Thread.current, Thread.current[:mq]
|
146
|
+
puts "!!!!!!!!! Existing connection: #{@conn}" if @conn
|
147
|
+
@conn = connect opts
|
148
|
+
# @conn ||= connect opts
|
149
|
+
@conn.callback(&block) if block
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Private method that closes AMQP connection and raises optional
|
154
|
+
# exception AFTER the AMQP connection is 100% closed
|
155
|
+
def amqp_stop exception
|
156
|
+
if AMQP.conn and not AMQP.closing
|
157
|
+
AMQP.instance_exec do #(@_em_spec_exception) do |exception|
|
158
|
+
@closing = true
|
159
|
+
@conn.close {
|
160
|
+
yield if block_given?
|
161
|
+
@conn = nil
|
162
|
+
@closing = false
|
163
|
+
raise exception if exception
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
module Spec
|
171
|
+
def self.included(cls)
|
172
|
+
cls.send(:include, SpecHelper)
|
173
|
+
end
|
174
|
+
|
175
|
+
def instance_eval(&block)
|
176
|
+
amqp do
|
177
|
+
super(&block)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
module EMSpec
|
183
|
+
def self.included(cls)
|
184
|
+
cls.send(:include, SpecHelper)
|
185
|
+
end
|
186
|
+
|
187
|
+
def instance_eval(&block)
|
188
|
+
em do
|
189
|
+
super(&block)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
|
data/lib/version.rb
ADDED
data/spec/amqp.yml
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# AMQP client configuration file
|
2
|
+
|
3
|
+
# These values will be used to configure the ampq gem, any values
|
4
|
+
# omitted will let the gem use it's own defaults.
|
5
|
+
|
6
|
+
# The configuration specifies the following keys:
|
7
|
+
# * user - Username for the broker
|
8
|
+
# * pass - Password for the broker
|
9
|
+
# * host - Hostname where the broker is running
|
10
|
+
# * vhost - Vhost to connect to
|
11
|
+
# * port - Port where the broker is running
|
12
|
+
# * ssl - Use ssl or not
|
13
|
+
# * timeout - Timeout
|
14
|
+
|
15
|
+
defaults: &defaults
|
16
|
+
user: guest
|
17
|
+
pass: guest
|
18
|
+
host: 10.211.55.2
|
19
|
+
vhost: /
|
20
|
+
|
21
|
+
development:
|
22
|
+
<<: *defaults
|
23
|
+
|
24
|
+
test:
|
25
|
+
<<: *defaults
|
26
|
+
|
27
|
+
production:
|
28
|
+
<<: *defaults
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative 'spec_helper.rb'
|
2
|
+
|
3
|
+
context 'Following examples should all be failing:' do
|
4
|
+
describe EventMachine, " when running failing examples" do
|
5
|
+
include AMQP::EMSpec
|
6
|
+
|
7
|
+
it "should not bubble failures beyond rspec" do
|
8
|
+
EM.add_timer(0.1) do
|
9
|
+
:should_not_bubble.should == :failures
|
10
|
+
done
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should not block on failure" do
|
15
|
+
1.should == 2
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe EventMachine, " when testing with AMQP::EMSpec with a maximum execution time per test" do
|
20
|
+
|
21
|
+
include AMQP::EMSpec
|
22
|
+
it 'should timeout before reaching done' do
|
23
|
+
EM.add_timer(2) {
|
24
|
+
done
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should timeout before reaching done' do
|
29
|
+
timeout(0.3)
|
30
|
+
EM.add_timer(0.6) {
|
31
|
+
done
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe AMQP, " when testing with AMQP::Spec with a maximum execution time per test" do
|
37
|
+
|
38
|
+
include AMQP::Spec
|
39
|
+
|
40
|
+
default_timeout 1
|
41
|
+
|
42
|
+
it 'should timeout before reaching done' do
|
43
|
+
EM.add_timer(2) {
|
44
|
+
done
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should timeout before reaching done' do
|
49
|
+
timeout(0.2)
|
50
|
+
EM.add_timer(0.5) {
|
51
|
+
done
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should fail due to timeout, not hang up' do
|
56
|
+
timeout(0.2)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should fail due to default timeout, not hang up' do
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
require_relative 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe 'Rspec' do
|
4
|
+
it 'should work as normal without AMQP-Spec' do
|
5
|
+
1.should == 1
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'Evented AMQP specs' do
|
10
|
+
describe AMQP, " when testing with AMQP::SpecHelper" do
|
11
|
+
include AMQP::SpecHelper
|
12
|
+
after(:each) do
|
13
|
+
EM.reactor_running?.should == false
|
14
|
+
AMQP.conn.should be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
default_options AMQP_OPTS if defined? AMQP_OPTS
|
18
|
+
default_timeout 1 # Can be used to set default :spec_timeout for all your amqp-based specs
|
19
|
+
|
20
|
+
p default_timeout, default_options
|
21
|
+
|
22
|
+
it "should not require a call to done when #em/#amqp is not used" do
|
23
|
+
1.should == 1
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should properly work" do
|
27
|
+
amqp do
|
28
|
+
done
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have timers" do
|
33
|
+
amqp do
|
34
|
+
start = Time.now
|
35
|
+
|
36
|
+
EM.add_timer(0.5) {
|
37
|
+
(Time.now-start).should be_close(0.5, 0.1)
|
38
|
+
done
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should run AMQP.start loop with options given to #amqp" do
|
44
|
+
amqp(:vhost => '/', :user => 'guest') do
|
45
|
+
AMQP.conn.should be_connected
|
46
|
+
done
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should properly close AMQP connection if block completes normally" do
|
51
|
+
amqp do
|
52
|
+
AMQP.conn.should be_connected
|
53
|
+
done
|
54
|
+
end
|
55
|
+
AMQP.conn.should be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should have deferrables' do
|
59
|
+
amqp do
|
60
|
+
defr = EM::DefaultDeferrable.new
|
61
|
+
defr.timeout(0.5)
|
62
|
+
defr.errback {
|
63
|
+
done
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'on exceptions/failures' do
|
69
|
+
# default_timeout 1 # Can be used to set default :spec_timeout for all your amqp-based specs
|
70
|
+
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe AMQP, " when testing with AMQP::Spec" do
|
76
|
+
include AMQP::Spec
|
77
|
+
after(:each) do
|
78
|
+
EM.reactor_running?.should == true
|
79
|
+
done
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should work' do
|
83
|
+
done
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should have timers' do
|
87
|
+
start = Time.now
|
88
|
+
|
89
|
+
EM.add_timer(0.5) {
|
90
|
+
(Time.now-start).should be_close(0.5, 0.1)
|
91
|
+
done
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should have periodic timers' do
|
96
|
+
num = 0
|
97
|
+
start = Time.now
|
98
|
+
|
99
|
+
timer = EM.add_periodic_timer(0.25) {
|
100
|
+
if (num += 1) == 2
|
101
|
+
(Time.now-start).should be_close(0.5, 0.1)
|
102
|
+
EM.cancel_timer timer
|
103
|
+
done
|
104
|
+
end
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should have deferrables' do
|
109
|
+
defr = EM::DefaultDeferrable.new
|
110
|
+
defr.timeout(0.5)
|
111
|
+
defr.errback {
|
112
|
+
done
|
113
|
+
}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
shared_examples_for 'timeout examples' do
|
118
|
+
include AMQP::SpecHelper
|
119
|
+
before(:each) { @start = Time.now }
|
120
|
+
|
121
|
+
it 'should timeout before reaching done because of default spec timeout' do
|
122
|
+
proc {
|
123
|
+
amqp do
|
124
|
+
EM.add_timer(2) { done }
|
125
|
+
end
|
126
|
+
}.should raise_error SpecTimeoutExceededError
|
127
|
+
(Time.now-@start).should be_close(1.0, 0.1)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should timeout before reaching done because of explicit in-loop timeout' do
|
131
|
+
proc {
|
132
|
+
amqp do
|
133
|
+
timeout(0.2)
|
134
|
+
EM.add_timer(0.5) { done }
|
135
|
+
end
|
136
|
+
}.should raise_error SpecTimeoutExceededError
|
137
|
+
(Time.now-@start).should be_close(0.2, 0.1)
|
138
|
+
end
|
139
|
+
|
140
|
+
specify "spec timeout given in amqp options has higher priority than default" do
|
141
|
+
proc {
|
142
|
+
amqp(:spec_timeout => 0.2) {}
|
143
|
+
}.should raise_error SpecTimeoutExceededError
|
144
|
+
(Time.now-@start).should be_close(0.2, 0.1)
|
145
|
+
end
|
146
|
+
|
147
|
+
specify "but timeout call inside amqp loop has even higher priority" do
|
148
|
+
proc {
|
149
|
+
amqp(:spec_timeout => 0.5) { timeout(0.2) }
|
150
|
+
}.should raise_error SpecTimeoutExceededError
|
151
|
+
(Time.now-@start).should be_close(0.2, 0.1)
|
152
|
+
end
|
153
|
+
|
154
|
+
specify "AMQP connection should not leak between examples" do
|
155
|
+
AMQP.conn.should be_nil
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe AMQP, " when testing with AMQP::SpecHelper with spec timeouts" do
|
160
|
+
it_should_behave_like 'timeout examples'
|
161
|
+
|
162
|
+
context 'inside embedded context / example group' do
|
163
|
+
it_should_behave_like 'timeout examples'
|
164
|
+
# it "should properly timeout " do
|
165
|
+
# amqp do
|
166
|
+
# timeout(0.2)
|
167
|
+
# end
|
168
|
+
# end
|
169
|
+
# it "should properly timeout inside embedded context/describe blocks" do
|
170
|
+
# amqp do
|
171
|
+
# end
|
172
|
+
# end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# PROBLEMATIC !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
177
|
+
describe AMQP, " when testing with AMQP::SpecHelper with spec timeouts" do
|
178
|
+
include AMQP::SpecHelper
|
179
|
+
|
180
|
+
it "should fail to provide context to next spec" do
|
181
|
+
begin
|
182
|
+
amqp do
|
183
|
+
:this.should == :fail
|
184
|
+
end
|
185
|
+
rescue => e
|
186
|
+
p e
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should properly close AMQP connection after Rspec failures" do
|
191
|
+
AMQP.conn.should == nil
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# describe MQ, " when MQ.queue or MQ.fanout etc is trying to access Thread-local mq across examples" do
|
196
|
+
# include AMQP::SpecHelper
|
197
|
+
#
|
198
|
+
# default_timeout 1
|
199
|
+
#
|
200
|
+
# it 'sends data to queue' do
|
201
|
+
# amqp do
|
202
|
+
# q = MQ.new.queue("test_sink")
|
203
|
+
# q.subscribe do |hdr, data|
|
204
|
+
# p hdr, data
|
205
|
+
# EM.next_tick {
|
206
|
+
# q.unsubscribe; q.delete
|
207
|
+
# AMQP.stop { EM.stop_event_loop }
|
208
|
+
# }
|
209
|
+
# end
|
210
|
+
# EM.add_timer(0.2) do
|
211
|
+
# p Thread.current, Thread.current[:mq]
|
212
|
+
# MQ.queue('test_sink').publish 'data' # MQ.new. !!!!!!!!!!!
|
213
|
+
# end
|
214
|
+
# end
|
215
|
+
# end
|
216
|
+
#
|
217
|
+
# it 'sends data to queue' do
|
218
|
+
# amqp do
|
219
|
+
# q = MQ.new.queue("test_sink")
|
220
|
+
# q.subscribe do |hdr, data|
|
221
|
+
# p hdr, data
|
222
|
+
# EM.next_tick {
|
223
|
+
# q.unsubscribe; q.delete
|
224
|
+
# AMQP.stop { EM.stop_event_loop }
|
225
|
+
# }
|
226
|
+
# end
|
227
|
+
# EM.add_timer(0.2) do
|
228
|
+
# p Thread.current, Thread.current[:mq]
|
229
|
+
# MQ.queue('test_sink').publish 'data' # MQ.new. !!!!!!!!!!!
|
230
|
+
# end
|
231
|
+
# end
|
232
|
+
# end
|
233
|
+
#
|
234
|
+
# end
|
235
|
+
end
|
236
|
+
|
237
|
+
context '!!!!!!!!!!! LEAKING !!!!!!!!!!!!!!!!!!' do
|
238
|
+
describe EventMachine, " when running failing examples" do
|
239
|
+
include AMQP::SpecHelper
|
240
|
+
|
241
|
+
it "should not bubble failures beyond rspec" do
|
242
|
+
amqp do
|
243
|
+
EM.add_timer(0.1) do
|
244
|
+
:should_not_bubble.should == :failures
|
245
|
+
done
|
246
|
+
end
|
247
|
+
end
|
248
|
+
AMQP.conn.should == nil
|
249
|
+
end
|
250
|
+
|
251
|
+
it "should not block on failure" do
|
252
|
+
1.should == 2
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe EventMachine, " when testing with AMQP::Spec with a maximum execution time per test" do
|
257
|
+
|
258
|
+
include AMQP::Spec
|
259
|
+
|
260
|
+
it 'should timeout before reaching done' do
|
261
|
+
EM.add_timer(2) {
|
262
|
+
done
|
263
|
+
}
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
describe "Rspec", " when running an example group after another group that uses AMQP-Spec " do
|
270
|
+
it "should work normally" do
|
271
|
+
:does_not_hang.should_not be_false
|
272
|
+
end
|
273
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative 'spec_helper.rb'
|
2
|
+
|
3
|
+
context 'Plain EM, no AMQP' do
|
4
|
+
describe EventMachine, " when testing with AMQP::SpecHelper" do
|
5
|
+
include AMQP::SpecHelper
|
6
|
+
|
7
|
+
it "should not require a call to done when #em is not used" do
|
8
|
+
1.should == 1
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have timers" do
|
12
|
+
em do
|
13
|
+
start = Time.now
|
14
|
+
|
15
|
+
EM.add_timer(0.5) {
|
16
|
+
(Time.now-start).should be_close(0.5, 0.1)
|
17
|
+
done
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe EventMachine, " when testing with AMQP::Spec" do
|
24
|
+
include AMQP::EMSpec
|
25
|
+
|
26
|
+
it 'should work' do
|
27
|
+
done
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should have timers' do
|
31
|
+
start = Time.now
|
32
|
+
|
33
|
+
EM.add_timer(0.5) {
|
34
|
+
(Time.now-start).should be_close(0.5, 0.1)
|
35
|
+
done
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should have periodic timers' do
|
40
|
+
num = 0
|
41
|
+
start = Time.now
|
42
|
+
|
43
|
+
timer = EM.add_periodic_timer(0.2) {
|
44
|
+
if (num += 1) == 2
|
45
|
+
(Time.now-start).should be_close(0.4, 0.1)
|
46
|
+
EM.__send__ :cancel_timer, timer
|
47
|
+
done
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should have deferrables' do
|
53
|
+
defr = EM::DefaultDeferrable.new
|
54
|
+
defr.timeout(0.5)
|
55
|
+
defr.errback {
|
56
|
+
done
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "Rspec", " when running an example group after groups that uses EM specs " do
|
64
|
+
it "should work normally" do
|
65
|
+
:does_not_hang.should_not be_false
|
66
|
+
end
|
67
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
|
3
|
+
$LOAD_PATH << "." unless $LOAD_PATH.include? "." # moronic 1.9.2 breaks things bad
|
4
|
+
|
5
|
+
require 'spec'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'amqp-spec', 'rspec.rb')
|
9
|
+
|
10
|
+
amqp_config = File.dirname(__FILE__) + '/amqp.yml'
|
11
|
+
if File.exists? amqp_config
|
12
|
+
|
13
|
+
class Hash
|
14
|
+
def symbolize_keys
|
15
|
+
self.inject({}) { |result, (key, value)|
|
16
|
+
new_key = case key
|
17
|
+
when String then
|
18
|
+
key.to_sym
|
19
|
+
else
|
20
|
+
key
|
21
|
+
end
|
22
|
+
new_value = case value
|
23
|
+
when Hash then
|
24
|
+
value.symbolize_keys
|
25
|
+
else
|
26
|
+
value
|
27
|
+
end
|
28
|
+
result[new_key] = new_value
|
29
|
+
result
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
AMQP_OPTS = YAML::load_file(amqp_config).symbolize_keys[:test]
|
35
|
+
end
|
data/tasks/common.rake
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#task :default => 'test:run'
|
2
|
+
#task 'gem:release' => 'test:run'
|
3
|
+
|
4
|
+
task :notes do
|
5
|
+
puts 'Output annotations (TBD)'
|
6
|
+
end
|
7
|
+
|
8
|
+
#Bundler not ready for prime time just yet
|
9
|
+
#desc 'Bundle dependencies'
|
10
|
+
#task :bundle do
|
11
|
+
# output = `bundle check 2>&1`
|
12
|
+
#
|
13
|
+
# unless $?.to_i == 0
|
14
|
+
# puts output
|
15
|
+
# system "bundle install"
|
16
|
+
# puts
|
17
|
+
# end
|
18
|
+
#end
|
data/tasks/doc.rake
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
desc 'Alias to doc:rdoc'
|
2
|
+
task :doc => 'doc:rdoc'
|
3
|
+
|
4
|
+
namespace :doc do
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
Rake::RDocTask.new do |rdoc|
|
7
|
+
# Rake::RDocTask.new(:rdoc => "rdoc", :clobber_rdoc => "clobber", :rerdoc => "rerdoc") do |rdoc|
|
8
|
+
rdoc.rdoc_dir = DOC_PATH.basename.to_s
|
9
|
+
rdoc.title = "#{NAME} #{VERSION} Documentation"
|
10
|
+
rdoc.main = "README.doc"
|
11
|
+
rdoc.rdoc_files.include('README*')
|
12
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
13
|
+
end
|
14
|
+
end
|
data/tasks/gem.rake
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
desc "Alias to gem:release"
|
2
|
+
task :release => 'gem:release'
|
3
|
+
|
4
|
+
desc "Alias to gem:install"
|
5
|
+
task :install => 'gem:install'
|
6
|
+
|
7
|
+
desc "Alias to gem:build"
|
8
|
+
task :gem => 'gem:build'
|
9
|
+
|
10
|
+
namespace :gem do
|
11
|
+
gem_file = "#{NAME}-#{VERSION}.gem"
|
12
|
+
|
13
|
+
desc "(Re-)Build gem"
|
14
|
+
task :build do
|
15
|
+
puts "Remove existing gem package"
|
16
|
+
rm_rf PKG_PATH
|
17
|
+
puts "Build new gem package"
|
18
|
+
system "gem build #{NAME}.gemspec"
|
19
|
+
puts "Move built gem to package dir"
|
20
|
+
mkdir_p PKG_PATH
|
21
|
+
mv gem_file, PKG_PATH
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Cleanup already installed gem(s)"
|
25
|
+
task :cleanup do
|
26
|
+
puts "Cleaning up installed gem(s)"
|
27
|
+
system "gem cleanup #{NAME}"
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Build and install gem"
|
31
|
+
task :install => :build do
|
32
|
+
system "gem install #{PKG_PATH}/#{gem_file}"
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Build and push gem to Gemcutter"
|
36
|
+
task :release => [:build, 'git:tag'] do
|
37
|
+
puts "Pushing gem to Gemcutter"
|
38
|
+
system "gem push #{PKG_PATH}/#{gem_file}"
|
39
|
+
end
|
40
|
+
end
|
data/tasks/git.rake
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
desc "Alias to git:commit"
|
2
|
+
task :git => 'git:commit'
|
3
|
+
|
4
|
+
namespace :git do
|
5
|
+
|
6
|
+
desc "Stage and commit your work [with message]"
|
7
|
+
task :commit, [:message] do |t, args|
|
8
|
+
puts "Staging new (unversioned) files"
|
9
|
+
system "git add --all"
|
10
|
+
if args.message
|
11
|
+
puts "Committing with message: #{args.message}"
|
12
|
+
system %Q[git commit -a -m "#{args.message}" --author arvicco]
|
13
|
+
else
|
14
|
+
puts "Committing"
|
15
|
+
system %Q[git commit -a -m "No message" --author arvicco]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Push local changes to Github"
|
20
|
+
task :push => :commit do
|
21
|
+
puts "Pushing local changes to remote"
|
22
|
+
system "git push"
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Create (release) tag on Github"
|
26
|
+
task :tag => :push do
|
27
|
+
tag = VERSION
|
28
|
+
puts "Creating git tag: #{tag}"
|
29
|
+
system %Q{git tag -a -m "Release tag #{tag}" #{tag}}
|
30
|
+
puts "Pushing #{tag} to remote"
|
31
|
+
system "git push origin #{tag}"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/tasks/spec.rake
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
desc 'Alias to spec:spec'
|
2
|
+
task :spec => 'spec:spec'
|
3
|
+
|
4
|
+
namespace :spec do
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
|
7
|
+
desc "Run all specs"
|
8
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
9
|
+
t.spec_opts = ['--options', %Q{"#{BASE_PATH}/spec/spec.opts"}]
|
10
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Run specs with RCov"
|
14
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
15
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
16
|
+
t.rcov = true
|
17
|
+
t.rcov_opts = ['--exclude', 'spec']
|
18
|
+
end
|
19
|
+
end
|
data/tasks/version.rake
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
class Version
|
2
|
+
attr_accessor :major, :minor, :patch, :build
|
3
|
+
|
4
|
+
def initialize(version_string)
|
5
|
+
raise "Invalid version #{version_string}" unless version_string =~ /^(\d+)\.(\d+)\.(\d+)(?:\.(.*?))?$/
|
6
|
+
@major = $1.to_i
|
7
|
+
@minor = $2.to_i
|
8
|
+
@patch = $3.to_i
|
9
|
+
@build = $4
|
10
|
+
end
|
11
|
+
|
12
|
+
def bump_major(x)
|
13
|
+
@major += x.to_i
|
14
|
+
@minor = 0
|
15
|
+
@patch = 0
|
16
|
+
@build = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def bump_minor(x)
|
20
|
+
@minor += x.to_i
|
21
|
+
@patch = 0
|
22
|
+
@build = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def bump_patch(x)
|
26
|
+
@patch += x.to_i
|
27
|
+
@build = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def update(major, minor, patch, build=nil)
|
31
|
+
@major = major
|
32
|
+
@minor = minor
|
33
|
+
@patch = patch
|
34
|
+
@build = build
|
35
|
+
end
|
36
|
+
|
37
|
+
def write(desc = nil)
|
38
|
+
CLASS_NAME::VERSION_FILE.open('w') {|file| file.puts to_s }
|
39
|
+
(BASE_PATH + 'HISTORY').open('a') do |file|
|
40
|
+
file.puts "\n== #{to_s} / #{Time.now.strftime '%Y-%m-%d'}\n"
|
41
|
+
file.puts "\n* #{desc}\n" if desc
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
[major, minor, patch, build].compact.join('.')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'Set version: [x.y.z] - explicitly, [1/10/100] - bump major/minor/patch, [.build] - build'
|
51
|
+
task :version, [:command, :desc] do |t, args|
|
52
|
+
version = Version.new(VERSION)
|
53
|
+
case args.command
|
54
|
+
when /^(\d+)\.(\d+)\.(\d+)(?:\.(.*?))?$/ # Set version explicitly
|
55
|
+
version.update($1, $2, $3, $4)
|
56
|
+
when /^\.(.*?)$/ # Set build
|
57
|
+
version.build = $1
|
58
|
+
when /^(\d{1})$/ # Bump patch
|
59
|
+
version.bump_patch $1
|
60
|
+
when /^(\d{1})0$/ # Bump minor
|
61
|
+
version.bump_minor $1
|
62
|
+
when /^(\d{1})00$/ # Bump major
|
63
|
+
version.bump_major $1
|
64
|
+
else # Unknown command, just display VERSION
|
65
|
+
puts "#{NAME} #{version}"
|
66
|
+
next
|
67
|
+
end
|
68
|
+
|
69
|
+
puts "Writing version #{version} to VERSION file"
|
70
|
+
version.write args.desc
|
71
|
+
end
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: amqp-spec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Arvicco
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-14 00:00:00 +04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 2
|
33
|
+
- 9
|
34
|
+
version: 1.2.9
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
description: Simple API for writing (asynchronous) AMQP specs
|
38
|
+
email: arvitallian@gmail.com
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files:
|
44
|
+
- LICENSE
|
45
|
+
- HISTORY
|
46
|
+
- README.rdoc
|
47
|
+
files:
|
48
|
+
- lib/amqp-spec/rspec.rb
|
49
|
+
- lib/amqp-spec.rb
|
50
|
+
- lib/version.rb
|
51
|
+
- spec/amqp.yml
|
52
|
+
- spec/failing_rspec_spec.rb
|
53
|
+
- spec/rspec_amqp_spec.rb
|
54
|
+
- spec/rspec_em_spec.rb
|
55
|
+
- spec/spec.opts
|
56
|
+
- spec/spec_helper.rb
|
57
|
+
- tasks/common.rake
|
58
|
+
- tasks/doc.rake
|
59
|
+
- tasks/gem.rake
|
60
|
+
- tasks/git.rake
|
61
|
+
- tasks/spec.rake
|
62
|
+
- tasks/version.rake
|
63
|
+
- Rakefile
|
64
|
+
- README.rdoc
|
65
|
+
- LICENSE
|
66
|
+
- VERSION
|
67
|
+
- HISTORY
|
68
|
+
- .gitignore
|
69
|
+
has_rdoc: true
|
70
|
+
homepage: http://github.com/arvicco/amqp-spec
|
71
|
+
licenses: []
|
72
|
+
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options:
|
75
|
+
- --charset
|
76
|
+
- UTF-8
|
77
|
+
- --main
|
78
|
+
- README.rdoc
|
79
|
+
- --title
|
80
|
+
- amqp-spec
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
hash: 3
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
version: "0"
|
101
|
+
requirements: []
|
102
|
+
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.3.7
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: Simple API for writing (asynchronous) AMQP specs
|
108
|
+
test_files:
|
109
|
+
- spec/amqp.yml
|
110
|
+
- spec/failing_rspec_spec.rb
|
111
|
+
- spec/rspec_amqp_spec.rb
|
112
|
+
- spec/rspec_em_spec.rb
|
113
|
+
- spec/spec.opts
|
114
|
+
- spec/spec_helper.rb
|