couchbase 0.9.8 → 1.0.0

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 (51) hide show
  1. data/.gitignore +8 -0
  2. data/.yardopts +5 -0
  3. data/HISTORY.markdown +14 -10
  4. data/README.markdown +293 -98
  5. data/Rakefile +19 -24
  6. data/couchbase.gemspec +25 -7
  7. data/ext/couchbase_ext/couchbase_ext.c +2332 -0
  8. data/ext/couchbase_ext/extconf.rb +102 -0
  9. data/lib/couchbase.rb +20 -30
  10. data/lib/couchbase/bucket.rb +43 -112
  11. data/lib/couchbase/version.rb +3 -2
  12. data/tasks/benchmark.rake +6 -0
  13. data/tasks/compile.rake +52 -0
  14. data/tasks/doc.rake +27 -0
  15. data/tasks/test.rake +94 -0
  16. data/tasks/util.rake +21 -0
  17. data/test/profile/.gitignore +1 -0
  18. data/test/profile/Gemfile +6 -0
  19. data/test/profile/benchmark.rb +195 -0
  20. data/test/setup.rb +107 -18
  21. data/test/test_arithmetic.rb +98 -0
  22. data/test/test_async.rb +211 -0
  23. data/test/test_bucket.rb +126 -23
  24. data/test/test_cas.rb +59 -0
  25. data/test/test_couchbase.rb +22 -3
  26. data/test/test_delete.rb +63 -0
  27. data/test/test_errors.rb +82 -0
  28. data/test/test_flush.rb +49 -0
  29. data/test/test_format.rb +98 -0
  30. data/test/test_get.rb +236 -0
  31. data/test/test_stats.rb +53 -0
  32. data/test/test_store.rb +186 -0
  33. data/test/test_touch.rb +57 -0
  34. data/test/test_version.rb +17 -0
  35. metadata +72 -58
  36. data/lib/couchbase/couchdb.rb +0 -107
  37. data/lib/couchbase/document.rb +0 -71
  38. data/lib/couchbase/http_status.rb +0 -118
  39. data/lib/couchbase/latch.rb +0 -71
  40. data/lib/couchbase/memcached.rb +0 -372
  41. data/lib/couchbase/node.rb +0 -49
  42. data/lib/couchbase/rest_client.rb +0 -124
  43. data/lib/couchbase/view.rb +0 -182
  44. data/test/support/buckets-config.json +0 -843
  45. data/test/support/sample_design_doc.json +0 -9
  46. data/test/test_couchdb.rb +0 -98
  47. data/test/test_document.rb +0 -11
  48. data/test/test_latch.rb +0 -88
  49. data/test/test_memcached.rb +0 -59
  50. data/test/test_rest_client.rb +0 -14
  51. data/test/test_view.rb +0 -98
@@ -0,0 +1,59 @@
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 TestCas < MiniTest::Unit::TestCase
21
+
22
+ def setup
23
+ @mock = start_mock
24
+ end
25
+
26
+ def teardown
27
+ stop_mock(@mock)
28
+ end
29
+
30
+ def test_compare_and_swap
31
+ connection = Couchbase.new(:port => @mock.port,
32
+ :default_format => :document)
33
+ connection.set(test_id, {"bar" => 1})
34
+ connection.cas(test_id) do |val|
35
+ val["baz"] = 2
36
+ val
37
+ end
38
+ val = connection.get(test_id)
39
+ expected = {"bar" => 1, "baz" => 2}
40
+ assert_equal expected, val
41
+ end
42
+
43
+ def test_compare_and_swap_async
44
+ connection = Couchbase.new(:port => @mock.port,
45
+ :default_format => :document)
46
+ connection.set(test_id, {"bar" => 1})
47
+ connection.run do |conn|
48
+ conn.cas(test_id) do |ret|
49
+ new_val = ret.value
50
+ new_val["baz"] = 2
51
+ new_val
52
+ end
53
+ end
54
+ val = connection.get(test_id)
55
+ expected = {"bar" => 1, "baz" => 2}
56
+ assert_equal expected, val
57
+ end
58
+
59
+ end
@@ -1,9 +1,28 @@
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
+
1
18
  require File.join(File.dirname(__FILE__), 'setup')
2
19
 
3
20
  class TestCouchbase < MiniTest::Unit::TestCase
21
+
4
22
  def test_that_it_create_instance_of_bucket
