siberite-client 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,175 @@
1
+ require 'spec_helper'
2
+
3
+ describe Siberite::Client do
4
+ describe "Instance Methods" do
5
+ before do
6
+ @client = Siberite::Client.new('localhost:22133')
7
+ end
8
+
9
+ describe "#get and #set" do
10
+ it "basic operation" do
11
+ @client.flush(queue = "test_queue")
12
+ @client.set(queue, value = "russell's reserve")
13
+ @client.get(queue).should == value
14
+ end
15
+
16
+ it "returns nil when getting from a queue that does not exist" do
17
+ @client.get('nonexistent_queue').should == nil
18
+ end
19
+
20
+ it "gets from the same server :gets_per_server times" do
21
+ client = @client.instance_variable_get(:@read_client)
22
+ mock(client).get("a_queue/t=10", true).times(102).returns('item')
23
+
24
+ 102.times { @client.get("a_queue") }
25
+ end
26
+
27
+ it "gets from a different server when the last result was nil" do
28
+ client = @client.instance_variable_get(:@read_client)
29
+ mock(client).get("a_queue/t=10", true).returns(nil).twice
30
+
31
+ 2.times { @client.get("a_queue") }
32
+ end
33
+
34
+ it "returns nil if there is a recoverable exception" do
35
+ mock(@client).shuffle_if_necessary!(@queue) { raise Memcached::SystemError }
36
+ @client.get(@queue).should == nil
37
+ end
38
+
39
+ it "raises the exception if the exception is not recoverable" do
40
+ mock(@client).shuffle_if_necessary!(@queue) { raise ArgumentError }
41
+ lambda { @client.get(@queue) }.should raise_error(ArgumentError)
42
+ end
43
+ end
44
+
45
+ describe "retry behavior" do
46
+ it "does not retry gets" do
47
+ mock(@client).with_retries.never
48
+ @client.get("a_queue")
49
+ end
50
+
51
+ it "retries sets" do
52
+ mock(@client).with_retries
53
+ @client.set("a_queue", "value")
54
+ end
55
+ end
56
+
57
+ describe "#flush" do
58
+ before do
59
+ @queue = "some_random_queue_#{Time.now.to_i}_#{rand(10000)}"
60
+ end
61
+
62
+ it "counts the number of items flushed and passes each of them to a given block" do
63
+ %w{A B C}.each { |item| @client.set(@queue, item) }
64
+ @client.flush(@queue).should == 3
65
+ end
66
+
67
+ it "does not attempt to Marshal load the data being flushed" do
68
+ @client.set(@queue, "some_stuff", 0, true)
69
+ mock(Marshal).load.never
70
+ @client.flush(@queue).should == 1
71
+ end
72
+ end
73
+
74
+ describe "#peek" do
75
+ it "should return first item from the queue and reenqueue" do
76
+ @queue = "some_random_queue_#{Time.now.to_i}_#{rand(10000)}"
77
+ @client.set(@queue, "item_1")
78
+ @client.set(@queue, "item_2")
79
+ @client.peek(@queue).should == "item_1"
80
+ @client.sizeof(@queue).should == 2
81
+ end
82
+ end
83
+
84
+ describe "#with_retries" do
85
+ it "retries a specified number of times" do
86
+ mock(@client).set(anything, anything) { raise Memcached::SystemError }.times(6)
87
+
88
+ lambda do
89
+ @client.send(:with_retries) { @client.set("a_queue", "foo") }
90
+ end.should raise_error(Memcached::SystemError)
91
+ end
92
+
93
+ it "does not raise if within the retry limit" do
94
+ mock(@client).set(anything, anything) { raise Memcached::SystemError }.times(5).
95
+ then.set(anything, anything) { true }
96
+
97
+ lambda do
98
+ @client.send(:with_retries) { @client.set("a_queue", "foo") }
99
+ end.should_not raise_error
100
+ end
101
+
102
+ it "does not catch unknown errors" do
103
+ mock(@client).set(anything, anything) { raise ArgumentError }
104
+
105
+ lambda do
106
+ @client.send(:with_retries) { @client.set("a_queue", "foo") }
107
+ end.should raise_error(ArgumentError)
108
+ end
109
+ end
110
+
111
+ describe "#stats" do
112
+ it "retrieves stats" do
113
+ @client.set("test-queue-name", 97)
114
+
115
+ stats = @client.stats
116
+ %w{uptime time version curr_items total_items bytes curr_connections total_connections
117
+ cmd_get cmd_set get_hits get_misses bytes_read bytes_written queues}.each do |stat|
118
+ stats[stat].should_not be_nil
119
+ end
120
+
121
+ stats['queues']["test-queue-name"].should_not be_nil
122
+ Siberite::Client::QUEUE_STAT_NAMES.each do |queue_stat|
123
+ stats['queues']['test-queue-name'][queue_stat].should_not be_nil
124
+ end
125
+ end
126
+
127
+ it "merge in stats from all the servers" do
128
+ server = @client.servers.first
129
+ stub(@client).servers { [server] }
130
+ stats_for_one_server = @client.stats
131
+
132
+ server = @client.servers.first
133
+ stub(@client).servers { [server] * 2 }
134
+ stats_for_two_servers = @client.stats
135
+
136
+ stats_for_two_servers['bytes'].should == 2*stats_for_one_server['bytes']
137
+ end
138
+ end
139
+
140
+ describe "#stat" do
141
+ it "get stats for single queue" do
142
+ @client.set(queue = "test-queue-name", 97)
143
+ all_stats = @client.stats
144
+ single_queue_stats = @client.stat(queue).except("age")
145
+
146
+ expect(single_queue_stats).to eq all_stats['queues'][queue].except("age")
147
+ end
148
+ end
149
+
150
+ describe "#sizeof" do
151
+ before do
152
+ @queue = "some_random_queue_#{Time.now.to_i}_#{rand(10000)}"
153
+ end
154
+
155
+ it "reports the size of the queue" do
156
+ 100.times { @client.set(@queue, true) }
157
+ @client.sizeof(@queue).should == 100
158
+ end
159
+
160
+ it "reports the size of a non-existant queue as 0" do
161
+ queue = "some_random_queue_#{Time.now.to_i}_#{rand(10000)}"
162
+ @client.sizeof(queue).should == 0
163
+ end
164
+ end
165
+
166
+ describe "#available_queues" do
167
+ it "returns all the queue names" do
168
+ @client.set("test-queue-name1", 97)
169
+ @client.set("test-queue-name2", 155)
170
+ @client.available_queues.should include('test-queue-name1')
171
+ @client.available_queues.should include('test-queue-name2')
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,42 @@
1
+ defaults: &defaults
2
+ distribution: :random
3
+ timeout: 0.1
4
+ connect_timeout: 0.5
5
+ server_failure_limit: 10
6
+ auto_eject_hosts: false
7
+
8
+ production: &production
9
+ <<: *defaults
10
+ auto_eject_hosts: true
11
+ server_failure_limit: 4
12
+ servers:
13
+ - localhost:22133
14
+
15
+ staging:
16
+ <<: *production
17
+ servers:
18
+ - localhost:22133
19
+
20
+ development: &development
21
+ <<: *defaults
22
+ show_backtraces: true
23
+ servers:
24
+ - localhost:22133
25
+
26
+ benchmark:
27
+ <<: *development
28
+
29
+ test:
30
+ <<: *development
31
+
32
+ replication_lag:
33
+ <<: *development
34
+
35
+ selenium:
36
+ <<: *development
37
+
38
+ foo_space:
39
+ production:
40
+ <<: *production
41
+ development:
42
+ <<: *development
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe Siberite::Config do
4
+ before do
5
+ # to sniff namespace foo_space
6
+ Siberite::Config.config['foo_space']['development']['connect_timeout'] = 8
7
+ end
8
+
9
+ describe "load" do
10
+ it "loads a yaml file" do
11
+ Siberite::Config.config = nil
12
+ lambda { Siberite::Config.default }.should raise_error
13
+
14
+ Siberite::Config.load TEST_CONFIG_FILE
15
+ lambda { Siberite::Config.default }.should_not raise_error
16
+ end
17
+ end
18
+
19
+ shared_examples_for "config getters" do
20
+ it "returns a tuple of [servers, options]" do
21
+ config = @configurer.call
22
+ config.should be_a(Array)
23
+
24
+ [String, Array].should include(config.first.class)
25
+ config.last.should be_a(Hash)
26
+
27
+ config.last.keys.map{|k| k.class }.uniq.should == [Symbol]
28
+ end
29
+
30
+ it "defaults to development enviroment" do
31
+ @configurer.call.last[:server_failure_limit].should == 10 # development options should pull 10 from defaults
32
+ end
33
+
34
+ it "returns config for the specified environment" do
35
+ Siberite::Config.environment = :production
36
+ @configurer.call.last[:server_failure_limit].should == 4 # production is set to 4
37
+ end
38
+ end
39
+
40
+ describe "namespace" do
41
+ before { @configurer = lambda { Siberite::Config.namespace(:foo_space) } }
42
+
43
+ it_should_behave_like "config getters"
44
+
45
+ it "returns args for Siberite::Client.new for the appropriate namespace" do
46
+ Siberite::Config.foo_space.last[:connect_timeout].should == 8
47
+ end
48
+
49
+ it "is aliased to method_missing" do
50
+ Siberite::Config.foo_space.should == Siberite::Config.namespace(:foo_space)
51
+ end
52
+ end
53
+
54
+ describe "default" do
55
+ before { @configurer = lambda { Siberite::Config.default } }
56
+
57
+ it_should_behave_like "config getters"
58
+ end
59
+
60
+ describe "new_client" do
61
+ it "returns a Siberite::Client instance" do
62
+ client = Siberite::Config.new_client
63
+ client.should be_a(Siberite::Client)
64
+ end
65
+
66
+ it "can take a namespace" do
67
+ client = Siberite::Config.new_client(:foo_space)
68
+ client.should be_a(Siberite::Client)
69
+ client.options[:connect_timeout].should == 8
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'benchmark'
3
+
4
+ describe Siberite::Client do
5
+ before do
6
+ @queue = "a_queue"
7
+ @client = Siberite::Client.new(*Siberite::Config.default)
8
+
9
+ @client.delete(@queue) rescue nil # Memcache::ServerEnd bug
10
+ end
11
+
12
+ it "is fast" do
13
+ @client.flush(@queue)
14
+ @value = { :value => "a value" }
15
+ @raw_value = Marshal.dump(@value)
16
+
17
+ times = 10_000
18
+
19
+ Benchmark.bm do |x|
20
+ x.report("set:") { for i in 1..times; @client.set(@queue, @value); end }
21
+ x.report("get:") { for i in 1..times; @client.get(@queue); end }
22
+ x.report("set (raw):") { for i in 1..times; @client.set(@queue, @raw_value, 0, true); end }
23
+ x.report("get (raw):") { for i in 1..times; @client.get(@queue, :raw => true); end }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format progress
3
+ --backtrace
@@ -0,0 +1,33 @@
1
+ require 'rspec'
2
+ require 'pry'
3
+ require 'pry-byebug'
4
+ require "active_support/core_ext/hash"
5
+
6
+ spec_dir = File.dirname(__FILE__)
7
+
8
+ # make sure we load local libs rather than gems first
9
+ $: << File.expand_path("#{spec_dir}/../lib")
10
+
11
+ require 'siberite'
12
+
13
+ TEST_CONFIG_FILE = File.expand_path("#{spec_dir}/siberite/config/siberite.yml")
14
+
15
+ RSpec.configure do |config|
16
+ config.mock_with :rr
17
+
18
+ config.expect_with :rspec do |c|
19
+ c.syntax = [:should, :expect]
20
+ end
21
+
22
+ config.before do
23
+ Siberite::Config.environment = nil
24
+ Siberite::Config.load TEST_CONFIG_FILE
25
+ end
26
+
27
+ config.after do
28
+ c = Siberite::Client.new(*Siberite::Config.default)
29
+ c.available_queues.uniq.each do |q|
30
+ c.delete(q) rescue nil
31
+ end
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,205 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: siberite-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ platform: ruby
6
+ authors:
7
+ - Matt Freels
8
+ - Rael Dornfest
9
+ - Anton Bogdanovich
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2015-11-23 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: memcached
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.19.6
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - '>='
27
+ - !ruby/object:Gem::Version
28
+ version: 0.19.6
29
+ - !ruby/object:Gem::Dependency
30
+ name: pry
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: '0.10'
36
+ type: :development
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ version: '0.10'
43
+ - !ruby/object:Gem::Dependency
44
+ name: pry-byebug
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ~>
48
+ - !ruby/object:Gem::Version
49
+ version: '2.0'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: '2.0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: rspec
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ~>
62
+ - !ruby/object:Gem::Version
63
+ version: '3.2'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: '3.2'
71
+ - !ruby/object:Gem::Dependency
72
+ name: rr
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '1.1'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ~>
83
+ - !ruby/object:Gem::Version
84
+ version: '1.1'
85
+ - !ruby/object:Gem::Dependency
86
+ name: activesupport
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>'
90
+ - !ruby/object:Gem::Version
91
+ version: '3.1'
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>'
97
+ - !ruby/object:Gem::Version
98
+ version: '3.1'
99
+ - !ruby/object:Gem::Dependency
100
+ name: bundler
101
+ requirement: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ~>
104
+ - !ruby/object:Gem::Version
105
+ version: '1.7'
106
+ type: :development
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ~>
111
+ - !ruby/object:Gem::Version
112
+ version: '1.7'
113
+ - !ruby/object:Gem::Dependency
114
+ name: rake
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ~>
118
+ - !ruby/object:Gem::Version
119
+ version: '10.0'
120
+ type: :development
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ~>
125
+ - !ruby/object:Gem::Version
126
+ version: '10.0'
127
+ description: Ruby client for the Siberite queue server
128
+ email: anton@bogdanovich.co
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files:
132
+ - README.md
133
+ files:
134
+ - .gitignore
135
+ - Gemfile
136
+ - LICENSE
137
+ - README.md
138
+ - Rakefile
139
+ - lib/siberite-client.rb
140
+ - lib/siberite.rb
141
+ - lib/siberite/client.rb
142
+ - lib/siberite/client/blocking.rb
143
+ - lib/siberite/client/envelope.rb
144
+ - lib/siberite/client/json.rb
145
+ - lib/siberite/client/namespace.rb
146
+ - lib/siberite/client/partitioning.rb
147
+ - lib/siberite/client/proxy.rb
148
+ - lib/siberite/client/stats_helper.rb
149
+ - lib/siberite/client/transactional.rb
150
+ - lib/siberite/client/unmarshal.rb
151
+ - lib/siberite/client/version.rb
152
+ - lib/siberite/config.rb
153
+ - siberite-client.gemspec
154
+ - spec/siberite/client/blocking_spec.rb
155
+ - spec/siberite/client/envelope_spec.rb
156
+ - spec/siberite/client/json_spec.rb
157
+ - spec/siberite/client/namespace_spec.rb
158
+ - spec/siberite/client/partitioning_spec.rb
159
+ - spec/siberite/client/transactional_spec.rb
160
+ - spec/siberite/client/unmarshal_spec.rb
161
+ - spec/siberite/client_spec.rb
162
+ - spec/siberite/config/siberite.yml
163
+ - spec/siberite/config_spec.rb
164
+ - spec/siberite_benchmark.rb
165
+ - spec/spec.opts
166
+ - spec/spec_helper.rb
167
+ homepage: http://github.com/bogdanovich/siberite-ruby
168
+ licenses:
169
+ - Apache-2
170
+ metadata: {}
171
+ post_install_message:
172
+ rdoc_options: []
173
+ require_paths:
174
+ - lib
175
+ required_ruby_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - '>='
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ required_rubygems_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - '>='
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ requirements: []
186
+ rubyforge_project:
187
+ rubygems_version: 2.2.2
188
+ signing_key:
189
+ specification_version: 4
190
+ summary: Ruby Siberite client
191
+ test_files:
192
+ - spec/siberite/client/blocking_spec.rb
193
+ - spec/siberite/client/envelope_spec.rb
194
+ - spec/siberite/client/json_spec.rb
195
+ - spec/siberite/client/namespace_spec.rb
196
+ - spec/siberite/client/partitioning_spec.rb
197
+ - spec/siberite/client/transactional_spec.rb
198
+ - spec/siberite/client/unmarshal_spec.rb
199
+ - spec/siberite/client_spec.rb
200
+ - spec/siberite/config/siberite.yml
201
+ - spec/siberite/config_spec.rb
202
+ - spec/siberite_benchmark.rb
203
+ - spec/spec.opts
204
+ - spec/spec_helper.rb
205
+ has_rdoc: