riak-client 1.4.5 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/Gemfile +0 -1
  4. data/{LICENSE → LICENSE.md} +0 -0
  5. data/README.markdown +211 -66
  6. data/RELEASE_NOTES.md +22 -47
  7. data/Rakefile +45 -0
  8. data/lib/riak.rb +1 -1
  9. data/lib/riak/bucket.rb +2 -2
  10. data/lib/riak/client.rb +22 -195
  11. data/lib/riak/client/beefcake/crdt_loader.rb +127 -0
  12. data/lib/riak/client/beefcake/crdt_operator.rb +222 -0
  13. data/lib/riak/client/beefcake/footer +4 -0
  14. data/lib/riak/client/beefcake/header +6 -0
  15. data/lib/riak/client/beefcake/message_codes.rb +29 -0
  16. data/lib/riak/client/beefcake/message_overlay.rb +61 -0
  17. data/lib/riak/client/beefcake/messages.rb +733 -371
  18. data/lib/riak/client/beefcake/object_methods.rb +1 -1
  19. data/lib/riak/client/beefcake/protocol.rb +105 -0
  20. data/lib/riak/client/beefcake/socket.rb +243 -0
  21. data/lib/riak/client/beefcake_protobuffs_backend.rb +262 -122
  22. data/lib/riak/client/node.rb +4 -75
  23. data/lib/riak/client/protobuffs_backend.rb +6 -14
  24. data/lib/riak/client/search.rb +0 -64
  25. data/lib/riak/client/yokozuna.rb +52 -0
  26. data/lib/riak/counter.rb +1 -1
  27. data/lib/riak/crdt.rb +21 -0
  28. data/lib/riak/crdt/base.rb +97 -0
  29. data/lib/riak/crdt/batch_counter.rb +19 -0
  30. data/lib/riak/crdt/batch_map.rb +41 -0
  31. data/lib/riak/crdt/counter.rb +71 -0
  32. data/lib/riak/crdt/inner_counter.rb +74 -0
  33. data/lib/riak/crdt/inner_flag.rb +42 -0
  34. data/lib/riak/crdt/inner_map.rb +53 -0
  35. data/lib/riak/crdt/inner_register.rb +26 -0
  36. data/lib/riak/crdt/inner_set.rb +95 -0
  37. data/lib/riak/crdt/map.rb +88 -0
  38. data/lib/riak/crdt/operation.rb +19 -0
  39. data/lib/riak/crdt/set.rb +156 -0
  40. data/lib/riak/crdt/typed_collection.rb +131 -0
  41. data/lib/riak/errors/base.rb +9 -0
  42. data/lib/riak/errors/connection_error.rb +44 -0
  43. data/lib/riak/errors/crdt_error.rb +18 -0
  44. data/lib/riak/errors/failed_request.rb +56 -0
  45. data/lib/riak/errors/protobuffs_error.rb +11 -0
  46. data/lib/riak/i18n.rb +2 -0
  47. data/lib/riak/json.rb +1 -1
  48. data/lib/riak/locale/en.yml +26 -1
  49. data/lib/riak/locale/fr.yml +0 -1
  50. data/lib/riak/map_reduce.rb +1 -1
  51. data/lib/riak/map_reduce/results.rb +1 -1
  52. data/lib/riak/multiget.rb +1 -2
  53. data/lib/riak/rcontent.rb +8 -3
  54. data/lib/riak/robject.rb +2 -8
  55. data/lib/riak/secondary_index.rb +4 -4
  56. data/lib/riak/serializers.rb +1 -1
  57. data/lib/riak/util/escape.rb +3 -5
  58. data/lib/riak/version.rb +1 -1
  59. data/lib/riak/walk_spec.rb +7 -3
  60. data/riak-client.gemspec +10 -8
  61. data/spec/fixtures/bitcask.txt +25 -0
  62. data/spec/integration/riak/bucket_types_spec.rb +61 -0
  63. data/spec/integration/riak/counters_spec.rb +17 -32
  64. data/spec/integration/riak/crdt_spec.rb +181 -0
  65. data/spec/integration/riak/crdt_validation/map_spec.rb +63 -0
  66. data/spec/integration/riak/crdt_validation/set_spec.rb +122 -0
  67. data/spec/integration/riak/protobuffs_backends_spec.rb +9 -26
  68. data/spec/integration/riak/security_spec.rb +94 -0
  69. data/spec/integration/riak/threading_spec.rb +24 -67
  70. data/spec/integration/yokozuna/index_spec.rb +61 -0
  71. data/spec/integration/yokozuna/queries_spec.rb +116 -0
  72. data/spec/integration/yokozuna/schema_spec.rb +49 -0
  73. data/spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb +222 -0
  74. data/spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb +4 -4
  75. data/spec/riak/beefcake_protobuffs_backend/protocol_spec.rb +189 -0
  76. data/spec/riak/beefcake_protobuffs_backend/socket_spec.rb +151 -0
  77. data/spec/riak/beefcake_protobuffs_backend_spec.rb +68 -106
  78. data/spec/riak/bucket_spec.rb +81 -77
  79. data/spec/riak/client_spec.rb +43 -340
  80. data/spec/riak/core_ext/to_param_spec.rb +2 -2
  81. data/spec/riak/counter_spec.rb +20 -20
  82. data/spec/riak/crdt/counter_spec.rb +52 -0
  83. data/spec/riak/crdt/inner_counter_spec.rb +21 -0
  84. data/spec/riak/crdt/inner_flag_spec.rb +39 -0
  85. data/spec/riak/crdt/inner_map_spec.rb +47 -0
  86. data/spec/riak/crdt/inner_register_spec.rb +40 -0
  87. data/spec/riak/crdt/inner_set_spec.rb +33 -0
  88. data/spec/riak/crdt/map_spec.rb +77 -0
  89. data/spec/riak/crdt/set_spec.rb +58 -0
  90. data/spec/riak/crdt/shared_examples.rb +74 -0
  91. data/spec/riak/crdt/typed_collection_spec.rb +231 -0
  92. data/spec/riak/escape_spec.rb +33 -37
  93. data/spec/riak/feature_detection_spec.rb +45 -45
  94. data/spec/riak/index_collection_spec.rb +12 -12
  95. data/spec/riak/link_spec.rb +34 -34
  96. data/spec/riak/list_buckets_spec.rb +7 -7
  97. data/spec/riak/map_reduce/filter_builder_spec.rb +6 -6
  98. data/spec/riak/map_reduce/phase_spec.rb +35 -35
  99. data/spec/riak/map_reduce_spec.rb +89 -87
  100. data/spec/riak/multiget_spec.rb +20 -15
  101. data/spec/riak/node_spec.rb +5 -152
  102. data/spec/riak/robject_spec.rb +95 -108
  103. data/spec/riak/search_spec.rb +17 -139
  104. data/spec/riak/secondary_index_spec.rb +49 -49
  105. data/spec/riak/serializers_spec.rb +9 -9
  106. data/spec/riak/stamp_spec.rb +9 -9
  107. data/spec/riak/walk_spec_spec.rb +46 -46
  108. data/spec/spec_helper.rb +14 -22
  109. data/spec/support/certs/README.md +13 -0
  110. data/spec/support/certs/ca.crt +22 -0
  111. data/spec/support/certs/client.crt +95 -0
  112. data/spec/support/certs/client.key +27 -0
  113. data/spec/support/certs/empty_ca.crt +21 -0
  114. data/spec/support/certs/server.crl +13 -0
  115. data/spec/support/certs/server.crt +95 -0
  116. data/spec/support/certs/server.key +27 -0
  117. data/spec/support/integration_setup.rb +1 -1
  118. data/spec/support/search_corpus_setup.rb +29 -8
  119. data/spec/support/test_client.rb +46 -0
  120. data/spec/support/test_client.yml.example +10 -0
  121. data/spec/support/unified_backend_examples.rb +104 -83
  122. data/spec/support/version_filter.rb +2 -2
  123. data/spec/support/wait_until.rb +14 -0
  124. metadata +134 -132
  125. data/erl_src/riak_kv_test014_backend.beam +0 -0
  126. data/erl_src/riak_kv_test014_backend.erl +0 -189
  127. data/erl_src/riak_kv_test_backend.beam +0 -0
  128. data/erl_src/riak_kv_test_backend.erl +0 -731
  129. data/erl_src/riak_search_test_backend.beam +0 -0
  130. data/erl_src/riak_search_test_backend.erl +0 -175
  131. data/lib/riak/client/excon_backend.rb +0 -172
  132. data/lib/riak/client/http_backend.rb +0 -413
  133. data/lib/riak/client/http_backend/bucket_streamer.rb +0 -15
  134. data/lib/riak/client/http_backend/chunked_json_streamer.rb +0 -42
  135. data/lib/riak/client/http_backend/configuration.rb +0 -227
  136. data/lib/riak/client/http_backend/key_streamer.rb +0 -15
  137. data/lib/riak/client/http_backend/object_methods.rb +0 -114
  138. data/lib/riak/client/http_backend/request_headers.rb +0 -34
  139. data/lib/riak/client/http_backend/transport_methods.rb +0 -201
  140. data/lib/riak/client/instrumentation.rb +0 -25
  141. data/lib/riak/client/net_http_backend.rb +0 -82
  142. data/lib/riak/cluster.rb +0 -151
  143. data/lib/riak/failed_request.rb +0 -81
  144. data/lib/riak/instrumentation.rb +0 -6
  145. data/lib/riak/node.rb +0 -40
  146. data/lib/riak/node/configuration.rb +0 -304
  147. data/lib/riak/node/console.rb +0 -133
  148. data/lib/riak/node/control.rb +0 -207
  149. data/lib/riak/node/defaults.rb +0 -85
  150. data/lib/riak/node/generation.rb +0 -127
  151. data/lib/riak/node/log.rb +0 -34
  152. data/lib/riak/node/version.rb +0 -29
  153. data/lib/riak/search.rb +0 -3
  154. data/lib/riak/test_server.rb +0 -89
  155. data/lib/riak/util/headers.rb +0 -32
  156. data/lib/riak/util/multipart.rb +0 -52
  157. data/lib/riak/util/multipart/stream_parser.rb +0 -62
  158. data/spec/fixtures/munchausen.txt +0 -1033
  159. data/spec/integration/riak/cluster_spec.rb +0 -88
  160. data/spec/integration/riak/http_backends_spec.rb +0 -180
  161. data/spec/integration/riak/node_spec.rb +0 -170
  162. data/spec/integration/riak/test_server_spec.rb +0 -57
  163. data/spec/riak/excon_backend_spec.rb +0 -102
  164. data/spec/riak/headers_spec.rb +0 -21
  165. data/spec/riak/http_backend/configuration_spec.rb +0 -273
  166. data/spec/riak/http_backend/object_methods_spec.rb +0 -243
  167. data/spec/riak/http_backend/transport_methods_spec.rb +0 -97
  168. data/spec/riak/http_backend_spec.rb +0 -367
  169. data/spec/riak/instrumentation_spec.rb +0 -167
  170. data/spec/riak/multipart_spec.rb +0 -23
  171. data/spec/riak/net_http_backend_spec.rb +0 -15
  172. data/spec/riak/stream_parser_spec.rb +0 -53
  173. data/spec/support/drb_mock_server.rb +0 -39
  174. data/spec/support/http_backend_implementation_examples.rb +0 -253
  175. data/spec/support/mock_server.rb +0 -81
  176. data/spec/support/mocks.rb +0 -4
  177. data/spec/support/riak_test.rb +0 -77
  178. data/spec/support/sometimes.rb +0 -46
  179. data/spec/support/test_server.rb +0 -61
  180. data/spec/support/test_server.yml.example +0 -14
