riak-client 2.2.2 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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