redistat 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.travis.yml +8 -0
  2. data/README.md +219 -97
  3. data/lib/redistat.rb +13 -13
  4. data/lib/redistat/buffer.rb +27 -24
  5. data/lib/redistat/collection.rb +5 -5
  6. data/lib/redistat/connection.rb +23 -18
  7. data/lib/redistat/core_ext.rb +1 -1
  8. data/lib/redistat/core_ext/bignum.rb +2 -2
  9. data/lib/redistat/core_ext/date.rb +2 -2
  10. data/lib/redistat/core_ext/fixnum.rb +2 -2
  11. data/lib/redistat/core_ext/hash.rb +4 -4
  12. data/lib/redistat/date.rb +11 -11
  13. data/lib/redistat/event.rb +18 -18
  14. data/lib/redistat/finder.rb +39 -39
  15. data/lib/redistat/finder/date_set.rb +4 -4
  16. data/lib/redistat/key.rb +16 -16
  17. data/lib/redistat/label.rb +14 -14
  18. data/lib/redistat/mixins/database.rb +1 -1
  19. data/lib/redistat/mixins/date_helper.rb +1 -1
  20. data/lib/redistat/mixins/options.rb +8 -8
  21. data/lib/redistat/mixins/synchronize.rb +12 -11
  22. data/lib/redistat/model.rb +25 -17
  23. data/lib/redistat/result.rb +4 -4
  24. data/lib/redistat/scope.rb +5 -5
  25. data/lib/redistat/summary.rb +33 -26
  26. data/lib/redistat/version.rb +1 -1
  27. data/redistat.gemspec +4 -3
  28. data/spec/buffer_spec.rb +27 -25
  29. data/spec/collection_spec.rb +4 -4
  30. data/spec/connection_spec.rb +12 -12
  31. data/spec/core_ext/hash_spec.rb +5 -5
  32. data/spec/database_spec.rb +3 -3
  33. data/spec/date_spec.rb +15 -15
  34. data/spec/event_spec.rb +8 -8
  35. data/spec/finder/date_set_spec.rb +134 -134
  36. data/spec/finder_spec.rb +36 -36
  37. data/spec/key_spec.rb +19 -19
  38. data/spec/label_spec.rb +10 -10
  39. data/spec/model_helper.rb +10 -9
  40. data/spec/model_spec.rb +38 -41
  41. data/spec/options_spec.rb +9 -9
  42. data/spec/result_spec.rb +4 -4
  43. data/spec/scope_spec.rb +6 -6
  44. data/spec/spec_helper.rb +6 -0
  45. data/spec/summary_spec.rb +31 -24
  46. data/spec/synchronize_spec.rb +118 -57
  47. data/spec/thread_safety_spec.rb +6 -6
  48. metadata +88 -126
  49. data/.rvmrc +0 -1
@@ -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
@@ -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
@@ -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
@@ -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'
@@ -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
@@ -1,63 +1,124 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Redistat::Synchronize do
4
- it { should respond_to(:monitor) }
5
- it { should respond_to(:thread_safe) }
6
- it { should respond_to(:thread_safe=) }
7
-
8
- describe "instanciated class with Redistat::Synchronize included" do
9
- subject { SynchronizeSpecHelper.new }
10
- it { should respond_to(:monitor) }
11
- it { should respond_to(:thread_safe) }
12
- it { should respond_to(:thread_safe=) }
13
- it { should respond_to(:synchronize) }
14
-
15
- end
16
-
17
- describe "#synchronize method" do
18
-
19
- before(:each) do
20
- Redistat::Synchronize.instance_variable_set("@thread_safe", nil)
21
- @obj = SynchronizeSpecHelper.new
22
- end
23
-
24
- it "should share single Monitor object across all objects" do
25
- @obj.monitor.should == Redistat::Synchronize.monitor
26
- end
27
-
28
- it "should share thread_safe option across all objects" do
29
- obj2 = SynchronizeSpecHelper.new
30
- Redistat::Synchronize.thread_safe.should be_false
31
- @obj.thread_safe.should be_false
32
- obj2.thread_safe.should be_false
33
- @obj.thread_safe = true
34
- Redistat::Synchronize.thread_safe.should be_true
35
- @obj.thread_safe.should be_true
36
- obj2.thread_safe.should be_true
37
- end
38
-
39
- it "should not synchronize when thread_safe is disabled" do
40
- # monitor receives :synchronize twice cause #thread_safe is _always_ synchronized
41
- Redistat::Synchronize.monitor.should_receive(:synchronize).twice
42
- @obj.thread_safe.should be_false # first #synchronize call
43
- @obj.synchronize { 'foo' } # one #synchronize call while checking #thread_safe
44
- end
45
-
46
- it "should synchronize when thread_safe is enabled" do
47
- Monitor.class_eval {
48
- # we're stubbing synchronize to ensure it's being called correctly, but still need it :P
49
- alias :real_synchronize :synchronize
50
- }
51
- Redistat::Synchronize.monitor.should_receive(:synchronize).with.exactly(4).times.and_return { |block|
52
- Redistat::Synchronize.monitor.real_synchronize(&block)
53
- }
54
- @obj.thread_safe.should be_false # first synchronize call
55
- Redistat::Synchronize.thread_safe = true # second synchronize call
56
- @obj.synchronize { 'foo' } # two synchronize calls, once while checking thread_safe, once to call black
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
- end
59
-
60
- end
119
+
120
+ end # Synchronize
121
+ end # Redistat
61
122
 
62
123
  class SynchronizeSpecHelper
63
124
  include Redistat::Synchronize
@@ -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