5
- assert_instance_of Couchbase::Bucket, Couchbase.new('http://localhost:8091/pools/default')
23
+ with_mock do |mock|
24
+ assert_instance_of Couchbase::Bucket, Couchbase.new("http://localhost:#{mock.port}/pools/default")
25
+ end
6
26
  end
7
- end
8
-
9
27
 
28
+ end
@@ -0,0 +1,63 @@
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::Unit::TestCase
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(:port => @mock.port)
32
+ connection.set(test_id, "bar")
33
+ assert connection.delete(test_id)
34
+ refute connection.delete(test_id)
35
+ end
36
+
37
+ def test_delete_missing
38
+ connection = Couchbase.new(:port => @mock.port)
39
+ refute connection.delete(test_id(:missing))
40
+ connection.quiet = false
41
+ assert_raises(Couchbase::Error::NotFound) do
42
+ connection.delete(test_id(:missing))
43
+ end
44
+ refute connection.delete(test_id(:missing), :quiet => true)
45
+ end
46
+
47
+ def test_delete_with_cas
48
+ connection = Couchbase.new(:port => @mock.port)
49
+ cas = connection.set(test_id, "bar")
50
+ missing_cas = cas - 1
51
+ assert_raises(Couchbase::Error::KeyExists) do
52
+ connection.delete(test_id, :cas => missing_cas)
53
+ end
54
+ assert connection.delete(test_id, :cas => cas)
55
+ end
56
+
57
+ def test_allow_fixnum_as_cas_parameter
58
+ connection = Couchbase.new(:port => @mock.port)
59
+ cas = connection.set(test_id, "bar")
60
+ assert connection.delete(test_id, cas)
61
+ end
62
+
63
+ 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::Unit::TestCase
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(:port => @mock.port)
38
+ msg1 = {"author" => "foo", "message" => "hi all", "time" => "2012-01-12 11:29:09"}
39
+ key1 = test_id(genkey(msg1))
40
+ msg2 = {"author" => "foo", "message" => "hi all", "time" => "2012-01-12 11:29:30"}
41
+ key2 = test_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 = test_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 = test_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 = test_id(genkey(msg5))
79
+ assert_equal msg5, connection.get(key5)
80
+ end
81
+
82
+ end
@@ -0,0 +1,49 @@
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 TestFlush < MiniTest::Unit::TestCase
21
+
22
+ def setup
23
+ @mock = start_mock(:num_nodes => 7)
24
+ end
25
+
26
+ def teardown
27
+ stop_mock(@mock)
28
+ end
29
+
30
+ def test_trivial_flush
31
+ connection = Couchbase.new(:port => @mock.port)
32
+ assert connection.flush
33
+ end
34
+
35
+ def test_flush_with_block
36
+ connection = Couchbase.new(:port => @mock.port)
37
+ flushed = {}
38
+ on_node_flush = lambda{|res| flushed[res.node] = res.success?}
39
+ connection.run do |conn|
40
+ conn.flush(&on_node_flush)
41
+ end
42
+ assert_equal 7, flushed.size
43
+ flushed.each do |node, res|
44
+ assert node.is_a?(String)
45
+ assert res
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,98 @@
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::Unit::TestCase
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(:port => @mock.port)
39
+ assert_equal :document, connection.default_format
40
+ connection.set(test_id, orig_doc)
41
+ doc, flags, cas = connection.get(test_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
+ orig_doc = SkinyClass.new("Twoflower", "The tourist")
50
+ refute orig_doc.respond_to?(:to_s)
51
+ refute orig_doc.respond_to?(:to_json)
52
+
53
+ connection = Couchbase.new(:port => @mock.port, :default_format => :document)
54
+ assert_raises(Couchbase::Error::ValueFormat) do
55
+ connection.set(test_id, orig_doc)
56
+ end
57
+
58
+ class << orig_doc
59
+ def to_json
60
+ JSON.dump(:name => name, :role => role)
61
+ end
62
+ end
63
+ connection.set(test_id, orig_doc) # OK
64
+
65
+ class << orig_doc
66
+ undef to_json
67
+ def to_s
68
+ JSON.dump(:name => name, :role => role)
69
+ end
70
+ end
71
+ connection.set(test_id, orig_doc) # OK
72
+ end
73
+
74
+ def test_it_could_dump_arbitrary_class_using_marshal_format
75
+ orig_doc = ArbitraryClass.new("Twoflower", "The tourist")
76
+ connection = Couchbase.new(:port => @mock.port)
77
+ connection.set(test_id, orig_doc, :format => :marshal)
78
+ doc, flags, cas = connection.get(test_id, :extended => true)
79
+ assert_equal 0x01, flags & 0x11
80
+ assert doc.is_a?(ArbitraryClass)
81
+ assert_equal 'Twoflower', doc.name
82
+ assert_equal 'The tourist', doc.role
83
+ end
84
+
85
+ def test_it_accepts_only_string_in_plain_mode
86
+ connection = Couchbase.new(:port => @mock.port, :default_format => :plain)
87
+ connection.set(test_id, "1")
88
+
89
+ assert_raises(Couchbase::Error::ValueFormat) do
90
+ connection.set(test_id, 1)
91
+ end
92
+
93
+ assert_raises(Couchbase::Error::ValueFormat) do
94
+ connection.set(test_id, {:foo => "bar"})
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,236 @@
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 TestGet < MiniTest::Unit::TestCase
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_get
31
+ connection = Couchbase.new(:port => @mock.port)
32
+ connection.set(test_id, "bar")
33
+ val = connection.get(test_id)
34
+ assert_equal "bar", val
35
+ end
36
+
37
+ def test_extended_get
38
+ connection = Couchbase.new(:port => @mock.port)
39
+
40
+ orig_cas = connection.set(test_id, "bar")
41
+ val, flags, cas = connection.get(test_id, :extended => true)
42
+ assert_equal "bar", val
43
+ assert_equal 0x0, flags
44
+ assert_equal orig_cas, cas
45
+
46
+ orig_cas = connection.set(test_id, "bar", :flags => 0x1000)
47
+ val, flags, cas = connection.get(test_id, :extended => true)
48
+ assert_equal "bar", val
49
+ assert_equal 0x1000, flags
50
+ assert_equal orig_cas, cas
51
+ end
52
+
53
+ def test_multi_get
54
+ connection = Couchbase.new(:port => @mock.port)
55
+
56
+ connection.set(test_id(1), "foo1")
57
+ connection.set(test_id(2), "foo2")
58
+
59
+ val1, val2 = connection.get(test_id(1), test_id(2))
60
+ assert_equal "foo1", val1
61
+ assert_equal "foo2", val2
62
+ end
63
+
64
+ def test_multi_get_extended
65
+ connection = Couchbase.new(:port => @mock.port)
66
+
67
+ cas1 = connection.set(test_id(1), "foo1")
68
+ cas2 = connection.set(test_id(2), "foo2")
69
+
70
+ results = connection.get(test_id(1), test_id(2), :extended => true)
71
+ assert_equal ["foo1", 0x0, cas1], results[test_id(1)]
72
+ assert_equal ["foo2", 0x0, cas2], results[test_id(2)]
73
+ end
74
+
75
+ def test_missing_in_quiet_mode
76
+ connection = Couchbase.new(:port => @mock.port)
77
+ cas1 = connection.set(test_id(1), "foo1")
78
+ cas2 = connection.set(test_id(2), "foo2")
79
+
80
+ val = connection.get(test_id(:missing))
81
+ refute(val)
82
+ val = connection.get(test_id(:missing), :extended => true)
83
+ refute(val)
84
+
85
+ val1, missing, val2 = connection.get(test_id(1), test_id(:missing), test_id(2))
86
+ assert_equal "foo1", val1
87
+ refute missing
88
+ assert_equal "foo2", val2
89
+
90
+ results = connection.get(test_id(1), test_id(:missing), test_id(2), :extended => true)
91
+ assert_equal ["foo1", 0x0, cas1], results[test_id(1)]
92
+ refute results[test_id(:missing)]
93
+ assert_equal ["foo2", 0x0, cas2], results[test_id(2)]
94
+ end
95
+
96
+ def test_it_allows_temporary_quiet_flag
97
+ connection = Couchbase.new(:port => @mock.port, :quiet => false)
98
+ assert_raises(Couchbase::Error::NotFound) do
99
+ connection.get(test_id(:missing))
100
+ end
101
+ refute connection.get(test_id(:missing), :quiet => true)
102
+ end
103
+
104
+ def test_missing_in_verbose_mode
105
+ connection = Couchbase.new(:port => @mock.port, :quiet => false)
106
+ connection.set(test_id(1), "foo1")
107
+ connection.set(test_id(2), "foo2")
108
+
109
+ assert_raises(Couchbase::Error::NotFound) do
110
+ connection.get(test_id(:missing))
111
+ end
112
+
113
+ assert_raises(Couchbase::Error::NotFound) do
114
+ connection.get(test_id(:missing), :extended => true)
115
+ end
116
+
117
+ assert_raises(Couchbase::Error::NotFound) do
118
+ connection.get(test_id(1), test_id(:missing), test_id(2))
119
+ end
120
+
121
+ assert_raises(Couchbase::Error::NotFound) do
122
+ connection.get(test_id(1), test_id(:missing), test_id(2), :extended => true)
123
+ end
124
+ end
125
+
126
+ def test_asynchronous_get
127
+ connection = Couchbase.new(:port => @mock.port)
128
+ cas = connection.set(test_id, "foo", :flags => 0x6660)
129
+ res = []
130
+
131
+ suite = lambda do |conn|
132
+ res.clear
133
+ conn.get(test_id) # ignore result
134
+ conn.get(test_id) {|ret| res << ret}
135
+ handler = lambda {|ret| res << ret}
136
+ conn.get(test_id, &handler)
137
+ assert_equal 3, conn.seqno
138
+ end
139
+
140
+ checks = lambda do
141
+ res.each do |r|
142
+ assert r.is_a?(Couchbase::Result)
143
+ assert r.success?
144
+ assert_equal test_id, r.key
145
+ assert_equal "foo", r.value
146
+ assert_equal 0x6660, r.flags
147
+ assert_equal cas, r.cas
148
+ end
149
+ end
150
+
151
+ connection.run(&suite)
152
+ checks.call
153
+
154
+ connection.run{ suite.call(connection) }
155
+ checks.call
156
+ end
157
+
158
+ def test_asynchronous_multi_get
159
+ connection = Couchbase.new(:port => @mock.port)
160
+ connection.set(test_id(1), "foo")
161
+ connection.set(test_id(2), "bar")
162
+
163
+ res = {}
164
+ connection.run do |conn|
165
+ conn.get(test_id(1), test_id(2)) {|ret| res[ret.key] = ret.value}
166
+ assert_equal 2, conn.seqno
167
+ end
168
+
169
+ assert res[test_id(1)]
170
+ assert_equal "foo", res[test_id(1)]
171
+ assert res[test_id(2)]
172
+ assert_equal "bar", res[test_id(2)]
173
+ end
174
+
175
+ def test_asynchronous_get_missing
176
+ connection = Couchbase.new(:port => @mock.port)
177
+ connection.set(test_id, "foo")
178
+ res = {}
179
+ missing = []
180
+
181
+ get_handler = lambda do |ret|
182
+ assert_equal :get, ret.operation
183
+ if ret.success?
184
+ res[ret.key] = ret.value
185
+ else
186
+ if ret.error.is_a?(Couchbase::Error::NotFound)
187
+ missing << ret.key
188
+ else
189
+ raise ret.error
190
+ end
191
+ end
192
+ end
193
+
194
+ suite = lambda do |conn|
195
+ res.clear
196
+ missing.clear
197
+ conn.get(test_id(:missing1), &get_handler)
198
+ conn.get(test_id, test_id(:missing2), &get_handler)
199
+ assert 3, conn.seqno
200
+ end
201
+
202
+ connection.run(&suite)
203
+ assert_equal "foo", res[test_id]
204
+ assert res.has_key?(test_id(:missing1)) # handler was called with nil
205
+ refute res[test_id(:missing1)]
206
+ assert res.has_key?(test_id(:missing2))
207
+ refute res[test_id(:missing2)]
208
+ assert_empty missing
209
+
210
+ connection.quiet = false
211
+
212
+ connection.run(&suite)
213
+ refute res.has_key?(test_id(:missing1))
214
+ refute res.has_key?(test_id(:missing2))
215
+ assert_equal [test_id(:missing1), test_id(:missing2)], missing.sort
216
+ assert_equal "foo", res[test_id]
217
+ end
218
+
219
+ def test_get_using_brackets
220
+ connection = Couchbase.new(:port => @mock.port)
221
+
222
+ orig_cas = connection.set(test_id, "foo", :flags => 0x1100)
223
+
224
+ val = connection[test_id]
225
+ assert_equal "foo", val
226
+
227
+ if RUBY_VERSION =~ /^1\.9/
228
+ eval <<-EOC
229
+ val, flags, cas = connection[test_id, :extended => true]
230
+ assert_equal "foo", val
231
+ assert_equal 0x1100, flags
232
+ assert_equal orig_cas, cas
233
+ EOC
234
+ end
235
+ end
236
+ end