riak-client 2.2.2 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/RELEASE_NOTES.md +16 -0
  4. data/Rakefile +3 -2
  5. data/lib/riak/client/beefcake/message_codes.rb +12 -0
  6. data/lib/riak/client/beefcake/messages.rb +205 -5
  7. data/lib/riak/client/beefcake/object_methods.rb +1 -2
  8. data/lib/riak/client/beefcake/operator.rb +9 -0
  9. data/lib/riak/client/beefcake/time_series_delete_operator.rb +24 -0
  10. data/lib/riak/client/beefcake/time_series_get_operator.rb +35 -0
  11. data/lib/riak/client/beefcake/time_series_list_operator.rb +42 -0
  12. data/lib/riak/client/beefcake/time_series_put_operator.rb +32 -0
  13. data/lib/riak/client/beefcake/time_series_query_operator.rb +42 -0
  14. data/lib/riak/client/beefcake/ts_cell_codec.rb +63 -0
  15. data/lib/riak/client/beefcake_protobuffs_backend.rb +5 -0
  16. data/lib/riak/client.rb +3 -0
  17. data/lib/riak/errors/time_series.rb +23 -0
  18. data/lib/riak/locale/en.yml +5 -0
  19. data/lib/riak/time_series/collection.rb +5 -0
  20. data/lib/riak/time_series/deletion.rb +26 -0
  21. data/lib/riak/time_series/list.rb +66 -0
  22. data/lib/riak/time_series/query.rb +43 -0
  23. data/lib/riak/time_series/read.rb +18 -0
  24. data/lib/riak/time_series/row.rb +4 -0
  25. data/lib/riak/time_series/submission.rb +32 -0
  26. data/lib/riak/time_series.rb +17 -0
  27. data/lib/riak/version.rb +1 -1
  28. data/lib/riak.rb +16 -0
  29. data/spec/integration/riak/bucket_types_spec.rb +6 -6
  30. data/spec/integration/riak/time_series_spec.rb +168 -0
  31. data/spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb +31 -2
  32. data/spec/riak/beefcake_protobuffs_backend/ts_cell_codec_spec.rb +116 -0
  33. data/spec/riak/client_spec.rb +11 -0
  34. data/spec/riak/crdt/inner_flag_spec.rb +1 -1
  35. data/spec/riak/time_series/deletion_spec.rb +33 -0
  36. data/spec/riak/time_series/listing_spec.rb +50 -0
  37. data/spec/riak/time_series/submission_spec.rb +35 -0
  38. data/spec/spec_helper.rb +1 -0
  39. data/spec/support/test_client.yml +0 -1
  40. metadata +29 -3
