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.
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