riak-client-noenc 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +42 -0
- data/.rspec +1 -0
- data/Gemfile +17 -0
- data/Guardfile +20 -0
- data/LICENSE.md +16 -0
- data/README.markdown +640 -0
- data/RELEASE_NOTES.md +392 -0
- data/Rakefile +119 -0
- data/lib/riak.rb +22 -0
- data/lib/riak/bucket.rb +297 -0
- data/lib/riak/bucket_properties.rb +74 -0
- data/lib/riak/bucket_type.rb +77 -0
- data/lib/riak/bucket_typed/bucket.rb +121 -0
- data/lib/riak/client.rb +433 -0
- data/lib/riak/client/beefcake/bucket_properties_operator.rb +178 -0
- data/lib/riak/client/beefcake/crdt/counter_loader.rb +18 -0
- data/lib/riak/client/beefcake/crdt/map_loader.rb +64 -0
- data/lib/riak/client/beefcake/crdt/set_loader.rb +18 -0
- data/lib/riak/client/beefcake/crdt_loader.rb +84 -0
- data/lib/riak/client/beefcake/crdt_operator.rb +223 -0
- data/lib/riak/client/beefcake/footer +4 -0
- data/lib/riak/client/beefcake/header +6 -0
- data/lib/riak/client/beefcake/message_codes.rb +89 -0
- data/lib/riak/client/beefcake/message_overlay.rb +87 -0
- data/lib/riak/client/beefcake/messages.rb +772 -0
- data/lib/riak/client/beefcake/object_methods.rb +112 -0
- data/lib/riak/client/beefcake/protocol.rb +105 -0
- data/lib/riak/client/beefcake/socket.rb +260 -0
- data/lib/riak/client/beefcake_protobuffs_backend.rb +538 -0
- data/lib/riak/client/decaying.rb +36 -0
- data/lib/riak/client/feature_detection.rb +120 -0
- data/lib/riak/client/instrumentation.rb +19 -0
- data/lib/riak/client/node.rb +49 -0
- data/lib/riak/client/protobuffs_backend.rb +143 -0
- data/lib/riak/client/search.rb +27 -0
- data/lib/riak/client/yokozuna.rb +52 -0
- data/lib/riak/conflict.rb +13 -0
- data/lib/riak/core_ext.rb +7 -0
- data/lib/riak/core_ext/blank.rb +53 -0
- data/lib/riak/core_ext/deep_dup.rb +13 -0
- data/lib/riak/core_ext/extract_options.rb +7 -0
- data/lib/riak/core_ext/json.rb +15 -0
- data/lib/riak/core_ext/slice.rb +18 -0
- data/lib/riak/core_ext/stringify_keys.rb +10 -0
- data/lib/riak/core_ext/symbolize_keys.rb +10 -0
- data/lib/riak/core_ext/to_param.rb +31 -0
- data/lib/riak/counter.rb +101 -0
- data/lib/riak/crdt.rb +21 -0
- data/lib/riak/crdt/base.rb +183 -0
- data/lib/riak/crdt/batch_counter.rb +19 -0
- data/lib/riak/crdt/batch_map.rb +41 -0
- data/lib/riak/crdt/counter.rb +82 -0
- data/lib/riak/crdt/inner_counter.rb +81 -0
- data/lib/riak/crdt/inner_flag.rb +42 -0
- data/lib/riak/crdt/inner_map.rb +75 -0
- data/lib/riak/crdt/inner_register.rb +26 -0
- data/lib/riak/crdt/inner_set.rb +102 -0
- data/lib/riak/crdt/map.rb +121 -0
- data/lib/riak/crdt/operation.rb +19 -0
- data/lib/riak/crdt/set.rb +166 -0
- data/lib/riak/crdt/typed_collection.rb +181 -0
- data/lib/riak/encoding.rb +6 -0
- data/lib/riak/errors/backend_creation.rb +9 -0
- data/lib/riak/errors/base.rb +9 -0
- data/lib/riak/errors/connection_error.rb +50 -0
- data/lib/riak/errors/crdt_error.rb +38 -0
- data/lib/riak/errors/failed_request.rb +58 -0
- data/lib/riak/errors/protobuffs_error.rb +11 -0
- data/lib/riak/errors/search_error.rb +35 -0
- data/lib/riak/i18n.rb +7 -0
- data/lib/riak/index_collection.rb +71 -0
- data/lib/riak/instrumentation.rb +6 -0
- data/lib/riak/json.rb +52 -0
- data/lib/riak/link.rb +96 -0
- data/lib/riak/list_buckets.rb +28 -0
- data/lib/riak/locale/en.yml +107 -0
- data/lib/riak/locale/fr.yml +51 -0
- data/lib/riak/map_reduce.rb +295 -0
- data/lib/riak/map_reduce/filter_builder.rb +103 -0
- data/lib/riak/map_reduce/phase.rb +98 -0
- data/lib/riak/map_reduce/results.rb +49 -0
- data/lib/riak/map_reduce_error.rb +7 -0
- data/lib/riak/multiget.rb +122 -0
- data/lib/riak/preflist_item.rb +7 -0
- data/lib/riak/rcontent.rb +173 -0
- data/lib/riak/robject.rb +222 -0
- data/lib/riak/search.rb +11 -0
- data/lib/riak/search/index.rb +87 -0
- data/lib/riak/search/query.rb +141 -0
- data/lib/riak/search/result_collection.rb +144 -0
- data/lib/riak/search/result_document.rb +129 -0
- data/lib/riak/search/schema.rb +65 -0
- data/lib/riak/secondary_index.rb +81 -0
- data/lib/riak/serializers.rb +73 -0
- data/lib/riak/stamp.rb +77 -0
- data/lib/riak/util/escape.rb +80 -0
- data/lib/riak/util/tcp_socket_extensions.rb +58 -0
- data/lib/riak/util/translation.rb +18 -0
- data/lib/riak/version.rb +3 -0
- data/lib/riak/walk_spec.rb +145 -0
- data/spec/failover/failover.rb +59 -0
- data/spec/fixtures/bitcask.txt +25 -0
- data/spec/fixtures/cat.jpg +0 -0
- data/spec/fixtures/multipart-basic-conflict.txt +15 -0
- data/spec/fixtures/multipart-blank.txt +7 -0
- data/spec/fixtures/multipart-mapreduce.txt +10 -0
- data/spec/fixtures/multipart-with-body.txt +16 -0
- data/spec/fixtures/multipart-with-marked-tombstones.txt +17 -0
- data/spec/fixtures/multipart-with-unmarked-tombstone.txt +16 -0
- data/spec/fixtures/server.cert.crt +15 -0
- data/spec/fixtures/server.cert.key +15 -0
- data/spec/fixtures/test.pem +1 -0
- data/spec/fixtures/yz_schema_template.xml +18 -0
- data/spec/integration/riak/bucket_types_spec.rb +270 -0
- data/spec/integration/riak/conflict_resolution_spec.rb +96 -0
- data/spec/integration/riak/counters_spec.rb +36 -0
- data/spec/integration/riak/crdt/configuration_spec.rb +37 -0
- data/spec/integration/riak/crdt_search_spec.rb +176 -0
- data/spec/integration/riak/crdt_spec.rb +250 -0
- data/spec/integration/riak/crdt_validation/map_spec.rb +63 -0
- data/spec/integration/riak/crdt_validation/set_spec.rb +122 -0
- data/spec/integration/riak/preflist_spec.rb +31 -0
- data/spec/integration/riak/properties_spec.rb +69 -0
- data/spec/integration/riak/protobuffs/interrupted_request_spec.rb +33 -0
- data/spec/integration/riak/protobuffs_backends_spec.rb +40 -0
- data/spec/integration/riak/search_spec.rb +104 -0
- data/spec/integration/riak/secondary_index_spec.rb +72 -0
- data/spec/integration/riak/security_spec.rb +100 -0
- data/spec/integration/riak/threading_spec.rb +150 -0
- data/spec/integration/yokozuna/index_spec.rb +61 -0
- data/spec/integration/yokozuna/queries_spec.rb +115 -0
- data/spec/integration/yokozuna/schema_spec.rb +49 -0
- data/spec/riak/beefcake_protobuffs_backend/bucket_properties_operator_spec.rb +247 -0
- data/spec/riak/beefcake_protobuffs_backend/crdt_operator_spec.rb +222 -0
- data/spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb +23 -0
- data/spec/riak/beefcake_protobuffs_backend/protocol_spec.rb +189 -0
- data/spec/riak/beefcake_protobuffs_backend_spec.rb +162 -0
- data/spec/riak/bucket_properties_spec.rb +135 -0
- data/spec/riak/bucket_spec.rb +275 -0
- data/spec/riak/bucket_type_spec.rb +50 -0
- data/spec/riak/bucket_typed/bucket_spec.rb +62 -0
- data/spec/riak/client_spec.rb +246 -0
- data/spec/riak/core_ext/to_param_spec.rb +15 -0
- data/spec/riak/counter_spec.rb +122 -0
- data/spec/riak/crdt/counter_spec.rb +55 -0
- data/spec/riak/crdt/inner_counter_spec.rb +21 -0
- data/spec/riak/crdt/inner_flag_spec.rb +39 -0
- data/spec/riak/crdt/inner_map_spec.rb +47 -0
- data/spec/riak/crdt/inner_register_spec.rb +40 -0
- data/spec/riak/crdt/inner_set_spec.rb +33 -0
- data/spec/riak/crdt/map_spec.rb +78 -0
- data/spec/riak/crdt/set_spec.rb +61 -0
- data/spec/riak/crdt/shared_examples.rb +74 -0
- data/spec/riak/crdt/typed_collection_spec.rb +225 -0
- data/spec/riak/escape_spec.rb +72 -0
- data/spec/riak/feature_detection_spec.rb +77 -0
- data/spec/riak/index_collection_spec.rb +53 -0
- data/spec/riak/instrumentation_spec.rb +124 -0
- data/spec/riak/link_spec.rb +85 -0
- data/spec/riak/list_buckets_spec.rb +41 -0
- data/spec/riak/map_reduce/filter_builder_spec.rb +32 -0
- data/spec/riak/map_reduce/phase_spec.rb +142 -0
- data/spec/riak/map_reduce_spec.rb +434 -0
- data/spec/riak/multiget_spec.rb +81 -0
- data/spec/riak/node_spec.rb +26 -0
- data/spec/riak/robject_spec.rb +496 -0
- data/spec/riak/search/index_spec.rb +72 -0
- data/spec/riak/search/query_spec.rb +88 -0
- data/spec/riak/search/result_collection_spec.rb +89 -0
- data/spec/riak/search/result_document_spec.rb +106 -0
- data/spec/riak/search/schema_spec.rb +63 -0
- data/spec/riak/search_spec.rb +107 -0
- data/spec/riak/secondary_index_spec.rb +225 -0
- data/spec/riak/serializers_spec.rb +121 -0
- data/spec/riak/stamp_spec.rb +54 -0
- data/spec/riak/walk_spec_spec.rb +203 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/support/certs/README.md +13 -0
- data/spec/support/certs/ca.crt +21 -0
- data/spec/support/certs/client.crl +13 -0
- data/spec/support/certs/client.crt +94 -0
- data/spec/support/certs/client.csr +18 -0
- data/spec/support/certs/client.key +27 -0
- data/spec/support/certs/empty_ca.crt +21 -0
- data/spec/support/certs/server.crl +13 -0
- data/spec/support/certs/server.crt +94 -0
- data/spec/support/certs/server.key +27 -0
- data/spec/support/crdt_search_config.rb +112 -0
- data/spec/support/crdt_search_fixtures.rb +42 -0
- data/spec/support/integration_setup.rb +10 -0
- data/spec/support/search_config.rb +83 -0
- data/spec/support/search_corpus_setup.rb +39 -0
- data/spec/support/test_client.rb +46 -0
- data/spec/support/test_client.yml.example +10 -0
- data/spec/support/unified_backend_examples.rb +380 -0
- data/spec/support/version_filter.rb +12 -0
- data/spec/support/wait_until.rb +20 -0
- metadata +511 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
module CrdtSearchFixtures
|
2
|
+
def map_result_score
|
3
|
+
43.21
|
4
|
+
end
|
5
|
+
|
6
|
+
def maps_type_name
|
7
|
+
'maps'
|
8
|
+
end
|
9
|
+
|
10
|
+
def maps_bucket_type
|
11
|
+
return @maps_bucket_type if defined? @maps_bucket_type
|
12
|
+
|
13
|
+
@maps_bucket_type = instance_double('Riak::BucketType').tap do |bt|
|
14
|
+
allow(bt).to receive(:bucket).
|
15
|
+
with(bucket_name).
|
16
|
+
and_return(map_bucket)
|
17
|
+
allow(bt).to receive(:data_type_class).
|
18
|
+
and_return(Riak::Crdt::Map)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def map_bucket
|
23
|
+
@map_bucket ||= instance_double('Riak::BucketTyped::Bucket')
|
24
|
+
end
|
25
|
+
|
26
|
+
def map_raw
|
27
|
+
@map_raw ||= {
|
28
|
+
'score'=>map_result_score,
|
29
|
+
'_yz_rb'=>bucket_name,
|
30
|
+
'_yz_rt'=>maps_type_name,
|
31
|
+
'_yz_rk'=>'map-key'
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def map_results
|
36
|
+
@map_results ||= Riak::Search::ResultDocument.new client, map_raw
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
RSpec.configure do |config|
|
41
|
+
config.include CrdtSearchFixtures, crdt_search_fixtures: true
|
42
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# auto-tag all integration specs with :integration => true
|
2
|
+
module IntegrationSpecs
|
3
|
+
def self.included(klass)
|
4
|
+
klass.metadata[:integration] = true
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.include IntegrationSpecs, file_path: %r{spec/integration}
|
10
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module SearchConfig
|
2
|
+
include TestClient
|
3
|
+
|
4
|
+
def search_bucket
|
5
|
+
return @search_bucket if defined? @search_bucket
|
6
|
+
type = test_client.bucket_type 'yokozuna'
|
7
|
+
@search_bucket = type.bucket "search_config-#{random_key}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def index_name
|
11
|
+
@index_name ||= search_bucket.name
|
12
|
+
end
|
13
|
+
|
14
|
+
def index
|
15
|
+
return @index if defined? @index
|
16
|
+
create_index
|
17
|
+
@index = Riak::Search::Index.new test_client, index_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_index
|
21
|
+
return if defined? @index_exists
|
22
|
+
|
23
|
+
test_client.create_search_index index_name
|
24
|
+
|
25
|
+
@index_exists = true
|
26
|
+
end
|
27
|
+
|
28
|
+
def configure_bucket
|
29
|
+
return if defined? @bucket_configured
|
30
|
+
|
31
|
+
create_index
|
32
|
+
|
33
|
+
test_client.set_bucket_props(search_bucket,
|
34
|
+
{ search_index: index_name },
|
35
|
+
'yokozuna')
|
36
|
+
|
37
|
+
wait_until do
|
38
|
+
props = test_client.get_bucket_props search_bucket, type: 'yokozuna'
|
39
|
+
props['search_index'] == index_name
|
40
|
+
end
|
41
|
+
|
42
|
+
@bucket_configred = true
|
43
|
+
end
|
44
|
+
|
45
|
+
def load_corpus
|
46
|
+
return if defined? @corpus_loaded
|
47
|
+
|
48
|
+
configure_bucket
|
49
|
+
|
50
|
+
old_encoding = Encoding.default_external
|
51
|
+
Encoding.default_external = Encoding::UTF_8
|
52
|
+
|
53
|
+
IO.foreach('spec/fixtures/bitcask.txt').with_index do |para, idx|
|
54
|
+
next if para =~ /^\s*$|introduction|chapter/ui
|
55
|
+
|
56
|
+
Riak::RObject.new(search_bucket, "bitcask-#{idx}") do |obj|
|
57
|
+
obj.content_type = 'text/plain'
|
58
|
+
obj.raw_data = para
|
59
|
+
obj.store
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
Encoding.default_external = old_encoding
|
64
|
+
|
65
|
+
wait_until do
|
66
|
+
results = @client.search(index_name,
|
67
|
+
'contain your entire keyspace',
|
68
|
+
df: 'text')
|
69
|
+
|
70
|
+
results['docs'].length > 0
|
71
|
+
end
|
72
|
+
|
73
|
+
@corpus_loaded = true
|
74
|
+
end
|
75
|
+
|
76
|
+
def schema_xml(schema_name)
|
77
|
+
File.read('spec/fixtures/yz_schema_template.xml').sub('SCHEMA_NAME', schema_name)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
RSpec.configure do |config|
|
82
|
+
config.include SearchConfig, search_config: true
|
83
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
shared_context "search corpus setup" do
|
3
|
+
before do
|
4
|
+
@search_bucket = random_bucket 'search_test'
|
5
|
+
@backend.create_search_index @search_bucket.name
|
6
|
+
|
7
|
+
wait_until{ !@backend.get_search_index(@search_bucket.name).nil? }
|
8
|
+
|
9
|
+
@client.set_bucket_props(@search_bucket,
|
10
|
+
{search_index: @search_bucket.name},
|
11
|
+
'yokozuna')
|
12
|
+
|
13
|
+
wait_until do
|
14
|
+
p = @client.get_bucket_props(@search_bucket, type: 'yokozuna')
|
15
|
+
p['search_index'] == @search_bucket.name
|
16
|
+
end
|
17
|
+
|
18
|
+
idx = 0
|
19
|
+
old_encoding = Encoding.default_external
|
20
|
+
Encoding.default_external = Encoding::UTF_8
|
21
|
+
IO.foreach("spec/fixtures/bitcask.txt") do |para|
|
22
|
+
next if para =~ /^\s*$|introduction|chapter/ui
|
23
|
+
idx += 1
|
24
|
+
Riak::RObject.new(@search_bucket, "bitcask-#{idx}") do |obj|
|
25
|
+
obj.content_type = 'text/plain'
|
26
|
+
obj.raw_data = para
|
27
|
+
@backend.store_object(obj, type: 'yokozuna')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
Encoding.default_external = old_encoding
|
31
|
+
|
32
|
+
wait_until do
|
33
|
+
results = @backend.search(@search_bucket.name,
|
34
|
+
'contain your entire keyspace',
|
35
|
+
df: 'text')
|
36
|
+
results['docs'].length > 0
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module TestClient
|
2
|
+
def test_client
|
3
|
+
if defined? $test_client and $test_client.ping
|
4
|
+
return $test_client
|
5
|
+
end
|
6
|
+
|
7
|
+
candidate_client = Riak::Client.new test_client_configuration
|
8
|
+
|
9
|
+
live = candidate_client.ping
|
10
|
+
|
11
|
+
return $test_client = candidate_client if live
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_client_configuration
|
15
|
+
TestClient.test_client_configuration
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.test_client_configuration
|
19
|
+
if defined? $test_client_configuration
|
20
|
+
return $test_client_configuration
|
21
|
+
end
|
22
|
+
|
23
|
+
config_path = File.expand_path '../test_client.yml', __FILE__
|
24
|
+
config = YAML.load_file(config_path).symbolize_keys
|
25
|
+
|
26
|
+
if config[:nodes]
|
27
|
+
new_nodes = config[:nodes].map(&:symbolize_keys)
|
28
|
+
config[:nodes] = new_nodes
|
29
|
+
end
|
30
|
+
|
31
|
+
$test_client_configuration = config
|
32
|
+
end
|
33
|
+
|
34
|
+
def random_bucket(name = 'test_client')
|
35
|
+
bucket_name = [name, Time.now.to_i, random_key].join('-')
|
36
|
+
test_client.bucket bucket_name
|
37
|
+
end
|
38
|
+
|
39
|
+
def random_key
|
40
|
+
rand(36**10).to_s(36)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
RSpec.configure do |config|
|
45
|
+
config.include TestClient, test_client: true
|
46
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# This file is used for configuring test_client used by
|
2
|
+
# many of the integration tests.
|
3
|
+
#
|
4
|
+
# Simply set the arguments you'd normally pass to
|
5
|
+
# Riak::Client.new in the file.
|
6
|
+
#
|
7
|
+
# Don't run multiple nodes, integration tests include
|
8
|
+
# quorum checks that may result in race conditions.
|
9
|
+
|
10
|
+
pb_port: 10017
|
@@ -0,0 +1,380 @@
|
|
1
|
+
shared_examples_for "Unified backend API" do
|
2
|
+
# ping
|
3
|
+
it "pings the server" do
|
4
|
+
expect(@backend.ping).to be_truthy
|
5
|
+
end
|
6
|
+
|
7
|
+
it "gets info about the server" do
|
8
|
+
expect{ @backend.server_info }.to_not raise_error
|
9
|
+
|
10
|
+
expect(@backend.server_info).to include(:node, :server_version)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "gets client id" do
|
14
|
+
expect{ @backend.get_client_id }.to_not raise_error
|
15
|
+
|
16
|
+
expect(@backend.get_client_id).to be_a String
|
17
|
+
end
|
18
|
+
|
19
|
+
# fetch_object
|
20
|
+
context "fetching an object" do
|
21
|
+
before do
|
22
|
+
@robject = Riak::RObject.new(@bucket, "fetch")
|
23
|
+
@robject.content_type = "application/json"
|
24
|
+
@robject.data = { "test" => "pass" }
|
25
|
+
@robject.indexes['test_bin'] << 'pass'
|
26
|
+
@robject.links << Riak::Link.new('/riak/foo/bar', 'next')
|
27
|
+
@robject.links << Riak::Link.new('/riak/foo/baz', 'next')
|
28
|
+
@backend.store_object(@robject)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "finds a stored object" do
|
32
|
+
robj = @backend.fetch_object(@bucket.name, "fetch")
|
33
|
+
expect(robj).to be_kind_of(Riak::RObject)
|
34
|
+
expect(robj.data).to eq({ "test" => "pass" })
|
35
|
+
expect(robj.links).to be_a Set
|
36
|
+
end
|
37
|
+
|
38
|
+
it "raises an error when the object is not found" do
|
39
|
+
begin
|
40
|
+
@backend.fetch_object(@bucket.name, "notfound")
|
41
|
+
rescue Riak::FailedRequest => exception
|
42
|
+
@exception = exception
|
43
|
+
end
|
44
|
+
expect(@exception).to be_kind_of(Riak::FailedRequest)
|
45
|
+
expect(@exception).to be_not_found
|
46
|
+
end
|
47
|
+
|
48
|
+
[1, 2, 3, :one, :quorum, :all, :default].each do |q|
|
49
|
+
it "accepts a R value of #{q.inspect} for the request" do
|
50
|
+
robj = @backend.fetch_object(@bucket.name, "fetch", :r => q)
|
51
|
+
expect(robj).to be_kind_of(Riak::RObject)
|
52
|
+
expect(robj.data).to eq({ "test" => "pass" })
|
53
|
+
end
|
54
|
+
|
55
|
+
it "accepts a PR value of #{q.inspect} for the request" do
|
56
|
+
robj = @backend.fetch_object(@bucket.name, "fetch", :pr => q)
|
57
|
+
expect(robj).to be_kind_of(Riak::RObject)
|
58
|
+
expect(robj.data).to eq({ "test" => "pass" })
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "marshals indexes properly", :retries => 5 do
|
63
|
+
robj = @backend.fetch_object(@bucket.name, 'fetch')
|
64
|
+
expect(robj.indexes['test_bin']).to be
|
65
|
+
expect(robj.indexes['test_bin']).to include('pass')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# reload_object
|
70
|
+
context "reloading an existing object" do
|
71
|
+
before do
|
72
|
+
@robject = Riak::RObject.new(@bucket, 'reload')
|
73
|
+
@robject.content_type = "application/json"
|
74
|
+
@robject.data = {"test" => "pass"}
|
75
|
+
@backend.store_object(@robject)
|
76
|
+
@robject2 = @backend.fetch_object(@bucket.name, "reload")
|
77
|
+
@robject2.data["test"] = "second"
|
78
|
+
@backend.store_object(@robject2, :returnbody => true)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "modifies the object with the reloaded data" do
|
82
|
+
@backend.reload_object(@robject)
|
83
|
+
end
|
84
|
+
|
85
|
+
[1, 2, 3, :one, :quorum, :all, :default].each do |q|
|
86
|
+
it "accepts a valid R value of #{q.inspect} for the request" do
|
87
|
+
@backend.reload_object(@robject, :r => q)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "accepts a valid PR value of #{q.inspect} for the request" do
|
91
|
+
@backend.reload_object(@robject, :pr => q)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
after do |example|
|
96
|
+
unless example.pending?
|
97
|
+
expect(@robject.vclock).to eq(@robject2.vclock)
|
98
|
+
expect(@robject.data['test']).to eq("second")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# store_object
|
104
|
+
context "storing an object" do
|
105
|
+
before do
|
106
|
+
@robject = Riak::RObject.new(@bucket, random_key)
|
107
|
+
@robject.content_type = "application/json"
|
108
|
+
@robject.data = {"test" => "pass"}
|
109
|
+
end
|
110
|
+
|
111
|
+
it "saves the object" do
|
112
|
+
@backend.store_object(@robject)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "modifies the object with the returned data if returnbody" do
|
116
|
+
@backend.store_object(@robject, :returnbody => true)
|
117
|
+
expect(@robject.vclock).to be_present
|
118
|
+
end
|
119
|
+
|
120
|
+
[1, 2, 3, :one, :quorum, :all, :default].each do |q|
|
121
|
+
it "accepts a W value of #{q.inspect} for the request" do
|
122
|
+
@backend.store_object(@robject, :returnbody => false, :w => q)
|
123
|
+
expect(@bucket.exists?(@robject.key)).to be_truthy
|
124
|
+
end
|
125
|
+
|
126
|
+
it "accepts a DW value of #{q.inspect} for the request" do
|
127
|
+
@backend.store_object(@robject, :returnbody => false, :w => :all, :dw => q)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "accepts a PW value of #{q.inspect} for the request" do
|
131
|
+
@backend.store_object(@robject, :returnbody => false, :pw => q)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
it "stores an object with indexes" do
|
136
|
+
@robject.indexes['foo_bin'] << 'bar'
|
137
|
+
@backend.store_object(@robject, :returnbody => true)
|
138
|
+
expect(@robject.indexes).to include('foo_bin')
|
139
|
+
expect(@robject.indexes['foo_bin']).to include('bar')
|
140
|
+
end
|
141
|
+
|
142
|
+
after do
|
143
|
+
expect { @backend.fetch_object(@bucket.name, @robject.key) }.not_to raise_error
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# delete_object
|
148
|
+
context "deleting an object" do
|
149
|
+
before do
|
150
|
+
@obj = Riak::RObject.new(@client.bucket("test"), "delete")
|
151
|
+
@obj.content_type = "application/json"
|
152
|
+
@obj.data = [1]
|
153
|
+
@backend.store_object(@obj)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "removes the object" do
|
157
|
+
@backend.delete_object("test", "delete")
|
158
|
+
expect(@obj.bucket.exists?("delete")).to be_falsey
|
159
|
+
end
|
160
|
+
|
161
|
+
[1, 2, 3, :one, :quorum, :all, :default].each do |q|
|
162
|
+
it "accepts an RW value of #{q.inspect} for the request" do
|
163
|
+
@backend.delete_object("test", "delete", :rw => q)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
it "accepts a vclock value for the request" do
|
168
|
+
@backend.delete_object("test", "delete", :vclock => @obj.vclock)
|
169
|
+
end
|
170
|
+
|
171
|
+
after do
|
172
|
+
expect(@obj.bucket.exists?("delete")).to be_falsey
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# get_bucket_props
|
177
|
+
context "fetching bucket properties" do
|
178
|
+
it "fetches a hash of bucket properties" do
|
179
|
+
props = @backend.get_bucket_props("test")
|
180
|
+
expect(props).to be_kind_of(Hash)
|
181
|
+
expect(props).to include("n_val")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# set_bucket_props
|
186
|
+
context "setting bucket properties" do
|
187
|
+
it "stores properties for the bucket" do
|
188
|
+
@backend.set_bucket_props("test", {"n_val" => 3})
|
189
|
+
expect(@backend.get_bucket_props("test")["n_val"]).to eq(3)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# list_keys
|
194
|
+
context "listing keys in a bucket" do
|
195
|
+
before do
|
196
|
+
@list_bucket = random_bucket 'unified_backend_list_keys'
|
197
|
+
obj = Riak::RObject.new(@list_bucket, "keys")
|
198
|
+
obj.content_type = "application/json"
|
199
|
+
obj.data = [1]
|
200
|
+
@backend.store_object(obj)
|
201
|
+
end
|
202
|
+
|
203
|
+
it "fetches an array of string keys" do
|
204
|
+
expect(@backend.list_keys(@list_bucket)).to eq(["keys"])
|
205
|
+
end
|
206
|
+
|
207
|
+
context "streaming through a block" do
|
208
|
+
it "handles a large number of keys" do
|
209
|
+
obj = Riak::RObject.new(@list_bucket)
|
210
|
+
obj.content_type = "application/json"
|
211
|
+
obj.data = [1]
|
212
|
+
750.times do |i|
|
213
|
+
obj.key = i.to_s
|
214
|
+
obj.store(:w => 1, :dw => 0, :returnbody => false)
|
215
|
+
end
|
216
|
+
@backend.list_keys(@list_bucket) do |keys|
|
217
|
+
expect(keys).to be_all {|k| k == 'keys' || (0..749).include?(k.to_i) }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
it "passes an array of keys to the block" do
|
222
|
+
@backend.list_keys(@list_bucket) do |keys|
|
223
|
+
expect(keys).to eq(["keys"]) unless keys.empty?
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
it "allows requests issued inside the block to execute" do
|
228
|
+
errors = []
|
229
|
+
@backend.list_keys(@list_bucket) do |keys|
|
230
|
+
keys.each do |key|
|
231
|
+
begin
|
232
|
+
@client.get_object(@list_bucket, key)
|
233
|
+
rescue => e
|
234
|
+
errors << e
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
expect(errors).to be_empty
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# list_buckets
|
244
|
+
context "listing buckets" do
|
245
|
+
before do
|
246
|
+
obj = Riak::RObject.new(@client.bucket("test"), "buckets")
|
247
|
+
obj.content_type = "application/json"
|
248
|
+
obj.data = [1]
|
249
|
+
@backend.store_object(obj)
|
250
|
+
end
|
251
|
+
|
252
|
+
it "fetches a list of string bucket names" do
|
253
|
+
list = @backend.list_buckets
|
254
|
+
expect(list).to be_kind_of(Array)
|
255
|
+
expect(list).to include("test")
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
# get_index
|
260
|
+
context "querying secondary indexes" do
|
261
|
+
before do
|
262
|
+
50.times do |i|
|
263
|
+
@client.bucket('test').new(i.to_s).tap do |obj|
|
264
|
+
obj.indexes["index_int"] << i
|
265
|
+
obj.data = [i]
|
266
|
+
@backend.store_object(obj)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
it "finds keys for an equality query" do
|
272
|
+
expect(@backend.get_index('test', 'index_int', 20)).to eq(["20"])
|
273
|
+
end
|
274
|
+
|
275
|
+
it "finds keys for a range query" do
|
276
|
+
expect(@backend.get_index('test', 'index_int', 19..21)).to match_array(%w(19 20 21))
|
277
|
+
end
|
278
|
+
|
279
|
+
it "returns an empty array for a query that does not match any keys" do
|
280
|
+
expect(@backend.get_index('test', 'index_int', 10000)).to eq([])
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# mapred
|
285
|
+
context "performing MapReduce" do
|
286
|
+
before do
|
287
|
+
@mapred_bucket = random_bucket("mapred_test")
|
288
|
+
obj = Riak::RObject.new(@mapred_bucket, "1")
|
289
|
+
obj.content_type = "application/json"
|
290
|
+
obj.data = {"value" => "1" }
|
291
|
+
@backend.store_object(obj)
|
292
|
+
@mapred = Riak::MapReduce.new(@client).
|
293
|
+
add(@mapred_bucket.name).
|
294
|
+
map("Riak.mapValuesJson", :keep => true)
|
295
|
+
end
|
296
|
+
|
297
|
+
it "doesn't raise an error without phases" do
|
298
|
+
@mapred.query.clear
|
299
|
+
@backend.mapred(@mapred)
|
300
|
+
end
|
301
|
+
|
302
|
+
it "performs a simple MapReduce request" do
|
303
|
+
expect(@backend.mapred(@mapred)).to eq([{"value" => "1"}])
|
304
|
+
end
|
305
|
+
|
306
|
+
it "returns an ordered array of results when multiple phases are kept" do
|
307
|
+
@mapred.reduce("function(objects){ return objects; }", :keep => true)
|
308
|
+
expect(@backend.mapred(@mapred)).to eq([[{"value" => "1"}], [{"value" => "1"}]])
|
309
|
+
end
|
310
|
+
|
311
|
+
it "doesn't remove empty phase results when multiple phases are kept" do
|
312
|
+
@mapred.reduce("function(){ return []; }", :keep => true)
|
313
|
+
expect(@backend.mapred(@mapred)).to eq([[{"value" => "1"}], []])
|
314
|
+
end
|
315
|
+
|
316
|
+
context "streaming results through a block" do
|
317
|
+
it "passes phase number and result to the block" do
|
318
|
+
@backend.mapred(@mapred) do |phase, result|
|
319
|
+
unless result.empty?
|
320
|
+
expect(phase).to eq(0)
|
321
|
+
expect(result).to eq([{"value" => "1"}])
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
it "allows requests issued inside the block to execute" do
|
327
|
+
errors = []
|
328
|
+
@backend.mapred(@mapred) do |phase, result|
|
329
|
+
unless result.empty?
|
330
|
+
result.each do |v|
|
331
|
+
begin
|
332
|
+
@client.get_object(@mapred_bucket, v['value'])
|
333
|
+
rescue => e
|
334
|
+
errors << e
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
expect(errors).to be_empty
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
# search
|
345
|
+
context "searching fulltext indexes" do
|
346
|
+
# Search functionality existed since Riak 0.13, but PBC only
|
347
|
+
# entered into the picture in 1.2. PBC can support searches
|
348
|
+
# against 1.1 and earlier nodes using MapReduce emulation, but has
|
349
|
+
# limited functionality. We'll enter separate tests for the
|
350
|
+
# pre-1.2 functionality.
|
351
|
+
include_context "search corpus setup"
|
352
|
+
|
353
|
+
it 'finds indexed documents, returning ids' do
|
354
|
+
results = @backend.search @search_bucket.name, 'predictable operations behavior', fl: '_yz_rk', df: 'text'
|
355
|
+
expect(results).to have_key 'docs'
|
356
|
+
expect(results).to have_key 'max_score'
|
357
|
+
expect(results).to have_key 'num_found'
|
358
|
+
|
359
|
+
found = results['docs'].any? do |e|
|
360
|
+
e['_yz_rk'] == 'bitcask-10'
|
361
|
+
end
|
362
|
+
|
363
|
+
expect(found).to be_truthy
|
364
|
+
end
|
365
|
+
|
366
|
+
it 'finds indexed documents, returning documents' do
|
367
|
+
# For now use '*' until #122 is merged into riak_search
|
368
|
+
results = @backend.search @search_bucket.name, 'predictable operations behavior', fl: '_yz_rk', df: 'text'
|
369
|
+
expect(results).to have_key 'docs'
|
370
|
+
expect(results).to have_key 'max_score'
|
371
|
+
expect(results).to have_key 'num_found'
|
372
|
+
|
373
|
+
found = results['docs'].any? do |e|
|
374
|
+
e['_yz_rk'] == 'bitcask-10'
|
375
|
+
end
|
376
|
+
|
377
|
+
expect(found).to be_truthy
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|