von 0.1.0 → 0.2.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.
@@ -0,0 +1,53 @@
1
+ require 'test_helper'
2
+
3
+ describe Von::Counters::Best do
4
+ BestCounter = Von::Counters::Best
5
+
6
+ before :each do
7
+ Timecop.freeze(Time.local(2013, 01, 01, 06))
8
+ Von.config.init!
9
+ @redis = Redis.new
10
+ @redis.flushall
11
+ end
12
+
13
+ it "increments the best counter for a period" do
14
+ counter = BestCounter.new('foo', [ Von::Period.new(:day) ])
15
+
16
+ counter.increment
17
+
18
+ Timecop.freeze(Time.local(2013, 01, 02))
19
+ 4.times { counter.increment }
20
+ Timecop.freeze(Time.local(2013, 01, 03))
21
+ 3.times { counter.increment }
22
+
23
+ @redis.hget('von:counters:bests:foo:day:current', 'timestamp').must_equal '2013-01-03'
24
+ @redis.hget('von:counters:bests:foo:day:current', 'total').must_equal '3'
25
+ @redis.hget('von:counters:bests:foo:day:best', 'timestamp').must_equal '2013-01-02'
26
+ @redis.hget('von:counters:bests:foo:day:best', 'total').must_equal '4'
27
+ end
28
+
29
+ it "increments the best counter for multiple periods" do
30
+ counter = BestCounter.new('foo', [
31
+ Von::Period.new(:minute),
32
+ Von::Period.new(:week),
33
+ ])
34
+
35
+ counter.increment
36
+
37
+ Timecop.freeze(Time.local(2013, 01, 13, 06, 05))
38
+ 4.times { counter.increment }
39
+ Timecop.freeze(Time.local(2013, 01, 20, 06, 10))
40
+ 3.times { counter.increment }
41
+
42
+ @redis.hget('von:counters:bests:foo:minute:current', 'timestamp').must_equal '2013-01-20 06:10'
43
+ @redis.hget('von:counters:bests:foo:minute:current', 'total').must_equal '3'
44
+ @redis.hget('von:counters:bests:foo:minute:best', 'timestamp').must_equal '2013-01-13 06:05'
45
+ @redis.hget('von:counters:bests:foo:minute:best', 'total').must_equal '4'
46
+
47
+ @redis.hget('von:counters:bests:foo:week:current', 'timestamp').must_equal '2013-01-14'
48
+ @redis.hget('von:counters:bests:foo:week:current', 'total').must_equal '3'
49
+ @redis.hget('von:counters:bests:foo:week:best', 'timestamp').must_equal '2013-01-07'
50
+ @redis.hget('von:counters:bests:foo:week:best', 'total').must_equal '4'
51
+ end
52
+
53
+ end
@@ -0,0 +1,55 @@
1
+ require 'test_helper'
2
+
3
+ describe Von::Counters::Current do
4
+ CurrentCounter = Von::Counters::Current
5
+
6
+ before :each do
7
+ Timecop.freeze(Time.local(2013, 01, 01, 06))
8
+ Von.config.init!
9
+ @redis = Redis.new
10
+ @redis.flushall
11
+ end
12
+
13
+ it "increments the current counter for a period" do
14
+ counter = CurrentCounter.new('foo', [ Von::Period.new(:day) ])
15
+
16
+ 4.times { counter.increment }
17
+ Timecop.freeze(Time.local(2013, 01, 02))
18
+ 3.times { counter.increment }
19
+
20
+ @redis.hget('von:counters:currents:foo:day', 'timestamp').must_equal '2013-01-02'
21
+ @redis.hget('von:counters:currents:foo:day', 'total').must_equal '3'
22
+ end
23
+
24
+ it "increments the current counter for multiple periods" do
25
+ counter = CurrentCounter.new('foo', [
26
+ Von::Period.new(:minute),
27
+ Von::Period.new(:week),
28
+ ])
29
+
30
+ 4.times { counter.increment }
31
+ Timecop.freeze(Time.local(2013, 01, 20, 06, 10))
32
+ 3.times { counter.increment }
33
+
34
+ @redis.hget('von:counters:currents:foo:minute', 'timestamp').must_equal '2013-01-20 06:10'
35
+ @redis.hget('von:counters:currents:foo:minute', 'total').must_equal '3'
36
+
37
+ @redis.hget('von:counters:currents:foo:week', 'timestamp').must_equal '2013-01-14'
38
+ @redis.hget('von:counters:currents:foo:week', 'total').must_equal '3'
39
+ end
40
+
41
+ it "counts acurrent counter for a period" do
42
+ counter = CurrentCounter.new('foo', [
43
+ Von::Period.new(:minute),
44
+ Von::Period.new(:day),
45
+ ])
46
+
47
+ 4.times { counter.increment }
48
+ Timecop.freeze(Time.local(2013, 01, 01, 06, 10))
49
+ 3.times { counter.increment }
50
+
51
+ counter.count(:minute).must_equal 3
52
+ counter.count(:day).must_equal 7
53
+ end
54
+
55
+ end
@@ -0,0 +1,78 @@
1
+ require 'test_helper'
2
+
3
+ describe Von::Counters::Period do
4
+ PeriodCounter = Von::Counters::Period
5
+
6
+ before :each do
7
+ Timecop.freeze(Time.local(2013, 01, 01, 01, 01))
8
+ Von.config.init!
9
+ @redis = Redis.new
10
+ @redis.flushall
11
+ end
12
+
13
+ it "increments a month counter" do
14
+ counter = PeriodCounter.new('foo', [
15
+ Von::Period.new(:monthly, 1)
16
+ ])
17
+
18
+ counter.increment
19
+ counter.increment
20
+
21
+ @redis.hget('von:counters:foo:month', '2013-01').must_equal '2'
22
+ @redis.lrange('von:lists:foo:month', 0, -1).size.must_equal 1
23
+ @redis.lrange('von:lists:foo:month', 0, -1).first.must_equal '2013-01'
24
+ end
25
+
26
+ it 'increments a minute counter' do
27
+ counter = PeriodCounter.new('foo', [
28
+ Von::Period.new(:minutely, 60)
29
+ ])
30
+
31
+ counter.increment
32
+ counter.increment
33
+
34
+ @redis.hget('von:counters:foo:minute', '2013-01-01 01:01').must_equal '2'
35
+ @redis.lrange('von:lists:foo:minute', 0, -1).size.must_equal 1
36
+ @redis.lrange('von:lists:foo:minute', 0, -1).first.must_equal '2013-01-01 01:01'
37
+ end
38
+
39
+ it "expires counters past the limit" do
40
+ counter = PeriodCounter.new('foo', [
41
+ Von::Period.new(:monthly, 1)
42
+ ])
43
+
44
+ counter.increment
45
+ Timecop.freeze(Time.local(2013, 02))
46
+ counter.increment
47
+
48
+ @redis.hget('von:counters:foo:month', '2013-02').must_equal '1'
49
+ @redis.lrange('von:lists:foo:month', 0, -1).size.must_equal 1
50
+ @redis.lrange('von:lists:foo:month', 0, -1).first.must_equal '2013-02'
51
+ end
52
+
53
+
54
+ it "gets a count for a time period and 0s missing entries" do
55
+ counter = PeriodCounter.new('foo', [
56
+ Von::Period.new(:monthly, 1),
57
+ Von::Period.new(:hourly, 6)
58
+ ])
59
+
60
+ counter.increment
61
+ counter.increment
62
+ Timecop.freeze(Time.local(2013, 02, 01, 7))
63
+ counter.increment
64
+ Timecop.freeze(Time.local(2013, 02, 01, 9))
65
+ counter.increment
66
+
67
+ counter.count(:month).must_equal [{:timestamp => "2013-02", :count => 2}]
68
+ counter.count(:hour).must_equal [
69
+ { :timestamp => "2013-02-01 04:00", :count => 0 },
70
+ { :timestamp => "2013-02-01 05:00", :count => 0 },
71
+ { :timestamp => "2013-02-01 06:00", :count => 0 },
72
+ { :timestamp => "2013-02-01 07:00", :count => 1 },
73
+ { :timestamp => "2013-02-01 08:00", :count => 0 },
74
+ { :timestamp => "2013-02-01 09:00", :count => 1 }
75
+ ]
76
+ end
77
+
78
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ describe Von::Counters::Total do
4
+ TotalCounter = Von::Counters::Total
5
+
6
+ before :each do
7
+ Timecop.freeze(Time.local(2013, 01, 01, 01, 01))
8
+ Von.config.init!
9
+ @redis = Redis.new
10
+ @redis.flushall
11
+ end
12
+
13
+ it "increments the total counter if given a single key" do
14
+ counter = TotalCounter.new('foo')
15
+
16
+ counter.increment
17
+ @redis.hget('von:counters:foo', 'total').must_equal '1'
18
+
19
+ counter.increment
20
+ @redis.hget('von:counters:foo', 'total').must_equal '2'
21
+ end
22
+
23
+ it "gets a total count for a counter" do
24
+ counter = TotalCounter.new('foo')
25
+ counter.increment
26
+ counter.increment
27
+ counter.increment
28
+
29
+ counter.count.must_equal 3
30
+ end
31
+
32
+
33
+ end
@@ -1,65 +1,87 @@
1
+ require 'test_helper'
2
+
1
3
  describe Von::Period do
