redistat 0.3.0 → 0.4.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.
- data/.travis.yml +8 -0
- data/README.md +219 -97
- data/lib/redistat.rb +13 -13
- data/lib/redistat/buffer.rb +27 -24
- data/lib/redistat/collection.rb +5 -5
- data/lib/redistat/connection.rb +23 -18
- data/lib/redistat/core_ext.rb +1 -1
- data/lib/redistat/core_ext/bignum.rb +2 -2
- data/lib/redistat/core_ext/date.rb +2 -2
- data/lib/redistat/core_ext/fixnum.rb +2 -2
- data/lib/redistat/core_ext/hash.rb +4 -4
- data/lib/redistat/date.rb +11 -11
- data/lib/redistat/event.rb +18 -18
- data/lib/redistat/finder.rb +39 -39
- data/lib/redistat/finder/date_set.rb +4 -4
- data/lib/redistat/key.rb +16 -16
- data/lib/redistat/label.rb +14 -14
- data/lib/redistat/mixins/database.rb +1 -1
- data/lib/redistat/mixins/date_helper.rb +1 -1
- data/lib/redistat/mixins/options.rb +8 -8
- data/lib/redistat/mixins/synchronize.rb +12 -11
- data/lib/redistat/model.rb +25 -17
- data/lib/redistat/result.rb +4 -4
- data/lib/redistat/scope.rb +5 -5
- data/lib/redistat/summary.rb +33 -26
- data/lib/redistat/version.rb +1 -1
- data/redistat.gemspec +4 -3
- data/spec/buffer_spec.rb +27 -25
- data/spec/collection_spec.rb +4 -4
- data/spec/connection_spec.rb +12 -12
- data/spec/core_ext/hash_spec.rb +5 -5
- data/spec/database_spec.rb +3 -3
- data/spec/date_spec.rb +15 -15
- data/spec/event_spec.rb +8 -8
- data/spec/finder/date_set_spec.rb +134 -134
- data/spec/finder_spec.rb +36 -36
- data/spec/key_spec.rb +19 -19
- data/spec/label_spec.rb +10 -10
- data/spec/model_helper.rb +10 -9
- data/spec/model_spec.rb +38 -41
- data/spec/options_spec.rb +9 -9
- data/spec/result_spec.rb +4 -4
- data/spec/scope_spec.rb +6 -6
- data/spec/spec_helper.rb +6 -0
- data/spec/summary_spec.rb +31 -24
- data/spec/synchronize_spec.rb +118 -57
- data/spec/thread_safety_spec.rb +6 -6
- metadata +88 -126
- data/.rvmrc +0 -1
data/spec/options_spec.rb
CHANGED
@@ -1,36 +1,36 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Redistat::Options do
|
4
|
-
|
4
|
+
|
5
5
|
before(:each) do
|
6
6
|
@helper = OptionsHelper.new
|
7
7
|
@helper.parse_options(:wtf => 'dude', :foo => 'booze')
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
it "should #parse_options" do
|
11
11
|
@helper.options[:hello].should == 'world'
|
12
12
|
@helper.options[:foo].should == 'booze'
|
13
13
|
@helper.options[:wtf].should == 'dude'
|
14
14
|
@helper.raw_options.should_not have_key(:hello)
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it "should create option_accessors" do
|
18
18
|
@helper.hello.should == 'world'
|
19
19
|
@helper.hello('woooo')
|
20
20
|
@helper.hello.should == 'woooo'
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
end
|
24
24
|
|
25
25
|
class OptionsHelper
|
26
26
|
include Redistat::Options
|
27
|
-
|
27
|
+
|
28
28
|
option_accessor :hello
|
29
|
-
|
29
|
+
|
30
30
|
def default_options
|
31
31
|
{ :hello => 'world',
|
32
32
|
:foo => 'bar' }
|
33
33
|
end
|
34
|
-
|
35
|
-
|
36
|
-
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
data/spec/result_spec.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Redistat::Result do
|
4
|
-
|
4
|
+
|
5
5
|
it "should should initialize properly" do
|
6
6
|
options = {:from => "from", :till => "till"}
|
7
7
|
result = Redistat::Result.new(options)
|
8
8
|
result.from.should == "from"
|
9
9
|
result.till.should == "till"
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
it "should have set_or_incr method" do
|
13
13
|
result = Redistat::Result.new
|
14
14
|
result[:world].should be_nil
|
@@ -17,5 +17,5 @@ describe Redistat::Result do
|
|
17
17
|
result.set_or_incr(:world, 8)
|
18
18
|
result[:world].should == 11
|
19
19
|
end
|
20
|
-
|
21
|
-
end
|
20
|
+
|
21
|
+
end
|
data/spec/scope_spec.rb
CHANGED
@@ -2,20 +2,20 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Redistat::Scope do
|
4
4
|
include Redistat::Database
|
5
|
-
|
5
|
+
|
6
6
|
before(:all) do
|
7
7
|
db.flushdb
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
before(:each) do
|
11
11
|
@name = "PageViews"
|
12
12
|
@scope = Redistat::Scope.new(@name)
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
it "should initialize properly" do
|
16
16
|
@scope.to_s.should == @name
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
it "should increment next_id" do
|
20
20
|
scope = Redistat::Scope.new("Visitors")
|
21
21
|
@scope.next_id.should == 1
|
@@ -23,5 +23,5 @@ describe Redistat::Scope do
|
|
23
23
|
@scope.next_id.should == 2
|
24
24
|
scope.next_id.should == 2
|
25
25
|
end
|
26
|
-
|
27
|
-
end
|
26
|
+
|
27
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
3
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
4
|
|
5
|
+
require 'simplecov'
|
6
|
+
SimpleCov.start do
|
7
|
+
add_filter '/spec'
|
8
|
+
add_filter '/vendor'
|
9
|
+
end
|
10
|
+
|
5
11
|
# require stuff
|
6
12
|
require 'redistat'
|
7
13
|
require 'rspec'
|
data/spec/summary_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Redistat::Summary do
|
4
4
|
include Redistat::Database
|
5
|
-
|
5
|
+
|
6
6
|
before(:each) do
|
7
7
|
db.flushdb
|
8
8
|
@scope = "PageViews"
|
@@ -10,28 +10,43 @@ describe Redistat::Summary do
|
|
10
10
|
@date = Time.now
|
11
11
|
@key = Redistat::Key.new(@scope, @label, @date, {:depth => :day})
|
12
12
|
@stats = {"views" => 3, "visitors" => 2}
|
13
|
+
@expire = {:hour => 24*3600}
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
it "should update a single summary properly" do
|
16
17
|
Redistat::Summary.send(:update_fields, @key, @stats, :hour)
|
17
18
|
summary = db.hgetall(@key.to_s(:hour))
|
18
19
|
summary.should have(2).items
|
19
20
|
summary["views"].should == "3"
|
20
21
|
summary["visitors"].should == "2"
|
21
|
-
|
22
|
+
|
22
23
|
Redistat::Summary.send(:update_fields, @key, @stats, :hour)
|
23
24
|
summary = db.hgetall(@key.to_s(:hour))
|
24
25
|
summary.should have(2).items
|
25
26
|
summary["views"].should == "6"
|
26
27
|
summary["visitors"].should == "4"
|
27
|
-
|
28
|
+
|
28
29
|
Redistat::Summary.send(:update_fields, @key, {"views" => -4, "visitors" => -3}, :hour)
|
29
30
|
summary = db.hgetall(@key.to_s(:hour))
|
30
31
|
summary.should have(2).items
|
31
32
|
summary["views"].should == "2"
|
32
33
|
summary["visitors"].should == "1"
|
33
34
|
end
|
34
|
-
|
35
|
+
|
36
|
+
it "should set key expiry properly" do
|
37
|
+
Redistat::Summary.update_all(@key, @stats, :hour,{:expire => @expire})
|
38
|
+
((24*3600)-1..(24*3600)+1).should include(db.ttl(@key.to_s(:hour)))
|
39
|
+
[:day, :month, :year].each do |depth|
|
40
|
+
db.ttl(@key.to_s(depth)).should == -1
|
41
|
+
end
|
42
|
+
|
43
|
+
db.flushdb
|
44
|
+
Redistat::Summary.update_all(@key, @stats, :hour, {:expire => {}})
|
45
|
+
[:hour, :day, :month, :year].each do |depth|
|
46
|
+
db.ttl(@key.to_s(depth)).should == -1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
35
50
|
it "should update all summaries properly" do
|
36
51
|
Redistat::Summary.update_all(@key, @stats, :sec)
|
37
52
|
[:year, :month, :day, :hour, :min, :sec, :usec].each do |depth|
|
@@ -45,7 +60,7 @@ describe Redistat::Summary do
|
|
45
60
|
end
|
46
61
|
end
|
47
62
|
end
|
48
|
-
|
63
|
+
|
49
64
|
it "should update summaries even if no label is set" do
|
50
65
|
key = Redistat::Key.new(@scope, nil, @date, {:depth => :day})
|
51
66
|
Redistat::Summary.send(:update_fields, key, @stats, :hour)
|
@@ -54,7 +69,7 @@ describe Redistat::Summary do
|
|
54
69
|
summary["views"].should == "3"
|
55
70
|
summary["visitors"].should == "2"
|
56
71
|
end
|
57
|
-
|
72
|
+
|
58
73
|
it "should inject stats key grouping summaries" do
|
59
74
|
hash = { "count/hello" => 3, "count/world" => 7,
|
60
75
|
"death/bomb" => 4, "death/unicorn" => 3,
|
@@ -64,7 +79,7 @@ describe Redistat::Summary do
|
|
64
79
|
"death" => 7, "death/bomb" => 4, "death/unicorn" => 3,
|
65
80
|
"od" => 15, :"od/sugar" => 7, :"od/meth" => 8 }
|
66
81
|
end
|
67
|
-
|
82
|
+
|
68
83
|
it "should properly store key group summaries" do
|
69
84
|
stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
|
70
85
|
Redistat::Summary.update_all(@key, stats, :hour)
|
@@ -75,7 +90,7 @@ describe Redistat::Summary do
|
|
75
90
|
summary["visitors/eu"].should == "2"
|
76
91
|
summary["visitors/us"].should == "4"
|
77
92
|
end
|
78
|
-
|
93
|
+
|
79
94
|
it "should not store key group summaries when option is disabled" do
|
80
95
|
stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
|
81
96
|
Redistat::Summary.update_all(@key, stats, :hour, {:enable_grouping => false})
|
@@ -85,7 +100,7 @@ describe Redistat::Summary do
|
|
85
100
|
summary["visitors/eu"].should == "2"
|
86
101
|
summary["visitors/us"].should == "4"
|
87
102
|
end
|
88
|
-
|
103
|
+
|
89
104
|
it "should store label-based grouping enabled stats" do
|
90
105
|
stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
|
91
106
|
label = "views/about_us"
|
@@ -96,37 +111,29 @@ describe Redistat::Summary do
|
|
96
111
|
key.groups[1].label.to_s.should == "views"
|
97
112
|
child1 = key.groups[0]
|
98
113
|
parent = key.groups[1]
|
99
|
-
|
114
|
+
|
100
115
|
label = "views/contact"
|
101
116
|
key = Redistat::Key.new(@scope, label, @date)
|
102
117
|
Redistat::Summary.update_all(key, stats, :hour)
|
103
|
-
|
118
|
+
|
104
119
|
key.groups[0].label.to_s.should == "views/contact"
|
105
120
|
key.groups[1].label.to_s.should == "views"
|
106
121
|
child2 = key.groups[0]
|
107
|
-
|
122
|
+
|
108
123
|
summary = db.hgetall(child1.to_s(:hour))
|
109
124
|
summary["views"].should == "3"
|
110
125
|
summary["visitors/eu"].should == "2"
|
111
126
|
summary["visitors/us"].should == "4"
|
112
|
-
|
127
|
+
|
113
128
|
summary = db.hgetall(child2.to_s(:hour))
|
114
129
|
summary["views"].should == "3"
|
115
130
|
summary["visitors/eu"].should == "2"
|
116
131
|
summary["visitors/us"].should == "4"
|
117
|
-
|
132
|
+
|
118
133
|
summary = db.hgetall(parent.to_s(:hour))
|
119
134
|
summary["views"].should == "6"
|
120
135
|
summary["visitors/eu"].should == "4"
|
121
136
|
summary["visitors/us"].should == "8"
|
122
137
|
end
|
123
|
-
|
124
|
-
end
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
138
|
|
139
|
+
end
|
data/spec/synchronize_spec.rb
CHANGED
@@ -1,63 +1,124 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
3
|
+
module Redistat
|
4
|
+
describe Synchronize do
|
5
|
+
|
6
|
+
let(:klass) { Synchronize }
|
7
|
+
|
8
|
+
describe '.included' do
|
9
|
+
it 'includes InstanceMethods in passed object' do
|
10
|
+
base = mock('Base')
|
11
|
+
base.should_receive(:include).with(klass::InstanceMethods)
|
12
|
+
klass.included(base)
|
13
|
+
end
|
14
|
+
end # included
|
15
|
+
|
16
|
+
describe '.monitor' do
|
17
|
+
it 'returns a Monitor instance' do
|
18
|
+
klass.monitor.should be_a(Monitor)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'caches Monitor instance' do
|
22
|
+
klass.monitor.object_id.should == klass.monitor.object_id
|
23
|
+
end
|
24
|
+
end # monitor
|
25
|
+
|
26
|
+
describe '.thread_safe' do
|
27
|
+
after { klass.instance_variable_set('@thread_safe', nil) }
|
28
|
+
|
29
|
+
it 'returns value of @thread_safe' do
|
30
|
+
klass.instance_variable_set('@thread_safe', true)
|
31
|
+
klass.thread_safe.should be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'defaults to false' do
|
35
|
+
klass.thread_safe.should be_false
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'uses #synchronize' do
|
39
|
+
klass.monitor.should_receive(:synchronize).once
|
40
|
+
klass.thread_safe.should be_nil
|
41
|
+
end
|
42
|
+
end # thread_safe
|
43
|
+
|
44
|
+
describe '.thread_safe=' do
|
45
|
+
after { klass.instance_variable_set('@thread_safe', nil) }
|
46
|
+
|
47
|
+
it 'sets @thread_safe' do
|
48
|
+
klass.instance_variable_get('@thread_safe').should be_nil
|
49
|
+
klass.thread_safe = true
|
50
|
+
klass.instance_variable_get('@thread_safe').should be_true
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'uses #synchronize' do
|
54
|
+
klass.monitor.should_receive(:synchronize).once
|
55
|
+
klass.thread_safe = true
|
56
|
+
klass.instance_variable_get('@thread_safe').should be_nil
|
57
|
+
end
|
58
|
+
end # thread_safe=
|
59
|
+
|
60
|
+
describe "InstanceMethods" do
|
61
|
+
subject { SynchronizeSpecHelper.new }
|
62
|
+
|
63
|
+
describe '.monitor' do
|
64
|
+
it 'defers to Redistat::Synchronize' do
|
65
|
+
klass.should_receive(:monitor).once
|
66
|
+
subject.monitor
|
67
|
+
end
|
68
|
+
end # monitor
|
69
|
+
|
70
|
+
describe '.thread_safe' do
|
71
|
+
it ' defers to Redistat::Synchronize' do
|
72
|
+
klass.should_receive(:thread_safe).once
|
73
|
+
subject.thread_safe
|
74
|
+
end
|
75
|
+
end # thread_safe
|
76
|
+
|
77
|
+
describe '.thread_safe=' do
|
78
|
+
it 'defers to Redistat::Synchronize' do
|
79
|
+
klass.should_receive(:thread_safe=).once.with(true)
|
80
|
+
subject.thread_safe = true
|
81
|
+
end
|
82
|
+
end # thread_safe=
|
83
|
+
|
84
|
+
describe 'when #thread_safe is true' do
|
85
|
+
before { subject.stub(:thread_safe).and_return(true) }
|
86
|
+
|
87
|
+
describe '.synchronize' do
|
88
|
+
it 'defers to #monitor' do
|
89
|
+
subject.monitor.should_receive(:synchronize).once
|
90
|
+
subject.synchronize { 'foo' }
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'passes block along to #monitor.synchronize' do
|
94
|
+
yielded = false
|
95
|
+
subject.synchronize { yielded = true }
|
96
|
+
yielded.should be_true
|
97
|
+
end
|
98
|
+
end # synchronize
|
99
|
+
end # when #thread_safe is true
|
100
|
+
|
101
|
+
describe 'when #thread_safe is false' do
|
102
|
+
before { subject.stub(:thread_safe).and_return(false) }
|
103
|
+
|
104
|
+
describe '.synchronize' do
|
105
|
+
it 'does not defer to #monitor' do
|
106
|
+
subject.monitor.should_not_receive(:synchronize)
|
107
|
+
subject.synchronize { 'foo' }
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'yields block' do
|
111
|
+
yielded = false
|
112
|
+
subject.synchronize { yielded = true }
|
113
|
+
yielded.should be_true
|
114
|
+
end
|
115
|
+
end # synchronize
|
116
|
+
end # when #thread_safe is false
|
117
|
+
|
57
118
|
end
|
58
|
-
|
59
|
-
|
60
|
-
end
|
119
|
+
|
120
|
+
end # Synchronize
|
121
|
+
end # Redistat
|
61
122
|
|
62
123
|
class SynchronizeSpecHelper
|
63
124
|
include Redistat::Synchronize
|
data/spec/thread_safety_spec.rb
CHANGED
@@ -2,13 +2,13 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe "Thread-Safety" do
|
4
4
|
include Redistat::Database
|
5
|
-
|
5
|
+
|
6
6
|
before(:each) do
|
7
7
|
db.flushdb
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
#TODO should have more comprehensive thread-safe tests
|
11
|
-
|
11
|
+
|
12
12
|
it "should incr in multiple threads" do
|
13
13
|
threads = []
|
14
14
|
50.times do
|
@@ -19,7 +19,7 @@ describe "Thread-Safety" do
|
|
19
19
|
threads.each { |t| t.join }
|
20
20
|
db.get("spec:incr").should == "50"
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
it "should store event in multiple threads" do
|
24
24
|
class ThreadSafetySpec
|
25
25
|
include Redistat::Model
|
@@ -35,5 +35,5 @@ describe "Thread-Safety" do
|
|
35
35
|
result.total[:count].should == 50
|
36
36
|
result.total[:rand].should <= 250
|
37
37
|
end
|
38
|
-
|
39
|
-
end
|
38
|
+
|
39
|
+
end
|