@@ -0,0 +1,5 @@
1
+ module Riak::TimeSeries
2
+ class Collection < Array
3
+ attr_accessor :columns
4
+ end
5
+ end
@@ -0,0 +1,26 @@
1
+ module Riak::TimeSeries
2
+
3
+ # Delete entries from Riak Time Series.
4
+ class Deletion
5
+ attr_accessor :key
6
+ attr_accessor :options
7
+
8
+ attr_reader :client
9
+ attr_reader :table_name
10
+
11
+ def initialize(client, table_name)
12
+ @client = client
13
+ @table_name = table_name
14
+ @options = Hash.new
15
+ end
16
+
17
+ def delete!
18
+ client.backend do |be|
19
+ be.time_series_delete_operator.delete(table_name,
20
+ key,
21
+ options)
22
+ end
23
+ true
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,66 @@
1
+ module Riak::TimeSeries
2
+
3
+ # A request to list keys in a Riak Time Series collection. Very expensive,
4
+ # not recommended for use in production.
5
+ class List
6
+ include Riak::Util::Translation
7
+
8
+ # @!attribute [r] table_name
9
+ # @return [String] the table name to list keys in
10
+ attr_reader :table_name
11
+
12
+ # @!attribute [r] client
13
+ # @return [Riak::Client] the Riak client to use for the list keys operation
14
+ attr_reader :client
15
+
16
+ # @!attribute [rw] timeout
17
+ # @return [Integer] how many milliseconds Riak should wait for listing
18
+ attr_accessor :timeout
19
+
20
+ # @!attribute [r] results
21
+ # @return [Riak::TimeSeries::Collection<Riak::TimeSeries::Row>] each key
22
+ # as a row in a collection; nil if keys were streamed to a block
23
+ attr_reader :results
24
+
25
+ # Initializes but does not issue the list keys operation
26
+ #
27
+ # @param [Riak::Client] client the Riak Client to list keys with
28
+ # @param [String] table_name the table name to list keys in
29
+ def initialize(client, table_name)
30
+ @client = client
31
+ @table_name = table_name
32
+ @timeout = nil
33
+ end
34
+
35
+ # Issue the list keys request. Takes a block for streaming results, or
36
+ # sets the #results read-only attribute iff no block is given.
37
+ #
38
+ # @yieldparam key [Riak::TimeSeries::Row] a listed key
39
+ def issue!(&block)
40
+ list_keys_warning(caller)
41
+
42
+ options = { timeout: self.timeout }
43
+
44
+ potential_results = nil
45
+
46
+ client.backend do |be|
47
+ potential_results = be.time_series_list_operator.list(table_name,
48
+ block,
49
+ options)
50
+ end
51
+
52
+ return @results = potential_results unless block_given?
53
+
54
+ true
55
+ end
56
+
57
+ private
58
+ def list_keys_warning(bound_caller)
59
+ return if Riak.disable_list_keys_warnings
60
+
61
+ backtrace = bound_caller.join("\n ")
62
+
63
+ warn(t('time_series.list_keys'), backtrace: backtrace)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,43 @@
1
+ module Riak::TimeSeries
2
+
3
+ # A query for Riak Time Series. Supports SQL for querying (data
4
+ # manipulation language, or DML).
5
+ class Query
6
+
7
+ # @!attribute [rw] query_text
8
+ # @return [String] the SQL query to run
9
+ attr_accessor :query_text
10
+
11
+ # Values to be interpolated into the query, support planned in Riak TS
12
+ # 1.2
13
+ attr_accessor :interpolations
14
+
15
+ # @!attribute [r] client
16
+ # @return [Riak::Client] the Riak client to use for the TS query
17
+ attr_reader :client
18
+
19
+ # #!attribute [r] results
20
+ # @return [Riak::Client::BeefcakeProtobuffsBackend::TsQueryResp]
21
+ # backend-dependent results object
22
+ attr_reader :results
23
+
24
+ # Initialize a query object
25
+ #
26
+ # @param [Riak::Client] client the client connected to the riak cluster
27
+ # @param [String] query_text the SQL query to run
28
+ # @param interpolations planned for Riak TS 1.1
29
+ def initialize(client, query_text, interpolations = {})
30
+ @client = client
31
+ @query_text = query_text
32
+ @interpolations = interpolations
33
+ end
34
+
35
+ # Run the query against Riak TS, and store the results in the `results`
36
+ # attribute
37
+ def issue!
38
+ @results = client.backend do |be|
39
+ be.time_series_query_operator.query(query_text, interpolations)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,18 @@
1
+ module Riak::TimeSeries
2
+ class Read
3
+ attr_accessor :key
4
+ attr_reader :client
5
+ attr_reader :table_name
6
+
7
+ def initialize(client, table_name)
8
+ @client = client
9
+ @table_name = table_name
10
+ end
11
+
12
+ def read!
13
+ client.backend do |be|
14
+ be.time_series_get_operator.get(table_name, key)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ module Riak::TimeSeries
2
+ class Row < Array
3
+ end
4
+ end
@@ -0,0 +1,32 @@
1
+ module Riak::TimeSeries
2
+ class Submission
3
+
4
+ # @!attributes [rw] measurements
5
+ # @return [Array<Array<Object>>] measurements to write to Riak TS
6
+ attr_accessor :measurements
7
+
8
+ # @!attribute [r] client
9
+ # @return [Riak::Client] the client to write submissions to
10
+ attr_reader :client
11
+
12
+ # @!attribute [r] table_name
13
+ # @return [String] the table name to write submissions to
14
+ attr_reader :table_name
15
+
16
+ # Initializes the submission object with a client and table name
17
+ #
18
+ # @param [Riak::Client] client the client connected to the Riak TS cluster
19
+ # @param [String] table_name the table name in the cluster
20
+ def initialize(client, table_name)
21
+ @client = client
22
+ @table_name = table_name
23
+ end
24
+
25
+ # Write the submitted data to Riak.
26
+ def write!
27
+ client.backend do |be|
28
+ be.time_series_put_operator.put(table_name, measurements)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ module Riak
2
+
3
+ # Container module for Riak Time Series features.
4
+ module TimeSeries
5
+ end
6
+ end
7
+
8
+ require 'riak/errors/time_series'
9
+
10
+ require 'riak/time_series/collection'
11
+ require 'riak/time_series/row'
12
+
13
+ require 'riak/time_series/deletion'
14
+ require 'riak/time_series/list'
15
+ require 'riak/time_series/query'
16
+ require 'riak/time_series/submission'
17
+ require 'riak/time_series/read'
data/lib/riak/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Riak
2
- VERSION = "2.2.2"
2
+ VERSION = "2.3.0"
3
3
  end