2
4
  Period = Von::Period
3
5
 
4
6
  before :each do
5
7
  @config = Von::Config
6
8
  @config.init!
9
+ Timecop.freeze(Time.local(2013, 01, 02, 03, 04))
7
10
  end
8
11
 
9
- it "intiializes given a counter, period, and length" do
10
- period = Period.new('foo', :monthly, 6)
11
- period.counter_key.must_equal 'foo'
12
- period.length.must_equal 6
12
+ it "intiializes given a period" do
13
+ period = Period.new(:monthly)
14
+ period.name.must_equal :monthly
15
+ period.length.must_be_nil
13
16
  period.format.must_equal '%Y-%m'
14
17
  end
15
18
 
16
- it "checks if the period is an hourly period" do
17
- Period.new('foo', :hourly, 6).must_be :hours?
18
- Period.new('foo', :daily, 6).wont_be :hours?
19
- Period.new('foo', :weekly, 6).wont_be :hours?
20
- Period.new('foo', :monthly, 6).wont_be :hours?
21
- Period.new('foo', :yearly, 6).wont_be :hours?
19
+ it "intiializes given a time unit" do
20
+ period = Period.new(:month)
21
+ period.name.must_equal :monthly
22
+ period.length.must_be_nil
23
+ period.format.must_equal '%Y-%m'
22
24
  end
