riak-ruby-ledger 0.0.4

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.
@@ -0,0 +1,9 @@
1
+ require_relative '../../test_helper'
2
+
3
+ describe Riak::Ledger do
4
+
5
+ it "must be defined" do
6
+ assert Riak::Ledger::VERSION
7
+ end
8
+
9
+ end
@@ -0,0 +1,142 @@
1
+ require_relative '../test_helper'
2
+ require 'riak'
3
+ I18n.enforce_available_locales = false
4
+
5
+ describe Riak::Ledger do
6
+ options1 = {:actor => "ACTOR1", :history_length => 5, :retry_count => 10}
7
+ options2 = {:actor => "ACTOR2", :history_length => 5, :retry_count => 10}
8
+
9
+ before do
10
+ client = Riak::Client.new pb_port: 8087
11
+ @bucket = client["ledger_test"]
12
+ @key = "player_1"
13
+
14
+
15
+ @ledger1 = Riak::Ledger.new(@bucket, @key, options1)
16
+ @ledger2 = Riak::Ledger.new(@bucket, @key, options2)
17
+ end
18
+
19
+ after do
20
+ @ledger1.delete()
21
+ @ledger2.delete()
22
+ end
23
+
24
+ it "have a valid starting state" do
25
+
26
+ assert_equal({:type=>"TGCounter", :c=>{"ACTOR1"=>{"total"=>0, "txns"=>[]}}}, @ledger1.counter.p.to_hash)
27
+ assert_equal({:type=>"TGCounter", :c=>{"ACTOR1"=>{"total"=>0, "txns"=>[]}}}, @ledger1.counter.n.to_hash)
28
+ end
29
+
30
+ it "must credit and debit" do
31
+ @ledger1.credit!("txn1", 10)
32
+ @ledger1.credit!("txn1", 10)
33
+ @ledger1.credit!("txn1", 10)
34
+
35
+ assert_equal 10, @ledger1.value
36
+
37
+ @ledger1.debit!("txn2", 5)
38
+ @ledger1.debit!("txn2", 5)
39
+ @ledger1.debit!("txn2", 5)
40
+
41
+ assert_equal 5, @ledger1.value
42
+ end
43
+
44
+ it "must have transaction" do
45
+ @ledger1.credit!("txn1", 10)
46
+ @ledger1.debit!("txn2", 5)
47
+
48
+ assert @ledger1.has_transaction? "txn1"
49
+ assert @ledger1.has_transaction? "txn2"
50
+ refute @ledger1.has_transaction? "txn3"
51
+ end
52
+
53
+ it "must save and find counters" do
54
+ @ledger1.credit!("txn1", 10)
55
+ @ledger1.debit!("txn2", 5)
56
+ @ledger2.credit!("txn1", 10) #ignore
57
+ @ledger2.debit!("txn2", 5) #ignore
58
+ @ledger2.debit!("txn3", 1)
59
+ @ledger2.credit!("txn5", 100)
60
+
61
+ l1 = Riak::Ledger.find!(@bucket, @key, options1)
62
+
63
+ l2 = Riak::Ledger.find!(@bucket, @key, options2)
64
+
65
+ assert_equal 104, l1.value
66
+ assert_equal 104, l2.value
67
+
68
+ assert l1.has_transaction? "txn1"
69
+ assert l1.has_transaction? "txn2"
70
+ assert l1.has_transaction? "txn5"
71
+ refute l1.has_transaction? "txn4"
72
+ end
73
+
74
+ it "must merge a single actor" do
75
+ @ledger1.credit!("txn1", 10)
76
+ @ledger1.credit!("txn2", 10)
77
+ @ledger1.credit!("txn3", 10)
78
+ @ledger1.credit!("txn4", 10)
79
+ @ledger1.credit!("txn5", 10)
80
+ @ledger1.credit!("txn6", 10)
81
+ @ledger1.credit!("txn7", 10)
82
+ @ledger1.credit!("txn8", 10)
83
+ @ledger1.credit!("txn9", 10)
84
+ @ledger1.credit!("txn10", 10)
85
+
86
+ @ledger1.credit!("txn11", 10)
87
+ @ledger1.credit!("txn11", 10)
88
+ @ledger1.credit!("txn11", 10)
89
+ @ledger1.credit!("txn11", 10)
90
+
91
+ assert_equal 110, @ledger1.value
92
+ #1st 5 transactions were merged into total
93
+ assert_equal 60, @ledger1.counter.p.counts["ACTOR1"]["total"]
94
+
95
+ refute @ledger1.has_transaction? "txn1"
96
+ refute @ledger1.has_transaction? "txn2"
97
+ refute @ledger1.has_transaction? "txn3"
98
+ refute @ledger1.has_transaction? "txn4"
99
+ refute @ledger1.has_transaction? "txn5"
100
+ refute @ledger1.has_transaction? "txn6"
101
+ assert @ledger1.has_transaction? "txn7"
102
+ assert @ledger1.has_transaction? "txn8"
103
+ assert @ledger1.has_transaction? "txn9"
104
+ assert @ledger1.has_transaction? "txn10"
105
+ assert @ledger1.has_transaction? "txn11"
106
+ end
107
+ #
108
+ #it "must merge a two actors" do
109
+ # @ledger1.debit!("txn1", 10)
110
+ # @ledger1.credit!("txn2", 10)
111
+ # @ledger1.credit!("txn3", 10)
112
+ # @ledger1.credit!("txn4", 10)
113
+ # @ledger1.credit!("txn5", 10)
114
+ # @ledger2.debit!("txn6", 10)
115
+ # @ledger2.credit!("txn7", 10)
116
+ # @ledger2.credit!("txn8", 10)
117
+ # @ledger2.credit!("txn9", 10)
118
+ # @ledger2.credit!("txn10", 10)
119
+ #
120
+ # @ledger1.credit!("txn11", 10)
121
+ # @ledger1.credit!("txn11", 10)
122
+ # @ledger2.credit!("txn11", 10)
123
+ # @ledger2.credit!("txn11", 10)
124
+ #
125
+ # assert_equal 110, @ledger1.value
126
+ # #1st 6 transactions were merged into total
127
+ # assert_equal 60, @ledger1.counter.p.counts["ACTOR1"]["total"]
128
+ #
129
+ # refute @ledger1.has_transaction? "txn1"
130
+ # refute @ledger1.has_transaction? "txn2"
131
+ # refute @ledger1.has_transaction? "txn3"
132
+ # refute @ledger1.has_transaction? "txn4"
133
+ # refute @ledger1.has_transaction? "txn5"
134
+ # refute @ledger1.has_transaction? "txn6"
135
+ # assert @ledger1.has_transaction? "txn7"
136
+ # assert @ledger1.has_transaction? "txn8"
137
+ # assert @ledger1.has_transaction? "txn9"
138
+ # assert @ledger1.has_transaction? "txn10"
139
+ # assert @ledger1.has_transaction? "txn11"
140
+ #end
141
+
142
+ end
@@ -0,0 +1,99 @@
1
+ require_relative '../test_helper'
2
+
3
+ describe Riak::CRDT::TGCounter do
4
+ options1 = {:actor => "ACTOR1", :history_length => 5}
5
+ options2 = {:actor => "ACTOR2", :history_length => 5}
6
+
7
+ it "must have empty counts on new" do
8
+ counter = Riak::CRDT::TGCounter.new(options1)
9
+ assert_equal(0, counter.counts["ACTOR1"]["total"])
10
+ assert_equal([], counter.counts["ACTOR1"]["txns"].arr)
11
+ end
12
+
13
+ it "must increment" do
14
+ counter = Riak::CRDT::TGCounter.new(options1)
15
+ counter.increment("txn1", 10)
16
+
17
+ assert_equal(0, counter.counts["ACTOR1"]["total"])
18
+ assert_equal(10, counter.counts["ACTOR1"]["txns"]["txn1"])
19
+ end
20
+
21
+ it "must have value" do
22
+ counter = Riak::CRDT::TGCounter.new(options1)
23
+ counter.increment("txn1", 10)
24
+ counter.increment("txn2", 10)
25
+
26
+ assert_equal(20, counter.value)
27
+ end
28
+
29
+ it "must be idempotent before merge" do
30
+ counter = Riak::CRDT::TGCounter.new(options1)
31
+ counter.increment("txn1", 10)
32
+ counter.increment("txn2", 10)
33
+ counter.increment("txn1", 10)
34
+ counter.increment("txn1", 10)
35
+ counter.increment("txn1", 10)
36
+
37
+ assert_equal(20, counter.value)
38
+ end
39
+
40
+ it "must have an added transaction" do
41
+ counter = Riak::CRDT::TGCounter.new(options1)
42
+ counter.increment("txn1", 10)
43
+ counter.increment("txn2", 10)
44
+
45
+ assert counter.has_transaction? "txn1"
46
+ refute counter.has_transaction? "txn3"
47
+ end
48
+
49
+ it "must translate to and from json" do
50
+ json = "{\"type\":\"TGCounter\",\"c\":{\"ACTOR1\":{\"total\":0,\"txns\":[[\"txn1\",10],[\"txn2\",10]]}}}"
51
+ counter = Riak::CRDT::TGCounter.new(options1)
52
+ counter.increment("txn1", 10)
53
+ counter.increment("txn2", 10)
54
+
55
+ c2 = counter.clone
56
+
57
+ assert_equal json, counter.to_json
58
+
59
+ assert_equal c2.counts, Riak::CRDT::TGCounter.from_json(json, options1).counts
60
+ end
61
+
62
+ it "must merge" do
63
+ counter = Riak::CRDT::TGCounter.new(options1)
64
+ counter.increment("txn1", 10)
65
+ counter.increment("txn2", 10)
66
+ counter.increment("txn1", 10)
67
+ counter.increment("txn1", 10)
68
+ counter.increment("txn3", 10)
69
+
70
+ counter.increment("txn4", 10)
71
+ counter.increment("txn5", 10)
72
+ counter.increment("txn6", 10)
73
+ counter.increment("txn7", 10)
74
+ counter.increment("txn8", 10)
75
+
76
+ counter2 = Riak::CRDT::TGCounter.new(options2)
77
+ counter2.increment("txn1", 10)
78
+ counter2.increment("txn2", 10)
79
+ counter2.increment("txn3", 10)
80
+ counter2.increment("txn1", 10)
81
+ counter2.increment("txn1", 10)
82
+
83
+ counter2.increment("txn9", 10)
84
+ counter2.increment("txn10", 10)
85
+ counter2.increment("txn11", 10)
86
+ counter2.increment("txn12", 10)
87
+ counter2.increment("txn13", 10)
88
+
89
+ counter.merge(counter2)
90
+
91
+ assert_equal(0, counter.counts["ACTOR1"]["total"])
92
+ assert_equal(130, counter.value)
93
+
94
+ counter2.merge(counter)
95
+
96
+ assert_equal(30, counter2.counts["ACTOR2"]["total"])
97
+ assert_equal(130, counter2.value)
98
+ end
99
+ end
@@ -0,0 +1,97 @@
1
+ require_relative '../test_helper'
2
+
3
+ describe Riak::CRDT::TPNCounter do
4
+ options1 = {:actor => "ACTOR1", :history_length => 5}
5
+ options2 = {:actor => "ACTOR2", :history_length => 5}
6
+
7
+ it "must have empty counts on new" do
8
+ assert_equal({:type=>"TGCounter", :c=>{"ACTOR1"=>{"total"=>0, "txns"=>[]}}}, Riak::CRDT::TPNCounter.new(options1).p.to_hash)
9
+ assert_equal({:type=>"TGCounter", :c=>{"ACTOR1"=>{"total"=>0, "txns"=>[]}}}, Riak::CRDT::TPNCounter.new(options1).n.to_hash)
10
+ end
11
+
12
+ it "must increment and decrement" do
13
+ counter = Riak::CRDT::TPNCounter.new(options1)
14
+ counter.increment("txn1", 10)
15
+ assert_equal(10, counter.value)
16
+
17
+ counter.decrement("txn2", 10)
18
+ assert_equal(0, counter.value)
19
+ end
20
+
21
+
22
+ it "must be idempotent before merge" do
23
+ counter = Riak::CRDT::TPNCounter.new(options1)
24
+ counter.increment("txn1", 10)
25
+ counter.increment("txn2", 10)
26
+ counter.increment("txn1", 10)
27
+ counter.increment("txn1", 10)
28
+ counter.increment("txn1", 10)
29
+ counter.decrement("txn3", 10)
30
+
31
+ assert_equal(10, counter.value)
32
+ end
33
+
34
+ it "must have an added transaction" do
35
+ counter = Riak::CRDT::TPNCounter.new(options1)
36
+ counter.increment("txn1", 10)
37
+ counter.increment("txn2", 10)
38
+ counter.decrement("txn4", 10)
39
+
40
+ assert counter.has_transaction? "txn1"
41
+ refute counter.has_transaction? "txn3"
42
+ assert counter.has_transaction? "txn4"
43
+ end
44
+
45
+ it "must translate to and from json" do
46
+ json = "{\"type\":\"TPNCounter\",\"p\":{\"type\":\"TGCounter\",\"c\":{\"ACTOR1\":{\"total\":0,\"txns\":[[\"txn1\",10]]}}},\"n\":{\"type\":\"TGCounter\",\"c\":{\"ACTOR1\":{\"total\":0,\"txns\":[[\"txn2\",5]]}}}}"
47
+ counter = Riak::CRDT::TPNCounter.new(options1)
48
+ counter.increment("txn1", 10)
49
+ counter.decrement("txn2", 5)
50
+
51
+ c2 = counter.clone
52
+
53
+ assert_equal json, counter.to_json
54
+
55
+ {"type"=>"TGCounter", "c"=>{"ACTOR1"=>{"total"=>0, "txns"=>[["txn1", 10]]}}}
56
+ assert_equal c2.p.counts, Riak::CRDT::TPNCounter.from_json(json, options1).p.counts
57
+ assert_equal c2.n.counts, Riak::CRDT::TPNCounter.from_json(json, options1).n.counts
58
+ end
59
+
60
+ it "must merge" do
61
+ counter = Riak::CRDT::TPNCounter.new(options1)
62
+ counter.increment("txn1", 10)
63
+ counter.increment("txn2", 10)
64
+ counter.increment("txn1", 10)
65
+ counter.increment("txn1", 10)
66
+ counter.decrement("txn3", 5)
67
+
68
+ counter.increment("txn4", 10)
69
+ counter.increment("txn5", 10)
70
+ counter.increment("txn6", 10)
71
+ counter.increment("txn7", 10)
72
+ counter.decrement("txn8", 5)
73
+
74
+ counter2 = Riak::CRDT::TPNCounter.new(options2)
75
+ counter2.increment("txn1", 10)
76
+ counter2.increment("txn2", 10)
77
+ counter2.increment("txn4", 10)
78
+ counter2.increment("txn1", 10)
79
+ counter2.decrement("txn5", 1)
80
+
81
+ counter2.increment("txn9", 10)
82
+ counter2.increment("txn10", 10)
83
+ counter2.increment("txn11", 10)
84
+ counter2.increment("txn12", 10)
85
+ counter2.decrement("txn13", 1)
86
+
87
+ counter.merge(counter2)
88
+
89
+ assert_equal(0, counter.p.counts["ACTOR1"]["total"])
90
+ assert_equal(88, counter.value)
91
+
92
+ counter2.merge(counter)
93
+
94
+ assert_equal(20, counter2.p.counts["ACTOR2"]["total"])
95
+ assert_equal(88, counter2.value)
96
+ end
97
+ end
@@ -0,0 +1,5 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/pride'
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'ledger'
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: riak-ruby-ledger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - drewkerrigan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: riak-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A PNCounter CRDT based ledger with support for transaction ids and tunable
70
+ write idempotence
71
+ email:
72
+ - dkerrigan@basho.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - Gemfile
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - lib/crdt/tgcounter.rb
83
+ - lib/crdt/tpncounter.rb
84
+ - lib/ledger.rb
85
+ - lib/ledger/version.rb
86
+ - riak-ruby-ledger.gemspec
87
+ - test/lib/ledger/version_test.rb
88
+ - test/lib/ledger_test.rb
89
+ - test/lib/tgcounter_test.rb
90
+ - test/lib/tpncounter_test.rb
91
+ - test/test_helper.rb
92
+ homepage: https://github.com/drewkerrigan/riak-ruby-ledger
93
+ licenses:
94
+ - Apache2
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.1.11
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: This gem attempts to provide a tunable Counter option by combining non-idempotent
116
+ GCounters and a partially idempotent GSet for calculating a running counter or ledger.
117
+ By allowing clients to set how many transactions to keep in the counter object as
118
+ well as set a retry policy on the Riak actions performed on the counter, a good
119
+ balance can be achieved.
120
+ test_files:
121
+ - test/lib/ledger/version_test.rb
122
+ - test/lib/ledger_test.rb
123
+ - test/lib/tgcounter_test.rb
124
+ - test/lib/tpncounter_test.rb
125
+ - test/test_helper.rb