redistat 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,112 @@
1
+ require "spec_helper"
2
+
3
+ describe Redistat::Finder do
4
+ include Redistat::Database
5
+
6
+ before(:each) do
7
+ db.flushdb
8
+ @scope = "PageViews"
9
+ @label = "about_us"
10
+ @date = Time.now
11
+ @key = Redistat::Key.new(@scope, @label, @date, {:depth => :day})
12
+ @stats = {"views" => 3, "visitors" => 2}
13
+ end
14
+
15
+ it "should initialize properly" do
16
+ two_hours_ago = 2.hours.ago
17
+ one_hour_ago = 1.hour.ago
18
+ options = {:scope => "PageViews", :label => "Label", :from => two_hours_ago, :till => one_hour_ago, :depth => :hour, :interval => :hour}
19
+
20
+ finder = Redistat::Finder.new(options)
21
+ finder.options.should == options
22
+
23
+ finder = Redistat::Finder.dates(two_hours_ago, one_hour_ago).scope("PageViews").label("Label").depth(:hour).interval(:hour)
24
+ finder.options.should == options
25
+
26
+ finder = Redistat::Finder.scope("PageViews").label("Label").from(two_hours_ago).till(one_hour_ago).depth(:hour).interval(:hour)
27
+ finder.options.should == options
28
+
29
+ finder = Redistat::Finder.label("Label").from(two_hours_ago).till(one_hour_ago).depth(:hour).interval(:hour).scope("PageViews")
30
+ finder.options.should == options
31
+
32
+ finder = Redistat::Finder.from(two_hours_ago).till(one_hour_ago).depth(:hour).interval(:hour).scope("PageViews").label("Label")
33
+ finder.options.should == options
34
+
35
+ finder = Redistat::Finder.till(one_hour_ago).depth(:hour).interval(:hour).scope("PageViews").label("Label").from(two_hours_ago)
36
+ finder.options.should == options
37
+
38
+ finder = Redistat::Finder.depth(:hour).interval(:hour).scope("PageViews").label("Label").from(two_hours_ago).till(one_hour_ago)
39
+ finder.options.should == options
40
+
41
+ finder = Redistat::Finder.interval(:hour).scope("PageViews").label("Label").from(two_hours_ago).till(one_hour_ago).depth(:hour)
42
+ finder.options.should == options
43
+
44
+ end
45
+
46
+ it "should fetch stats properly" do
47
+ first_stat, last_stat = create_example_stats
48
+
49
+ stats = Redistat::Finder.find({:from => first_stat, :till => last_stat, :scope => @scope, :label => @label, :depth => :hour})
50
+ stats.from.should == first_stat
51
+ stats.till.should == last_stat
52
+ stats.depth.should == :hour
53
+
54
+ stats.total.should == { "views" => 12, "visitors" => 8 }
55
+ stats.total.from.should == first_stat
56
+ stats.total.till.should == last_stat
57
+ stats.first.should == stats.total
58
+ end
59
+
60
+ it "should fetch data per unit when interval option is specified" do
61
+ first_stat, last_stat = create_example_stats
62
+
63
+ stats = Redistat::Finder.find(:from => first_stat, :till => last_stat, :scope => @scope, :label => @label, :depth => :hour, :interval => :hour)
64
+ stats.from.should == first_stat
65
+ stats.till.should == last_stat
66
+ stats.total.should == { "views" => 12, "visitors" => 8 }
67
+ stats[0].should == {}
68
+ stats[0].date.should == Time.parse("2010-05-14 12:00")
69
+ stats[1].should == {"visitors"=>"4", "views"=>"6"}
70
+ stats[1].date.should == Time.parse("2010-05-14 13:00")
71
+ stats[2].should == {"visitors"=>"2", "views"=>"3"}
72
+ stats[2].date.should == Time.parse("2010-05-14 14:00")
73
+ stats[3].should == {"visitors"=>"2", "views"=>"3"}
74
+ stats[3].date.should == Time.parse("2010-05-14 15:00")
75
+ stats[4].should == {}
76
+ stats[4].date.should == Time.parse("2010-05-14 16:00")
77
+ end
78
+
79
+ it "should return empty hash when attempting to fetch non-existent results" do
80
+ stats = Redistat::Finder.find({:from => 3.hours.ago, :till => 2.hours.from_now, :scope => @scope, :label => @label, :depth => :hour})
81
+ stats.total.should == {}
82
+ end
83
+
84
+ it "should throw error on invalid options" do
85
+ lambda { Redistat::Finder.find(:from => 3.hours.ago) }.should raise_error(Redistat::InvalidOptions)
86
+ end
87
+
88
+
89
+ # helper methods
90
+
91
+ def create_example_stats
92
+ key = Redistat::Key.new(@scope, @label, (first = Time.parse("2010-05-14 13:43")))
93
+ Redistat::Summary.update(key, @stats, :hour)
94
+ key = Redistat::Key.new(@scope, @label, Time.parse("2010-05-14 13:53"))
95
+ Redistat::Summary.update(key, @stats, :hour)
96
+ key = Redistat::Key.new(@scope, @label, Time.parse("2010-05-14 14:32"))
97
+ Redistat::Summary.update(key, @stats, :hour)
98
+ key = Redistat::Key.new(@scope, @label, (last = Time.parse("2010-05-14 15:02")))
99
+ Redistat::Summary.update(key, @stats, :hour)
100
+ [first - 1.hour, last + 1.hour]
101
+ end
102
+
103
+ end
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
data/spec/key_spec.rb ADDED
@@ -0,0 +1,63 @@
1
+ require "spec_helper"
2
+
3
+ describe Redistat::Key do
4
+
5
+ before(:each) do
6
+ @scope = "PageViews"
7
+ @label = "about_us"
8
+ @label_hash = Digest::SHA1.hexdigest(@label)
9
+ @date = Time.now
10
+ @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour})
11
+ end
12
+
13
+ it "should initialize properly" do
14
+ @key.scope.should == @scope
15
+ @key.label.should == @label
16
+ @key.label_hash.should == @label_hash
17
+ @key.date.should be_instance_of(Redistat::Date)
18
+ @key.date.to_time.to_s.should == @date.to_s
19
+ end
20
+
21
+ it "should convert to string properly" do
22
+ @key.to_s.should == "#{@scope}/#{@label_hash}:#{@key.date.to_s(:hour)}"
23
+ props = [:year, :month, :day, :hour, :min, :sec]
24
+ props.each do
25
+ @key.to_s(props.last).should == "#{@scope}/#{@label_hash}:#{@key.date.to_s(props.last)}"
26
+ props.pop
27
+ end
28
+ end
29
+
30
+ it "should abide to hash_label option" do
31
+ @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour, :label_hash => true})
32
+ @key.to_s.should == "#{@scope}/#{@label_hash}:#{@key.date.to_s(:hour)}"
33
+ @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour, :label_hash => false})
34
+ @key.to_s.should == "#{@scope}/#{@label}:#{@key.date.to_s(:hour)}"
35
+ end
36
+
37
+ it "should have default depth option" do
38
+ @key = Redistat::Key.new(@scope, @label, @date)
39
+ @key.depth.should == :day
40
+ end
41
+
42
+ it "should allow changing attributes" do
43
+ # scope
44
+ @key.scope.should == @scope
45
+ @scope = "VisitorCount"
46
+ @key.scope = @scope
47
+ @key.scope.should == @scope
48
+ # date
49
+ @key.date.to_time.should == @date
50
+ @date = Time.now
51
+ @key.date = @date
52
+ @key.date.to_time.should == @date
53
+ # label
54
+ @key.label.should == @label
55
+ @key.label_hash == @label_hash
56
+ @label = "contact_us"
57
+ @label_hash = Digest::SHA1.hexdigest(@label)
58
+ @key.label = @label
59
+ @key.label.should == @label
60
+ @key.label_hash == @label_hash
61
+ end
62
+
63
+ end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ describe Redistat::Label do
4
+ include Redistat::Database
5
+
6
+ before(:each) do
7
+ db.flushdb
8
+ @name = "about_us"
9
+ @label = Redistat::Label.new(@name)
10
+ end
11
+
12
+ it "should initialize properly and SHA1 hash the label name" do
13
+ @label.name.should == @name
14
+ @label.hash.should == Digest::SHA1.hexdigest(@name)
15
+ end
16
+
17
+ it "should store a label hash lookup key" do
18
+ @label.save
19
+ @label.saved?.should be_true
20
+ db.get("#{Redistat::KEY_LEBELS}#{@label.hash}").should == @name
21
+
22
+ @name = "contact_us"
23
+ @label = Redistat::Label.create(@name)
24
+ @label.saved?.should be_true
25
+ db.get("#{Redistat::KEY_LEBELS}#{@label.hash}").should == @name
26
+ end
27
+
28
+ end
@@ -0,0 +1,15 @@
1
+ require "redistat"
2
+
3
+ class ModelHelper
4
+ include Redistat::Model
5
+
6
+
7
+ end
8
+
9
+ class ModelHelper2
10
+ include Redistat::Model
11
+
12
+ depth :day
13
+ store_event true
14
+
15
+ end
@@ -0,0 +1,60 @@
1
+ require "spec_helper"
2
+ require "model_helper"
3
+
4
+ describe Redistat::Model do
5
+ include Redistat::Database
6
+
7
+ before(:each) do
8
+ db.flushdb
9
+ end
10
+
11
+ it "should should name itself correctly" do
12
+ ModelHelper.send(:name).should == "ModelHelper"
13
+ ModelHelper2.send(:name).should == "ModelHelper2"
14
+ end
15
+
16
+ it "should listen to model-defined options" do
17
+ ModelHelper2.depth.should == :day
18
+ ModelHelper2.store_event.should == true
19
+
20
+ ModelHelper.depth.should == nil
21
+ ModelHelper.store_event.should == nil
22
+ ModelHelper.depth(:hour)
23
+ ModelHelper.depth.should == :hour
24
+ ModelHelper.store_event(true)
25
+ ModelHelper.store_event.should == true
26
+ ModelHelper.options[:depth] = nil
27
+ ModelHelper.options[:store_event] = nil
28
+ ModelHelper.depth.should == nil
29
+ ModelHelper.store_event.should == nil
30
+ end
31
+
32
+ it "should store and fetch stats" do
33
+ ModelHelper.store("sheep.black", {:count => 6, :weight => 461}, 4.hours.ago)
34
+ ModelHelper.store("sheep.black", {:count => 2, :weight => 156})
35
+
36
+ stats = ModelHelper.fetch("sheep.black", 2.hours.ago, 1.hour.from_now)
37
+ stats.total["count"].should == 2
38
+ stats.total["weight"].should == 156
39
+ stats.first.should == stats.total
40
+
41
+ stats = ModelHelper.fetch("sheep.black", 5.hours.ago, 1.hour.from_now)
42
+ stats.total[:count].should == 8
43
+ stats.total[:weight].should == 617
44
+ stats.first.should == stats.total
45
+
46
+ ModelHelper.store("sheep.white", {:count => 5, :weight => 393}, 4.hours.ago)
47
+ ModelHelper.store("sheep.white", {:count => 4, :weight => 316})
48
+
49
+ stats = ModelHelper.fetch("sheep.white", 2.hours.ago, 1.hour.from_now)
50
+ stats.total[:count].should == 4
51
+ stats.total[:weight].should == 316
52
+ stats.first.should == stats.total
53
+
54
+ stats = ModelHelper.fetch("sheep.white", 5.hours.ago, 1.hour.from_now)
55
+ stats.total[:count].should == 9
56
+ stats.total[:weight].should == 709
57
+ stats.first.should == stats.total
58
+ end
59
+
60
+ end
@@ -0,0 +1,9 @@
1
+ daemonize yes
2
+ dir ./spec/db
3
+ pidfile ./redis.pid
4
+ port 8379
5
+ bind 127.0.0.1
6
+ timeout 300
7
+ loglevel debug
8
+ logfile stdout
9
+ databases 16
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ describe Redistat::Result do
4
+
5
+ it "should should initialize properly" do
6
+ options = {:from => "from", :till => "till"}
7
+ result = Redistat::Result.new(options)
8
+ result.from.should == "from"
9
+ result.till.should == "till"
10
+ end
11
+
12
+ it "should have set_or_incr method" do
13
+ result = Redistat::Result.new
14
+ result[:world].should be_nil
15
+ result.set_or_incr(:world, 3)
16
+ result[:world].should == 3
17
+ result.set_or_incr(:world, 8)
18
+ result[:world].should == 11
19
+ end
20
+
21
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ describe Redistat::Scope do
4
+ include Redistat::Database
5
+
6
+ before(:all) do
7
+ db.flushdb
8
+ end
9
+
10
+ before(:each) do
11
+ @name = "PageViews"
12
+ @scope = Redistat::Scope.new(@name)
13
+ end
14
+
15
+ it "should initialize properly" do
16
+ @scope.to_s.should == @name
17
+ end
18
+
19
+ it "should increment next_id" do
20
+ scope = Redistat::Scope.new("Visitors")
21
+ @scope.next_id.should == 1
22
+ scope.next_id.should == 1
23
+ @scope.next_id.should == 2
24
+ scope.next_id.should == 2
25
+ end
26
+
27
+ end
@@ -0,0 +1,12 @@
1
+ # add project-relative load paths
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+
5
+ # require stuff
6
+ require 'redistat'
7
+ require 'rspec'
8
+ require 'rspec/autorun'
9
+
10
+ # use the test Redistat instance
11
+ Redistat.connect({:port => 8379, :db => 15})
12
+ Redistat.flush
@@ -0,0 +1,72 @@
1
+ require "spec_helper"
2
+
3
+ describe Redistat::Summary do
4
+ include Redistat::Database
5
+
6
+ before(:each) do
7
+ db.flushdb
8
+ @scope = "PageViews"
9
+ @label = "about_us"
10
+ @date = Time.now
11
+ @key = Redistat::Key.new(@scope, @label, @date, {:depth => :day})
12
+ @stats = {"views" => 3, "visitors" => 2}
13
+ end
14
+
15
+ it "should update a single summary properly" do
16
+ Redistat::Summary.update(@key, @stats, :hour)
17
+ summary = db.hgetall(@key.to_s(:hour))
18
+ summary.should have(2).items
19
+ summary["views"].should == "3"
20
+ summary["visitors"].should == "2"
21
+
22
+ Redistat::Summary.update(@key, @stats, :hour)
23
+ summary = db.hgetall(@key.to_s(:hour))
24
+ summary.should have(2).items
25
+ summary["views"].should == "6"
26
+ summary["visitors"].should == "4"
27
+
28
+ Redistat::Summary.update(@key, {"views" => -4, "visitors" => -3}, :hour)
29
+ summary = db.hgetall(@key.to_s(:hour))
30
+ summary.should have(2).items
31
+ summary["views"].should == "2"
32
+ summary["visitors"].should == "1"
33
+ end
34
+
35
+ it "should update all summaries properly" do
36
+ Redistat::Summary.update_all(@key, @stats, :sec)
37
+ [:year, :month, :day, :hour, :min, :sec, :usec].each do |depth|
38
+ summary = db.hgetall(@key.to_s(depth))
39
+ if depth != :usec
40
+ summary.should have(2).items
41
+ summary["views"].should == "3"
42
+ summary["visitors"].should == "2"
43
+ else
44
+ summary.should have(0).items
45
+ end
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+
72
+
metadata ADDED
@@ -0,0 +1,216 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redistat
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jim Myhrberg
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-22 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activesupport
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 2
32
+ - 3
33
+ - 0
34
+ version: 2.3.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: json
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 23
46
+ segments:
47
+ - 1
48
+ - 0
49
+ - 0
50
+ version: 1.0.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: redis
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 15
62
+ segments:
63
+ - 2
64
+ - 0
65
+ - 0
66
+ version: 2.0.0
67
+ type: :runtime
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: time_ext
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 27
78
+ segments:
79
+ - 0
80
+ - 2
81
+ - 6
82
+ version: 0.2.6
83
+ type: :runtime
84
+ version_requirements: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ name: rspec
87
+ prerelease: false
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 13
94
+ segments:
95
+ - 2
96
+ - 0
97
+ - 1
98
+ version: 2.0.1
99
+ type: :development
100
+ version_requirements: *id005
101
+ - !ruby/object:Gem::Dependency
102
+ name: yard
103
+ prerelease: false
104
+ requirement: &id006 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 5
110
+ segments:
111
+ - 0
112
+ - 6
113
+ - 1
114
+ version: 0.6.1
115
+ type: :development
116
+ version_requirements: *id006
117
+ description: A Redis-backed statistics storage and querying library written in Ruby.
118
+ email: contact@jimeh.me
119
+ executables: []
120
+
121
+ extensions: []
122
+
123
+ extra_rdoc_files:
124
+ - LICENSE
125
+ - README.md
126
+ files:
127
+ - .document
128
+ - .gitignore
129
+ - .rspec
130
+ - Gemfile
131
+ - Gemfile.lock
132
+ - LICENSE
133
+ - README.md
134
+ - Rakefile
135
+ - VERSION
136
+ - lib/redistat.rb
137
+ - lib/redistat/collection.rb
138
+ - lib/redistat/core_ext/date.rb
139
+ - lib/redistat/core_ext/fixnum.rb
140
+ - lib/redistat/core_ext/time.rb
141
+ - lib/redistat/database.rb
142
+ - lib/redistat/date.rb
143
+ - lib/redistat/event.rb
144
+ - lib/redistat/finder.rb
145
+ - lib/redistat/finder/date_set.rb
146
+ - lib/redistat/key.rb
147
+ - lib/redistat/label.rb
148
+ - lib/redistat/model.rb
149
+ - lib/redistat/result.rb
150
+ - lib/redistat/scope.rb
151
+ - lib/redistat/summary.rb
152
+ - spec/_redistat_spec.rb
153
+ - spec/collection_spec.rb
154
+ - spec/date_spec.rb
155
+ - spec/db/.emptydir
156
+ - spec/event_spec.rb
157
+ - spec/finder/date_set_spec.rb
158
+ - spec/finder_spec.rb
159
+ - spec/key_spec.rb
160
+ - spec/label_spec.rb
161
+ - spec/model_helper.rb
162
+ - spec/model_spec.rb
163
+ - spec/redis-test.conf
164
+ - spec/result_spec.rb
165
+ - spec/scope_spec.rb
166
+ - spec/spec_helper.rb
167
+ - spec/summary_spec.rb
168
+ has_rdoc: true
169
+ homepage: http://github.com/jimeh/redistat
170
+ licenses: []
171
+
172
+ post_install_message:
173
+ rdoc_options:
174
+ - --charset=UTF-8
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ hash: 3
183
+ segments:
184
+ - 0
185
+ version: "0"
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ none: false
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ hash: 3
192
+ segments:
193
+ - 0
194
+ version: "0"
195
+ requirements: []
196
+
197
+ rubyforge_project:
198
+ rubygems_version: 1.3.7
199
+ signing_key:
200
+ specification_version: 3
201
+ summary: A Redis-backed statistics storage and querying library written in Ruby.
202
+ test_files:
203
+ - spec/_redistat_spec.rb
204
+ - spec/collection_spec.rb
205
+ - spec/date_spec.rb
206
+ - spec/event_spec.rb
207
+ - spec/finder/date_set_spec.rb
208
+ - spec/finder_spec.rb
209
+ - spec/key_spec.rb
210
+ - spec/label_spec.rb
211
+ - spec/model_helper.rb
212
+ - spec/model_spec.rb
213
+ - spec/result_spec.rb
214
+ - spec/scope_spec.rb
215
+ - spec/spec_helper.rb
216
+ - spec/summary_spec.rb