@@ -1,97 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Riak::Client::HTTPBackend::TransportMethods do
4
- before :each do
5
- @client = Riak::Client.new
6
- @backend = Riak::Client::HTTPBackend.new(@client, @client.node)
7
- @backend.instance_variable_set(:@server_config, {})
8
- end
9
-
10
- it "should generate default headers for requests based on the client settings" do
11
- @client.client_id = "testing"
12
- @backend.default_headers.should == {"X-Riak-ClientId" => "testing", "Accept" => "multipart/mixed, application/json;q=0.7, */*;q=0.5"}
13
- end
14
-
15
- it "should generate a root URI based on the client settings" do
16
- @backend.root_uri.should be_kind_of(URI)
17
- @backend.root_uri.to_s.should == "http://127.0.0.1:8098"
18
- end
19
-
20
- it "should compute a URI from a relative resource path" do
21
- @backend.path("baz").should be_kind_of(URI)
22
- @backend.path("foo").to_s.should == "http://127.0.0.1:8098/foo"
23
- @backend.path("foo", "bar").to_s.should == "http://127.0.0.1:8098/foo/bar"
24
- @backend.path("/foo/bar").to_s.should == "http://127.0.0.1:8098/foo/bar"
25
- end
26
-
27
- it "should compute a URI from a relative resource path with a hash of query parameters" do
28
- @backend.path("baz", :r => 2).to_s.should == "http://127.0.0.1:8098/baz?r=2"
29
- end
30
-
31
- describe "verify_body!" do
32
- it "should raise an error if the body is not a string or IO or IO-like (responds to :read)" do
33
- lambda { @backend.verify_body!(nil) }.should raise_error(ArgumentError)
34
- lambda { @backend.verify_body!(File.open("spec/fixtures/cat.jpg")) }.should_not raise_error(ArgumentError)
35
- lambda { @backend.verify_body!(Tempfile.new('riak-spec')) }.should_not raise_error(ArgumentError)
36
- end
37
- end
38
-
39
- describe "detecting valid response codes" do
40
- it "should accept strings or integers for either argument" do
41
- @backend.should be_valid_response("300", "300")
42
- @backend.should be_valid_response(300, "300")
43
- @backend.should be_valid_response("300", 300)
44
- end
45
-
46
- it "should accept an array of strings or integers for the expected code" do
47
- @backend.should be_valid_response([200,304], "200")
48
- @backend.should be_valid_response(["200",304], "200")
49
- @backend.should be_valid_response([200,"304"], "200")
50
- @backend.should be_valid_response(["200","304"], "200")
51
- @backend.should be_valid_response([200,304], 200)
52
- end
53
-
54
- it "should be false when none of the response codes match" do
55
- @backend.should_not be_valid_response(200, 404)
56
- @backend.should_not be_valid_response(["200","304"], 404)
57
- @backend.should_not be_valid_response([200,304], 404)
58
- end
59
- end
60
-
61
- describe "detecting whether a body should be returned" do
62
- it "should be false when the method is :head" do
63
- @backend.should_not be_return_body(:head, 200, false)
64
- end
65
-
66
- it "should be false when the response code is 204, 205, or 304" do
67
- @backend.should_not be_return_body(:get, 204, false)
68
- @backend.should_not be_return_body(:get, 205, false)
69
- @backend.should_not be_return_body(:get, 304, false)
70
- end
71
-
72
- it "should be false when a streaming block was passed" do
73
- @backend.should_not be_return_body(:get, 200, true)
74
- end
75
-
76
- it "should be true when the method is not head, a code other than 204, 205, or 304 was given, and there was no streaming block" do
77
- [:get, :put, :post, :delete].each do |method|
78
- [100,101,200,201,202,203,206,300,301,302,303,305,307,400,401,
79
- 402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,
80
- 500,501,502,503,504,505].each do |code|
81
- @backend.should be_return_body(method, code, false)
82
- @backend.should be_return_body(method, code.to_s, false)
83
- end
84
- end
85
- end
86
- end
87
-
88
- it "should force subclasses to implement the perform method" do
89
- lambda { @backend.send(:perform, :get, "/foo", {}, 200) }.should raise_error(NotImplementedError)
90
- end
91
-
92
- it "should allow using the https protocol" do
93
- @client = Riak::Client.new(:protocol => 'https')
94
- @backend = Riak::Client::HTTPBackend.new(@client, @client.node)
95
- @backend.root_uri.to_s.should eq("https://127.0.0.1:8098")
96
- end
97
- end
@@ -1,367 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Riak::Client::HTTPBackend do
4
- before :each do
5
- @client = Riak::Client.new
6
- @node = @client.nodes.first
7
- @backend = Riak::Client::HTTPBackend.new(@client, @node)
8
- @backend.instance_variable_set(:@server_config, {})
9
- end
10
-
11
- it "should take the Riak::Client and Riak::Node when creating" do
12
- lambda { Riak::Client::HTTPBackend.new(nil) }.should raise_error(ArgumentError)
13
- lambda { Riak::Client::HTTPBackend.new(@client) }.should raise_error(ArgumentError)
14
- lambda { Riak::Client::HTTPBackend.new(@client, @node) }.should_not raise_error
15
- end
16
-
17
- it "should make the client accessible" do
18
- @backend.client.should == @client
19
- end
20
-
21
- it 'should make the node accessible' do
22
- @backend.node.should == @node
23
- end
24
-
25
- context "pinging the server" do
26
- it "should succeed on 200" do
27
- @backend.should_receive(:get).with(200, @backend.ping_path).and_return({:code => 200, :body => "OK"})
28
- @backend.ping.should be_true
29
- end
30
-
31
- it "should fail on any other code or error" do
32
- @backend.should_receive(:get).and_raise("socket closed")
33
- @backend.ping.should be_false
34
- end
35
- end
36
-
37
- context "fetching an object" do
38
- it "should perform a GET request and return an RObject" do
39
- @backend.should_receive(:get).with([200,300], @backend.object_path('foo', 'db')).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
40
- @backend.fetch_object("foo", "db").should be_kind_of(Riak::RObject)
41
- end
42
-
43
- it "should pass the R quorum as a query parameter" do
44
- @backend.should_receive(:get).with([200,300], @backend.object_path("foo", "db", {:r => 2})).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
45
- @backend.fetch_object("foo", "db", :r => 2)
46
- end
47
-
48
- it "should escape the bucket and key names" do
49
- @backend.should_receive(:get).with([200,300], @backend.object_path('foo ', ' bar')).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
50
- @backend.fetch_object('foo ',' bar').should be_kind_of(Riak::RObject)
51
- end
52
-
53
- it "should escape brackets in the bucket and key names" do
54
- @backend.should_receive(:get).with([200,300], @backend.object_path('[foo]', '[bar]')).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"name":"Riak","company":"Basho"}'})
55
- @backend.fetch_object('[foo]','[bar]').should be_kind_of(Riak::RObject)
56
- end
57
- end
58
-
59
- context "reloading an object" do
60
- before do
61
- @object = Riak::RObject.new(@client.bucket("foo"), "bar")
62
- end
63
-
64
- it "should use conditional request headers" do
65
- @object.etag = "etag"
66
- @backend.should_receive(:get).with([200,300,304], @backend.object_path('foo', 'bar'), {'If-None-Match' => "etag"}).and_return({:code => 304})
67
- @backend.reload_object(@object)
68
- end
69
-
70
- it "should return without modifying the object if the response is 304 Not Modified" do
71
- @backend.should_receive(:get).and_return({:code => 304})
72
- @backend.should_not_receive(:load_object)
73
- @backend.reload_object(@object)
74
- end
75
-
76
- it "should raise an exception when the response code is not 200 or 304" do
77
- @backend.should_receive(:get).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 500, {}, ''))
78
- lambda { @backend.reload_object(@object) }.should raise_error(Riak::FailedRequest)
79
- end
80
-
81
- it "should escape the bucket and key names" do
82
- # @bucket.should_receive(:name).and_return("some/deep/path")
83
- @object.bucket = @client.bucket("some/deep/path")
84
- @object.key = "another/deep/path"
85
- @backend.should_receive(:get).with([200,300,304], @backend.object_path(@object.bucket.name, @object.key), {}).and_return({:code => 304})
86
- @backend.reload_object(@object)
87
- end
88
- end
89
-
90
- context "storing an object" do
91
- before do
92
- @bucket = Riak::Bucket.new(@client, "foo")
93
- @object = Riak::RObject.new(@bucket)
94
- @object.content_type = "text/plain"
95
- @object.data = "This is some text."
96
- @headers = @backend.store_headers(@object)
97
- end
98
-
99
- it "should use the raw_data as the request body" do
100
- @object.content_type = "application/json"
101
- body = @object.raw_data = "{this is probably invalid json!}}"
102
- @backend.stub(:post).and_return({})
103
- @object.should_not_receive(:serialize)
104
- @backend.store_object(@object, :returnbody => false)
105
- end
106
-
107
- context "when the object has no key" do
108
- it "should issue a POST request to the bucket, and update the object properties (returning the body by default)" do
109
- @backend.should_receive(:post).with(201, @backend.object_path("foo", nil, {:returnbody => true}), "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 201})
110
- @backend.store_object(@object, :returnbody => true)
111
- @object.key.should == "somereallylongstring"
112
- @object.vclock.should == "areallylonghashvalue"
113
- end
114
-
115
- it "should include persistence-tuning parameters in the query string" do
116
- @backend.should_receive(:post).with(201, @backend.object_path("foo", nil, {:dw => 2, :returnbody => true}), "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 201})
117
- @backend.store_object(@object, :returnbody => true, :dw => 2)
118
- end
119
- end
120
-
121
- context "when the object has a key" do
122
- before :each do
123
- @object.key = "bar"
124
- end
125
-
126
- it "should issue a PUT request to the bucket, and update the object properties (returning the body by default)" do
127
- @backend.should_receive(:put).with([200,204,300], @backend.object_path("foo", "bar", {:returnbody => true}), "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 204})
128
- @backend.store_object(@object, :returnbody => true)
129
- @object.key.should == "somereallylongstring"
130
- @object.vclock.should == "areallylonghashvalue"
131
- end
132
-
133
- it "should include persistence-tuning parameters in the query string" do
134
- @backend.should_receive(:put).with([200,204,300], @backend.object_path("foo", "bar", {:w => 2, :returnbody => true}), "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/somereallylongstring"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 204})
135
- @backend.store_object(@object, :returnbody => true, :w => 2)
136
- end
137
- end
138
-
139
- context "when the object's key contains square brackets" do
140
- before :each do
141
- @object.key = "[bar]"
142
- end
143
-
144
- it "should escape the key name" do
145
- @backend.should_receive(:put).with([200,204,300], @backend.object_path("foo", "[bar]", {:returnbody => true}), "This is some text.", @headers).and_return({:headers => {'location' => ["/riak/foo/%5Bbar%5D"], "x-riak-vclock" => ["areallylonghashvalue"]}, :code => 204})
146
- @backend.store_object(@object, :returnbody => true)
147
- @object.key.should == "[bar]"
148
- end
149
- end
150
- end
151
-
152
- context "deleting an object" do
153
- it "should perform a DELETE request" do
154
- @backend.should_receive(:delete).with([204,404], @backend.object_path("foo", 'bar'), {}).and_return(:code => 204)
155
- @backend.delete_object("foo", "bar")
156
- end
157
-
158
- it "should perform a DELETE request with the provided vclock" do
159
- @backend.should_receive(:delete).with([204,404], @backend.object_path("foo", 'bar'), {'X-Riak-VClock' => "myvclock"}).and_return(:code => 204)
160
- @backend.delete_object('foo', 'bar', :vclock => "myvclock")
161
- end
162
-
163
- it "should perform a DELETE request with the requested quorum value" do
164
- @backend.should_receive(:delete).with([204,404], @backend.object_path("foo", 'bar', {:rw => 2}), {'X-Riak-VClock' => "myvclock"}).and_return(:code => 204)
165
- @backend.delete_object('foo', 'bar', :vclock => "myvclock", :rw => 2)
166
- end
167
- end
168
-
169
- context "fetching bucket properties" do
170
- it "should GET the bucket URL and parse the response as JSON" do
171
- @backend.should_receive(:get).with(200, @backend.bucket_properties_path('foo')).and_return({:body => '{"props":{"n_val":3}}'})
172
- @backend.get_bucket_props("foo").should == {"n_val" => 3}
173
- end
174
- end
175
-
176
- context "setting bucket properties" do
177
- it "should PUT the properties to the bucket URL as JSON" do
178
- @backend.should_receive(:put).with(204, @backend.bucket_properties_path('foo'), '{"props":{"n_val":2}}', {"Content-Type" => "application/json"}).and_return({:body => "", :headers => {}})
179
- @backend.set_bucket_props("foo", {:n_val => 2})
180
- end
181
- end
182
-
183
- context "listing keys" do
184
- it "should unescape key names" do
185
- @backend.should_receive(:get).with(200, @backend.key_list_path('foo')).and_return({:headers => {"content-type" => ["application/json"]}, :body => '{"keys":["bar%20baz"]}'})
186
- @backend.list_keys("foo").should == ["bar baz"]
187
- end
188
- end
189
-
190
- context "listing buckets" do
191
- before(:each) do
192
- @backend.should_receive(:get).with(200, @backend.bucket_list_path).and_return({:body => '{"buckets":["foo", "bar", "baz"]}'})
193
- end
194
-
195
- context "given no arguments" do
196
- it "should GET the bucket list URL and parse the response as JSON" do
197
- @backend.list_buckets.should == ["foo", "bar", "baz"]
198
- end
199
- end
200
-
201
- context "given a hash of options" do
202
- it "should GET the bucket list URL and parse the response as JSON" do
203
- @backend.list_buckets({}).should == ["foo", "bar", "baz"]
204
- end
205
- end
206
- end
207
-
208
- context "performing a MapReduce query" do
209
- before do
210
- @mr = Riak::MapReduce.new(@client).map("Riak.mapValues", :keep => true)
211
- end
212
-
213
- it "should issue POST request to the mapred endpoint" do
214
- @backend.should_receive(:post).with(200, @backend.mapred_path(:chunked => true), @mr.to_json, hash_including("Content-Type" => "application/json")).and_yield(%Q|--foo\r\nContent-Type: application/json\r\n\r\n{"phase":0,"data":[]}\r\n--foo--\r\n|)
215
- @backend.mapred(@mr)
216
- end
217
-
218
- it "should vivify JSON responses" do
219
- @backend.stub!(:post).and_yield(%Q|--foo\r\nContent-Type: application/json\r\n\r\n{"phase":0,"data":[{"key":"value"}]}\r\n--foo--\r\n|)
220
- @backend.mapred(@mr).should == [{"key" => "value"}]
221
- end
222
-
223
- it "should return the full response hash for non-JSON responses" do
224
- pending "It is not clear when Riak would ever return a non-JSON or non-multipart response for mapred."
225
- response = {:code => 200, :headers => {'content-type' => ["text/plain"]}, :body => 'This is some text.'}
226
- @backend.stub!(:post).and_return(response)
227
- @backend.mapred(@mr).should == response
228
- end
229
-
230
- it "should stream results through the block" do
231
- data = File.read("spec/fixtures/multipart-mapreduce.txt")
232
- @backend.should_receive(:post).with(200, @backend.mapred_path(:chunked => true), @mr.to_json, hash_including("Content-Type" => "application/json")).and_yield(data)
233
- block = mock
234
- block.should_receive(:ping).twice.and_return(true)
235
- @backend.mapred(@mr) do |phase, data|
236
- block.ping
237
- phase.should == 0
238
- data.should have(1).item
239
- end
240
- end
241
- end
242
-
243
- context "getting statistics" do
244
- it "should get the status URL and parse the response as JSON" do
245
- @backend.should_receive(:get).with(200, @backend.stats_path).and_return({:body => '{"vnode_gets":20348}'})
246
- @backend.stats.should == {"vnode_gets" => 20348}
247
- end
248
- end
249
-
250
- context "performing a link-walking query" do
251
- before do
252
- @bucket = Riak::Bucket.new(@client, "foo")
253
- @object = Riak::RObject.new(@bucket, "bar")
254
- @body = File.read(File.expand_path("#{File.dirname(__FILE__)}/../fixtures/multipart-with-body.txt"))
255
- @specs = [Riak::WalkSpec.new(:tag => "next", :keep => true)]
256
- end
257
-
258
- it "should perform a GET request for the given object and walk specs" do
259
- @backend.should_receive(:get).with(200, @backend.link_walk_path(@bucket.name, @object.key, @specs)).and_return(:headers => {"content-type" => ["multipart/mixed; boundary=12345"]}, :body => "\n--12345\nContent-Type: multipart/mixed; boundary=09876\n\n--09876--\n\n--12345--\n")
260
- @backend.link_walk(@object, @specs)
261
- end
262
-
263
- it "should parse the results into arrays of objects" do
264
- @backend.should_receive(:get).and_return(:headers => {"content-type" => ["multipart/mixed; boundary=5EiMOjuGavQ2IbXAqsJPLLfJNlA"]}, :body => @body)
265
- results = @backend.link_walk(@object, @specs)
266
- results.should be_kind_of(Array)
267
- results.first.should be_kind_of(Array)
268
- obj = results.first.first
269
- obj.should be_kind_of(Riak::RObject)
270
- obj.content_type.should == "text/plain"
271
- obj.key.should == "baz"
272
- obj.bucket.should == @bucket
273
- end
274
-
275
- it "should assign the bucket for newly parsed objects" do
276
- @backend.stub!(:get).and_return(:headers => {"content-type" => ["multipart/mixed; boundary=5EiMOjuGavQ2IbXAqsJPLLfJNlA"]}, :body => @body)
277
- @client.should_receive(:bucket).with("foo").and_return(@bucket)
278
- @backend.link_walk(@object, @specs)
279
- end
280
-
281
- it "should discard unmarked tombstones" do
282
- @backend.should_receive(:get).and_return(:headers => {"content-type" => ["multipart/mixed; boundary=CvfrSTCWwIiwezy0Zt1B2zwKgS7"]}, :body => File.read(File.expand_path("../../fixtures/multipart-with-unmarked-tombstone.txt", __FILE__)))
283
- results = @backend.link_walk(@object, @specs)
284
- results.first.should be_empty
285
- end
286
-
287
- it "should discard marked tombstones" do
288
- @backend.should_receive(:get).and_return(:headers => {"content-type" => ["multipart/mixed; boundary=ADqgQtdmA5iQgyR5UGzX6V3HZtI"]}, :body => File.read(File.expand_path("../../fixtures/multipart-with-marked-tombstones.txt", __FILE__)))
289
- results = @backend.link_walk(@object, @specs)
290
- results.first.should be_empty
291
- end
292
- end
293
-
294
- context "performing a search" do
295
- before { @backend.send(:server_config)[:riak_solr_searcher_wm] = '/solr' }
296
-
297
- it "should request the searcher resource" do
298
- @backend.should_receive(:get).
299
- with(200, @backend.solr_select_path(nil, 'foo', {'wt' => 'json'})).
300
- and_return(:code => 200, :headers => {"content-type" => ['application/json']}, :body => '{}')
301
- @backend.search(nil, 'foo')
302
- end
303
-
304
- it "should vivify and normalize JSON responses" do
305
- @backend.should_receive(:get).and_return({:code => 200, :headers => {"content-type"=>["application/json"]}, :body => '{"response":{"docs":[{"id":"foo","fields":{},"props":{}}],"maxScore":"0.0345","numFound":1}}'})
306
- @backend.search(nil, "foo").should == {"docs" => [{"id" => "foo"}], "max_score" => 0.0345, "num_found" => 1}
307
- end
308
-
309
- it "should return non-JSON responses raw" do
310
- @backend.should_receive(:get).and_return({:code => 200, :headers => {"content-type"=>["text/plain"]}, :body => '{"response":{"docs":["foo"]}}'})
311
- @backend.search(nil, "foo").should == '{"response":{"docs":["foo"]}}'
312
- end
313
- end
314
-
315
- context "updating a search index" do
316
- before { @backend.send(:server_config)[:riak_solr_indexer_wm] = '/solr' }
317
-
318
- it "should request the indexer resource" do
319
- @backend.should_receive(:post).with(200, @backend.solr_update_path(nil), 'postbody', {"Content-Type" => "text/xml"})
320
- @backend.update_search_index(nil, 'postbody')
321
- end
322
- end
323
- context "Luwak" do
324
- before { @backend.send(:server_config)[:luwak_wm_file] = '/luwak' }
325
- context "fetching a file" do
326
- before do
327
-
328
- @backend.should_receive(:get).with(200, @backend.luwak_path("greeting.txt")).and_yield("Hello,").and_yield(" world!").and_return({:code => 200, :headers => {"content-type" => ["text/plain"]}})
329
- end
330
-
331
- it "should return a tempfile when no block is given" do
332
- file = @backend.get_file("greeting.txt")
333
- file.open {|f| f.read.should == "Hello, world!" }
334
- end
335
-
336
- it "should expose the original key and content-type on the temporary file" do
337
- file = @backend.get_file("greeting.txt")
338
- file.original_filename.should == 'greeting.txt'
339
- file.content_type.should == 'text/plain'
340
- end
341
-
342
- it "should yield chunks of the file to the block and return nil" do
343
- string = ""
344
- result = @backend.get_file("greeting.txt"){|chunk| string << chunk }
345
- result.should be_nil
346
- string.should == "Hello, world!"
347
- end
348
- end
349
-
350
- context "storing a file" do
351
- it "should store a file with the given filename" do
352
- @backend.should_receive(:put).with(204, @backend.luwak_path("greeting.txt"), anything, {"Content-Type" => "text/plain"}).and_return({:code => 204, :headers => {}})
353
- @backend.store_file("greeting.txt", "text/plain", "Hello, world").should == 'greeting.txt'
354
- end
355
-
356
- it "should store a file and return the key/filename when none is given" do
357
- @backend.should_receive(:post).with(201, @backend.luwak_path(nil), anything, {"Content-Type" => "text/plain"}).and_return({:code => 201, :headers => {'location' => ["/luwak/123456789"]}})
358
- @backend.store_file("text/plain", "Hello, world").should == '123456789'
359
- end
360
- end
361
-
362
- it "should detect whether a file exists" do
363
- @backend.should_receive(:head).with([200,404], @backend.luwak_path("foo")).and_return({:code => 200})
364
- @backend.file_exists?("foo").should be_true
365
- end
366
- end
367
- end