data/lib/riak.rb CHANGED
@@ -13,11 +13,27 @@ module Riak
13
13
  module Util; end
14
14
  extend Util::Translation
15
15
 
16
+ class NullLogger
17
+ def fatal(msg) end
18
+
19
+ def error(msg) end
20
+
21
+ def warn(msg) end
22
+
23
+ def info(msg) end
24
+
25
+ def debug(msg) end
26
+ end
27
+
16
28
  class << self
17
29
  # Only change this if you really know what you're doing. Better to
18
30
  # err on the side of caution and assume you don't.
19
31
  # @private
20
32
  attr_accessor :disable_list_keys_warnings
33
+
34
+ # Set a custom logger object (e.g. Riak.logger = Rails.logger)
35
+ attr_accessor :logger
21
36
  end
22
37
  self.disable_list_keys_warnings = false
38
+ self.logger = NullLogger.new
23
39
  end
@@ -162,15 +162,15 @@ describe 'Bucket Types', test_client: true, integration: true do
162
162
  let(:untyped_bucket){ test_client.bucket bucket.name }
163
163
 
164
164
  it 'allows reading and writing bucket properties' do
165
- expect(test_client.get_bucket_props(bucket, type: 'yokozuna')['last_write_wins']).to_not be
166
- expect(test_client.get_bucket_props(untyped_bucket)['last_write_wins']).to_not be
165
+ expect(test_client.get_bucket_props(bucket, type: 'yokozuna')['notfound_ok']).to be
166
+ expect(test_client.get_bucket_props(untyped_bucket)['notfound_ok']).to be
167
167
 
168
168
  # test setting
169
- expect{ bucket.props = {'last_write_wins' => true} }.to_not raise_error
169
+ expect{ bucket.props = {'notfound_ok' => false} }.to_not raise_error
170
170
 
171
171
  # make sure setting doesn't leak to untyped bucket
172
- expect(test_client.get_bucket_props(bucket, type: 'yokozuna')['last_write_wins']).to be
173
- expect(test_client.get_bucket_props(untyped_bucket)['last_write_wins']).to_not be
172
+ expect(test_client.get_bucket_props(bucket, type: 'yokozuna')['notfound_ok']).to_not be
173
+ expect(test_client.get_bucket_props(untyped_bucket)['notfound_ok']).to be
174
174
 
175
175
  # add canary setting on untyped bucket
176
176
  expect{ untyped_bucket.props = { 'n_val' => 1} }.to_not raise_error
@@ -183,7 +183,7 @@ describe 'Bucket Types', test_client: true, integration: true do
183
183
  expect{ bucket.clear_props }.to_not raise_error
184
184
 