23
25
 
24
- it "knows what time unit it is" do
25
- Period.new('foo', :hourly, 6).time_unit.must_equal :hour
26
- Period.new('foo', :daily, 6).time_unit.must_equal :day
27
- Period.new('foo', :weekly, 6).time_unit.must_equal :week
28
- Period.new('foo', :monthly, 6).time_unit.must_equal :month
29
- Period.new('foo', :yearly, 6).time_unit.must_equal :year
26
+ it "intiializes given a period and length" do
27
+ period = Period.new(:monthly, 3)
28
+ period.name.must_equal :monthly
29
+ period.length.must_equal 3
30
+ period.format.must_equal '%Y-%m'
30
31
  end
31
32
 
32
- it "pulls a time format from config options" do
33
- Period.new('foo', :hourly, 6).format.must_equal Von.config.hourly_format
34
- Period.new('foo', :daily, 6).format.must_equal Von.config.daily_format
35
- Period.new('foo', :weekly, 6).format.must_equal Von.config.weekly_format
36
- Period.new('foo', :monthly, 6).format.must_equal Von.config.monthly_format
37
- Period.new('foo', :yearly, 6).format.must_equal Von.config.yearly_format
33
+ it "generates a timestamp for now" do
34
+ Period.new(:minutely).timestamp.must_equal '2013-01-02 03:04'
35
+ Period.new(:hourly).timestamp.must_equal '2013-01-02 03:00'
36
+ Period.new(:daily).timestamp.must_equal '2013-01-02'
37
+ Period.new(:weekly).timestamp.must_equal '2012-12-31'
38
+ Period.new(:monthly).timestamp.must_equal '2013-01'
39
+ Period.new(:yearly).timestamp.must_equal '2013'
38
40
  end
