riak-ruby-ledger 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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