couchbase 0.9.8 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.yardopts +5 -0
- data/HISTORY.markdown +14 -10
- data/README.markdown +293 -98
- data/Rakefile +19 -24
- data/couchbase.gemspec +25 -7
- data/ext/couchbase_ext/couchbase_ext.c +2332 -0
- data/ext/couchbase_ext/extconf.rb +102 -0
- data/lib/couchbase.rb +20 -30
- data/lib/couchbase/bucket.rb +43 -112
- data/lib/couchbase/version.rb +3 -2
- data/tasks/benchmark.rake +6 -0
- data/tasks/compile.rake +52 -0
- data/tasks/doc.rake +27 -0
- data/tasks/test.rake +94 -0
- data/tasks/util.rake +21 -0
- data/test/profile/.gitignore +1 -0
- data/test/profile/Gemfile +6 -0
- data/test/profile/benchmark.rb +195 -0
- data/test/setup.rb +107 -18
- data/test/test_arithmetic.rb +98 -0
- data/test/test_async.rb +211 -0
- data/test/test_bucket.rb +126 -23
- data/test/test_cas.rb +59 -0
- data/test/test_couchbase.rb +22 -3
- data/test/test_delete.rb +63 -0
- data/test/test_errors.rb +82 -0
- data/test/test_flush.rb +49 -0
- data/test/test_format.rb +98 -0
- data/test/test_get.rb +236 -0
- data/test/test_stats.rb +53 -0
- data/test/test_store.rb +186 -0
- data/test/test_touch.rb +57 -0
- data/test/test_version.rb +17 -0
- metadata +72 -58
- data/lib/couchbase/couchdb.rb +0 -107
- data/lib/couchbase/document.rb +0 -71
- data/lib/couchbase/http_status.rb +0 -118
- data/lib/couchbase/latch.rb +0 -71
- data/lib/couchbase/memcached.rb +0 -372
- data/lib/couchbase/node.rb +0 -49
- data/lib/couchbase/rest_client.rb +0 -124
- data/lib/couchbase/view.rb +0 -182
- data/test/support/buckets-config.json +0 -843
- data/test/support/sample_design_doc.json +0 -9
- data/test/test_couchdb.rb +0 -98
- data/test/test_document.rb +0 -11
- data/test/test_latch.rb +0 -88
- data/test/test_memcached.rb +0 -59
- data/test/test_rest_client.rb +0 -14
- data/test/test_view.rb +0 -98
data/test/test_couchdb.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'setup')
|
2
|
-
|
3
|
-
class TestCouchdb < MiniTest::Unit::TestCase
|
4
|
-
def setup
|
5
|
-
@bucket = Couchbase.new('http://localhost:8091/pools/default')
|
6
|
-
end
|
7
|
-
|
8
|
-
def test_that_it_could_connect_to_couchdb
|
9
|
-
server_uri = @bucket.next_node.couch_api_base[/http:\/\/[^\/]+/]
|
10
|
-
assert_equal %w(couchbase couchdb version), @bucket.http_get(server_uri).keys.sort
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_that_it_raises_error_if_couch_api_isnt_implemented
|
14
|
-
bucket = Couchbase.new('http://localhost:8091/pools/default')
|
15
|
-
bucket.nodes.each{|node| node.couch_api_base = nil}
|
16
|
-
assert_raises(Couchbase::NotImplemented) do
|
17
|
-
bucket.design_docs
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_that_it_could_create_doc_using_memcached_api
|
22
|
-
# cleanup
|
23
|
-
@bucket.delete(test_id) rescue Memcached::NotFound
|
24
|
-
@bucket.delete_design_doc(test_id)
|
25
|
-
|
26
|
-
@bucket[test_id] = {'msg' => 'hello world'}
|
27
|
-
@bucket.save_design_doc('_id' => "_design/#{test_id}",
|
28
|
-
'views' => {'all' => {'map' => 'function(doc){if(doc.msg){emit(doc._id, doc.msg)}}'}})
|
29
|
-
assert_operation_completed { database_ready(@bucket) }
|
30
|
-
ddoc = @bucket.design_docs[test_id]
|
31
|
-
assert ddoc, "design document '_design/#{test_id}' not found"
|
32
|
-
doc = ddoc.all.detect{|doc| doc['id'] == test_id && doc['value'] == 'hello world'}
|
33
|
-
assert doc, "object '#{test_id}' not found"
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_that_it_could_remove_design_doc
|
37
|
-
@bucket.delete_design_doc(test_id)
|
38
|
-
@bucket[test_id] = {'msg' => 'hello world'}
|
39
|
-
@bucket.save_design_doc('_id' => "_design/#{test_id}",
|
40
|
-
'views' => {'all' => {'map' => 'function(doc){if(doc.msg){emit(doc._id, doc.msg)}}'}})
|
41
|
-
assert_operation_completed { database_ready(@bucket) }
|
42
|
-
ddoc = @bucket.design_docs[test_id]
|
43
|
-
assert ddoc, "design document '_design/#{test_id}' not found"
|
44
|
-
@bucket.delete_design_doc("_design/#{test_id}")
|
45
|
-
ddoc = @bucket.design_docs[test_id]
|
46
|
-
refute ddoc, "design document '_design/#{test_id}' still here"
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_it_creates_design_doc_from_string
|
50
|
-
doc = <<-EOD
|
51
|
-
{
|
52
|
-
"_id": "_design/#{test_id}",
|
53
|
-
"language": "javascript",
|
54
|
-
"views": {
|
55
|
-
"all": {
|
56
|
-
"map": "function(doc){ if(doc.msg){ emit(doc._id, doc.msg) } }"
|
57
|
-
}
|
58
|
-
}
|
59
|
-
}
|
60
|
-
EOD
|
61
|
-
|
62
|
-
@bucket.delete_design_doc(test_id)
|
63
|
-
@bucket.save_design_doc(doc)
|
64
|
-
assert_operation_completed { database_ready(@bucket) }
|
65
|
-
assert @bucket.design_docs[test_id], "design document '_design/#{test_id}' not found"
|
66
|
-
end
|
67
|
-
|
68
|
-
def test_it_creates_design_doc_from_io
|
69
|
-
doc = File.open(File.join(File.dirname(__FILE__), 'support', 'sample_design_doc.json'))
|
70
|
-
@bucket.delete_design_doc(test_id)
|
71
|
-
@bucket.save_design_doc(doc)
|
72
|
-
assert_operation_completed { database_ready(@bucket) }
|
73
|
-
assert @bucket.design_docs[test_id], "design document '_design/#{test_id}' not found"
|
74
|
-
end
|
75
|
-
|
76
|
-
def test_it_creates_design_doc_from_hash
|
77
|
-
doc = {
|
78
|
-
"_id" => "_design/#{test_id}",
|
79
|
-
"language" => "javascript",
|
80
|
-
"views" => {
|
81
|
-
"all" => {
|
82
|
-
"map" => "function(doc){ if(doc.msg){ emit(doc._id, doc.msg) } }"
|
83
|
-
}
|
84
|
-
}
|
85
|
-
}
|
86
|
-
|
87
|
-
@bucket.delete_design_doc(test_id)
|
88
|
-
@bucket.save_design_doc(doc)
|
89
|
-
assert_operation_completed { database_ready(@bucket) }
|
90
|
-
assert @bucket.design_docs[test_id], "design document '_design/#{test_id}' not found"
|
91
|
-
end
|
92
|
-
|
93
|
-
protected
|
94
|
-
|
95
|
-
def test_id
|
96
|
-
name = caller.first[/.*[` ](.*)'/, 1]
|
97
|
-
end
|
98
|
-
end
|
data/test/test_document.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'couchbase'
|
3
|
-
|
4
|
-
class TestView < MiniTest::Unit::TestCase
|
5
|
-
def test_that_it_defines_views_for_design_documents_only
|
6
|
-
design_doc = Couchbase::Document.new(:mock, {'_id' => '_design/foo', 'views' => {'all' => {'map' => 'function(doc){}'}}})
|
7
|
-
assert_respond_to(design_doc, :all)
|
8
|
-
regular_doc = Couchbase::Document.new(:mock, {'_id' => 'foo', 'views' => {'all' => {'map' => 'function(doc){}'}}})
|
9
|
-
refute_respond_to(regular_doc, :all)
|
10
|
-
end
|
11
|
-
end
|
data/test/test_latch.rb
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'setup')
|
2
|
-
|
3
|
-
class TestLatch < MiniTest::Unit::TestCase
|
4
|
-
def test_properly_initialize
|
5
|
-
l = Couchbase::Latch.new(true, false)
|
6
|
-
assert_equal(true, l.state)
|
7
|
-
assert_equal(false, l.target)
|
8
|
-
end
|
9
|
-
|
10
|
-
def test_basic_latch_usage
|
11
|
-
latch = Couchbase::Latch.new(:dirty, :ready)
|
12
|
-
obj = "bar"
|
13
|
-
Thread.new do
|
14
|
-
obj = "foo"
|
15
|
-
latch.toggle
|
16
|
-
end
|
17
|
-
latch.wait
|
18
|
-
assert_equal(:ready, latch.state)
|
19
|
-
assert_equal("foo", obj)
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_basic_latch_usage_inverted
|
23
|
-
latch = Couchbase::Latch.new(:dirty, :ready)
|
24
|
-
obj = "bar"
|
25
|
-
Thread.new do
|
26
|
-
latch.wait
|
27
|
-
assert_equal(:ready, latch.state)
|
28
|
-
assert_equal("foo", obj)
|
29
|
-
end
|
30
|
-
obj = "foo"
|
31
|
-
latch.toggle
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_latch_with_identical_values_skips_wait
|
35
|
-
latch = Couchbase::Latch.new(:ready, :ready)
|
36
|
-
latch.wait
|
37
|
-
assert_equal(:ready, latch.state)
|
38
|
-
end
|
39
|
-
|
40
|
-
def test_toggle_with_two_chained_threads
|
41
|
-
latch = Couchbase::Latch.new(:start, :end)
|
42
|
-
name = "foo"
|
43
|
-
Thread.new do
|
44
|
-
Thread.new do
|
45
|
-
name = "bar"
|
46
|
-
latch.toggle
|
47
|
-
end
|
48
|
-
end
|
49
|
-
latch.wait
|
50
|
-
assert_equal(:end, latch.state)
|
51
|
-
assert_equal("bar", name)
|
52
|
-
end
|
53
|
-
|
54
|
-
def test_toggle_with_multiple_waiters
|
55
|
-
proceed_latch = Couchbase::Latch.new(:start, :end)
|
56
|
-
result = :bar
|
57
|
-
Thread.new do
|
58
|
-
proceed_latch.wait
|
59
|
-
assert_equal(:foo, result)
|
60
|
-
end
|
61
|
-
Thread.new do
|
62
|
-
proceed_latch.wait
|
63
|
-
assert_equal(:foo, result)
|
64
|
-
end
|
65
|
-
assert_equal(:bar, result)
|
66
|
-
proceed_latch.toggle
|
67
|
-
assert_equal(:end, proceed_latch.state)
|
68
|
-
end
|
69
|
-
|
70
|
-
def test_interleaved_latches
|
71
|
-
check_latch = Couchbase::Latch.new(:dirty, :ready)
|
72
|
-
change_1_latch = Couchbase::Latch.new(:dirty, :ready)
|
73
|
-
change_2_latch = Couchbase::Latch.new(:dirty, :ready)
|
74
|
-
name = "foo"
|
75
|
-
Thread.new do
|
76
|
-
name = "bar"
|
77
|
-
change_1_latch.toggle
|
78
|
-
check_latch.wait
|
79
|
-
name = "man"
|
80
|
-
change_2_latch.toggle
|
81
|
-
end
|
82
|
-
change_1_latch.wait
|
83
|
-
assert_equal("bar", name)
|
84
|
-
check_latch.toggle
|
85
|
-
change_2_latch.wait
|
86
|
-
assert_equal("man", name)
|
87
|
-
end
|
88
|
-
end
|
data/test/test_memcached.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'setup')
|
2
|
-
|
3
|
-
class TestMemcached < MiniTest::Unit::TestCase
|
4
|
-
|
5
|
-
def test_race_absence_during_initialization
|
6
|
-
session = connect
|
7
|
-
assert_raises(Memcached::NotFound) do
|
8
|
-
session.get(test_id)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_experimental_features_is_always_on
|
13
|
-
assert_respond_to connect, :touch
|
14
|
-
assert_respond_to connect(:experimental_features => false), :touch
|
15
|
-
assert_respond_to connect('experimental_features' => false), :touch
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_single_get
|
19
|
-
session = connect
|
20
|
-
session.set(test_id, "foo")
|
21
|
-
assert "foo", session.get(test_id)
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_single_get_missing
|
25
|
-
assert_raises(Memcached::NotFound) do
|
26
|
-
connect.get("missing-key")
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_multi_get
|
31
|
-
session = connect
|
32
|
-
session.set(test_id(1), "foo")
|
33
|
-
session.set(test_id(2), "bar")
|
34
|
-
expected = {test_id(1) => "foo", test_id(2) => "bar"}
|
35
|
-
assert expected, session.get(test_id(1), test_id(2))
|
36
|
-
ids = [1, 2].map{|n| test_id(n)}
|
37
|
-
assert expected, session.get(ids)
|
38
|
-
end
|
39
|
-
|
40
|
-
def test_multi_get_missing
|
41
|
-
session = connect
|
42
|
-
session.set(test_id(1), "foo")
|
43
|
-
expected = {test_id(1) => "foo"}
|
44
|
-
assert expected, session.get(test_id(1), test_id(2))
|
45
|
-
ids = [1, 2].map{|n| test_id(n)}
|
46
|
-
assert expected, session.get(ids)
|
47
|
-
end
|
48
|
-
|
49
|
-
protected
|
50
|
-
|
51
|
-
def connect(options = {})
|
52
|
-
uri = options.delete(:pool_uri) || "http://localhost:8091/pools/default"
|
53
|
-
Couchbase.new(uri, options)
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_id(suffix = nil)
|
57
|
-
"#{caller.first[/.*[` ](.*)'/, 1]}#{suffix}"
|
58
|
-
end
|
59
|
-
end
|
data/test/test_rest_client.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'couchbase'
|
3
|
-
|
4
|
-
class TestRestClient < MiniTest::Unit::TestCase
|
5
|
-
class RestClientMock
|
6
|
-
extend Couchbase::RestClient
|
7
|
-
end
|
8
|
-
|
9
|
-
def test_that_build_uri_duplicates_string
|
10
|
-
uri = "http://example.com/"
|
11
|
-
assert_equal "http://example.com/?foo=bar", RestClientMock.send(:build_query, uri, {'foo' => 'bar'})
|
12
|
-
assert_equal "http://example.com/", uri
|
13
|
-
end
|
14
|
-
end
|
data/test/test_view.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'setup')
|
2
|
-
|
3
|
-
class TestView < MiniTest::Unit::TestCase
|
4
|
-
def test_pagination
|
5
|
-
connection = populate_database
|
6
|
-
view = connection.design_docs['test_view'].all
|
7
|
-
|
8
|
-
# fetch all records
|
9
|
-
collection = view.fetch(:limit => 10)
|
10
|
-
assert_equal 10, collection.size
|
11
|
-
assert_equal 100, collection.total_entries
|
12
|
-
|
13
|
-
# fetch with reduce
|
14
|
-
view = connection.design_docs['test_view'].sum
|
15
|
-
docs = view.fetch(:limit => 2, :group => true)
|
16
|
-
assert_equal 2, docs.size
|
17
|
-
assert_equal nil, docs.total_entries
|
18
|
-
|
19
|
-
assert_instance_of Couchbase::View, connection.all_docs
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_when_stream_has_errors_it_raises_error_by_default
|
23
|
-
response = <<-EOR
|
24
|
-
{
|
25
|
-
"total_rows": 0,
|
26
|
-
"rows": [ ],
|
27
|
-
"errors": [
|
28
|
-
{
|
29
|
-
"from": "127.0.0.1:5984",
|
30
|
-
"reason": "Design document `_design/testfoobar` missing in database `test_db_b`."
|
31
|
-
},
|
32
|
-
{
|
33
|
-
"from": "http:// localhost:5984/_view_merge/",
|
34
|
-
"reason": "Design document `_design/testfoobar` missing in database `test_db_c`."
|
35
|
-
}
|
36
|
-
]
|
37
|
-
}
|
38
|
-
EOR
|
39
|
-
view = Couchbase::View.new(stub(:curl_easy => response),
|
40
|
-
"http://localhost:5984/default/_design/test/_view/all")
|
41
|
-
assert_raises(Couchbase::ViewError) do
|
42
|
-
view.fetch
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_when_stream_has_errors_and_error_callback_provided_it_executes_the_callback
|
47
|
-
response = <<-EOR
|
48
|
-
{
|
49
|
-
"total_rows": 0,
|
50
|
-
"rows": [ ],
|
51
|
-
"errors": [
|
52
|
-
{
|
53
|
-
"from": "127.0.0.1:5984",
|
54
|
-
"reason": "Design document `_design/testfoobar` missing in database `test_db_b`."
|
55
|
-
},
|
56
|
-
{
|
57
|
-
"from": "http:// localhost:5984/_view_merge/",
|
58
|
-
"reason": "Design document `_design/testfoobar` missing in database `test_db_c`."
|
59
|
-
}
|
60
|
-
]
|
61
|
-
}
|
62
|
-
EOR
|
63
|
-
view = Couchbase::View.new(stub(:curl_easy => response),
|
64
|
-
"http://localhost:5984/default/_design/test/_view/all")
|
65
|
-
errcount = 0
|
66
|
-
view.on_error{|from, reason| errcount += 1}
|
67
|
-
view.fetch
|
68
|
-
assert 2, errcount
|
69
|
-
end
|
70
|
-
|
71
|
-
protected
|
72
|
-
|
73
|
-
def populate_database
|
74
|
-
connection = Couchbase.new('http://localhost:8091/pools/default')
|
75
|
-
# clear storage
|
76
|
-
connection.flush
|
77
|
-
# save 100 documents
|
78
|
-
toys = %w(buzz rex bo hamm slink potato)
|
79
|
-
100.times do |t|
|
80
|
-
connection["test_view_#{t}"]= {:counter => t+1, :toy => toys[t%6]}
|
81
|
-
end
|
82
|
-
|
83
|
-
connection.delete_design_doc('test_view')
|
84
|
-
connection.save_design_doc('_id' => '_design/test_view',
|
85
|
-
'views' => {
|
86
|
-
'all' => {'map' => 'function(doc){if(doc.counter){emit(doc._id, doc)}}'},
|
87
|
-
'sum' => {'map' => 'function(doc){if(doc.counter){emit(doc.toy, doc.counter)}}',
|
88
|
-
'reduce' => 'function(keys,values,rereduce){return sum(values)}'}})
|
89
|
-
|
90
|
-
assert connection.design_docs['test_view']
|
91
|
-
|
92
|
-
assert_operation_completed do
|
93
|
-
database_ready(connection) && connection.all_docs.count > 100
|
94
|
-
end
|
95
|
-
connection
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|