39
41
 
40
- it "builds a redis hash key string" do
41
- field = 'foo'
42
- period = :hourly
43
- period_obj = Period.new(field, period, 6)
42
+ it "knows the prev time period" do
43
+ Period.new(:minutely).prev.must_equal '2013-01-02 03:03'
44
+ Period.new(:hourly).prev.must_equal '2013-01-02 02:00'
45
+ Period.new(:daily).prev.must_equal '2013-01-01'
46
+ Period.new(:weekly).prev.must_equal '2012-12-24'
47
+ Period.new(:monthly).prev.must_equal '2012-12'
48
+ Period.new(:yearly).prev.must_equal '2012'
49
+ end
44
50
 
45
- period_obj.hash_key.must_equal "#{@config.namespace}:counters:#{field}:#{period}"
51
+ it "checks if the period is an hourly period" do
52
+ Period.new(:minutely).wont_be :hours?
53
+ Period.new(:hourly).must_be :hours?
54
+ Period.new(:daily).wont_be :hours?
55
+ Period.new(:weekly).wont_be :hours?
56
+ Period.new(:monthly).wont_be :hours?
57
+ Period.new(:yearly).wont_be :hours?
46
58
  end
47
59
 
48
- it "builds a redis list key string" do
49
- field = 'foo'
50
- period = :hourly
51
- period_obj = Period.new(field, period, 6)
60
+ it "checks if the period is an hourly period" do
61
+ Period.new(:minutely).must_be :minutes?
62
+ Period.new(:hourly).wont_be :minutes?
63
+ Period.new(:daily).wont_be :minutes?
64
+ Period.new(:weekly).wont_be :minutes?
65
+ Period.new(:monthly).wont_be :minutes?
66
+ Period.new(:yearly).wont_be :minutes?
67
+ end
52
68
 
53
- period_obj.list_key.must_equal "#{@config.namespace}:lists:#{field}:#{period}"
69
+ it "knows what time unit it is" do
70
+ Period.new(:minutely).time_unit.must_equal :minute
71
+ Period.new(:hourly).time_unit.must_equal :hour
72
+ Period.new(:daily).time_unit.must_equal :day
73
+ Period.new(:weekly).time_unit.must_equal :week
74
+ Period.new(:monthly).time_unit.must_equal :month
75
+ Period.new(:yearly).time_unit.must_equal :year
54
76
  end
55
77
 
56
- it "builds a redis field for the given period and current time" do
57
- Timecop.freeze(Time.local(2013, 02, 01, 05))
58
- Period.new('foo', :hourly, 6).field.must_equal '2013-02-01 05:00'
59
- Period.new('foo', :daily, 6).field.must_equal '2013-02-01'
60
- Period.new('foo', :weekly, 6).field.must_equal '2013-02-01'
61
- Period.new('foo', :monthly, 6).field.must_equal '2013-02'
62
- Period.new('foo', :yearly, 6).field.must_equal '2013'
78
+ it "gets a time format from config" do
79
+ Period.new(:minutely).format.must_equal Von.config.minutely_format
80
+ Period.new(:hourly).format.must_equal Von.config.hourly_format
81
+ Period.new(:daily).format.must_equal Von.config.daily_format
82
+ Period.new(:weekly).format.must_equal Von.config.weekly_format
83
+ Period.new(:monthly).format.must_equal Von.config.monthly_format
84
+ Period.new(:yearly).format.must_equal Von.config.yearly_format
63
85
  end
