couchbase 1.1.5-x86-mingw32 → 1.2.0.beta-x86-mingw32
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.
- data/.gitignore +2 -1
- data/.travis.yml +12 -1
- data/HISTORY.markdown +112 -1
- data/README.markdown +149 -6
- data/couchbase.gemspec +5 -1
- data/ext/couchbase_ext/.gitignore +4 -0
- data/ext/couchbase_ext/arguments.c +973 -0
- data/ext/couchbase_ext/arithmetic.c +322 -0
- data/ext/couchbase_ext/bucket.c +1092 -0
- data/ext/couchbase_ext/couchbase_ext.c +618 -3247
- data/ext/couchbase_ext/couchbase_ext.h +519 -0
- data/ext/couchbase_ext/delete.c +167 -0
- data/ext/couchbase_ext/extconf.rb +24 -5
- data/ext/couchbase_ext/get.c +301 -0
- data/ext/couchbase_ext/gethrtime.c +124 -0
- data/ext/couchbase_ext/http.c +402 -0
- data/ext/couchbase_ext/observe.c +174 -0
- data/ext/couchbase_ext/result.c +126 -0
- data/ext/couchbase_ext/stats.c +169 -0
- data/ext/couchbase_ext/store.c +522 -0
- data/ext/couchbase_ext/timer.c +192 -0
- data/ext/couchbase_ext/touch.c +190 -0
- data/ext/couchbase_ext/unlock.c +180 -0
- data/ext/couchbase_ext/utils.c +471 -0
- data/ext/couchbase_ext/version.c +147 -0
- data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
- data/lib/active_support/cache/couchbase_store.rb +356 -0
- data/lib/couchbase.rb +24 -3
- data/lib/couchbase/bucket.rb +372 -9
- data/lib/couchbase/result.rb +26 -0
- data/lib/couchbase/utils.rb +59 -0
- data/lib/couchbase/version.rb +1 -1
- data/lib/couchbase/view.rb +305 -0
- data/lib/couchbase/view_row.rb +230 -0
- data/lib/ext/multi_json_fix.rb +47 -0
- data/lib/rack/session/couchbase.rb +104 -0
- data/tasks/compile.rake +5 -14
- data/test/setup.rb +6 -2
- data/test/test_arithmetic.rb +32 -2
- data/test/test_async.rb +18 -4
- data/test/test_bucket.rb +11 -1
- data/test/test_cas.rb +13 -3
- data/test/test_couchbase_rails_cache_store.rb +294 -0
- data/test/test_delete.rb +60 -3
- data/test/test_format.rb +28 -17
- data/test/test_get.rb +91 -14
- data/test/test_store.rb +31 -1
- data/test/{test_flush.rb → test_timer.rb} +11 -18
- data/test/test_touch.rb +33 -5
- data/test/test_unlock.rb +120 -0
- data/test/test_utils.rb +26 -0
- metadata +102 -12
@@ -0,0 +1,47 @@
|
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
# This patch fixing loading primitives like strings, numbers and booleans
|
19
|
+
# using json_gem. It amends behaviour of MultiJson::Engines::JsonGem#load
|
20
|
+
# when it receives JSON string which neither Array nor Object.
|
21
|
+
|
22
|
+
if MultiJson.respond_to?(:engine)
|
23
|
+
multi_json_engine = MultiJson.send(:engine)
|
24
|
+
else
|
25
|
+
multi_json_engine = MultiJson.send(:adapter)
|
26
|
+
end
|
27
|
+
if multi_json_engine.name =~ /JsonGem$/
|
28
|
+
class << multi_json_engine
|
29
|
+
alias _load_object load
|
30
|
+
def load(string, options = {})
|
31
|
+
if string =~ /\A\s*[{\[]/
|
32
|
+
_load_object(string, options)
|
33
|
+
else
|
34
|
+
_load_object("[#{string}]", options)[0]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Patch for MultiJson versions < 1.3.3
|
41
|
+
if MultiJson.respond_to?(:decode) && MultiJson.respond_to?(:encode) &&
|
42
|
+
!MultiJson.respond_to?(:load) && !MultiJson.respond_to?(:dump)
|
43
|
+
class << MultiJson
|
44
|
+
alias :dump :encode
|
45
|
+
alias :load :decode
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'rack/session/abstract/id'
|
19
|
+
require 'couchbase'
|
20
|
+
require 'thread'
|
21
|
+
|
22
|
+
module Rack
|
23
|
+
module Session
|
24
|
+
|
25
|
+
# This is Couchbase-powered session store for rack applications
|
26
|
+
#
|
27
|
+
# To use it just load it as usual middleware in your `config.ru` file
|
28
|
+
#
|
29
|
+
# require 'rack/session/couchbase'
|
30
|
+
# use Rack::Session::Couchbase
|
31
|
+
#
|
32
|
+
# You can also pass additional options:
|
33
|
+
#
|
34
|
+
# require 'rack/session/couchbase'
|
35
|
+
# use Rack::Session::Couchbase, :expire_after => 5.minutes,
|
36
|
+
# :couchbase => {:bucket => "sessions", :default_format => :marshal}
|
37
|
+
#
|
38
|
+
# By default sessions will be serialized to JSON, to allow analyse them
|
39
|
+
# using Map/Reduce.
|
40
|
+
#
|
41
|
+
class Couchbase < Abstract::ID
|
42
|
+
attr_reader :mutex, :pool
|
43
|
+
|
44
|
+
DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge(
|
45
|
+
:couchbase => {:default_format => :document, :key_prefix => 'rack:session:'})
|
46
|
+
|
47
|
+
def initialize(app, options = {})
|
48
|
+
# Support old :expires option
|
49
|
+
options[:expire_after] ||= options[:expires]
|
50
|
+
super
|
51
|
+
|
52
|
+
@default_options[:couchbase][:default_ttl] ||= options[:expire_after]
|
53
|
+
@default_options[:couchbase][:key_prefix] ||= options[:namespace]
|
54
|
+
@namespace = @default_options[:couchbase][:key_prefix]
|
55
|
+
@mutex = Mutex.new
|
56
|
+
@pool = ::Couchbase.connect(@default_options[:couchbase])
|
57
|
+
end
|
58
|
+
|
59
|
+
def generate_sid
|
60
|
+
loop do
|
61
|
+
sid = super
|
62
|
+
break sid unless @pool.get(sid)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_session(env, sid)
|
67
|
+
with_lock(env, [nil, {}]) do
|
68
|
+
unless sid and session = @pool.get(sid)
|
69
|
+
sid, session = generate_sid, {}
|
70
|
+
@pool.set(sid, session)
|
71
|
+
end
|
72
|
+
[sid, session]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def set_session(env, session_id, new_session, options)
|
77
|
+
with_lock(env, false) do
|
78
|
+
@pool.set session_id, new_session, options
|
79
|
+
session_id
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def destroy_session(env, session_id, options)
|
84
|
+
with_lock(env) do
|
85
|
+
@pool.delete(session_id)
|
86
|
+
generate_sid unless options[:drop]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def with_lock(env, default = nil)
|
91
|
+
@mutex.lock if env['rack.multithread']
|
92
|
+
yield
|
93
|
+
rescue Couchbase::Error::Connect, Couchbase::Error::Timeout
|
94
|
+
if $VERBOSE
|
95
|
+
warn "#{self} is unable to find Couchbase server."
|
96
|
+
warn $!.inspect
|
97
|
+
end
|
98
|
+
default
|
99
|
+
ensure
|
100
|
+
@mutex.unlock if @mutex.locked?
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/tasks/compile.rake
CHANGED
@@ -57,7 +57,6 @@ end
|
|
57
57
|
|
58
58
|
require 'rubygems/package_task'
|
59
59
|
Gem::PackageTask.new(gemspec) do |pkg|
|
60
|
-
pkg.need_zip = true
|
61
60
|
pkg.need_tar = true
|
62
61
|
end
|
63
62
|
|
@@ -84,22 +83,14 @@ end
|
|
84
83
|
namespace :ports do
|
85
84
|
directory "ports"
|
86
85
|
|
87
|
-
task :
|
88
|
-
recipe = MiniPortile.new "
|
89
|
-
recipe.files << "http://packages.couchbase.com/clients/c
|
90
|
-
recipe.configure_options.push("--disable-debug",
|
91
|
-
"--without-docs",
|
92
|
-
"--disable-dependency-tracking")
|
93
|
-
recipe.cook
|
94
|
-
recipe.activate
|
95
|
-
end
|
96
|
-
|
97
|
-
task :libcouchbase => [:libvbucket] do
|
98
|
-
recipe = MiniPortile.new "libcouchbase", "1.0.6"
|
99
|
-
recipe.files << "http://packages.couchbase.com/clients/c/#{recipe.name}-#{recipe.version}.tar.gz"
|
86
|
+
task :libcouchbase => ["ports"] do
|
87
|
+
recipe = MiniPortile.new "libcouchbase", "2.0.0beta_5_g970a292"
|
88
|
+
recipe.files << "http://packages.couchbase.com/clients/c/libcouchbase-#{recipe.version}.tar.gz"
|
100
89
|
recipe.configure_options.push("--disable-debug",
|
101
90
|
"--disable-dependency-tracking",
|
102
91
|
"--disable-couchbasemock",
|
92
|
+
"--disable-cxx",
|
93
|
+
"--disable-examples",
|
103
94
|
"--disable-tools")
|
104
95
|
recipe.cook
|
105
96
|
recipe.activate
|
data/test/setup.rb
CHANGED
@@ -36,7 +36,7 @@ class CouchbaseServer
|
|
36
36
|
raise ArgumentError, "Check COUCHBASE_SERVER variable. It should be hostname:port"
|
37
37
|
end
|
38
38
|
|
39
|
-
@config =
|
39
|
+
@config = MultiJson.load(open("http://#{@host}:#{@port}/pools/default"))
|
40
40
|
@num_nodes = @config["nodes"].size
|
41
41
|
@buckets_spec = params[:buckets_spec] || "default:" # "default:,protected:secret,cache::memcache"
|
42
42
|
end
|
@@ -50,7 +50,11 @@ class CouchbaseServer
|
|
50
50
|
:username => name,
|
51
51
|
:bucket => name,
|
52
52
|
:password => password)
|
53
|
-
|
53
|
+
begin
|
54
|
+
connection.flush
|
55
|
+
rescue Couchbase::Error::NotSupported
|
56
|
+
# on recent server flush is disabled
|
57
|
+
end
|
54
58
|
end
|
55
59
|
end
|
56
60
|
def stop; end
|
data/test/test_arithmetic.rb
CHANGED
@@ -84,7 +84,9 @@ class TestArithmetic < MiniTest::Unit::TestCase
|
|
84
84
|
val = connection.incr(uniq_id(:missing), :create => true)
|
85
85
|
assert_equal 1, val
|
86
86
|
sleep(2)
|
87
|
-
|
87
|
+
assert_raises(Couchbase::Error::NotFound) do
|
88
|
+
connection.get(uniq_id(:missing))
|
89
|
+
end
|
88
90
|
end
|
89
91
|
|
90
92
|
def test_decrement_with_absolute_ttl
|
@@ -95,7 +97,9 @@ class TestArithmetic < MiniTest::Unit::TestCase
|
|
95
97
|
assert_equal 0, val
|
96
98
|
assert_equal 0, connection.get(uniq_id)
|
97
99
|
sleep(2)
|
98
|
-
|
100
|
+
assert_raises(Couchbase::Error::NotFound) do
|
101
|
+
refute connection.get(uniq_id)
|
102
|
+
end
|
99
103
|
end
|
100
104
|
|
101
105
|
def test_it_allows_custom_delta
|
@@ -106,4 +110,30 @@ class TestArithmetic < MiniTest::Unit::TestCase
|
|
106
110
|
assert_equal 22, val
|
107
111
|
end
|
108
112
|
|
113
|
+
def test_it_allows_to_specify_delta_in_options
|
114
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
115
|
+
|
116
|
+
connection.set(uniq_id, 12)
|
117
|
+
options = {:delta => 10}
|
118
|
+
val = connection.incr(uniq_id, options)
|
119
|
+
assert_equal 22, val
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_multi_incr
|
123
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
124
|
+
connection.set(uniq_id(:foo) => 1, uniq_id(:bar) => 1)
|
125
|
+
|
126
|
+
assert_equal [2, 2], connection.incr(uniq_id(:foo), uniq_id(:bar)).values.sort
|
127
|
+
assert_equal [12, 12], connection.incr(uniq_id(:foo), uniq_id(:bar), :delta => 10).values.sort
|
128
|
+
assert_equal [14, 15], connection.incr(uniq_id(:foo) => 2, uniq_id(:bar) => 3).values.sort
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_multi_decr
|
132
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
133
|
+
connection.set(uniq_id(:foo) => 14, uniq_id(:bar) => 15)
|
134
|
+
|
135
|
+
assert_equal [12, 12], connection.decr(uniq_id(:foo) => 2, uniq_id(:bar) => 3).values.sort
|
136
|
+
assert_equal [2, 2], connection.decr(uniq_id(:foo), uniq_id(:bar), :delta => 10).values.sort
|
137
|
+
assert_equal [1, 1], connection.decr(uniq_id(:foo), uniq_id(:bar)).values.sort
|
138
|
+
end
|
109
139
|
end
|
data/test/test_async.rb
CHANGED
@@ -110,7 +110,9 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
110
110
|
assert success
|
111
111
|
assert_equal "foo", val
|
112
112
|
sleep(2)
|
113
|
-
|
113
|
+
assert_raises(Couchbase::Error::NotFound) do
|
114
|
+
connection.get(uniq_id)
|
115
|
+
end
|
114
116
|
end
|
115
117
|
|
116
118
|
def test_nested_async_delete_get
|
@@ -167,7 +169,9 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
167
169
|
end
|
168
170
|
end
|
169
171
|
|
170
|
-
|
172
|
+
assert_raises(Couchbase::Error::NotFound) do
|
173
|
+
connection.get(uniq_id)
|
174
|
+
end
|
171
175
|
res.keys.each do |key|
|
172
176
|
assert res[key].is_a?(Numeric)
|
173
177
|
assert connection.get(key)
|
@@ -222,13 +226,23 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
222
226
|
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
223
227
|
connection.set(uniq_id, "foo")
|
224
228
|
|
225
|
-
connection.timeout =
|
229
|
+
connection.timeout = 100_000 # 100_000 us
|
226
230
|
connection.run do
|
227
231
|
connection.get(uniq_id) do |ret|
|
228
232
|
assert ret.success?
|
229
233
|
assert_equal "foo", ret.value
|
230
234
|
end
|
231
|
-
sleep(1.5)
|
235
|
+
sleep(1.5) # 1_500_000 us
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_send_threshold
|
240
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
241
|
+
|
242
|
+
sent = false
|
243
|
+
connection.run(:send_threshold => 100) do # 100 bytes
|
244
|
+
connection.set(uniq_id, "foo" * 100) {|r| sent = true}
|
245
|
+
assert sent
|
232
246
|
end
|
233
247
|
end
|
234
248
|
|
data/test/test_bucket.rb
CHANGED
@@ -151,7 +151,7 @@ class TestBucket < MiniTest::Unit::TestCase
|
|
151
151
|
with_mock do |mock|
|
152
152
|
connection = Couchbase.new(:hostname => mock.host,
|
153
153
|
:port => mock.port)
|
154
|
-
|
154
|
+
refute connection.quiet?
|
155
155
|
|
156
156
|
connection = Couchbase.new(:hostname => mock.host,
|
157
157
|
:port => mock.port,
|
@@ -224,4 +224,14 @@ class TestBucket < MiniTest::Unit::TestCase
|
|
224
224
|
end
|
225
225
|
end
|
226
226
|
|
227
|
+
def test_it_uses_bucket_name_as_username_if_username_is_empty
|
228
|
+
with_mock(:buckets_spec => 'protected:secret') do |mock|
|
229
|
+
connection = Couchbase.new(:hostname => mock.host,
|
230
|
+
:port => mock.port,
|
231
|
+
:bucket => 'protected',
|
232
|
+
:password => 'secret')
|
233
|
+
assert connection.connected?
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
227
237
|
end
|
data/test/test_cas.rb
CHANGED
@@ -44,13 +44,23 @@ class TestCas < MiniTest::Unit::TestCase
|
|
44
44
|
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
|
45
45
|
:default_format => :document)
|
46
46
|
connection.set(uniq_id, {"bar" => 1})
|
47
|
+
calls = 0
|
47
48
|
connection.run do |conn|
|
48
49
|
conn.cas(uniq_id) do |ret|
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
calls += 1
|
51
|
+
case ret.operation
|
52
|
+
when :get
|
53
|
+
new_val = ret.value
|
54
|
+
new_val["baz"] = 2
|
55
|
+
new_val
|
56
|
+
when :set
|
57
|
+
assert ret.success?
|
58
|
+
else
|
59
|
+
flunk "Unexpected operation: #{ret.operation.inspect}"
|
60
|
+
end
|
52
61
|
end
|
53
62
|
end
|
63
|
+
assert_equal 2, calls
|
54
64
|
val = connection.get(uniq_id)
|
55
65
|
expected = {"bar" => 1, "baz" => 2}
|
56
66
|
assert_equal expected, val
|
@@ -0,0 +1,294 @@
|
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require File.join(File.dirname(__FILE__), 'setup')
|
19
|
+
require 'active_support/cache/couchbase_store'
|
20
|
+
require 'active_support/notifications'
|
21
|
+
require 'ostruct'
|
22
|
+
|
23
|
+
class TestCouchbaseRailsCacheStore < MiniTest::Unit::TestCase
|
24
|
+
|
25
|
+
def setup
|
26
|
+
@mock = start_mock
|
27
|
+
@foo = OpenStruct.new :payload => "foo"
|
28
|
+
@foobar = OpenStruct.new :payload => "foobar"
|
29
|
+
end
|
30
|
+
|
31
|
+
def teardown
|
32
|
+
stop_mock(@mock)
|
33
|
+
end
|
34
|
+
|
35
|
+
def store
|
36
|
+
@store ||= ActiveSupport::Cache::CouchbaseStore.new(:hostname => @mock.host,
|
37
|
+
:port => @mock.port)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_it_supported_methods
|
41
|
+
supported_methods = store.public_methods(false).map(&:to_sym)
|
42
|
+
assert supported_methods.include?(:fetch)
|
43
|
+
assert supported_methods.include?(:write)
|
44
|
+
assert supported_methods.include?(:read)
|
45
|
+
assert supported_methods.include?(:read_multi)
|
46
|
+
assert supported_methods.include?(:increment)
|
47
|
+
assert supported_methods.include?(:decrement)
|
48
|
+
assert supported_methods.include?(:exists?)
|
49
|
+
assert supported_methods.include?(:delete)
|
50
|
+
assert supported_methods.include?(:stats)
|
51
|
+
refute supported_methods.include?(:clear)
|
52
|
+
assert_raises(NotImplementedError) do
|
53
|
+
store.clear
|
54
|
+
end
|
55
|
+
refute supported_methods.include?(:cleanup)
|
56
|
+
assert_raises(NotImplementedError) do
|
57
|
+
store.cleanup
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_it_writes_and_reads_the_data
|
62
|
+
store.write uniq_id, @foobar
|
63
|
+
assert_equal @foobar, store.read(uniq_id)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_it_writes_the_data_with_expiration_time
|
67
|
+
store.write(uniq_id, @foobar, :expires_in => 1.second)
|
68
|
+
assert_equal @foobar, store.read(uniq_id)
|
69
|
+
sleep 2
|
70
|
+
refute store.read(uniq_id)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_it_doest_write_data_if_unless_exist_option_is_true
|
74
|
+
store.write uniq_id, @foo
|
75
|
+
[:unless_exist, :unless_exists].each do |unless_exists|
|
76
|
+
store.write uniq_id, @foobar, unless_exists => true
|
77
|
+
assert_equal @foo, store.read(uniq_id)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
if RUBY_VERSION.match /1\.9/
|
82
|
+
def test_it_reads_raw_data
|
83
|
+
store.write uniq_id, @foo
|
84
|
+
assert_equal "\x04\bU:\x0FOpenStruct{\x06:\fpayloadI\"\bfoo\x06:\x06EF",
|
85
|
+
store.read(uniq_id, :raw => true)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
def test_it_reads_raw_data
|
89
|
+
store.write uniq_id, @foo
|
90
|
+
assert_equal "\004\bU:\017OpenStruct{\006:\fpayload\"\bfoo",
|
91
|
+
store.read(uniq_id, :raw => true)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_it_writes_raw_data
|
96
|
+
store.write uniq_id, @foobar, :raw => true
|
97
|
+
assert_equal '#<OpenStruct payload="foobar">', store.read(uniq_id, :raw => true)
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_it_deletes_data
|
101
|
+
store.write uniq_id, @foo
|
102
|
+
store.delete uniq_id
|
103
|
+
refute store.read(uniq_id)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_it_verifies_existence_of_an_object_in_the_store
|
107
|
+
store.write uniq_id, @foo
|
108
|
+
assert store.exist?(uniq_id)
|
109
|
+
refute store.exist?(uniq_id(:missing))
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_it_initializes_key_on_first_increment_with_zero
|
113
|
+
store.increment(uniq_id)
|
114
|
+
assert_equal 0, store.read(uniq_id)
|
115
|
+
assert_equal "0", store.read(uniq_id, :raw => true)
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_it_initializes_key_on_first_decrement_with_zero
|
119
|
+
store.decrement(uniq_id)
|
120
|
+
assert_equal 0, store.read(uniq_id)
|
121
|
+
assert_equal "0", store.read(uniq_id, :raw => true)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_it_initializes_key_with_given_value_on_increment
|
125
|
+
store.increment(uniq_id, 1, :initial => 5)
|
126
|
+
assert_equal 5, store.read(uniq_id)
|
127
|
+
assert_equal "5", store.read(uniq_id, :raw => true)
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_it_initializes_key_with_given_value_on_decrement
|
131
|
+
store.decrement(uniq_id, 1, :initial => 5)
|
132
|
+
assert_equal 5, store.read(uniq_id)
|
133
|
+
assert_equal "5", store.read(uniq_id, :raw => true)
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_it_increments_a_key
|
137
|
+
3.times { store.increment uniq_id }
|
138
|
+
assert_equal 2, store.read(uniq_id)
|
139
|
+
assert_equal "2", store.read(uniq_id, :raw => true)
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_it_decrements_a_key
|
143
|
+
4.times { store.increment uniq_id }
|
144
|
+
2.times { store.decrement uniq_id }
|
145
|
+
assert_equal 1, store.read(uniq_id)
|
146
|
+
assert_equal "1", store.read(uniq_id, :raw => true)
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_it_increments_a_raw_key
|
150
|
+
assert store.write(uniq_id, 1, :raw => true)
|
151
|
+
store.increment(uniq_id, 2)
|
152
|
+
assert_equal 3, store.read(uniq_id, :raw => true).to_i
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_it_decrements_a_raw_key
|
156
|
+
assert store.write(uniq_id, 3, :raw => true)
|
157
|
+
store.decrement(uniq_id, 2)
|
158
|
+
assert_equal 1, store.read(uniq_id, :raw => true).to_i
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_it_increments_a_key_by_given_value
|
162
|
+
store.write(uniq_id, 0, :raw => true)
|
163
|
+
store.increment uniq_id, 3
|
164
|
+
assert_equal 3, store.read(uniq_id, :raw => true).to_i
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_it_decrements_a_key_by_given_value
|
168
|
+
store.write(uniq_id, 0, :raw => true)
|
169
|
+
3.times { store.increment uniq_id }
|
170
|
+
store.decrement uniq_id, 2
|
171
|
+
assert_equal 1, store.read(uniq_id, :raw => true).to_i
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_it_provides_store_stats
|
175
|
+
refute store.stats.empty?
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_it_fetches_data
|
179
|
+
assert store.write(uniq_id, @foo)
|
180
|
+
assert_equal @foo, store.fetch(uniq_id)
|
181
|
+
refute store.fetch("rub-a-dub")
|
182
|
+
store.fetch("rub-a-dub") { "Flora de Cana" }
|
183
|
+
assert_equal "Flora de Cana", store.fetch("rub-a-dub")
|
184
|
+
store.fetch(uniq_id, :force => true) # force cache miss
|
185
|
+
store.fetch(uniq_id, :force => true, :expires_in => 1.second) { @foobar }
|
186
|
+
assert_equal @foobar, store.fetch(uniq_id)
|
187
|
+
sleep 2
|
188
|
+
refute store.fetch(uniq_id)
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_it_reads_multiple_keys
|
192
|
+
assert store.write(uniq_id(1), @foo)
|
193
|
+
assert store.write(uniq_id(2), "foo")
|
194
|
+
result = store.read_multi uniq_id(1), uniq_id(2)
|
195
|
+
assert_equal @foo, result[uniq_id(1)]
|
196
|
+
assert_equal "foo", result[uniq_id(2)]
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_it_reads_multiple_keys_and_returns_only_the_matched_ones
|
200
|
+
assert store.write(uniq_id, @foo)
|
201
|
+
result = store.read_multi uniq_id, uniq_id(:missing)
|
202
|
+
assert result[uniq_id]
|
203
|
+
refute result[uniq_id(:missing)]
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_it_notifies_on_fetch
|
207
|
+
collect_notifications do
|
208
|
+
store.fetch(uniq_id) { "foo" }
|
209
|
+
end
|
210
|
+
|
211
|
+
read, generate, write = @events
|
212
|
+
|
213
|
+
assert_equal 'cache_read.active_support', read.name
|
214
|
+
assert_equal({:key => uniq_id, :super_operation => :fetch}, read.payload)
|
215
|
+
|
216
|
+
assert_equal 'cache_generate.active_support', generate.name
|
217
|
+
assert_equal({:key => uniq_id}, generate.payload)
|
218
|
+
|
219
|
+
assert_equal 'cache_write.active_support', write.name
|
220
|
+
assert_equal({:key => uniq_id}, write.payload)
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_it_notifies_on_read
|
224
|
+
collect_notifications do
|
225
|
+
store.read uniq_id
|
226
|
+
end
|
227
|
+
|
228
|
+
read = @events.first
|
229
|
+
assert_equal 'cache_read.active_support', read.name
|
230
|
+
assert_equal({:key => uniq_id, :hit => false}, read.payload)
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_it_notifies_on_write
|
234
|
+
collect_notifications do
|
235
|
+
store.write uniq_id, "foo"
|
236
|
+
end
|
237
|
+
|
238
|
+
write = @events.first
|
239
|
+
assert_equal 'cache_write.active_support', write.name
|
240
|
+
assert_equal({:key => uniq_id}, write.payload)
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_it_notifies_on_delete
|
244
|
+
collect_notifications do
|
245
|
+
store.delete uniq_id
|
246
|
+
end
|
247
|
+
|
248
|
+
delete = @events.first
|
249
|
+
assert_equal 'cache_delete.active_support', delete.name
|
250
|
+
assert_equal({:key => uniq_id}, delete.payload)
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_it_notifies_on_exist?
|
254
|
+
collect_notifications do
|
255
|
+
store.exist? uniq_id
|
256
|
+
end
|
257
|
+
|
258
|
+
exist = @events.first
|
259
|
+
assert_equal 'cache_exists?.active_support', exist.name
|
260
|
+
assert_equal({:key => uniq_id}, exist.payload)
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_it_notifies_on_increment
|
264
|
+
collect_notifications do
|
265
|
+
store.increment uniq_id
|
266
|
+
end
|
267
|
+
|
268
|
+
increment = @events.first
|
269
|
+
assert_equal 'cache_increment.active_support', increment.name
|
270
|
+
assert_equal({:key => uniq_id, :amount => 1, :create => true}, increment.payload)
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_it_notifies_on_decrement
|
274
|
+
collect_notifications do
|
275
|
+
store.decrement uniq_id
|
276
|
+
end
|
277
|
+
|
278
|
+
decrement = @events.first
|
279
|
+
assert_equal 'cache_decrement.active_support', decrement.name
|
280
|
+
assert_equal({:key => uniq_id, :amount => 1, :create => true}, decrement.payload)
|
281
|
+
end
|
282
|
+
|
283
|
+
private
|
284
|
+
|
285
|
+
def collect_notifications
|
286
|
+
@events = [ ]
|
287
|
+
ActiveSupport::Cache::CouchbaseStore.instrument = true
|
288
|
+
ActiveSupport::Notifications.subscribe(/^cache_(.*)\.active_support$/) do |*args|
|
289
|
+
@events << ActiveSupport::Notifications::Event.new(*args)
|
290
|
+
end
|
291
|
+
yield
|
292
|
+
ActiveSupport::Cache::CouchbaseStore.instrument = false
|
293
|
+
end
|
294
|
+
end
|