beaneater 0.3.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,79 +0,0 @@
1
- require 'set'
2
-
3
- module Beaneater
4
- # Represents collection of pool related commands.
5
- class PoolCommand
6
- # @!attribute pool
7
- # @return [Beaneater::Pool] returns Pool object
8
- attr_reader :pool
9
-
10
- # Initialize new connection
11
- #
12
- # @param [Beaneater::Pool] pool Pool object
13
- def initialize(pool)
14
- @pool = pool
15
- end
16
-
17
- # Delegate to Pool#transmit_to_all and if needed will merge responses from beanstalkd.
18
- #
19
- # @param [String] body Beanstalkd command
20
- # @param [Hash{String => String, Boolean}] options socket connections options
21
- # @option options [Boolean] merge Ask for merging responses or not
22
- # @param [Proc] block Block passed in socket connection object
23
- # @example
24
- # @pool.transmit_to_all("stats")
25
- #
26
- def transmit_to_all(body, options={}, &block)
27
- merge = options.delete(:merge)
28
- res = pool.transmit_to_all(body, options, &block)
29
- first = res.find { |r| r && r[:status] }
30
- if first && merge
31
- res = { :status => first[:status], :body => sum_items(res.map { |r| r[:body] }) }
32
- end
33
- res
34
- end
35
-
36
- # Delegate missing methods to pool
37
- # @api public
38
- def method_missing(name, *args, &block)
39
- if pool.respond_to?(name)
40
- pool.send(name, *args, &block)
41
- else # not a known pool command
42
- super
43
- end
44
- end
45
-
46
- protected
47
-
48
- # Selects items from collection and then merges the individual values
49
- # Supports array of hashes or array of arrays
50
- #
51
- # @param [Array<Hash, Array>] hs Collection of responses returned from beanstalkd
52
- # @return [Hash{Symbol => String}] Merged responses combining values from all the hash bodies
53
- # @example
54
- # self.sum_items([{ :foo => 1, :bar => 5 }, { :foo => 2, :bar => 3 }])
55
- # => { :foo => 3, :bar => 8 }
56
- # self.sum_items([['foo', 'bar'], ['foo', 'bar', 'baz']])
57
- # => ['foo', 'bar', 'baz']
58
- #
59
- def sum_items(items)
60
- if items.first.is_a?(Hash)
61
- items.select { |h| h.is_a?(Hash) }.
62
- inject({}) { |a,b| a.merge(b) { |k,o,n| combine_stats(k, o, n) } }
63
- elsif items.first.is_a?(Array)
64
- items.flatten.uniq
65
- end
66
- end
67
-
68
- # Combine two values for given key
69
- #
70
- # @param [String] k key name within response hash
71
- # @return [Set,Integer] combined value for stat
72
- # @example
73
- # self.combine_stats('total_connections', 4, 5) # => 9
74
- #
75
- def combine_stats(k, a, b)
76
- ['name', 'version', 'pid'].include?(k) ? Set[a] + Set[b] : a + b
77
- end
78
- end # PoolCommand
79
- end # Beaneater
@@ -1,90 +0,0 @@
1
- # test/connection_test.rb
2
-
3
- require File.expand_path('../test_helper', __FILE__)
4
-
5
- describe Beaneater::PoolCommand do
6
-
7
- describe 'for #new' do
8
- before do
9
- @pool = stub
10
- @command = Beaneater::PoolCommand.new(@pool)
11
- end
12
-
13
- it "should store pool" do
14
- assert_equal @pool, @command.pool
15
- end
16
- end #new
17
-
18
- describe 'for #transmit_to_all' do
19
- describe 'for regular command' do
20
- before do
21
- @pool = stub(:transmit_to_all => [{ :body => "foo", :status => "OK" }])
22
- @command = Beaneater::PoolCommand.new(@pool)
23
- end
24
-
25
- it "can run regular command" do
26
- res = @command.transmit_to_all("foo")
27
- assert_equal "OK", res[0][:status]
28
- assert_equal "foo", res[0][:body]
29
- end
30
- end # regular command
31
-
32
- describe 'for merge command with hashes' do
33
- before do
34
- @pool = stub(:transmit_to_all => [
35
- { :body => { 'x' => 1, 'version' => 1.1 }, :status => "OK"},
36
- { :body => { 'x' => 3,'version' => 1.2 }, :status => "OK" }
37
- ])
38
- @command = Beaneater::PoolCommand.new(@pool)
39
- end
40
-
41
- it "can run merge command " do
42
- cmd = @command.transmit_to_all("bar", :merge => true)
43
- assert_equal "OK", cmd[:status]
44
- assert_equal 4, cmd[:body]['x']
45
- assert_equal Set[1.1, 1.2], cmd[:body]['version']
46
- end
47
- end # merged command
48
-
49
- describe 'for merge command with arrays' do
50
- before do
51
- @pool = stub(:transmit_to_all => [
52
- { :body => ['foo', 'bar'], :status => "OK"},
53
- { :body => ['foo', 'bar', 'baz'], :status => "OK" }
54
- ])
55
- @command = Beaneater::PoolCommand.new(@pool)
56
- end
57
-
58
- it "can run merge command " do
59
- cmd = @command.transmit_to_all("bar", :merge => true)
60
- assert_equal "OK", cmd[:status]
61
- assert_equal ['foo', 'bar', 'baz'].sort, cmd[:body].sort
62
- end
63
- end # merged command
64
- end # transmit_to_all
65
-
66
- describe 'for #method_missing' do
67
- describe '#transmit_to_rand' do
68
- before do
69
- @pool = stub
70
- @pool.expects(:transmit_to_rand).with('foo').returns('OK')
71
- @command = Beaneater::PoolCommand.new(@pool)
72
- end
73
-
74
- it 'delegates to connection' do
75
- assert_equal 'OK', @command.transmit_to_rand('foo')
76
- end
77
- end # transmit_to_rand
78
-
79
- describe 'invalid method' do
80
- before do
81
- @pool = stub
82
- @command = Beaneater::PoolCommand.new(@pool)
83
- end
84
-
85
- it 'raises no method error' do
86
- assert_raises(NoMethodError) { @command.foo('foo') }
87
- end
88
- end # transmit_to_rand
89
- end
90
- end # Beaneater::PoolCommand
data/test/pool_test.rb DELETED
@@ -1,180 +0,0 @@
1
- # test/connection_test.rb
2
-
3
- require File.expand_path('../test_helper', __FILE__)
4
-
5
- describe Beaneater::Pool do
6
-
7
- before do
8
- @hosts = ['localhost', 'localhost']
9
- @bp = Beaneater::Pool.new(@hosts)
10
- end
11
-
12
- describe 'for #new' do
13
-
14
- describe "for multiple connection" do
15
- before do
16
- @host_string_port = 'localhost:11301'
17
- @host_num_port = '127.0.0.1:11302'
18
- @host_string = 'host.local'
19
- @host_num = '1.1.1.1:11303'
20
- @hosts = [@host_string_port, @host_num_port, @host_string, @host_num]
21
-
22
- TCPSocket.expects(:new).with('localhost',11301).once
23
- TCPSocket.expects(:new).with('127.0.0.1',11302).once
24
- TCPSocket.expects(:new).with('host.local',11300).once
25
- TCPSocket.expects(:new).with('1.1.1.1',11303).once
26
-
27
- @bp = Beaneater::Pool.new(@hosts)
28
- end
29
-
30
- it "should init 4 connections" do
31
- assert_equal 4, @bp.connections.size
32
- end
33
- end
34
-
35
- describe "for invalid connection in setup" do
36
- it "should raise NotConnected" do
37
- assert_raises(Beaneater::NotConnected) { Beaneater::Pool.new('localhost:5679') }
38
- end
39
- end
40
-
41
- describe "for clearing watch list" do
42
- it "should clear connections of tube watches" do
43
- @bp.tubes.watch!('foo', 'bar')
44
- assert_equal ['foo', 'bar'].sort, @bp.tubes.watched.map(&:name).sort
45
- @bp2 = Beaneater::Pool.new(@hosts)
46
- assert_equal ['default'], @bp2.tubes.watched.map(&:name)
47
- end
48
- end
49
-
50
- describe "with ENV variable set" do
51
- before do
52
- ENV['BEANSTALKD_URL'] = '0.0.0.0:11300,127.0.0.1:11300'
53
- end
54
-
55
- it "should create 1 connection" do
56
- bp = Beaneater::Pool.new
57
- bc = bp.connections.first
58
- bc2 = bp.connections.last
59
-
60
- assert_equal 2, bp.connections.size
61
- assert_equal '0.0.0.0', bc.host
62
- assert_equal 11300, bc.port
63
-
64
- assert_equal '127.0.0.1', bc2.host
65
- assert_equal 11300, bc2.port
66
- end
67
-
68
- after do
69
- ENV['BEANSTALKD_URL'] = nil
70
- end
71
- end
72
-
73
- describe "by configuring via Beaneater.configure" do
74
- before do
75
- Beaneater.configure.beanstalkd_url = ['0.0.0.0:11300', '127.0.0.1:11300']
76
- end
77
-
78
- it "should create 1 connection" do
79
- bp = Beaneater::Pool.new
80
- bc = bp.connections.first
81
- bc2 = bp.connections.last
82
-
83
- assert_equal 2, bp.connections.size
84
- assert_equal '0.0.0.0', bc.host
85
- assert_equal 11300, bc.port
86
-
87
- assert_equal '127.0.0.1', bc2.host
88
- assert_equal 11300, bc2.port
89
- end
90
-
91
- after do
92
- Beaneater.configure.beanstalkd_url = ['0.0.0.0:11300']
93
- end
94
- end
95
- end # new
96
-
97
- describe 'for #transmit_to_all' do
98
- it "should return yaml loaded response" do
99
- res = @bp.transmit_to_all 'stats'
100
- assert_equal 2, res.size
101
- refute_nil res.first[:body]['current-connections']
102
- end
103
- end # transmit_to_all
104
-
105
- describe 'for #transmit_to_rand' do
106
- it "should return yaml loaded response" do
107
- res = @bp.transmit_to_rand 'stats'
108
- refute_nil res[:body]['current-connections']
109
- assert_equal 'OK', res[:status]
110
- end
111
-
112
- it "should return id" do
113
- Beaneater::Connection.any_instance.expects(:transmit).with("foo",{}).returns({:id => "254", :status => "INSERTED"})
114
- res = @bp.transmit_to_rand 'foo'
115
- assert_equal '254', res[:id]
116
- assert_equal 'INSERTED', res[:status]
117
- end
118
- end # transmit_to_rand
119
-
120
- describe 'for #transmit_until_res' do
121
- before do
122
- Beaneater::Connection.any_instance.expects(:transmit).with('foo', {}).twice.
123
- returns({:status => "FAILED", :body => 'x'}).then.
124
- returns({:status => "OK", :body => 'y'}).then.returns({:status => "OK", :body => 'z'})
125
- end
126
-
127
- it "should returns first matching status" do
128
- assert_equal 'y', @bp.transmit_until_res('foo', :status => 'OK')[:body]
129
- end
130
- end # transmit_until_res
131
-
132
- describe 'for #stats' do
133
- it("should return stats object"){ assert_kind_of Beaneater::Stats, @bp.stats }
134
- end # stats
135
-
136
- describe 'for #tubes' do
137
- it("should return Tubes object"){ assert_kind_of Beaneater::Tubes, @bp.tubes }
138
- end # tubes
139
-
140
- describe "for #safe_transmit" do
141
- it "should retry 3 times for temporary failed connection" do
142
- TCPSocket.any_instance.expects(:write).times(3)
143
- TCPSocket.any_instance.expects(:gets).raises(Errno::ECONNRESET).then.
144
- raises(Errno::ECONNRESET).then.returns('INSERTED 254').times(3)
145
- res = @bp.transmit_to_rand "put 0 0 10 2\r\nxy"
146
- assert_equal '254', res[:id]
147
- assert_equal 'INSERTED', res[:status]
148
- end
149
-
150
- it 'should raise proper exception for invalid status NOT_FOUND' do
151
- TCPSocket.any_instance.expects(:write).once
152
- TCPSocket.any_instance.expects(:gets).returns('NOT_FOUND')
153
- assert_raises(Beaneater::NotFoundError) { @bp.transmit_to_rand 'foo' }
154
- end
155
-
156
- it 'should raise proper exception for invalid status BAD_FORMAT' do
157
- TCPSocket.any_instance.expects(:write).once
158
- TCPSocket.any_instance.expects(:gets).returns('BAD_FORMAT')
159
- assert_raises(Beaneater::BadFormatError) { @bp.transmit_to_rand 'foo' }
160
- end
161
-
162
- it 'should raise proper exception for invalid status DEADLINE_SOON' do
163
- TCPSocket.any_instance.expects(:write).once
164
- TCPSocket.any_instance.expects(:gets).once.returns('DEADLINE_SOON')
165
- assert_raises(Beaneater::DeadlineSoonError) { @bp.transmit_to_rand 'expecting deadline' }
166
- end
167
- end
168
-
169
- describe "for #close" do
170
- it "should support closing the pool" do
171
- connection = @bp.connections.first
172
- assert_equal 2, @bp.connections.size
173
- assert_kind_of Beaneater::Connection, connection
174
- assert_kind_of TCPSocket, connection.connection
175
- @bp.close
176
- assert_equal 0, @bp.connections.size
177
- assert_nil connection.connection
178
- end
179
- end # close
180
- end # Beaneater::Pool