185
185
  # make sure clearing doesn't leak to canary setting on untyped bucket
186
- expect(test_client.get_bucket_props(bucket, type: 'yokozuna')['last_write_wins']).to_not be
186
+ expect(test_client.get_bucket_props(bucket, type: 'yokozuna')['notfound_ok']).to be
187
187
  expect(test_client.get_bucket_props(untyped_bucket)['n_val']).to eq 1
188
188
  end
189
189
  end
@@ -0,0 +1,168 @@
1
+ require 'spec_helper'
2
+ require 'riak'
3
+
4
+ describe 'Time Series',
5
+ test_client: true, integration: true, time_series: true do
6
+ let(:table_name){ 'GeoCheckin' }
7
+
8
+ let(:now){ Time.at(Time.now.to_i) }
9
+ let(:five_minutes_ago){ now - 300 }
10
+ let(:now_range_str) do
11
+ past = (now.to_i - 100) * 1000
12
+ future = (now.to_i + 100) * 1000
13
+ "time > #{ past } AND time < #{ future }"
14
+ end
15
+ let(:never_range_str) do
16
+ range_start = '1'
17
+ range_end = '2'
18
+ "time > #{range_start} AND time < #{range_end}"
19
+ end
20
+
21
+ let(:family){ 'family-' + random_key }
22
+ let(:series){ 'series-' + random_key }
23
+
24
+ let(:key){ [family, series, now] }
25
+ let(:key2){ [family, series, five_minutes_ago] }
26
+ let(:datum){ [*key, 'cloudy', 27.1] }
27
+ let(:datum_null){ [*key2, 'cloudy', nil] }
28
+
29
+ let(:family_series_str) do
30
+ "myfamily = '#{family}' AND myseries = '#{series}'"
31
+ end
32
+
33
+ let(:query) do
34
+ <<-SQL
35
+ SELECT * FROM #{table_name}
36
+ WHERE
37
+ #{family_series_str} AND
38
+ #{now_range_str}
39
+ SQL
40
+ end
41
+ let(:no_data_query) do
42
+ <<-SQL
43
+ SELECT * FROM #{table_name}
44
+ WHERE
45
+ #{family_series_str} AND
46
+ #{never_range_str}
47
+ SQL
48
+ end
49
+
50
+ let(:stored_datum_expectation) do
51
+ submission = Riak::TimeSeries::Submission.new test_client, table_name
52
+ submission.measurements = [datum]
53
+ expect{ submission.write! }.to_not raise_error
54
+ end
55
+
56
+ let(:stored_datum_null_expectation) do
57
+ submission = Riak::TimeSeries::Submission.new test_client, table_name
58
+ submission.measurements = [datum_null]
59
+ expect{ submission.write! }.to_not raise_error
60
+ end
61
+
62
+ describe 'query interface' do
63
+ subject{ Riak::TimeSeries::Query.new test_client, query }
64
+ let(:subject_without_data) do
65
+ Riak::TimeSeries::Query.new test_client, no_data_query
66
+ end
67
+
68
+ it 'queries data without error' do
69
+ stored_datum_expectation
70
+
71
+ expect{ subject.issue! }.to_not raise_error
72
+ expect(subject.results).to be
73
+ expect(subject.results).to_not be_empty
74
+ expect(subject.results.columns).to_not be_empty
75
+ end
76
+
77
+ it 'returns an empty collection when not finding data' do
78
+ expect{ subject_without_data.issue! }.to_not raise_error
79
+ expect(subject.results).to_not be
80
+ end
81
+ end
82
+
83
+ describe 'single-key get interface' do
84
+ subject{ Riak::TimeSeries::Read.new test_client, table_name }
85
+ it 'retrieves data without error' do
86
+ stored_datum_expectation
87
+
88
+ subject.key = key
89
+ result = nil
90
+ expect{ result = subject.read! }.to_not raise_error
91
+ expect(result).to be
92
+ expect(result).to_not be_empty
93
+ expect(result.first).to_not be_empty
94
+ end
95
+
96
+ it 'retrieves data with a null value without error' do
97
+ stored_datum_null_expectation
98
+
99
+ subject.key = key2
100
+ result = nil
101
+ expect{ result = subject.read! }.to_not raise_error
102
+ expect(result).to be
103
+ expect(result).to_not be_empty
104
+
105
+ row = result.first
106
+ expect(row).to_not be_empty
107
+ expect(row[4]).to_not be
108
+ end
109
+
110
+ it 'attempts retrieval of non-existent data without error' do
111
+ subject.key = [ 'foo', 'bar', now ]
112
+ result = nil
113
+ expect{ result = subject.read! }.to_not raise_error
114
+ expect(result).to_not be
115
+ end
116
+ end
117
+
118
+ describe 'single-key delete interface' do
119
+ subject{ Riak::TimeSeries::Deletion.new test_client, table_name }
120
+ let(:test_read){ Riak::TimeSeries::Read.new test_client, table_name }
121
+
122
+ it 'deletes data without error' do
123
+ stored_datum_expectation
124
+
125
+ test_read.key = key
126
+ expect(test_read.read!).to_not be_empty
127
+
128
+ subject.key = key
129
+ expect{ subject.delete! }.to_not raise_error
130
+
131
+ expect(test_read.read!).to_not be
132
+ end
133
+ end
134
+
135
+ describe 'submission interface' do
136
+ it 'writes data without error' do
137
+ stored_datum_expectation
138
+ end
139
+ it 'writes data with a null value without error' do
140
+ stored_datum_null_expectation
141
+ end
142
+ end
143
+
144
+ describe 'list interface' do
145
+ it 'passes listed keys to a block' do
146
+ stored_datum_expectation
147
+ found_expectation = double 'expectation'
148
+ expect(found_expectation).to receive(:found!).once
149
+
150
+ lister = Riak::TimeSeries::List.new test_client, table_name
151
+
152
+ lister.issue! do |row|
153
+ found_expectation.found! if row.to_a == key
154
+ end
155
+ end
156
+
157
+ it 'returns a list of keys without a block' do
158
+ stored_datum_expectation
159
+ found_expectation = double 'expectation'
160
+
161
+ lister = Riak::TimeSeries::List.new test_client, table_name
162
+
163
+ results = lister.issue!
164
+
165
+ expect(results).to include key
166
+ end
167
+ end
168
+ end
@@ -8,16 +8,45 @@ describe Riak::Client::BeefcakeProtobuffsBackend::ObjectMethods do
8
8
  @backend = Riak::Client::BeefcakeProtobuffsBackend.new(@client, @client.node)
