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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +203 -0
  6. data/README.md +347 -0
  7. data/Rakefile +10 -0
  8. data/couchbase-jruby-client.gemspec +30 -0
  9. data/lib/couchbase/async/callback.rb +19 -0
  10. data/lib/couchbase/async/queue.rb +26 -0
  11. data/lib/couchbase/async.rb +139 -0
  12. data/lib/couchbase/bucket.rb +663 -0
  13. data/lib/couchbase/cluster.rb +105 -0
  14. data/lib/couchbase/constants.rb +12 -0
  15. data/lib/couchbase/error.rb +28 -0
  16. data/lib/couchbase/jruby/couchbase_client.rb +22 -0
  17. data/lib/couchbase/jruby/future.rb +8 -0
  18. data/lib/couchbase/operations/arithmetic.rb +301 -0
  19. data/lib/couchbase/operations/delete.rb +104 -0
  20. data/lib/couchbase/operations/get.rb +298 -0
  21. data/lib/couchbase/operations/stats.rb +16 -0
  22. data/lib/couchbase/operations/store.rb +468 -0
  23. data/lib/couchbase/operations/touch.rb +123 -0
  24. data/lib/couchbase/operations/utils.rb +49 -0
  25. data/lib/couchbase/operations.rb +23 -0
  26. data/lib/couchbase/result.rb +43 -0
  27. data/lib/couchbase/transcoder.rb +83 -0
  28. data/lib/couchbase/utils.rb +62 -0
  29. data/lib/couchbase/version.rb +3 -0
  30. data/lib/couchbase/view.rb +506 -0
  31. data/lib/couchbase/view_row.rb +272 -0
  32. data/lib/couchbase.rb +177 -0
  33. data/lib/jars/commons-codec-1.5.jar +0 -0
  34. data/lib/jars/couchbase-client-1.2.0-javadoc.jar +0 -0
  35. data/lib/jars/couchbase-client-1.2.0-sources.jar +0 -0
  36. data/lib/jars/couchbase-client-1.2.0.jar +0 -0
  37. data/lib/jars/httpcore-4.1.1.jar +0 -0
  38. data/lib/jars/httpcore-nio-4.1.1.jar +0 -0
  39. data/lib/jars/jettison-1.1.jar +0 -0
  40. data/lib/jars/netty-3.5.5.Final.jar +0 -0
  41. data/lib/jars/spymemcached-2.10.0-javadoc.jar +0 -0
  42. data/lib/jars/spymemcached-2.10.0-sources.jar +0 -0
  43. data/lib/jars/spymemcached-2.10.0.jar +0 -0
  44. data/test/profile/.gitignore +1 -0
  45. data/test/profile/Gemfile +6 -0
  46. data/test/profile/benchmark.rb +195 -0
  47. data/test/setup.rb +201 -0
  48. data/test/test_arithmetic.rb +177 -0
  49. data/test/test_async.rb +324 -0
  50. data/test/test_bucket.rb +213 -0
  51. data/test/test_cas.rb +78 -0
  52. data/test/test_couchbase.rb +29 -0
  53. data/test/test_couchbase_rails_cache_store.rb +341 -0
  54. data/test/test_delete.rb +125 -0
  55. data/test/test_errors.rb +82 -0
  56. data/test/test_format.rb +161 -0
  57. data/test/test_get.rb +417 -0
  58. data/test/test_stats.rb +57 -0
  59. data/test/test_store.rb +216 -0
  60. data/test/test_timer.rb +42 -0
  61. data/test/test_touch.rb +97 -0
  62. data/test/test_unlock.rb +119 -0
  63. data/test/test_utils.rb +58 -0
  64. data/test/test_version.rb +52 -0
  65. metadata +226 -0
@@ -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
@@ -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
@@ -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