gemerald_beanstalk 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +2 -0
- data/.yardopts +7 -0
- data/Gemfile +0 -1
- data/README.md +4 -1
- data/Rakefile +5 -4
- data/gemerald_beanstalk.gemspec +3 -0
- data/lib/gemerald_beanstalk.rb +7 -1
- data/lib/gemerald_beanstalk/beanstalk.rb +1 -15
- data/lib/gemerald_beanstalk/beanstalk_helper.rb +15 -1
- data/lib/gemerald_beanstalk/event_server.rb +36 -0
- data/lib/gemerald_beanstalk/plugins/direct_connection.rb +11 -0
- data/lib/gemerald_beanstalk/plugins/direct_connection/client.rb +38 -0
- data/lib/gemerald_beanstalk/plugins/introspection.rb +19 -0
- data/lib/gemerald_beanstalk/server.rb +118 -33
- data/lib/gemerald_beanstalk/tube.rb +1 -1
- data/lib/gemerald_beanstalk/version.rb +1 -1
- data/test/test_helper.rb +9 -1
- data/test/unit/beanstalk_test.rb +23 -0
- data/test/unit/plugins/direct_connection/client_test.rb +90 -0
- data/test/unit/plugins/direct_connection_test.rb +36 -0
- data/test/unit/plugins/introspection_test.rb +52 -0
- data/test/unit/server_test.rb +152 -0
- metadata +74 -28
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 41a9a36dce59da44d721a91e44b7198756fa55a7
|
4
|
+
data.tar.gz: 7fec76d5aa209abc2dd69cd9c4b826e2e1025646
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 15a963ae599e27e9df6a908b284eecbca492c08193e78c5ab824741a81c82214134766a70b76a3a769d2311f0f51397f450374b9bf2314b28b8387affb564867
|
7
|
+
data.tar.gz: 00d797ae54d95b37c161c40ec8fb3eb414e9d8f88cabf96200a4dc19d45be43c14a6d515de87ecc5ddb52eff4d2276a931ca28718d087cb9f6837c37d77cb384
|
data/.travis.yml
CHANGED
data/.yardopts
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# GemeraldBeanstalk
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/gemerald_beanstalk.png)](http://badge.fury.io/rb/gemerald_beanstalk)
|
2
3
|
[![Build Status](https://travis-ci.org/gemeraldbeanstalk/gemerald_beanstalk.png?branch=master)](https://travis-ci.org/gemeraldbeanstalk/gemerald_beanstalk)
|
3
4
|
[![Coverage Status](https://coveralls.io/repos/gemeraldbeanstalk/gemerald_beanstalk/badge.png)](https://coveralls.io/r/gemeraldbeanstalk/gemerald_beanstalk)
|
4
5
|
[![Code Climate](https://codeclimate.com/github/gemeraldbeanstalk/gemerald_beanstalk.png)](https://codeclimate.com/github/gemeraldbeanstalk/gemerald_beanstalk)
|
@@ -27,7 +28,9 @@ The internals of GemeraldBeanstalk are undocumented at this point, with the
|
|
27
28
|
expectation being that it should be interacted with strictly via the [beanstalkd
|
28
29
|
protocol](https://github.com/kr/beanstalkd/blob/master/doc/protocol.md). This
|
29
30
|
will likely change in the future, allowing more programatic access directly to
|
30
|
-
the GemeraldBeanstalk::Beanstalk.
|
31
|
+
the GemeraldBeanstalk::Beanstalk. If you think better documentation is needed
|
32
|
+
pronto, create an issue and I will add docs.
|
33
|
+
|
31
34
|
|
32
35
|
## Installation
|
33
36
|
|
data/Rakefile
CHANGED
@@ -10,10 +10,11 @@ end
|
|
10
10
|
|
11
11
|
task :start_gemerald_beanstalk_test_server do
|
12
12
|
Thread.abort_on_exception = true
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
server = GemeraldBeanstalk::Server.new(ENV['BIND_ADDRESS'], ENV['PORT'])
|
14
|
+
event_reactor = GemeraldBeanstalk::Server.event_reactor_thread
|
15
|
+
trap("SIGINT") { event_reactor.kill }
|
16
|
+
puts "GemeraldBeanstalk listening on #{server.full_address}"
|
17
|
+
event_reactor.join
|
17
18
|
end
|
18
19
|
|
19
20
|
task :default => :test
|
data/gemerald_beanstalk.gemspec
CHANGED
@@ -22,4 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_dependency 'thread_safe'
|
23
23
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
24
24
|
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'beanstalk_integration_tests', '~> 0.0.8'
|
26
|
+
spec.add_development_dependency 'minitest_should'
|
27
|
+
spec.add_development_dependency 'mocha'
|
25
28
|
end
|
data/lib/gemerald_beanstalk.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
require 'set'
|
2
|
-
require 'gemerald_beanstalk/version'
|
3
2
|
require 'thread_safe'
|
3
|
+
require 'gemerald_beanstalk/version'
|
4
4
|
require 'gemerald_beanstalk/job'
|
5
5
|
require 'gemerald_beanstalk/beanstalk'
|
6
6
|
require 'gemerald_beanstalk/connection'
|
7
7
|
require 'gemerald_beanstalk/command'
|
8
8
|
require 'gemerald_beanstalk/jobs'
|
9
9
|
require 'gemerald_beanstalk/tube'
|
10
|
+
require 'gemerald_beanstalk/event_server'
|
10
11
|
require 'gemerald_beanstalk/server'
|
12
|
+
|
13
|
+
module GemeraldBeanstalk
|
14
|
+
module Plugin
|
15
|
+
end
|
16
|
+
end
|
@@ -4,25 +4,11 @@ require 'gemerald_beanstalk/beanstalk_helper'
|
|
4
4
|
|
5
5
|
class GemeraldBeanstalk::Beanstalk
|
6
6
|
|
7
|
-
# contains functionality supporting core commands
|
8
7
|
include GemeraldBeanstalk::BeanstalkHelper
|
9
8
|
|
10
|
-
|
11
|
-
# running on.
|
12
|
-
attr_reader :address
|
9
|
+
attr_reader :address, :max_job_size
|
13
10
|
|
14
|
-
# The maximum size in bytes that a job can be. Jobs exceeding this threshold
|
15
|
-
# will result in JOB_TOO_BIG responses.
|
16
|
-
attr_reader :max_job_size
|
17
11
|
|
18
|
-
|
19
|
-
# Initializes a new Beanstalk instance with the given +address+ and
|
20
|
-
# +maximum_job_size+. +address+ is a string identifying the host and port
|
21
|
-
# that the Beanstalk instance is running on. +maximum_job_size+ is the
|
22
|
-
# maximum size in bytes that a job can be. Jobs exceeding this threshold will
|
23
|
-
# result in JOB_TOO_BIG responses.
|
24
|
-
#
|
25
|
-
# beanstalk = GemeraldBeanstalk::Beanstalk.new('localhost:11300')
|
26
12
|
def initialize(address, maximum_job_size = 2**16)
|
27
13
|
@max_job_size = maximum_job_size
|
28
14
|
@address = address
|
@@ -19,6 +19,21 @@ module GemeraldBeanstalk::BeanstalkHelper
|
|
19
19
|
JOB_INACTIVE_STATES = GemeraldBeanstalk::Job::INACTIVE_STATES
|
20
20
|
JOB_RESERVED_STATES = GemeraldBeanstalk::Job::RESERVED_STATES
|
21
21
|
|
22
|
+
|
23
|
+
def self.included(beanstalk)
|
24
|
+
beanstalk.extend(ClassMethods)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
|
30
|
+
def load_plugin(plugin_name)
|
31
|
+
include(GemeraldBeanstalk::Plugin.const_get(plugin_name))
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
22
37
|
# ease handling of odd case where put can return BAD_FORMAT but increment stats
|
23
38
|
def adjust_stats_cmd_put
|
24
39
|
adjust_stats_key(:'cmd-put')
|
@@ -296,5 +311,4 @@ module GemeraldBeanstalk::BeanstalkHelper
|
|
296
311
|
return "OK #{response.bytesize}\r\n#{response}\r\n"
|
297
312
|
end
|
298
313
|
|
299
|
-
|
300
314
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module GemeraldBeanstalk::EventServer
|
2
|
+
|
3
|
+
def beanstalk
|
4
|
+
return @beanstalk
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
def initialize(beanstalk)
|
9
|
+
@beanstalk = beanstalk
|
10
|
+
@partial_message = ''
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def post_init
|
16
|
+
@connection = beanstalk.connect(self)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def receive_data(data)
|
21
|
+
if data[-2, 2] == "\r\n"
|
22
|
+
message = @partial_message + data
|
23
|
+
@partial_message = ''
|
24
|
+
EventMachine.defer(proc { @connection.execute(message) })
|
25
|
+
else
|
26
|
+
@partial_message += data
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def unbind
|
32
|
+
beanstalk.disconnect(@connection)
|
33
|
+
@connection.close_connection
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'gemerald_beanstalk/plugins/direct_connection/client'
|
2
|
+
|
3
|
+
module GemeraldBeanstalk::Plugin::DirectConnection
|
4
|
+
|
5
|
+
def direct_connection_client
|
6
|
+
return GemeraldBeanstalk::Plugin::DirectConnection::Client.new(self)
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
GemeraldBeanstalk::Beanstalk.load_plugin(:DirectConnection)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module GemeraldBeanstalk::Plugin::DirectConnection
|
2
|
+
class Client
|
3
|
+
|
4
|
+
attr_reader :beanstalk, :connection
|
5
|
+
|
6
|
+
def close_connection
|
7
|
+
return unless connection.alive?
|
8
|
+
connection.close_connection
|
9
|
+
beanstalk.disconnect(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def initialize(beanstalk)
|
14
|
+
@beanstalk = beanstalk
|
15
|
+
@connection = beanstalk.connect(self)
|
16
|
+
@async_response = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def transmit(message)
|
21
|
+
message += "\r\n" unless message[-2, 2] == "\r\n"
|
22
|
+
connection.execute(message)
|
23
|
+
while (async_response = @async_response).nil?
|
24
|
+
sleep 0.1
|
25
|
+
end
|
26
|
+
@async_response = nil
|
27
|
+
return async_response
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def send_data(message)
|
32
|
+
@async_response = message
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module GemeraldBeanstalk::Plugin::Introspection
|
2
|
+
|
3
|
+
def connections
|
4
|
+
return @connections
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
def jobs
|
9
|
+
return @jobs.compact
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def tubes
|
14
|
+
return active_tubes
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
GemeraldBeanstalk::Beanstalk.load_plugin(:Introspection)
|
@@ -1,54 +1,139 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
3
|
+
class GemeraldBeanstalk::Server
|
4
|
+
|
5
|
+
# The default address to bind a server to. Matches beanstalkd.
|
6
|
+
DEFAULT_BIND_ADDRESS = '0.0.0.0'
|
7
|
+
|
8
|
+
# The default port that a server should listen on. Matches beanstalkd.
|
9
|
+
DEFAULT_PORT = 11300
|
10
|
+
|
11
|
+
# The address or hostname of the host the server is bound to
|
12
|
+
attr_reader :bind_address
|
13
|
+
|
14
|
+
# The port the server should listen on
|
15
|
+
attr_reader :port
|
16
|
+
|
17
|
+
# The bind_address and port of the server
|
18
|
+
attr_reader :full_address
|
19
|
+
|
20
|
+
# The beanstalk instance the server provides an interface for
|
21
|
+
attr_reader :beanstalk
|
22
|
+
|
23
|
+
# Index of existing servers
|
24
|
+
@@servers = ThreadSafe::Cache.new
|
25
|
+
|
26
|
+
|
27
|
+
# Returns the thread that the EventMachine event reactor is running in.
|
28
|
+
#
|
29
|
+
# @return [Thread] the thread the event reactor is running in.
|
30
|
+
def self.event_reactor_thread
|
31
|
+
return @@event_reactor_thread
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# Create a new GemeraldBeanstalk::Server at the given `bind_address` and
|
36
|
+
# `port`. `start_on_init` controls whether the server is immediately started
|
37
|
+
# or starting the server should be deferred.
|
38
|
+
#
|
39
|
+
# @param bind_address [String] IP or hostname of the host the server is bound
|
40
|
+
# to
|
41
|
+
# @param port [Integer, String] The port the server should listen on
|
42
|
+
# @param start_on_init [Boolean] A boolean indicating whether or not the
|
43
|
+
# server should be started immediately or deferred.
|
44
|
+
# @example Start a new server immediately at 0.0.0.0:11300
|
45
|
+
# GemeraldBeanstalk::Server.new
|
46
|
+
# @example Create a new server at 127.0.0.1:11301 to be started later
|
47
|
+
# GemeraldBeanstalk::Server.new('127.0.0.1', 11301, false)
|
48
|
+
def initialize(bind_address = nil, port = nil, start_on_init = true)
|
49
|
+
@bind_address = bind_address || DEFAULT_BIND_ADDRESS
|
50
|
+
@port = port.nil? ? DEFAULT_PORT : Integer(port)
|
51
|
+
@full_address = "#{@bind_address}:#{@port}"
|
52
|
+
@started = false
|
53
|
+
start if start_on_init
|
18
54
|
end
|
19
55
|
|
20
56
|
|
21
|
-
|
22
|
-
|
57
|
+
# Flag indicating whether the server has been started and is currently
|
58
|
+
# running
|
59
|
+
def running?
|
60
|
+
return @started
|
23
61
|
end
|
24
62
|
|
25
63
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
64
|
+
# Adds the server to the EventMachine reactor, effectively starting the
|
65
|
+
# server. If the EventMachine reactor has not been started, it is started in
|
66
|
+
# a new thread. In the process create a new GemeraldBeanstalk::Beanstalk that
|
67
|
+
# the server provides the interface for. Returns after the server is open for
|
68
|
+
# connections.
|
69
|
+
#
|
70
|
+
# Currently changes $PROGRAM_NAME, however this behavior is likely to change.
|
71
|
+
#
|
72
|
+
# @raise RuntimeError if a server is already registered at the server's full
|
73
|
+
# address
|
74
|
+
# @return [GemeraldBeanstalk::Server] returns self
|
75
|
+
def start
|
76
|
+
raise RuntimeError, "Server already exists for address #{full_address}" if @@servers.put_if_absent(full_address, self)
|
77
|
+
@beanstalk = GemeraldBeanstalk::Beanstalk.new(full_address)
|
78
|
+
start_event_reactor
|
79
|
+
EventMachine.run do
|
80
|
+
@event_server = EventMachine.start_server(bind_address, port, GemeraldBeanstalk::EventServer, beanstalk)
|
81
|
+
EventMachine.add_periodic_timer(0.01, beanstalk.method(:update_state))
|
82
|
+
end
|
83
|
+
$PROGRAM_NAME = "gemerald_beanstalk:#{full_address}"
|
84
|
+
wait_for_action(:start)
|
85
|
+
@started = true
|
86
|
+
return self
|
30
87
|
end
|
31
88
|
|
32
89
|
|
33
|
-
|
34
|
-
|
90
|
+
# Stops the server by removing it from the EventMachine reactor. Returns when
|
91
|
+
# the server is no longer available for connections.
|
92
|
+
#
|
93
|
+
# @raise RuntimeError if no server is registered at the server's full address.
|
94
|
+
# @return [GemeraldBeanstalk::Server] returns self
|
95
|
+
def stop
|
96
|
+
registered_server = @@servers[full_address]
|
97
|
+
raise "Server with address #{full_address} does not appear to have been started" unless registered_server
|
98
|
+
EventMachine.stop_server(@event_server)
|
99
|
+
wait_for_action(:stop)
|
100
|
+
@@servers.delete(full_address)
|
101
|
+
@started = false
|
102
|
+
return self
|
35
103
|
end
|
36
104
|
|
37
105
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
106
|
+
private
|
107
|
+
|
108
|
+
|
109
|
+
# Starts the EventMachine reactor in a new thread.
|
110
|
+
def start_event_reactor
|
111
|
+
return true if EventMachine.reactor_running?
|
112
|
+
unless EventMachine.reactor_running?
|
113
|
+
@@event_reactor_thread = Thread.new { EventMachine.run }
|
114
|
+
while !EventMachine.reactor_running?
|
115
|
+
sleep 0.1
|
116
|
+
end
|
45
117
|
end
|
118
|
+
return true
|
46
119
|
end
|
47
120
|
|
48
121
|
|
49
|
-
|
50
|
-
|
51
|
-
|
122
|
+
# Handles waiting for a server instance to start or stop by repeatedly
|
123
|
+
# attempting to open TCPSocket connections.
|
124
|
+
def wait_for_action(action)
|
125
|
+
action = action.to_sym
|
126
|
+
loop do
|
127
|
+
begin
|
128
|
+
TCPSocket.new(bind_address, port)
|
129
|
+
rescue Errno::ECONNREFUSED
|
130
|
+
next if action == :start
|
131
|
+
break if action == :stop
|
132
|
+
rescue Errno::ECONNRESET
|
133
|
+
break if action == :stop
|
134
|
+
end
|
135
|
+
break if action == :start
|
136
|
+
end
|
52
137
|
end
|
53
138
|
|
54
139
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
require 'coveralls'
|
2
2
|
Coveralls.wear!
|
3
3
|
|
4
|
+
require 'test/unit'
|
5
|
+
require 'mocha/setup'
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require 'minitest/should'
|
8
|
+
|
4
9
|
lib = File.expand_path('../../lib', __FILE__)
|
5
10
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
11
|
|
7
12
|
require 'gemerald_beanstalk'
|
8
|
-
$server ||= GemeraldBeanstalk::Server.
|
13
|
+
$server ||= GemeraldBeanstalk::Server.new(ENV['BIND_ADDRESS'], ENV['PORT'])
|
14
|
+
|
15
|
+
class GemeraldBeanstalkTest < MiniTest::Should::TestCase
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BeanstalkTest < GemeraldBeanstalkTest
|
4
|
+
|
5
|
+
context '::load_plugin' do
|
6
|
+
|
7
|
+
should 'raise NameError if unknown plugin' do
|
8
|
+
assert_raises(NameError) do
|
9
|
+
GemeraldBeanstalk::Beanstalk.load_plugin(:Foo)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
should 'include the given plugin' do
|
15
|
+
GemeraldBeanstalk::Beanstalk.load_plugin(:Dummy)
|
16
|
+
assert GemeraldBeanstalk::Beanstalk.included_modules.include?(GemeraldBeanstalk::Plugin::Dummy)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
module GemeraldBeanstalk::Plugin::Dummy; end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'gemerald_beanstalk/plugins/direct_connection'
|
3
|
+
|
4
|
+
class DirectConnectionClientTest < GemeraldBeanstalkTest
|
5
|
+
|
6
|
+
setup do
|
7
|
+
@beanstalk = GemeraldBeanstalk::Beanstalk.new('localhost:11300')
|
8
|
+
@beanstalk.extend(GemeraldBeanstalk::Plugin::DirectConnection)
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
context '#transmit' do
|
13
|
+
|
14
|
+
should 'connect directly to Gemerald server' do
|
15
|
+
GemeraldBeanstalk::EventServer.expects(:new).never
|
16
|
+
|
17
|
+
current_connections = @beanstalk.send(:stats_connections)['current-connections']
|
18
|
+
client = @beanstalk.direct_connection_client
|
19
|
+
assert_equal "WATCHING 2\r\n", client.transmit("watch foo\r\n")
|
20
|
+
assert_equal "WATCHING 1\r\n", client.transmit("ignore default\r\n")
|
21
|
+
response = client.transmit("list-tubes-watched\r\n")
|
22
|
+
assert_equal "OK 9\r\n---\n- foo\r\n", response
|
23
|
+
assert_equal current_connections + 1, @beanstalk.send(:stats_connections)['current-connections']
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
should 'reset @async_response after receiving message' do
|
28
|
+
message = 'foo'
|
29
|
+
client = @beanstalk.direct_connection_client
|
30
|
+
connection = client.instance_variable_get(:@connection)
|
31
|
+
connection.expects(:execute)
|
32
|
+
client.instance_variable_set(:@async_response, message)
|
33
|
+
assert_equal message, client.transmit("stats\r\n")
|
34
|
+
assert_nil client.instance_variable_get(:@async_response)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
should 'wait for and return response' do
|
39
|
+
client = @beanstalk.direct_connection_client
|
40
|
+
|
41
|
+
# Overwrite send_data to sleep to ensure delay
|
42
|
+
client.instance_eval do
|
43
|
+
def self.send_data(*)
|
44
|
+
sleep 1
|
45
|
+
@async_response = 'foo'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
assert_equal 'foo', client.transmit("stats\r\n")
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
context '#close_connection' do
|
56
|
+
|
57
|
+
setup do
|
58
|
+
@client = @beanstalk.direct_connection_client
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
should 'only execute when connection is alive to avoid stack overflow' do
|
63
|
+
@client.instance_variable_get(:@beanstalk).expects(:disconnect).never
|
64
|
+
@client.instance_variable_get(:@connection).expects(:alive?).returns(false)
|
65
|
+
@client.close_connection
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
should 'close connection connection and disconnect from beanstalk' do
|
70
|
+
@client.instance_variable_get(:@connection).expects(:close_connection)
|
71
|
+
@client.instance_variable_get(:@beanstalk).expects(:disconnect)
|
72
|
+
@client.close_connection
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
context '#send_data' do
|
79
|
+
|
80
|
+
should 'set @async_response to argument' do
|
81
|
+
assert_equal nil, @client.instance_variable_get(:@async_response)
|
82
|
+
@client = @beanstalk.direct_connection_client
|
83
|
+
message = 'foo'
|
84
|
+
@client.send_data(message)
|
85
|
+
assert_equal message, @client.instance_variable_get(:@async_response)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DirectConnectionTest < GemeraldBeanstalkTest
|
4
|
+
|
5
|
+
context 'autoload' do
|
6
|
+
|
7
|
+
should 'automatically load plugin' do
|
8
|
+
GemeraldBeanstalk::Beanstalk.expects(:load_plugin).with(:DirectConnection)
|
9
|
+
load 'gemerald_beanstalk/plugins/direct_connection.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
context 'instance methods' do
|
16
|
+
|
17
|
+
setup do
|
18
|
+
@beanstalk = GemeraldBeanstalk::Beanstalk.new('localhost:11300')
|
19
|
+
@beanstalk.extend(GemeraldBeanstalk::Plugin::DirectConnection)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
context '#direct_connection_client' do
|
24
|
+
|
25
|
+
should 'return a new GemeraldBeanstalk::DirrectConnection' do
|
26
|
+
assert_kind_of(
|
27
|
+
GemeraldBeanstalk::Plugin::DirectConnection::Client,
|
28
|
+
@beanstalk.direct_connection_client
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class IntrospectionTest < GemeraldBeanstalkTest
|
4
|
+
|
5
|
+
context 'autoload' do
|
6
|
+
|
7
|
+
should 'automatically load plugin' do
|
8
|
+
GemeraldBeanstalk::Beanstalk.expects(:load_plugin).with(:Introspection)
|
9
|
+
load 'gemerald_beanstalk/plugins/introspection.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
context 'instance methods' do
|
16
|
+
|
17
|
+
setup do
|
18
|
+
@beanstalk = GemeraldBeanstalk::Beanstalk.new('localhost:11300')
|
19
|
+
@beanstalk.extend(GemeraldBeanstalk::Plugin::Introspection)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
context '#connections' do
|
24
|
+
|
25
|
+
should 'return the beanstalk instance connections object' do
|
26
|
+
assert_equal @beanstalk.instance_variable_get(:@connections), @beanstalk.connections
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
context '#jobs' do
|
33
|
+
|
34
|
+
should 'return the compacted beanstalk instance jobs object' do
|
35
|
+
assert_equal @beanstalk.instance_variable_get(:@jobs).compact, @beanstalk.jobs
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
context '#tubes' do
|
42
|
+
|
43
|
+
should 'return the beanstalk instance active_tubes' do
|
44
|
+
@beanstalk.expects(:active_tubes).once.returns({})
|
45
|
+
@beanstalk.tubes
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ServerTest < GemeraldBeanstalkTest
|
4
|
+
|
5
|
+
context '#new' do
|
6
|
+
|
7
|
+
should 'use defaults if specific values are not provided' do
|
8
|
+
default_bind_address = GemeraldBeanstalk::Server::DEFAULT_BIND_ADDRESS
|
9
|
+
default_port = GemeraldBeanstalk::Server::DEFAULT_PORT
|
10
|
+
GemeraldBeanstalk::Server.any_instance.expects(:start)
|
11
|
+
server = GemeraldBeanstalk::Server.new
|
12
|
+
assert_equal default_bind_address, server.bind_address
|
13
|
+
assert_equal default_port, server.port
|
14
|
+
assert_equal "#{default_bind_address}:#{default_port}", server.full_address
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
should 'take a bind_address, port, and auto start value' do
|
19
|
+
GemeraldBeanstalk::Server.any_instance.expects(:start).never
|
20
|
+
bind_address = '127.0.0.1'
|
21
|
+
port = 11301
|
22
|
+
server = GemeraldBeanstalk::Server.new(bind_address, port, false)
|
23
|
+
assert_equal bind_address, server.bind_address
|
24
|
+
assert_equal port, server.port
|
25
|
+
assert_equal "#{bind_address}:#{port}", server.full_address
|
26
|
+
assert_equal false, server.running?
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
should 'raise ArgumentError if port is not a valid integer' do
|
31
|
+
assert_raises(ArgumentError) do
|
32
|
+
GemeraldBeanstalk::Server.new('0.0.0.0', 'xxx', false)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
context '#start' do
|
40
|
+
|
41
|
+
setup do
|
42
|
+
@bind_address = '0.0.0.0'
|
43
|
+
@port = 11400
|
44
|
+
@full_address = "#{@bind_address}:#{@port}"
|
45
|
+
@server = GemeraldBeanstalk::Server.new(@bind_address, @port, false)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
teardown do
|
50
|
+
@server.stop if @server.running?
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
should 'raise RuntimeError if a server is already registered at given address' do
|
55
|
+
@server.start
|
56
|
+
assert_raises(RuntimeError) do
|
57
|
+
GemeraldBeanstalk::Server.new(@bind_address, @port)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
should 'create a beanstalk with correct address for the server' do
|
63
|
+
beanstalk = GemeraldBeanstalk::Beanstalk.new(@full_address)
|
64
|
+
GemeraldBeanstalk::Beanstalk.expects(:new).with(@full_address).returns(beanstalk)
|
65
|
+
@server.start
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
should 'wait for server to start and set started to true' do
|
70
|
+
@server.start
|
71
|
+
begin
|
72
|
+
socket = TCPSocket.new(@bind_address, @port)
|
73
|
+
socket.close
|
74
|
+
started = true
|
75
|
+
rescue
|
76
|
+
started = false
|
77
|
+
end
|
78
|
+
assert_equal true, @server.running?
|
79
|
+
assert started, 'Expected to be able to open TCP connection to started server'
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
should 'register the server' do
|
84
|
+
@server.start
|
85
|
+
assert_equal GemeraldBeanstalk::Server.class_variable_get(:@@servers)[@full_address], @server
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
context '#stop' do
|
92
|
+
|
93
|
+
setup do
|
94
|
+
@bind_address = '0.0.0.0'
|
95
|
+
@port = 11400
|
96
|
+
@full_address = "#{@bind_address}:#{@port}"
|
97
|
+
@server = GemeraldBeanstalk::Server.new(@bind_address, @port, false)
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
should 'raise an error if the server is not registered' do
|
102
|
+
assert_raises(RuntimeError) do
|
103
|
+
@server.stop
|
104
|
+
end
|
105
|
+
@server.start
|
106
|
+
@server.stop
|
107
|
+
assert_equal false, @server.running?
|
108
|
+
assert_raises(RuntimeError) do
|
109
|
+
@server.stop
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
should 'kill the server and wait for its death' do
|
115
|
+
@server.start
|
116
|
+
@server.stop
|
117
|
+
assert_equal false, @server.running?
|
118
|
+
begin
|
119
|
+
socket = TCPSocket.new(@bind_address, @port)
|
120
|
+
socket.close
|
121
|
+
stopped = false
|
122
|
+
rescue
|
123
|
+
stopped = true
|
124
|
+
end
|
125
|
+
assert stopped, 'Did not expect to be able to open TCP connection to stopped server'
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
context '#start_event_reactor' do
|
132
|
+
|
133
|
+
setup do
|
134
|
+
@server = GemeraldBeanstalk::Server.new(nil, nil, false)
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
should 'start the EventMachine reactor' do
|
139
|
+
@server.send(:start_event_reactor)
|
140
|
+
assert EventMachine.reactor_running?
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
should 'not try to start EventMachine reactor if already running' do
|
145
|
+
@server.send(:start_event_reactor)
|
146
|
+
Thread.expects(:new).never
|
147
|
+
@server.send(:start_event_reactor)
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
metadata
CHANGED
@@ -1,78 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gemerald_beanstalk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Freewrite.org
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-01-26 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: eventmachine
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: thread_safe
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: bundler
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- - ~>
|
45
|
+
- - "~>"
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '1.3'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- - ~>
|
52
|
+
- - "~>"
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '1.3'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: rake
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - ">="
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: '0'
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: beanstalk_integration_tests
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.0.8
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.0.8
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest_should
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: mocha
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
76
109
|
- !ruby/object:Gem::Version
|
77
110
|
version: '0'
|
78
111
|
description: RubyGem implementation of beanstalkd
|
@@ -82,8 +115,9 @@ executables: []
|
|
82
115
|
extensions: []
|
83
116
|
extra_rdoc_files: []
|
84
117
|
files:
|
85
|
-
- .gitignore
|
86
|
-
- .travis.yml
|
118
|
+
- ".gitignore"
|
119
|
+
- ".travis.yml"
|
120
|
+
- ".yardopts"
|
87
121
|
- Gemfile
|
88
122
|
- LICENSE
|
89
123
|
- README.md
|
@@ -94,40 +128,52 @@ files:
|
|
94
128
|
- lib/gemerald_beanstalk/beanstalk_helper.rb
|
95
129
|
- lib/gemerald_beanstalk/command.rb
|
96
130
|
- lib/gemerald_beanstalk/connection.rb
|
131
|
+
- lib/gemerald_beanstalk/event_server.rb
|
97
132
|
- lib/gemerald_beanstalk/job.rb
|
98
133
|
- lib/gemerald_beanstalk/jobs.rb
|
134
|
+
- lib/gemerald_beanstalk/plugins/direct_connection.rb
|
135
|
+
- lib/gemerald_beanstalk/plugins/direct_connection/client.rb
|
136
|
+
- lib/gemerald_beanstalk/plugins/introspection.rb
|
99
137
|
- lib/gemerald_beanstalk/server.rb
|
100
138
|
- lib/gemerald_beanstalk/tube.rb
|
101
139
|
- lib/gemerald_beanstalk/version.rb
|
102
140
|
- test/beanstalk_integration_tests_test.rb
|
103
141
|
- test/test_helper.rb
|
142
|
+
- test/unit/beanstalk_test.rb
|
143
|
+
- test/unit/plugins/direct_connection/client_test.rb
|
144
|
+
- test/unit/plugins/direct_connection_test.rb
|
145
|
+
- test/unit/plugins/introspection_test.rb
|
146
|
+
- test/unit/server_test.rb
|
104
147
|
homepage: https://github.com/gemeraldbeanstalk/gemerald_beanstalk
|
105
148
|
licenses:
|
106
149
|
- MIT
|
150
|
+
metadata: {}
|
107
151
|
post_install_message:
|
108
152
|
rdoc_options: []
|
109
153
|
require_paths:
|
110
154
|
- lib
|
111
155
|
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
-
none: false
|
113
156
|
requirements:
|
114
|
-
- -
|
157
|
+
- - ">="
|
115
158
|
- !ruby/object:Gem::Version
|
116
159
|
version: '0'
|
117
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
-
none: false
|
119
161
|
requirements:
|
120
|
-
- -
|
162
|
+
- - ">="
|
121
163
|
- !ruby/object:Gem::Version
|
122
164
|
version: '0'
|
123
165
|
requirements: []
|
124
166
|
rubyforge_project:
|
125
|
-
rubygems_version:
|
167
|
+
rubygems_version: 2.2.1
|
126
168
|
signing_key:
|
127
|
-
specification_version:
|
169
|
+
specification_version: 4
|
128
170
|
summary: Gemerald Beanstalk offers a Ruby implementation of beanstalkd for testing
|
129
171
|
and other uses.
|
130
172
|
test_files:
|
131
173
|
- test/beanstalk_integration_tests_test.rb
|
132
174
|
- test/test_helper.rb
|
133
|
-
|
175
|
+
- test/unit/beanstalk_test.rb
|
176
|
+
- test/unit/plugins/direct_connection/client_test.rb
|
177
|
+
- test/unit/plugins/direct_connection_test.rb
|
178
|
+
- test/unit/plugins/introspection_test.rb
|
179
|
+
- test/unit/server_test.rb
|