9
9
  @bucket = Riak::Bucket.new(@client, "bucket")
10
10
  @object = Riak::RObject.new(@bucket, "bar")
11
+ @content = double(
12
+ :value => '',
13
+ :vtag => nil,
14
+ :content_type => nil,
15
+ :links => nil,
16
+ :usermeta => nil,
17
+ :last_mod => nil,
18
+ :last_mod_usecs => nil,
19
+ :indexes => nil,
20
+ :charset => nil
21
+ )
11
22
  end
12
23
 
13
24
  describe "loading object data from the response" do
14
25
  it "loads the key" do
15
- content = double(:value => '', :vtag => nil, :content_type => nil, :links => nil, :usermeta => nil, :last_mod => nil, :indexes => nil, :charset => nil)
16
- pbuf = double(:vclock => nil, :content => [content], :value => nil, :key => 'akey')
26
+ pbuf = double(:vclock => nil, :content => [@content], :value => nil, :key => 'akey')
17
27
  o = @backend.load_object(pbuf, @object)
18
28
  expect(o).to eq(@object)
19
29
  expect(o.key).to eq(pbuf.key)
20
30
  end
31
+
32
+ describe "last_modified" do
33
+ before :each do
34
+ allow(@content).to receive(:last_mod) { 1271442363 }
35
+ end
36
+
37
+ it "is set to time of last_mod with microseconds from last_mod_usecs" do
38
+ allow(@content).to receive(:last_mod_usecs) { 105696 }
39
+ pbuf = double(:vclock => nil, :content => [@content], :value => nil, :key => 'akey')
40
+ o = @backend.load_object(pbuf, @object)
41
+ expect(o.last_modified).to eq(Time.at(1271442363, 105696))
42
+ end
43
+
44
+ it "is set to time of last_mod without microseconds if last_mod_usecs is missing" do
45
+ pbuf = double(:vclock => nil, :content => [@content], :value => nil, :key => 'akey')
46
+ o = @backend.load_object(pbuf, @object)
47
+ expect(o.last_modified).to eq(Time.at(1271442363, 0))
48
+ end
49
+ end
21
50
  end
