couchbase 0.9.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,9 +0,0 @@
1
- {
2
- "_id": "_design/test_it_creates_design_doc_from_io",
3
- "language": "javascript",
4
- "views": {
5
- "all": {
6
- "map": "function(doc){ if(doc.msg){ emit(doc._id, doc.msg) } }"
7
- }
8
- }
9
- }
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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