64
86
 
65
- end
87
+ end
@@ -6,68 +6,8 @@ Bundler.setup
6
6
 
7
7
  require 'minitest/autorun'
8
8
  require 'minitest/pride'
9
+ require 'fakeredis'
9
10
  require 'mocha'
10
11
  require 'timecop'
11
12
 
12
- require 'von'
13
-
14
- module Von
15
- class TestConnection
16
- attr_reader :store
17
-
18
- def initialize
19
- @store = {}
20
- end
21
-
22
- def hincrby(hash, key, counter)
23
- @store[hash] ||= {}
24
-
25
- if @store[hash].has_key?(key)
26
- @store[hash][key] += counter
27
- else
28
- @store[hash][key] = counter
29
- end
30
-
31
- @store[hash][key]
32
- end
33
-
34
- def hget(hash, key)
35
- @store[hash][key]
36
- end
37
-
38
- def hgetall(hash)
39
- @store.fetch(hash, {})
40
- end
41
-
42
- def hdel(hash, key)
43
- @store[hash].delete(key)
44
- end
45
-
46
- def rpush(list, member)
47
- @store[list] ||= []
48
- @store[list] << member
49
- end
50
-
51
- def lpop(list)
52
- @store[list].shift
53
- end
54
-
55
- def lrange(list, start, stop)
56
- @store[list] ||= []
57
- @store[list][start..stop]
58
- end
59
-
60
- def llen(list)
61
- @store[list].length
62
- end
63
-
64
- end
65
- end
66
-
67
- module MiniTest::Expectations
68
- def mock_connection!
69
- connection = Von::TestConnection.new
70
- @store = connection.store
71
- Von.expects(:connection).returns(connection).at_least_once
72
- end
73
- end
13
+ require 'von'
@@ -3,20 +3,42 @@ require 'test_helper'
3
3
  describe Von do
4
4
 
5
5
  before :each do
6
+ Timecop.freeze(Time.local(2013, 01, 01, 01, 01))
6
7
  Von.config.init!
8
+ @redis = Redis.new
9
+ @redis.flushall
7
10
  end
8
11
 
9
12
  it "increments a counter and counts it" do
10
- mock_connection!
13
+ 3.times { Von.increment('foo') }
14
+ Von.count('foo').total.must_equal 3
15
+ end
16
+
17
+ it "increments a counter and parent counters and counts them" do
18
+ 3.times { Von.increment('foo:bar') }
19
+ Von.count('foo').total.must_equal 3
20
+ Von.count('foo:bar').total.must_equal 3
21
+ end
22
+
23
+ it "increments period/best counters and counts them" do
24
+ Von.configure do |config|
25
+ config.counter 'foo', :monthly => 2, :best => :day
26
+ end
11
27
 
12
28
  Von.increment('foo')
29
+ Timecop.freeze(Time.local(2013, 02, 03))
13
30
  Von.increment('foo')
14
- Von.count('foo').must_equal 2
31
+ Von.increment('foo')
32
+ Timecop.freeze(Time.local(2013, 03, 04))
33
+ Von.increment('foo')
34
+
35
+ Von.count('foo').best(:day).must_equal({:timestamp => "2013-02-03", :count => 2})
36
+ Von.count('foo').per(:month).must_equal [{:timestamp => "2013-02", :count => 2}, {:timestamp => "2013-03", :count => 1}]
15
37
  end
16
38
 
17
39
  it "raises a Redis connection errors if raise_connection_errors is true" do
18
40
  Von.config.raise_connection_errors = true
19
- Redis.expects(:new).raises(Redis::CannotConnectError)
41
+ Von.expects(:increment).raises(Redis::CannotConnectError)
20
42
 
21
43
  lambda { Von.increment('foo') }.must_raise Redis::CannotConnectError
22
44
  end