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 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
@@ -3,6 +3,7 @@ language: ruby
3
3
  rvm:
4
4
  - 1.9.3
5
5
  - 2.0.0
6
+ - 2.1.0
6
7
  - jruby-19mode
7
8
  - rbx-19mode
8
9
 
@@ -25,3 +26,4 @@ script:
25
26
  matrix:
26
27
  allow_failures:
27
28
  - rvm: jruby-19mode
29
+ - rvm: rbx-19mode
data/.yardopts ADDED
@@ -0,0 +1,7 @@
1
+ --output-dir doc/
2
+ --readme README.md
3
+ --title GemeraldBeanstalk
4
+ --markup=markdown
5
+ --protected
6
+ --private
7
+ lib/gemerald_beanstalk/**/*.rb
data/Gemfile CHANGED
@@ -3,6 +3,5 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  group :test do
6
- gem 'beanstalk_integration_tests', '~> 0.0.8'
7
6
  gem 'coveralls', :require => false
8
7
  end
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
- server_thread, beanstalk = GemeraldBeanstalk::Server.start(ENV['BIND_ADDRESS'], ENV['PORT'])
14
- trap("SIGINT") { server_thread.kill }
15
- puts "GemeraldBeanstalk listening on #{beanstalk.address}"
16
- server_thread.join
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
@@ -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
@@ -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
- # Colon-separated host and port of the Server the Beanstalk instance is
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
- module GemeraldBeanstalk::Server
4
-
5
- def self.start(bind_address = nil, port = nil)
6
- bind_address ||= '0.0.0.0'
7
- port ||= 11300
8
- full_address = "#{bind_address}:#{port}"
9
- beanstalk = GemeraldBeanstalk::Beanstalk.new(full_address)
10
- thread = Thread.new do
11
- EventMachine.run do
12
- EventMachine.start_server(bind_address, port, GemeraldBeanstalk::Server, beanstalk)
13
- EventMachine.add_periodic_timer(0.01, beanstalk.method(:update_state))
14
- end
15
- end
16
- $PROGRAM_NAME = "gemerald_beanstalk:#{full_address}"
17
- return [thread, beanstalk]
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
- def beanstalk
22
- return @beanstalk
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
- def initialize(beanstalk)
27
- @beanstalk = beanstalk
28
- @partial_message = ''
29
- super
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
- def post_init
34
- @connection = beanstalk.connect(self)
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
- def receive_data(data)
39
- if data[-2, 2] == "\r\n"
40
- message = @partial_message + data
41
- @partial_message = ''
42
- EventMachine.defer(proc { @connection.execute(message) })
43
- else
44
- @partial_message += data
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
- def unbind
50
- beanstalk.disconnect(@connection)
51
- @connection.close_connection
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
@@ -1,6 +1,6 @@
1
1
  class GemeraldBeanstalk::Tube
2
2
 
3
- attr_reader :jobs, :name, :reservartions
3
+ attr_reader :jobs, :name, :reservations
4
4
 
5
5
 
6
6
  def active?
@@ -1,3 +1,3 @@
1
1
  module GemeraldBeanstalk
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  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.start(ENV['BIND_ADDRESS'], ENV['PORT']).first
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.1
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: 2013-12-20 00:00:00.000000000 Z
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: 1.8.25
167
+ rubygems_version: 2.2.1
126
168
  signing_key:
127
- specification_version: 3
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
- has_rdoc:
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