22
51
 
23
52
  end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+ require 'bigdecimal'
3
+ require 'time'
4
+
5
+ Riak::Client::BeefcakeProtobuffsBackend.configured?
6
+
7
+ describe Riak::Client::BeefcakeProtobuffsBackend::TsCellCodec do
8
+ describe 'symmetric serialziation' do
9
+ it { is_expected.to symmetric_serialize("hello", varchar_value: "hello")}
10
+ it { is_expected.to symmetric_serialize(5, sint64_value: 5)}
11
+ it { is_expected.to symmetric_serialize(123.45, double_value: 123.45) }
12
+ it do
13
+ is_expected.to symmetric_serialize(Time.parse("June 23, 2015 at 9:46:28 EDT"),
14
+ timestamp_value: 1_435_067_188_000)
15
+ end
16
+ it { is_expected.to symmetric_serialize(true, boolean_value: true) }
17
+ it { is_expected.to symmetric_serialize(false, boolean_value: false) }
18
+ it { is_expected.to symmetric_serialize(nil, {}) }
19
+ end
20
+
21
+ describe 'serializing values' do
22
+ it do
23
+ is_expected.to serialize(BigDecimal.new("0.1"), double_value: 0.1)
24
+ end
25
+
26
+ it 'refuses to serialize big numbers' do
27
+ expect{ subject.cell_for 2**64 }.
28
+ to raise_error Riak::TimeSeriesError::SerializeBigIntegerError
29
+ end
30
+
31
+ it 'refuses to serialize complex numbers' do
32
+ expect{ subject.cell_for(Complex(1, 1)) }.
33
+ to raise_error Riak::TimeSeriesError::SerializeComplexNumberError
34
+ end
35
+
36
+ it 'refuses to serialize rational numbers' do
37
+ expect{ subject.cell_for(Rational(1, 1)) }.
38
+ to raise_error Riak::TimeSeriesError::SerializeRationalNumberError
39
+ end
40
+ end
41
+
42
+ # deserialization is handled by the symmetric cases above
43
+ # describe 'deserializing values'
44
+
45
+ describe 'with a collection' do
46
+ let(:not_serialized){ ['hi', 5, 12.34] }
47
+ let(:serialized) do
48
+ [
49
+ Riak::Client::BeefcakeProtobuffsBackend::TsCell.new(varchar_value: 'hi'),
50
+ Riak::Client::BeefcakeProtobuffsBackend::TsCell.new(sint64_value: 5),
51
+ Riak::Client::BeefcakeProtobuffsBackend::TsCell.new(double_value: 12.34)
52
+ ]
53
+ end
54
+
55
+ it 'serializes' do
56
+ expect(subject.cells_for(not_serialized)).to eq serialized
57
+ end
58
+
59
+ it 'deserializes' do
60
+ expect(subject.scalars_for(serialized)).to eq not_serialized
61
+ end
62
+ end
63
+
64
+ RSpec::Matchers.define :symmetric_serialize do |scalar, cell_options|
65
+ match do |codec|
66
+ expect(codec).to(
67
+ serialize(scalar, cell_options)
68
+ .and(deserialize(scalar, cell_options)))
69
+ end
70
+
71
+ failure_message do |codec|
72
+ cell = Riak::Client::BeefcakeProtobuffsBackend::TsCell.new cell_options
73
+ deserialized = codec.scalar_for cell
74
+ "expected #{scalar} => #{cell_options} => #{scalar}, got #{scalar} => #{cell.to_hash} => #{deserialized}"
75
+ end
76
+
77
+ description do
78
+ "serialize #{scalar.class} #{scalar.inspect} to and from TsCell #{cell_options}"
79
+ end
80
+ end
81
+
82
+ RSpec::Matchers.define :serialize do |measure, options|
83
+ match do |actual|
84
+ serialized = actual.cell_for(measure)
85
+ serialized.to_hash == options
86
+ end
87
+
88
+ failure_message do |actual|
89
+ serialized = actual.cell_for(measure)
90
+ "expected #{options}, got #{serialized.to_hash}"
91
+ end
92
+
93
+ description do
94
+ "serialize #{measure.class} #{measure.inspect} to TsCell #{options}"
95
+ end
96
+ end
97
+
98
+ RSpec::Matchers.define :deserialize do |expected, options|
99
+
100
+ cell = Riak::Client::BeefcakeProtobuffsBackend::TsCell.new options
101
+
102
+ match do |codec|
103
+ deserialized = codec.scalar_for cell
104
+ deserialized == expected
105
+ end
106
+
107
+ failure_message do |codec|
108
+ deserialized = codec.scalar_for cell
109
+ "expected TsCell #{options.inspect} to deserialize to #{expected.class} #{expected.inspect}"
110
+ end
111
+
112
+ description do
113
+ "deserialize TsCell #{options} to #{expected.class} #{expected.inspect}"
114
+ end
115
+ end
116
+ end
@@ -242,5 +242,16 @@ describe Riak::Client, test_client: true do
242
242
  expect(error).not_to be_nil
