time_window_drop_collector 0.0.5

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/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ tmp
6
+ .rvmrc
data/.rvmrc.example ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2@time_window_drop_collector
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # Time Window Drop Collector
2
+
3
+ System to keep record of an _amount_ for a concrete duration.
4
+
5
+ With _Time Window Drop Collector_ you can define a **maximun time** you want to keep the record.
6
+
7
+ You can also keep record for **different keys**.
8
+
9
+ ## How to use
10
+
11
+ ### Install
12
+
13
+ gem install time_window_drop_collector
14
+
15
+ ### Config
16
+
17
+ These are the default values
18
+
19
+ twdc =
20
+ TimeWindowDropCollector.new do
21
+ client :memcache, "localhost:11211" # underneeth client
22
+ window 600 # in seconds
23
+ slices 10 # one slice every minute
24
+ end
25
+
26
+ ### Use
27
+
28
+ twdc.drop( "id1" )
29
+ twdc.drop( "id1" )
30
+ twdc.drop( "id2" )
31
+ twdc.drop( ["id1", "id2"] )
32
+
33
+ twdc.count( "id1" ) # => 3
34
+
35
+ # after 10 minutes
36
+ twdc.count( "id1" ) # => 0
37
+
38
+ ## Cache clients wrappers
39
+
40
+ Now we have implementation for 3 diferent underneeth cache clients.
41
+
42
+ ### Memcache
43
+
44
+ It uses the Dalli Client for memcache.
45
+
46
+ twdc =
47
+ TimeWindowDropCollector.new do
48
+ client :memcache, "localhost:11211"
49
+ end
50
+
51
+ ### Rails cache
52
+
53
+ It uses the `Rails.cache` accesible
54
+
55
+ twdc =
56
+ TimeWindowDropCollector.new do
57
+ client :rails_cache
58
+ end
59
+
60
+
61
+ ### Redis
62
+
63
+ twdc =
64
+ TimeWindowDropCollector.new do
65
+ client :redis, { :host => "host", :port => "port" }
66
+ end
67
+
68
+ At the moment this wrapper does not support auto-key-clean so the stored keys will be there until anyone delete them.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ # require 'bundler/gem_tasks'
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'bundler'
6
+
7
+ include Rake::DSL
8
+
9
+ Bundler::GemHelper.install_tasks
10
+
11
+ task :default => :test
12
+
13
+ Rake::TestTask.new do |t|
14
+ t.libs << '.'
15
+ t.test_files = FileList['test/*_test.rb']
16
+ t.verbose = true
17
+ end
18
+
@@ -0,0 +1,20 @@
1
+ module TimeWindowDropCollector::Config
2
+ def self.extract( block )
3
+ @opts = {}
4
+ instance_eval( &block )
5
+ @opts
6
+ end
7
+
8
+ def self.client( type, *opts )
9
+ @opts[:client] = type
10
+ @opts[:client_opts] = opts
11
+ end
12
+
13
+ def self.window( seconds )
14
+ @opts[:window] = seconds
15
+ end
16
+
17
+ def self.slices( num )
18
+ @opts[:slices] = num
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module TimeWindowDropCollector::Logger
2
+ def self.log( message )
3
+ puts "[TWDC #{Time.now.strftime( "%F %T" )}] #{message}"
4
+ end
5
+ end
@@ -0,0 +1,46 @@
1
+ class TimeWindowDropCollector::Storage
2
+ attr_reader :wrapper, :window, :slices
3
+
4
+ def initialize( wrapper, window, slices )
5
+ @wrapper = wrapper
6
+ @window = window
7
+ @slices = slices
8
+ end
9
+
10
+ def incr( key )
11
+ wrapper.incr( time_key( key ), window )
12
+ end
13
+
14
+ def count( key )
15
+ time_keys = time_keys( key )
16
+ values = wrapper.values_for( time_keys )
17
+
18
+ values.map( &:to_i ).inject( :+ ).to_i
19
+ end
20
+
21
+ def time_key( key, time = timestamp )
22
+ "drop_window_#{key}_#{slice_start_timestamp( time )}"
23
+ end
24
+
25
+ def time_keys( key )
26
+ now = timestamp
27
+
28
+ ( 0..( slices - 1 ) ).map{ |i|
29
+ time_key( key, now - ( ( i*slice_milliseconds ) / 1000 ) )
30
+ }
31
+ end
32
+
33
+ def timestamp
34
+ Time.now
35
+ end
36
+
37
+ def slice_milliseconds
38
+ ( window * 1000 ) / slices
39
+ end
40
+
41
+ def slice_start_timestamp( time )
42
+ time_milliseconds = ( time.to_f * 1000 ).truncate
43
+
44
+ ( time_milliseconds / slice_milliseconds ) * slice_milliseconds
45
+ end
46
+ end
@@ -0,0 +1,3 @@
1
+ class TimeWindowDropCollector
2
+ VERSION = "0.0.5"
3
+ end
@@ -0,0 +1,16 @@
1
+ module TimeWindowDropCollector::Wrapper
2
+ def self.instance( type, opts = nil )
3
+ case type
4
+ when :memcache
5
+ TimeWindowDropCollector::Wrappers::Memcache.new( opts )
6
+ when :redis
7
+ TimeWindowDropCollector::Wrappers::Redis.new( opts )
8
+ when :rails_cache
9
+ TimeWindowDropCollector::Wrappers::RailsCache.new( opts )
10
+ when :mock
11
+ TimeWindowDropCollector::Wrappers::Mock.new( opts )
12
+ else
13
+ raise ArgumentError, "type not supported: '#{type}'"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ class TimeWindowDropCollector
2
+ module Wrappers
3
+ class Memcache
4
+ attr_reader :client
5
+
6
+ def initialize( opts )
7
+ @client = Dalli::Client.new( *opts )
8
+ end
9
+
10
+ def incr( key, expire_time )
11
+ client.incr( key, 1, expire_time, 1 )
12
+ end
13
+
14
+ def values_for( keys )
15
+ client.get_multi( keys ).values
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ class TimeWindowDropCollector
2
+ module Wrappers
3
+ class Mock
4
+ attr_reader :client
5
+
6
+ def initialize( opts )
7
+ @client = MemcacheMock.new
8
+ end
9
+
10
+ def incr( key, expire_time )
11
+ client.incr( key, 1, nil, 1 )
12
+ end
13
+
14
+ def values_for( keys )
15
+ client.get_multi( keys ).values
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ class TimeWindowDropCollector
2
+ module Wrappers
3
+ class RailsCache
4
+ attr_reader :client
5
+
6
+ def initialize( opts )
7
+ @client = Rails.cache
8
+ end
9
+
10
+ def incr( key, expire_time )
11
+ value = client.read( key ).to_i + 1
12
+ client.write( key, value, :expires_in => expire_time )
13
+ end
14
+
15
+ def values_for( keys )
16
+ client.read_multi( keys ).values
17
+ end
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,20 @@
1
+ class TimeWindowDropCollector
2
+ module Wrappers
3
+ class Redis
4
+ attr_reader :client
5
+
6
+ def initialize( opts )
7
+ @client = ::Redis.new( *opts )
8
+ end
9
+
10
+ def incr( key, expire_time )
11
+ client.incr( key )
12
+ end
13
+
14
+ def values_for( keys )
15
+ client.mget( *keys )
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,37 @@
1
+ require "dalli"
2
+
3
+ require_relative "time_window_drop_collector/version"
4
+ require_relative "time_window_drop_collector/config"
5
+ require_relative "time_window_drop_collector/logger"
6
+ require_relative "time_window_drop_collector/storage"
7
+ require_relative "time_window_drop_collector/wrapper"
8
+ require_relative "time_window_drop_collector/wrappers/memcache"
9
+ require_relative "time_window_drop_collector/wrappers/mock"
10
+ require_relative "time_window_drop_collector/wrappers/redis"
11
+ require_relative "time_window_drop_collector/wrappers/rails_cache"
12
+
13
+ class TimeWindowDropCollector
14
+ attr_reader :config, :wrapper, :storage
15
+
16
+ def initialize( &block )
17
+ @config = {
18
+ :window => 600,
19
+ :slices => 10,
20
+ :client => :memcache,
21
+ :client_opts => "localhost:11211"
22
+ }
23
+
24
+ @config.merge!( TimeWindowDropCollector::Config.extract( block ) ) if block_given?
25
+
26
+ @wrapper = TimeWindowDropCollector::Wrapper.instance( config[:client], config[:client_opts] )
27
+ @storage = TimeWindowDropCollector::Storage.new( wrapper, config[:window], config[:slices] )
28
+ end
29
+
30
+ def drop( key )
31
+ storage.incr( key )
32
+ end
33
+
34
+ def count( key )
35
+ storage.count( key )
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ require_relative "test_helper"
2
+
3
+ class ConfigTest < Test::Unit::TestCase
4
+ def setup
5
+ TimeWindowDropCollector::Logger.stubs( :log )
6
+ end
7
+
8
+ def test_config
9
+ proc =
10
+ Proc.new do
11
+ client "client", "client_opt1", "client_opt2"
12
+ window "window"
13
+ slices "slices"
14
+ end
15
+
16
+ config = TimeWindowDropCollector::Config.extract( proc )
17
+
18
+ assert_equal( "client", config[:client] )
19
+ assert_equal( ["client_opt1", "client_opt2"], config[:client_opts] )
20
+ assert_equal( "window", config[:window] )
21
+ assert_equal( "slices", config[:slices] )
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ require_relative "test_helper"
2
+
3
+ class LoggerTest < Test::Unit::TestCase
4
+ def test_log
5
+ IO.any_instance.expects( :puts ).with( "[TWDC 2001-02-01 04:05:06] hello!" )
6
+
7
+ Delorean.time_travel_to( "2001-02-01 04:05:06" ) do
8
+ TimeWindowDropCollector::Logger.log( "hello!" )
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "test_helper"
2
+
3
+ class MemcacheWrapperTest < Test::Unit::TestCase
4
+ def test_initialize
5
+ Dalli::Client.expects( :new ).with( "arg1" ).returns( "client" )
6
+ wrapper = TimeWindowDropCollector::Wrappers::Memcache.new( ["arg1"] )
7
+ assert_equal( "client", wrapper.client )
8
+ end
9
+
10
+ def test_incr
11
+ wrapper = TimeWindowDropCollector::Wrappers::Memcache.new( ["arg1"] )
12
+ wrapper.client.expects( :incr ).with( "key", 1, "expire_time", 1 )
13
+ wrapper.incr( "key", "expire_time" )
14
+ end
15
+
16
+ def test_values_for
17
+ wrapper = TimeWindowDropCollector::Wrappers::Memcache.new( ["arg1"] )
18
+ wrapper.client.expects( :get_multi ).with( "keys" ).returns( {:a => 1, :b => 2} )
19
+ assert_equal( [1, 2], wrapper.values_for( "keys" ))
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "test_helper"
2
+
3
+ class MockWrapperTest < Test::Unit::TestCase
4
+ def test_initialize
5
+ MemcacheMock.expects( :new ).returns( "client" )
6
+ wrapper = TimeWindowDropCollector::Wrappers::Mock.new( ["arg1"] )
7
+ assert_equal( "client", wrapper.client )
8
+ end
9
+
10
+ def test_incr
11
+ wrapper = TimeWindowDropCollector::Wrappers::Mock.new( ["arg1"] )
12
+ wrapper.client.expects( :incr ).with( "key", 1, nil, 1 )
13
+ wrapper.incr( "key", "expire_time" )
14
+ end
15
+
16
+ def test_values_for
17
+ wrapper = TimeWindowDropCollector::Wrappers::Mock.new( ["arg1"] )
18
+ wrapper.client.expects( :get_multi ).with( "keys" ).returns( {:a => 1, :b => 2} )
19
+ assert_equal( [1, 2], wrapper.values_for( "keys" ))
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ require_relative "test_helper"
2
+
3
+ class MemcacheWrapperTest < Test::Unit::TestCase
4
+ def setup
5
+ @rails_client = mock()
6
+ Rails.stubs( :cache ).returns( @rails_cache )
7
+ end
8
+
9
+ def test_initialize
10
+ Rails.expects( :cache ).returns( "client" )
11
+ wrapper = TimeWindowDropCollector::Wrappers::RailsCache.new( ["arg1"] )
12
+ assert_equal( "client", wrapper.client )
13
+ end
14
+
15
+ def test_incr
16
+ wrapper = TimeWindowDropCollector::Wrappers::RailsCache.new( ["arg1"] )
17
+ wrapper.client.expects( :read ).with( "key" ).returns( 2 )
18
+ wrapper.client.expects( :write ).with( "key", 3, :expires_in => "expire_time" )
19
+
20
+ wrapper.incr( "key", "expire_time" )
21
+ end
22
+
23
+ def test_values_for
24
+ wrapper = TimeWindowDropCollector::Wrappers::RailsCache.new( ["arg1"] )
25
+ wrapper.client.expects( :read_multi ).with( "keys" ).returns( {:a => 1, :b => 2} )
26
+ assert_equal( [1, 2], wrapper.values_for( "keys" ))
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ require_relative "test_helper"
2
+
3
+ class Redis
4
+ def initialize( *opts )
5
+ end
6
+ end
7
+
8
+ class MemcacheWrapperTest < Test::Unit::TestCase
9
+ def test_initialize
10
+ Redis.expects( :new ).with( "arg1", "arg2" ).returns( "client" )
11
+ wrapper = TimeWindowDropCollector::Wrappers::Redis.new( ["arg1", "arg2"] )
12
+ assert_equal( "client", wrapper.client )
13
+ end
14
+
15
+ def test_incr
16
+ wrapper = TimeWindowDropCollector::Wrappers::Redis.new( ["arg1"] )
17
+ wrapper.client.expects( :incr ).with( "key" )
18
+ wrapper.incr( "key", "expire_time" )
19
+ end
20
+
21
+ def test_values_for
22
+ wrapper = TimeWindowDropCollector::Wrappers::Redis.new( ["arg1"] )
23
+ wrapper.client.expects( :mget ).with( "key1", "key2" ).returns( [1, 2] )
24
+ assert_equal( [1, 2], wrapper.values_for( ["key1", "key2"] ))
25
+ end
26
+ end
@@ -0,0 +1,234 @@
1
+ require_relative "test_helper"
2
+
3
+ class StorageTest < Test::Unit::TestCase
4
+ def setup
5
+ @client = mock()
6
+ @storage = TimeWindowDropCollector::Storage.new( @client, 600, 10 )
7
+ end
8
+
9
+ def test_time_key_when_time_is_present
10
+ timestamp = Time.new( 2001, 2, 3, 4, 5 )
11
+ assert_equal( "drop_window_key_981169500000", @storage.time_key( "key", timestamp ) )
12
+ end
13
+
14
+ def test_time_key_when_time_is_not_present
15
+ @storage.stubs( :timestamp ).returns( Time.new( 2012, 4, 3, 2, 1 ))
16
+ assert_equal( "drop_window_key_1333411260000", @storage.time_key( "key" ))
17
+ end
18
+
19
+ def test_time_keys_should_return_10_keys_for_the_last_10_minutes
20
+ keys = [
21
+ "drop_window_key_1325560800000",
22
+ "drop_window_key_1325560740000",
23
+ "drop_window_key_1325560680000",
24
+ "drop_window_key_1325560620000",
25
+ "drop_window_key_1325560560000",
26
+ "drop_window_key_1325560500000",
27
+ "drop_window_key_1325560440000",
28
+ "drop_window_key_1325560380000",
29
+ "drop_window_key_1325560320000",
30
+ "drop_window_key_1325560260000"
31
+ ]
32
+
33
+ Delorean.time_travel_to( '2012-01-03 04:20' ) do
34
+ assert_equal( keys, @storage.time_keys( "key" ))
35
+ end
36
+ end
37
+
38
+ def test_incr
39
+ @storage.expects( :time_key ).with( "key" ).returns( "time_key" )
40
+ @client.expects( :incr ).with( "time_key", 600 )
41
+
42
+ @storage.incr( "key" )
43
+ end
44
+
45
+ def test_count
46
+ keys = [
47
+ "drop_window_key_201201031416",
48
+ "drop_window_key_201201031415",
49
+ "drop_window_key_201201031414",
50
+ "drop_window_key_201201031413",
51
+ "drop_window_key_201201031412"
52
+ ]
53
+
54
+ values = [nil, 1, "2", 3, 4, 5]
55
+
56
+ @storage.expects( :time_keys ).with( "key" ).returns( "keys" )
57
+ @client.expects( :values_for ).with( "keys" ).returns( values )
58
+
59
+ assert_equal( 15, @storage.count( "key" ))
60
+ end
61
+
62
+ def test_count_when_empty_values
63
+ @storage.stubs( :time_keys )
64
+ @client.expects( :values_for ).returns( [] )
65
+ assert_equal( 0, @storage.count( "key" ))
66
+ end
67
+
68
+ def test_integration_count
69
+ client = TimeWindowDropCollector::Wrapper.instance( :mock )
70
+ storage = TimeWindowDropCollector::Storage.new( client, 600, 10 )
71
+
72
+ key_1 = 1
73
+ key_2 = 2
74
+ key_3 = 3
75
+
76
+ storage.incr( key_1 )
77
+ storage.incr( key_2 )
78
+ storage.incr( key_3 )
79
+ storage.incr( key_2 )
80
+
81
+ assert_equal( 1, storage.count( key_1 ))
82
+ assert_equal( 2, storage.count( key_2 ))
83
+ assert_equal( 1, storage.count( key_3 ))
84
+ end
85
+
86
+ def test_slice_start_timestamp
87
+ storage = TimeWindowDropCollector::Storage.new( nil, 100, 10 )
88
+ time = Time.new( 2001, 2, 3, 4, 5 )
89
+
90
+ assert_equal( 981169500000, storage.slice_start_timestamp( time ) )
91
+ assert_equal( 981169500000, storage.slice_start_timestamp( time + 1 ) )
92
+ assert_equal( 981169500000, storage.slice_start_timestamp( time + 9 ) )
93
+ assert_equal( 981169520000, storage.slice_start_timestamp( time + 25 ) )
94
+ assert_equal( 981169600000, storage.slice_start_timestamp( time + 100 ) )
95
+ end
96
+
97
+ def test_slice_start_timestamp_with_slice_sizes_no_integer
98
+ storage = TimeWindowDropCollector::Storage.new( nil, 100, 12 )
99
+ time = Time.new( 2001, 2, 3, 4, 5 )
100
+
101
+ assert_equal( 981169493317, storage.slice_start_timestamp( time ) )
102
+ assert_equal( 981169493317, storage.slice_start_timestamp( time + 1 ) )
103
+ assert_equal( 981169501650, storage.slice_start_timestamp( time + 9 ) )
104
+ assert_equal( 981169518316, storage.slice_start_timestamp( time + 25 ) )
105
+ assert_equal( 981169593313, storage.slice_start_timestamp( time + 100 ) )
106
+ end
107
+
108
+ def test_slice_start_timestamp_with_slice_size_less_than_a_second
109
+ storage = TimeWindowDropCollector::Storage.new( nil, 100, 101 )
110
+ time = Time.new( 2001, 2, 3, 4, 5 )
111
+
112
+ assert_equal( 981169499970, storage.slice_start_timestamp( time ) )
113
+ assert_equal( 981169500960, storage.slice_start_timestamp( time + 1 ) )
114
+ assert_equal( 981169508880, storage.slice_start_timestamp( time + 9 ) )
115
+ assert_equal( 981169524720, storage.slice_start_timestamp( time + 25 ) )
116
+ assert_equal( 981169599960, storage.slice_start_timestamp( time + 100 ) )
117
+ end
118
+
119
+ def test_window_size_consistency
120
+ window = 100
121
+ slices = 10
122
+ storage = TimeWindowDropCollector::Storage.new( nil, window, slices )
123
+ time = Time.new( 2001, 2, 3, 4, 5 )
124
+
125
+ first_slice = storage.slice_start_timestamp( time )
126
+ last_slice = storage.slice_start_timestamp( time + 101 )
127
+
128
+ assert_equal( window, ( last_slice - first_slice ) / 1000 )
129
+ end
130
+
131
+ def test_window_size_consistency_with_slice_sizes_no_integer
132
+ window = 100
133
+ slices = 12
134
+ storage = TimeWindowDropCollector::Storage.new( nil, window, slices )
135
+ time = Time.new( 2001, 2, 3, 4, 5 )
136
+
137
+ first_slice = storage.slice_start_timestamp( time )
138
+ last_slice = storage.slice_start_timestamp( time + 101 )
139
+
140
+ assert_equal( 99, ( last_slice - first_slice ) / 1000 )
141
+ end
142
+
143
+ def test_window_size_consistency_with_slice_sizes_less_than_a_second
144
+ window = 100
145
+ slices = 101
146
+ storage = TimeWindowDropCollector::Storage.new( nil, window, slices )
147
+ time = Time.new( 2001, 2, 3, 4, 5 )
148
+
149
+ first_slice = storage.slice_start_timestamp( time )
150
+ last_slice = storage.slice_start_timestamp( time + 101 )
151
+
152
+ assert_equal( window, ( last_slice - first_slice ) / 1000 )
153
+ end
154
+
155
+ def test_integration_store_of_the_count_for_10_minutes
156
+ client = TimeWindowDropCollector::Wrapper.instance( :mock )
157
+ storage = TimeWindowDropCollector::Storage.new( client, 600, 10 )
158
+
159
+ key_1 = 1
160
+
161
+ Delorean.time_travel_to( '2012-01-03 11:00' ) do
162
+ storage.incr( key_1 )
163
+ end
164
+
165
+ Delorean.time_travel_to( '2012-01-03 11:01' ) do
166
+ storage.incr( key_1 )
167
+ end
168
+
169
+ Delorean.time_travel_to( '2012-01-03 11:02' ) do
170
+ storage.incr( key_1 )
171
+ end
172
+
173
+ Delorean.time_travel_to( '2012-01-03 11:03' ) do
174
+ storage.incr( key_1 )
175
+ end
176
+
177
+ Delorean.time_travel_to( '2012-01-03 11:04' ) do
178
+ storage.incr( key_1 )
179
+ end
180
+
181
+ Delorean.time_travel_to( '2012-01-03 11:05' ) do
182
+ storage.incr( key_1 )
183
+ end
184
+
185
+ Delorean.time_travel_to( '2012-01-03 11:06' ) do
186
+ storage.incr( key_1 )
187
+ end
188
+
189
+ Delorean.time_travel_to( '2012-01-03 11:07' ) do
190
+ storage.incr( key_1 )
191
+ end
192
+
193
+ Delorean.time_travel_to( '2012-01-03 11:08' ) do
194
+ storage.incr( key_1 )
195
+ end
196
+
197
+ Delorean.time_travel_to( '2012-01-03 11:09' ) do
198
+ storage.incr( key_1 )
199
+ end
200
+
201
+ Delorean.time_travel_to( '2012-01-03 11:10' ) do
202
+ storage.incr( key_1 )
203
+ end
204
+
205
+ # counters
206
+ Delorean.time_travel_to( '2012-01-03 10:59' ) do
207
+ assert_equal( 0, storage.count( key_1 ))
208
+ end
209
+
210
+ Delorean.time_travel_to( '2012-01-03 11:00' ) do
211
+ assert_equal( 1, storage.count( key_1 ))
212
+ end
213
+
214
+ Delorean.time_travel_to( '2012-01-03 11:05' ) do
215
+ assert_equal( 6, storage.count( key_1 ))
216
+ end
217
+
218
+ Delorean.time_travel_to( '2012-01-03 11:10' ) do
219
+ assert_equal( 10, storage.count( key_1 ))
220
+ end
221
+
222
+ Delorean.time_travel_to( '2012-01-03 11:15' ) do
223
+ assert_equal( 5, storage.count( key_1 ))
224
+ end
225
+
226
+ Delorean.time_travel_to( '2012-01-03 11:19' ) do
227
+ assert_equal( 1, storage.count( key_1 ))
228
+ end
229
+
230
+ Delorean.time_travel_to( '2012-01-03 11:20' ) do
231
+ assert_equal( 0, storage.count( key_1 ))
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,16 @@
1
+ require "test/unit"
2
+ require "mocha"
3
+ require "delorean"
4
+ require "memcache_mock"
5
+
6
+ require_relative "../lib/time_window_drop_collector.rb"
7
+
8
+ # mocking big classes
9
+ class Rails
10
+ def self.cache
11
+ end
12
+ end
13
+
14
+ class Redis
15
+ end
16
+
@@ -0,0 +1,70 @@
1
+ require_relative "test_helper"
2
+
3
+ class TimeWindowDropCollectorTest < Test::Unit::TestCase
4
+ def setup
5
+ @twdc = TimeWindowDropCollector::Logger.stubs( :log )
6
+ end
7
+
8
+ def test_initialize_with_empty_config
9
+ TimeWindowDropCollector::Config.expects( :extract ).never
10
+ TimeWindowDropCollector::Wrapper.expects( :instance ).with( :memcache, "localhost:11211" ).returns( "wrapper" )
11
+ TimeWindowDropCollector::Storage.expects( :new ).with( "wrapper", 600, 10 ).returns( "storage" )
12
+
13
+ twdc = TimeWindowDropCollector.new
14
+
15
+ assert_equal( "wrapper", twdc.wrapper )
16
+ assert_equal( "storage", twdc.storage )
17
+ end
18
+
19
+
20
+ def test_initialize_with_block_config
21
+ config = {
22
+ :window => "window",
23
+ :slices => "slices",
24
+ :client => "client",
25
+ :client_opts => "client_opts"
26
+ }
27
+
28
+ TimeWindowDropCollector::Config.expects( :extract ).returns( config )
29
+ TimeWindowDropCollector::Wrapper.expects( :instance ).with( "client", "client_opts" ).returns( "wrapper" )
30
+ TimeWindowDropCollector::Storage.expects( :new ).with( "wrapper", "window", "slices" ).returns( "storage" )
31
+
32
+ twdc = TimeWindowDropCollector.new {}
33
+ end
34
+
35
+ def test_drop
36
+ storage = mock()
37
+ storage.expects( :incr ).with( "key" )
38
+
39
+ twdc = TimeWindowDropCollector.new
40
+ twdc.stubs( :storage ).returns( storage )
41
+
42
+ twdc.drop( "key" )
43
+ end
44
+
45
+ def test_count
46
+ storage = mock()
47
+ storage.expects( :count ).with( "key" )
48
+
49
+ twdc = TimeWindowDropCollector.new
50
+ twdc.stubs( :storage ).returns( storage )
51
+
52
+ twdc.count( "key" )
53
+ end
54
+
55
+ def test_integration_new
56
+ twdc =
57
+ TimeWindowDropCollector.new do
58
+ client :memcache
59
+ window 100
60
+ slices 20
61
+ end
62
+
63
+ assert( twdc.wrapper.is_a? TimeWindowDropCollector::Wrappers::Memcache )
64
+ assert( twdc.wrapper.client.is_a? Dalli::Client )
65
+ assert( twdc.storage.is_a? TimeWindowDropCollector::Storage )
66
+
67
+ assert_equal( 100, twdc.storage.window )
68
+ assert_equal( 20, twdc.storage.slices )
69
+ end
70
+ end
@@ -0,0 +1,23 @@
1
+ require_relative "test_helper"
2
+
3
+ class WrapperTest < Test::Unit::TestCase
4
+ def test_instance_when_memcache
5
+ instance = TimeWindowDropCollector::Wrapper.instance( :memcache, "localhost:11211" )
6
+ assert( instance.is_a? TimeWindowDropCollector::Wrappers::Memcache )
7
+ end
8
+
9
+ def test_instance_when_mock
10
+ instance = TimeWindowDropCollector::Wrapper.instance( :mock )
11
+ assert( instance.is_a? TimeWindowDropCollector::Wrappers::Mock )
12
+ end
13
+
14
+ def test_instance_when_redis
15
+ instance = TimeWindowDropCollector::Wrapper.instance( :redis, ["server", "port"] )
16
+ assert( instance.is_a? TimeWindowDropCollector::Wrappers::Redis )
17
+ end
18
+
19
+ def test_instance_when_rails_cache
20
+ instance = TimeWindowDropCollector::Wrapper.instance( :rails_cache )
21
+ assert( instance.is_a? TimeWindowDropCollector::Wrappers::RailsCache )
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path( "../lib", __FILE__ )
3
+ require "time_window_drop_collector/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "time_window_drop_collector"
7
+ s.version = TimeWindowDropCollector::VERSION
8
+ s.authors = ["Fernando Guillen", "Carlos Moutinho"]
9
+ s.email = ["fguillen.mail@gmail.com", "carlosmoutinho@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = "Counter storage system for a concrete time window"
12
+ s.description = "Counter storage system for a concrete time window"
13
+
14
+ s.rubyforge_project = "time_window_drop_collector"
15
+
16
+ s.files = `git ls-files`.split( "\n" )
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split( "\n" )
18
+ s.executables = `git ls-files -- bin/*`.split( "\n" ).map{ |f| File.basename( f ) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "bundler", "1.0.21"
22
+ s.add_development_dependency "rake", "0.9.2.2"
23
+ s.add_development_dependency "mocha", "0.10.0"
24
+ s.add_development_dependency "delorean", "1.2.0"
25
+ s.add_development_dependency "memcache_mock", "0.0.1"
26
+
27
+ s.add_dependency "dalli"
28
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: time_window_drop_collector
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Fernando Guillen
9
+ - Carlos Moutinho
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-01-23 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bundler
17
+ requirement: &70242052766820 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - =
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.21
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *70242052766820
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: &70242052766320 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - =
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.2.2
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *70242052766320
37
+ - !ruby/object:Gem::Dependency
38
+ name: mocha
39
+ requirement: &70242052765860 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - =
43
+ - !ruby/object:Gem::Version
44
+ version: 0.10.0
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *70242052765860
48
+ - !ruby/object:Gem::Dependency
49
+ name: delorean
50
+ requirement: &70242052765400 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - =
54
+ - !ruby/object:Gem::Version
55
+ version: 1.2.0
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *70242052765400
59
+ - !ruby/object:Gem::Dependency
60
+ name: memcache_mock
61
+ requirement: &70242052764940 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - =
65
+ - !ruby/object:Gem::Version
66
+ version: 0.0.1
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *70242052764940
70
+ - !ruby/object:Gem::Dependency
71
+ name: dalli
72
+ requirement: &70242052764560 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: *70242052764560
81
+ description: Counter storage system for a concrete time window
82
+ email:
83
+ - fguillen.mail@gmail.com
84
+ - carlosmoutinho@gmail.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - .gitignore
90
+ - .rvmrc.example
91
+ - .travis.yml
92
+ - Gemfile
93
+ - README.md
94
+ - Rakefile
95
+ - lib/time_window_drop_collector.rb
96
+ - lib/time_window_drop_collector/config.rb
97
+ - lib/time_window_drop_collector/logger.rb
98
+ - lib/time_window_drop_collector/storage.rb
99
+ - lib/time_window_drop_collector/version.rb
100
+ - lib/time_window_drop_collector/wrapper.rb
101
+ - lib/time_window_drop_collector/wrappers/memcache.rb
102
+ - lib/time_window_drop_collector/wrappers/mock.rb
103
+ - lib/time_window_drop_collector/wrappers/rails_cache.rb
104
+ - lib/time_window_drop_collector/wrappers/redis.rb
105
+ - test/config_test.rb
106
+ - test/logger_test.rb
107
+ - test/memcache_wrapper_test.rb
108
+ - test/mock_wrapper_test.rb
109
+ - test/rails_cache_wrapper_test.rb
110
+ - test/redis_wrapper_test.rb
111
+ - test/storage_test.rb
112
+ - test/test_helper.rb
113
+ - test/time_window_drop_collector_test.rb
114
+ - test/wrapper_test.rb
115
+ - time_window_drop_collector.gemspec
116
+ homepage: ''
117
+ licenses: []
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project: time_window_drop_collector
136
+ rubygems_version: 1.8.15
137
+ signing_key:
138
+ specification_version: 3
139
+ summary: Counter storage system for a concrete time window
140
+ test_files:
141
+ - test/config_test.rb
142
+ - test/logger_test.rb
143
+ - test/memcache_wrapper_test.rb
144
+ - test/mock_wrapper_test.rb
145
+ - test/rails_cache_wrapper_test.rb
146
+ - test/redis_wrapper_test.rb
147
+ - test/storage_test.rb
148
+ - test/test_helper.rb
149
+ - test/time_window_drop_collector_test.rb
150
+ - test/wrapper_test.rb