couchbase-jruby-client 0.1.0-java
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +203 -0
- data/README.md +347 -0
- data/Rakefile +10 -0
- data/couchbase-jruby-client.gemspec +30 -0
- data/lib/couchbase/async/callback.rb +19 -0
- data/lib/couchbase/async/queue.rb +26 -0
- data/lib/couchbase/async.rb +139 -0
- data/lib/couchbase/bucket.rb +663 -0
- data/lib/couchbase/cluster.rb +105 -0
- data/lib/couchbase/constants.rb +12 -0
- data/lib/couchbase/error.rb +28 -0
- data/lib/couchbase/jruby/couchbase_client.rb +22 -0
- data/lib/couchbase/jruby/future.rb +8 -0
- data/lib/couchbase/operations/arithmetic.rb +301 -0
- data/lib/couchbase/operations/delete.rb +104 -0
- data/lib/couchbase/operations/get.rb +298 -0
- data/lib/couchbase/operations/stats.rb +16 -0
- data/lib/couchbase/operations/store.rb +468 -0
- data/lib/couchbase/operations/touch.rb +123 -0
- data/lib/couchbase/operations/utils.rb +49 -0
- data/lib/couchbase/operations.rb +23 -0
- data/lib/couchbase/result.rb +43 -0
- data/lib/couchbase/transcoder.rb +83 -0
- data/lib/couchbase/utils.rb +62 -0
- data/lib/couchbase/version.rb +3 -0
- data/lib/couchbase/view.rb +506 -0
- data/lib/couchbase/view_row.rb +272 -0
- data/lib/couchbase.rb +177 -0
- data/lib/jars/commons-codec-1.5.jar +0 -0
- data/lib/jars/couchbase-client-1.2.0-javadoc.jar +0 -0
- data/lib/jars/couchbase-client-1.2.0-sources.jar +0 -0
- data/lib/jars/couchbase-client-1.2.0.jar +0 -0
- data/lib/jars/httpcore-4.1.1.jar +0 -0
- data/lib/jars/httpcore-nio-4.1.1.jar +0 -0
- data/lib/jars/jettison-1.1.jar +0 -0
- data/lib/jars/netty-3.5.5.Final.jar +0 -0
- data/lib/jars/spymemcached-2.10.0-javadoc.jar +0 -0
- data/lib/jars/spymemcached-2.10.0-sources.jar +0 -0
- data/lib/jars/spymemcached-2.10.0.jar +0 -0
- data/test/profile/.gitignore +1 -0
- data/test/profile/Gemfile +6 -0
- data/test/profile/benchmark.rb +195 -0
- data/test/setup.rb +201 -0
- data/test/test_arithmetic.rb +177 -0
- data/test/test_async.rb +324 -0
- data/test/test_bucket.rb +213 -0
- data/test/test_cas.rb +78 -0
- data/test/test_couchbase.rb +29 -0
- data/test/test_couchbase_rails_cache_store.rb +341 -0
- data/test/test_delete.rb +125 -0
- data/test/test_errors.rb +82 -0
- data/test/test_format.rb +161 -0
- data/test/test_get.rb +417 -0
- data/test/test_stats.rb +57 -0
- data/test/test_store.rb +216 -0
- data/test/test_timer.rb +42 -0
- data/test/test_touch.rb +97 -0
- data/test/test_unlock.rb +119 -0
- data/test/test_utils.rb +58 -0
- data/test/test_version.rb +52 -0
- metadata +226 -0
data/test/test_delete.rb
ADDED
@@ -0,0 +1,125 @@
|
|
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
|
+
|
20
|
+
class TestStore < MiniTest::Test
|
21
|
+
|
22
|
+
def setup
|
23
|
+
@mock = start_mock
|
24
|
+
end
|
25
|
+
|
26
|
+
def teardown
|
27
|
+
stop_mock(@mock)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_trivial_delete
|
31
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
32
|
+
connection.set(uniq_id, "bar")
|
33
|
+
assert connection.delete(uniq_id)
|
34
|
+
assert_raises(Couchbase::Error::NotFound) do
|
35
|
+
connection.delete(uniq_id)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_delete_missing
|
40
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
41
|
+
assert_raises(Couchbase::Error::NotFound) do
|
42
|
+
connection.delete(uniq_id(:missing))
|
43
|
+
end
|
44
|
+
refute connection.delete(uniq_id(:missing), :quiet => true)
|
45
|
+
refute connection.quiet?
|
46
|
+
connection.quiet = true
|
47
|
+
refute connection.delete(uniq_id(:missing))
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_delete_with_cas
|
51
|
+
skip
|
52
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
53
|
+
cas = connection.set(uniq_id, "bar")
|
54
|
+
missing_cas = cas - 1
|
55
|
+
assert_raises(Couchbase::Error::KeyExists) do
|
56
|
+
connection.delete(uniq_id, :cas => missing_cas)
|
57
|
+
end
|
58
|
+
assert connection.delete(uniq_id, :cas => cas)
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_allow_fixnum_as_cas_parameter
|
62
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
63
|
+
cas = connection.set(uniq_id, "bar")
|
64
|
+
assert connection.delete(uniq_id, cas)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_delete_with_prefix
|
68
|
+
skip
|
69
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :key_prefix => "prefix:")
|
70
|
+
connection.set(uniq_id(:foo), "bar")
|
71
|
+
assert connection.delete(uniq_id(:foo))
|
72
|
+
assert_raises(Couchbase::Error::NotFound) do
|
73
|
+
connection.get(uniq_id(:foo))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_simple_multi_delete
|
78
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :quiet => true)
|
79
|
+
connection.set(uniq_id(1) => "bar", uniq_id(2) => "foo")
|
80
|
+
res = connection.delete(uniq_id(1), uniq_id(2))
|
81
|
+
assert res.is_a?(Hash)
|
82
|
+
assert res[uniq_id(1)]
|
83
|
+
assert res[uniq_id(2)]
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_simple_multi_delete_missing
|
87
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :quiet => true)
|
88
|
+
connection.set(uniq_id(1) => "bar", uniq_id(2) => "foo")
|
89
|
+
res = connection.delete(uniq_id(1), uniq_id(:missing), :quiet => true)
|
90
|
+
assert res.is_a?(Hash)
|
91
|
+
assert res[uniq_id(1)]
|
92
|
+
refute res[uniq_id(:missing)]
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_multi_delete_with_cas_check
|
96
|
+
skip
|
97
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :quiet => true)
|
98
|
+
cas = connection.set(uniq_id(1) => "bar", uniq_id(2) => "foo")
|
99
|
+
res = connection.delete(uniq_id(1) => cas[uniq_id(1)], uniq_id(2) => cas[uniq_id(2)])
|
100
|
+
assert res.is_a?(Hash)
|
101
|
+
assert res[uniq_id(1)]
|
102
|
+
assert res[uniq_id(2)]
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_multi_delete_missing_with_cas_check
|
106
|
+
skip
|
107
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :quiet => true)
|
108
|
+
cas = connection.set(uniq_id(1) => "bar", uniq_id(2) => "foo")
|
109
|
+
res = connection.delete(uniq_id(1) => cas[uniq_id(1)], uniq_id(:missing) => cas[uniq_id(2)])
|
110
|
+
assert res.is_a?(Hash)
|
111
|
+
assert res[uniq_id(1)]
|
112
|
+
refute res[uniq_id(:missing)]
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_multi_delete_with_cas_check_mismatch
|
116
|
+
skip
|
117
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :quiet => true)
|
118
|
+
cas = connection.set(uniq_id(1) => "bar", uniq_id(2) => "foo")
|
119
|
+
|
120
|
+
assert_raises(Couchbase::Error::KeyExists) do
|
121
|
+
connection.delete(uniq_id(1) => cas[uniq_id(1)] + 1,
|
122
|
+
uniq_id(2) => cas[uniq_id(2)])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/test/test_errors.rb
ADDED
@@ -0,0 +1,82 @@
|
|
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 'digest/md5'
|
20
|
+
|
21
|
+
class TestErrors < MiniTest::Test
|
22
|
+
|
23
|
+
def setup
|
24
|
+
@mock = start_mock
|
25
|
+
end
|
26
|
+
|
27
|
+
def teardown
|
28
|
+
stop_mock(@mock)
|
29
|
+
end
|
30
|
+
|
31
|
+
def genkey(item)
|
32
|
+
tuple = [item["author"], item["message"]]
|
33
|
+
Digest::MD5.hexdigest(tuple.join('-'))
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_graceful_add_with_collision
|
37
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
38
|
+
msg1 = {"author" => "foo", "message" => "hi all", "time" => "2012-01-12 11:29:09"}
|
39
|
+
key1 = uniq_id(genkey(msg1))
|
40
|
+
msg2 = {"author" => "foo", "message" => "hi all", "time" => "2012-01-12 11:29:30"}
|
41
|
+
key2 = uniq_id(genkey(msg2))
|
42
|
+
|
43
|
+
connection.add(key1, msg1)
|
44
|
+
begin
|
45
|
+
connection.add(key2, msg2)
|
46
|
+
rescue Couchbase::Error::KeyExists => ex
|
47
|
+
# using info from exception
|
48
|
+
# it could be done with cas operation, but we can save one request
|
49
|
+
# here (in real world cas operation will be more consistent because it
|
50
|
+
# fetch fresh version from the cluster)
|
51
|
+
#
|
52
|
+
# connection.cas(key2) do |msg|
|
53
|
+
# msg.merge("time" => [msg["time"], msg2["time"]])
|
54
|
+
# end
|
55
|
+
msg2 = msg1.merge("time" => [msg1["time"], msg2["time"]])
|
56
|
+
connection.set(key2, msg2, :cas => ex.cas)
|
57
|
+
end
|
58
|
+
|
59
|
+
msg3 = {"author" => "foo", "message" => "hi all",
|
60
|
+
"time" => ["2012-01-12 11:29:09", "2012-01-12 11:29:30"]}
|
61
|
+
key3 = uniq_id(genkey(msg3))
|
62
|
+
assert_equal msg3, connection.get(key3)
|
63
|
+
|
64
|
+
connection.run do |conn|
|
65
|
+
msg4 = {"author" => "foo", "message" => "hi all", "time" => "2012-01-12 11:45:34"}
|
66
|
+
key4 = uniq_id(genkey(msg4))
|
67
|
+
|
68
|
+
connection.add(key4, msg4) do |ret|
|
69
|
+
assert_equal :add, ret.operation
|
70
|
+
assert_equal key4, ret.key
|
71
|
+
msg4 = msg3.merge("time" => msg3["time"] + [msg4["time"]])
|
72
|
+
connection.set(ret.key, msg4, :cas => ret.cas)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
msg5 = {"author" => "foo", "message" => "hi all",
|
77
|
+
"time" => ["2012-01-12 11:29:09", "2012-01-12 11:29:30", "2012-01-12 11:45:34"]}
|
78
|
+
key5 = uniq_id(genkey(msg5))
|
79
|
+
assert_equal msg5, connection.get(key5)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
data/test/test_format.rb
ADDED
@@ -0,0 +1,161 @@
|
|
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
|
+
|
20
|
+
class TestFormat < MiniTest::Test
|
21
|
+
|
22
|
+
ArbitraryClass = Struct.new(:name, :role)
|
23
|
+
class SkinyClass < Struct.new(:name, :role)
|
24
|
+
undef to_s rescue nil
|
25
|
+
undef to_json rescue nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup
|
29
|
+
@mock = start_mock
|
30
|
+
end
|
31
|
+
|
32
|
+
def teardown
|
33
|
+
stop_mock(@mock)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_default_document_format
|
37
|
+
orig_doc = {'name' => 'Twoflower', 'role' => 'The tourist'}
|
38
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
39
|
+
assert_equal :document, connection.default_format
|
40
|
+
connection.set(uniq_id, orig_doc)
|
41
|
+
doc, flags, cas = connection.get(uniq_id, :extended => true)
|
42
|
+
# assert_equal 0x00, flags & 0x11
|
43
|
+
assert doc.is_a?(Hash)
|
44
|
+
assert_equal 'Twoflower', doc['name']
|
45
|
+
assert_equal 'The tourist', doc['role']
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_it_raises_error_for_document_format_when_neither_to_json_nor_to_s_defined
|
49
|
+
if (MultiJson.respond_to?(:engine) ? MultiJson.engine : MultiJson.adapter).name =~ /Yajl$/
|
50
|
+
orig_doc = SkinyClass.new("Twoflower", "The tourist")
|
51
|
+
refute orig_doc.respond_to?(:to_s)
|
52
|
+
refute orig_doc.respond_to?(:to_json)
|
53
|
+
|
54
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :default_format => :document)
|
55
|
+
assert_raises(Couchbase::Error::ValueFormat) do
|
56
|
+
connection.set(uniq_id, orig_doc)
|
57
|
+
end
|
58
|
+
|
59
|
+
class << orig_doc
|
60
|
+
def to_json
|
61
|
+
MultiJson.dump(:name => name, :role => role)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
connection.set(uniq_id, orig_doc) # OK
|
65
|
+
|
66
|
+
class << orig_doc
|
67
|
+
undef to_json
|
68
|
+
def to_s
|
69
|
+
MultiJson.dump(:name => name, :role => role)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
connection.set(uniq_id, orig_doc) # OK
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_it_could_dump_arbitrary_class_using_marshal_format
|
77
|
+
orig_doc = ArbitraryClass.new("Twoflower", "The tourist")
|
78
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
79
|
+
connection.set(uniq_id, orig_doc, :format => :marshal)
|
80
|
+
doc, flags, cas = connection.get(uniq_id, :extended => true)
|
81
|
+
# assert_equal Couchbase::Bucket::FMT_MARSHAL, flags & Couchbase::Bucket::FMT_MASK
|
82
|
+
assert doc.is_a?(ArbitraryClass)
|
83
|
+
assert_equal 'Twoflower', doc.name
|
84
|
+
assert_equal 'The tourist', doc.role
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_it_accepts_only_string_in_plain_mode
|
88
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :default_format => :plain)
|
89
|
+
connection.set(uniq_id, "1")
|
90
|
+
|
91
|
+
assert_raises(Couchbase::Error::ValueFormat) do
|
92
|
+
connection.set(uniq_id, 1)
|
93
|
+
end
|
94
|
+
|
95
|
+
assert_raises(Couchbase::Error::ValueFormat) do
|
96
|
+
connection.set(uniq_id, {:foo => "bar"})
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_bignum_conversion
|
101
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :default_format => :plain)
|
102
|
+
cas = 0xffff_ffff_ffff_ffff
|
103
|
+
assert cas.is_a?(Bignum)
|
104
|
+
assert_raises(Couchbase::Error::NotFound) do
|
105
|
+
connection.delete(uniq_id => cas)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_it_allows_to_turn_off_transcoder
|
110
|
+
skip
|
111
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :transcoder => nil)
|
112
|
+
connection.set(uniq_id, "value", :flags => 0xffff_ffff)
|
113
|
+
doc, flags, _ = connection.get(uniq_id, :extended => true)
|
114
|
+
assert_equal "value", doc
|
115
|
+
assert_equal 0xffff_ffff, flags
|
116
|
+
end
|
117
|
+
|
118
|
+
require 'zlib'
|
119
|
+
# This class wraps any other transcoder and performs compression
|
120
|
+
# using zlib
|
121
|
+
class ZlibTranscoder
|
122
|
+
FMT_ZLIB = 0x04
|
123
|
+
|
124
|
+
def initialize(base)
|
125
|
+
@base = base
|
126
|
+
end
|
127
|
+
|
128
|
+
def dump(obj, flags, options = {})
|
129
|
+
obj, flags = @base.dump(obj, flags, options)
|
130
|
+
z = Zlib::Deflate.new(Zlib::BEST_SPEED)
|
131
|
+
buffer = z.deflate(obj, Zlib::FINISH)
|
132
|
+
z.close
|
133
|
+
[buffer, flags|FMT_ZLIB]
|
134
|
+
end
|
135
|
+
|
136
|
+
def load(blob, flags, options = {})
|
137
|
+
# decompress value only if Zlib flag set
|
138
|
+
if (flags & FMT_ZLIB) == FMT_ZLIB
|
139
|
+
z = Zlib::Inflate.new
|
140
|
+
blob = z.inflate(blob)
|
141
|
+
z.finish
|
142
|
+
z.close
|
143
|
+
end
|
144
|
+
@base.load(blob, flags, options)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_it_can_use_custom_transcoder
|
149
|
+
skip
|
150
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
151
|
+
connection.transcoder = ZlibTranscoder.new(Couchbase::Transcoder::Document)
|
152
|
+
connection.set(uniq_id, {"foo" => "bar"})
|
153
|
+
doc, flags, _ = connection.get(uniq_id, :extended => true)
|
154
|
+
assert_equal({"foo" => "bar"}, doc)
|
155
|
+
assert_equal(ZlibTranscoder::FMT_ZLIB|Couchbase::Bucket::FMT_DOCUMENT, flags)
|
156
|
+
connection.transcoder = nil
|
157
|
+
doc = connection.get(uniq_id)
|
158
|
+
assert_equal "x\x01\xABVJ\xCB\xCFW\xB2RJJ,R\xAA\x05\0\x1Dz\x044", doc
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|