243
243
  expect(error).to be_instance_of(RuntimeError)
244
244
  end
245
+
246
+ it "logs the error" do
247
+ expect(Riak.logger).to receive(:warn).with(/Riak::ProtobuffsFailedHeader/).at_least(:once)
248
+
249
+ begin
250
+ @client.backend do |b|
251
+ raise Riak::ProtobuffsFailedHeader
252
+ end
253
+ rescue RuntimeError
254
+ end
255
+ end
245
256
  end
246
257
  end
@@ -21,7 +21,7 @@ describe Riak::Crdt::InnerFlag do
21
21
  describe 'updating' do
22
22
  let(:new_value){ false }
23
23
 
24
- it '\asks the class for an update operation' do
24
+ it 'asks the class for an update operation' do
25
25
  operation = described_class.update(new_value)
26
26
 
27
27
  expect(operation.value).to eq new_value
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Riak::TimeSeries::Deletion do
4
+ subject{ described_class.new client, table_name }
5
+ let(:table_name){ 'GeoCheckin' }
6
+ let(:client){ instance_double('Riak::Client') }
7
+ let(:key){ double 'key' }
8
+ let(:backend) do
9
+ instance_double('Riak::Client::BeefcakeProtobuffsBackend').tap do |be|
10
+ allow(client).to receive(:backend).and_yield be
11
+ end
12
+ end
13
+ let(:operator) do
14
+ Riak::Client::BeefcakeProtobuffsBackend.configured?
15
+ instance_double(
16
+ 'Riak::Client::BeefcakeProtobuffsBackend::TimeSeriesDeleteOperator'
17
+ ).tap do |op|
18
+ allow(backend).to receive(:time_series_delete_operator).
19
+ and_return(op)
20
+ end
21
+ end
22
+
23
+ it 'initializes with client and table name' do
24
+ expect{ described_class.new client, table_name }.to_not raise_error
25
+ expect{ described_class.new client }.to raise_error ArgumentError
26
+ end
27
+
28
+ it 'passes keys to delete to a delete operator' do
29
+ expect{ subject.key = key }.to_not raise_error
30
+ expect(operator).to receive(:delete).with(table_name, key, Hash.new)
31
+ expect{ subject.delete! }.to_not raise_error
32
+ end
33
+ end