event-counter 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
1
  # This module contains VERSION
2
2
  module EventCounterVersion
3
- VERSION = '0.0.1'
3
+ VERSION = '0.1.0'
4
4
  end
data/log/.gitkeep ADDED
File without changes
File without changes
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe EventCounter do
4
- let(:ball) { Fabricate(:ball) }
4
+ let(:ball) { Ball.create! }
5
5
 
6
6
  it 'has version' do
7
7
  expect(EventCounter::VERSION).to match(/\d+\.\d+\.\d+/)
@@ -15,7 +15,7 @@ describe EventCounter do
15
15
  expected = {
16
16
  countable_id: ball.id,
17
17
  countable_type: ball.class.name,
18
- created_at: Time.now.floor(300),
18
+ created_at: Time.zone.now.floor(300),
19
19
  name: 'rotations',
20
20
  value: 3
21
21
  }.with_indifferent_access
@@ -27,7 +27,7 @@ describe EventCounter do
27
27
  end
28
28
 
29
29
  it '#make on time' do
30
- on_time = Time.mktime(2012, 12, 12, 12, 12)
30
+ on_time = Time.mktime(2014, 1, 1, 1, 14).in_time_zone
31
31
  expect {
32
32
  counter = ball.rotations.make(
33
33
  3, on_time: on_time)
@@ -48,7 +48,7 @@ describe EventCounter do
48
48
  end
49
49
 
50
50
  it '#make on time with interval as symbol' do
51
- on_time = Time.mktime(2012, 12, 12, 12, 12)
51
+ on_time = Time.mktime(2014, 1, 1, 1, 1).in_time_zone
52
52
  [:week, :month, :year].each do |interval|
53
53
  expect {
54
54
  counter = ball.send(:"rotations_by_#{interval}").make(
@@ -73,7 +73,7 @@ describe EventCounter do
73
73
  end
74
74
 
75
75
  describe Ball do
76
- let(:ball) { Fabricate(:ball) }
76
+ let(:ball) { Ball.create! }
77
77
 
78
78
  it 'creates a new counter while incrementing' do
79
79
  expect {
@@ -230,12 +230,12 @@ describe Ball do
230
230
 
231
231
  def setup_counters(countable_count = 1)
232
232
  [1, 1, 2, 3, 5, 8, 13, 21, 34].each do |n|
233
- on_time = Time.mktime(2012, 12, 12, 12, n)
233
+ on_time = Time.mktime(2014, 1, 1, 1, n).in_time_zone
234
234
  if countable_count == 1
235
235
  ball.rotations.make n, on_time: on_time
236
236
  else
237
237
  countable_count.times do
238
- Fabricate(:ball).rotations.make n, on_time: on_time
238
+ Ball.create!.rotations.make n, on_time: on_time
239
239
  end
240
240
  end
241
241
  end
@@ -282,9 +282,9 @@ describe Ball do
282
282
  end
283
283
 
284
284
  it 'with a greater interval and a time range' do
285
- range_start = Time.mktime 2012, 12, 12, 12, 15
286
- range_end = Time.mktime 2012, 12, 12, 12, 45
287
- range = range_start..range_end
285
+ range_start = Time.mktime 2014, 1, 1, 1, 15
286
+ range_end = Time.mktime 2014, 1, 1, 1, 45
287
+ range = range_start.in_time_zone..range_end.in_time_zone
288
288
 
289
289
  data = [ [ 10, 13 ], [ 20, 21 ], [ 30, 34 ], [ 40, 0] ]
290
290
 
@@ -293,7 +293,7 @@ describe Ball do
293
293
  end
294
294
 
295
295
  it 'with a greater interval as symbol' do
296
- beginning_of_week = Time.mktime(2012, 12, 12).beginning_of_week
296
+ beginning_of_week = Time.mktime(2014).in_time_zone.beginning_of_week
297
297
 
298
298
  data = [ [ beginning_of_week, 88 ] ]
299
299
 
@@ -305,29 +305,64 @@ describe Ball do
305
305
 
306
306
  context '.data_for' do
307
307
 
308
+ subject { Ball }
309
+
308
310
  before { setup_counters(3) }
309
311
 
310
312
  it 'with a default interval' do
311
313
  data = [
312
314
  # [ minute, value ]
313
- [ 0, 21 ],
314
- [ 5, 39 ],
315
+ [ 0, 21 ],
316
+ [ 5, 39 ],
315
317
  [ 10, 39 ],
316
- [ 15, 0 ],
318
+ [ 15, 0 ],
317
319
  [ 20, 63 ],
318
- [ 25, 0 ],
320
+ [ 25, 0 ],
319
321
  [ 30, 102 ]
320
322
  ]
321
323
  expect(subject.data_for(:rotations)).to eql_data(data)
322
324
  end
323
325
 
326
+ it 'with a greater interval' do
327
+ data = [ [ 0, 60 ], [ 10, 39 ], [ 20, 63 ], [ 30, 102 ] ]
328
+
329
+ expect(subject.data_for(:rotations, interval: 10.minutes))
330
+ .to eql_data(data)
331
+ end
332
+
333
+ it 'with a greater interval within range' do
334
+ data = [ [ 10, 39 ], [ 20, 63 ] ]
335
+
336
+ range_start = Time.mktime(2014, 1, 1, 1, 15).in_time_zone
337
+ range_end = Time.mktime(2014, 1, 1, 1, 29).in_time_zone
338
+ range = range_start..range_end
339
+
340
+ expect(subject.data_for(:rotations, interval: 10.minutes, range: range))
341
+ .to eql_data(data)
342
+ end
343
+
324
344
  it 'with a greater interval as symbol and a simple data' do
325
- beginning_of_month = Time.mktime(2012, 12, 12).beginning_of_month
326
- data = [ [ beginning_of_month, 264 ] ]
327
- expect(subject.data_for(:rotations, interval: :month)).to eql(data)
345
+ bmonth = Time.mktime(2014, 1, 1).in_time_zone.beginning_of_month
346
+ data = [ [ bmonth, 264 ] ]
347
+
348
+ expect(subject.data_for(:rotations, interval: :month))
349
+ .to match_array(data)
328
350
  end
329
351
 
330
- it 'with a greater interval as symbol and a large data' do
352
+ it 'with a greater interval as symbol and a simple data within range' do
353
+ bmonth = Time.mktime(2014, 1, 1).in_time_zone.beginning_of_month
354
+ data = [ [ bmonth, 264 ] ]
355
+
356
+ range_start = bmonth
357
+ range_end = bmonth.end_of_month
358
+ range = range_start..range_end
359
+
360
+ expect(subject.data_for(:rotations, interval: :month, range: range))
361
+ .to match_array(data)
362
+ end
363
+
364
+
365
+ it 'with a greater interval as symbol on large data set within range' do
331
366
  EventCounter.all.each do |counter|
332
367
  11.times do |x|
333
368
  created_at = counter.created_at - (x + 1).months
@@ -337,9 +372,14 @@ describe Ball do
337
372
  end
338
373
  end
339
374
 
340
- data = (1..12).map { |x| [ Time.mktime(2012, x), 264 ] }
375
+ data = (6..12).map { |x| [ Time.mktime(2013, x).in_time_zone, 264 ] }
376
+
377
+ range_start = data[0][0].beginning_of_month
378
+ range_end = data[-1][0].end_of_month
379
+ range = range_start..range_end
341
380
 
342
- expect(subject.data_for(:rotations, interval: :month)).to eql(data)
381
+ expect(subject.data_for(:rotations, interval: :month, range: range))
382
+ .to match_array(data)
343
383
  end
344
384
 
345
385
  end
@@ -1,55 +1,106 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Ball, performance: true do
3
+ describe Ball, slow: true do
4
4
 
5
- let(:range_start) { (Time.mktime 2011, 12).beginning_of_month }
6
- let(:range_end) { (Time.mktime 2012, 11).end_of_month }
5
+ before(:suite) do
6
+ DatabaseCleaner.strategy = :truncation
7
+ DatabaseCleaner.clean_with(:truncation)
8
+ end
9
+
10
+ let(:range_start) { (Time.mktime 2013, 7).in_time_zone.beginning_of_month }
11
+ let(:range_end) { (Time.mktime 2014, 6).in_time_zone.end_of_month }
7
12
  let(:range) { range_start..range_end }
8
13
 
9
- before(:all) do
10
- @logger = ActiveRecord::Base.logger
14
+ def disable_logging(&blk)
15
+ logger = ActiveRecord::Base.logger
11
16
  ActiveRecord::Base.logger = nil
17
+ yield
18
+ ActiveRecord::Base.logger = logger
12
19
  end
13
20
 
14
- after(:all) do
15
- ActiveRecord::Base.logger = @logger
21
+
22
+ def connection
23
+ ActiveRecord::Base.connection.raw_connection
16
24
  end
17
25
 
18
- def setup_data(countable = 10, step = 1.day)
19
- (1..countable).map do |x|
20
- ball = Fabricate(:ball)
26
+ def setup_data(countable = 1000, step = 1.day)
27
+
28
+ ball = Ball.create!
29
+
30
+ (Time.mktime(2012).to_i..Time.mktime(2015).to_i).step(step) do |i|
31
+ on_time = Time.at(i)
32
+ ball.rotations.make on_time: on_time
33
+ end
34
+
35
+ path = File.expand_path('../../fixtures/event_counters.sql', __FILE__)
36
+
37
+ skip_count = 0
38
+
21
39
 
22
- (range_start.to_i..range_end.to_i).step(step) do |i|
23
- on_time = Time.at(i)
24
- ball.rotations.make on_time: on_time
40
+ export_sql = "COPY event_counters TO STDOUT (DELIMITER '|')"
41
+ connection.copy_data(export_sql) do
42
+ File.open(path, 'w') do |f|
43
+ while line = connection.get_copy_data
44
+ skip_count += 1
45
+ f.write(line)
46
+ end
47
+ end
48
+ end
49
+
50
+ File.open(path, 'a+') do |f|
51
+ lines = f.readlines
52
+ last_ids = lines.last.split('|')[0, 4]
53
+ id, countable_id = last_ids.first.to_i, last_ids.last.to_i
54
+ (2..countable).each do |i|
55
+ countable_id += 1
56
+ lines.each do |line|
57
+ id += 1
58
+ split = line.split('|')
59
+ split[0] = id
60
+ split[3] = countable_id
61
+ f.write split.join('|')
62
+ end
63
+ end
64
+ end
65
+
66
+ import_sql = "COPY event_counters FROM STDIN (DELIMITER '|')"
67
+ connection.copy_data(import_sql) do
68
+ File.open(path, 'r') do |f|
69
+ i = 0
70
+ while line = f.gets
71
+ i += 1
72
+ next if i <= skip_count
73
+ connection.put_copy_data line
74
+ end
25
75
  end
26
76
  end
27
77
  end
28
78
 
29
79
  context '#data_for' do
30
80
 
31
- before { setup_data }
32
-
33
81
  it 'performance is adequate' do
82
+ disable_logging { setup_data }
83
+
34
84
  data = [
35
- {"created_at"=>"2011-12-01 00:00:00+04", "value"=>"310"},
36
- {"created_at"=>"2012-01-01 00:00:00+04", "value"=>"310"},
37
- {"created_at"=>"2012-02-01 00:00:00+04", "value"=>"290"},
38
- {"created_at"=>"2012-03-01 00:00:00+04", "value"=>"310"},
39
- {"created_at"=>"2012-04-01 00:00:00+04", "value"=>"300"},
40
- {"created_at"=>"2012-05-01 00:00:00+04", "value"=>"310"},
41
- {"created_at"=>"2012-06-01 00:00:00+04", "value"=>"300"},
42
- {"created_at"=>"2012-07-01 00:00:00+04", "value"=>"310"},
43
- {"created_at"=>"2012-08-01 00:00:00+04", "value"=>"310"},
44
- {"created_at"=>"2012-09-01 00:00:00+04", "value"=>"300"},
45
- {"created_at"=>"2012-10-01 00:00:00+04", "value"=>"310"},
46
- {"created_at"=>"2012-11-01 00:00:00+04", "value"=>"300"}
85
+ {"created_at"=>"2013-07-01 00:00:00", "value"=>"31000"},
86
+ {"created_at"=>"2013-08-01 00:00:00", "value"=>"31000"},
87
+ {"created_at"=>"2013-09-01 00:00:00", "value"=>"30000"},
88
+ {"created_at"=>"2013-10-01 00:00:00", "value"=>"31000"},
89
+ {"created_at"=>"2013-11-01 00:00:00", "value"=>"30000"},
90
+ {"created_at"=>"2013-12-01 00:00:00", "value"=>"31000"},
91
+ {"created_at"=>"2014-01-01 00:00:00", "value"=>"31000"},
92
+ {"created_at"=>"2014-02-01 00:00:00", "value"=>"28000"},
93
+ {"created_at"=>"2014-03-01 00:00:00", "value"=>"31000"},
94
+ {"created_at"=>"2014-04-01 00:00:00", "value"=>"30000"},
95
+ {"created_at"=>"2014-05-01 00:00:00", "value"=>"31000"},
96
+ {"created_at"=>"2014-06-01 00:00:00", "value"=>"30000"}
47
97
  ]
48
98
 
49
- expect {
50
- expect(Ball.data_for(:rotations, interval: :month, range: range, raw: true))
51
- .to eql(data)
52
- }.to take_less_than(0.1).seconds
99
+ #expect {
100
+ expect(
101
+ Ball.data_for(:rotations, interval: :month, range: range, raw: true)
102
+ ).to match_array(data)
103
+ #}.to take_less_than(0.1).seconds
53
104
  end
54
105
  end
55
106
  end
data/spec/spec_helper.rb CHANGED
@@ -3,7 +3,6 @@ require 'bundler/setup'
3
3
 
4
4
  require 'active_record'
5
5
  require 'database_cleaner'
6
- require 'fabrication'
7
6
  require 'logger'
8
7
  require 'event_counter'
9
8
 
@@ -20,11 +19,12 @@ YAML.load(File.open(conf).read).values.each do |config|
20
19
  ActiveRecord::Base.establish_connection config
21
20
  end
22
21
 
22
+ ActiveRecord::Base.default_timezone = :utc
23
+ Time.zone = 'Moscow'
24
+
23
25
  ActiveRecord::Schema.define do
24
26
  self.verbose = false
25
27
 
26
- create_table :cubes, force: true
27
-
28
28
  create_table :balls, force: true
29
29
 
30
30
  create_table :event_counters, force: true do |t|
@@ -35,9 +35,9 @@ ActiveRecord::Schema.define do
35
35
  t.datetime :created_at
36
36
  end
37
37
 
38
- add_index :event_counters, :countable_type
39
- add_index :event_counters, [:countable_type, :name, :countable_id, :created_at],
40
- name: 'composite'
38
+ add_index :event_counters, :created_at#, name: 'idx_created_at_desc'
39
+ add_index :event_counters, [:countable_type, :name, :countable_id],
40
+ name: 'idx_composite'
41
41
  end
42
42
 
43
43
  # :nodoc:
@@ -54,18 +54,15 @@ Dir[File.expand_path('../support/*.rb', __FILE__)].each do |file|
54
54
  end
55
55
 
56
56
  RSpec.configure do |config|
57
+
57
58
  config.before(:suite) do
58
59
  DatabaseCleaner.strategy = :transaction
59
60
  DatabaseCleaner.clean_with(:truncation)
60
61
  end
61
62
 
62
- config.before(:each) do
63
- DatabaseCleaner.start
64
- end
65
-
66
- config.after(:each) do
67
- DatabaseCleaner.clean
63
+ config.around(:each) do |example|
64
+ DatabaseCleaner.cleaning { example.run }
68
65
  end
69
66
 
70
- config.filter_run_excluding performance: true
67
+ config.filter_run_excluding slow: true unless ENV['RUN_ALL']
71
68
  end
@@ -11,10 +11,12 @@ RSpec::Matchers.define :be_eql do |expected|
11
11
  diffable
12
12
  end
13
13
 
14
- RSpec::Matchers.define :eql_data do |expected|
15
- match do |actual|
16
- expected.map! { |a, b| [ Time.mktime(2012, 12, 12, 12, a), b ] }
17
- expect(actual).to eql(expected)
14
+ module RSpec
15
+ module Matchers
16
+ def eql_data(items)
17
+ items.map! { |a, b| [ Time.mktime(2014, 1, 1, 1, a).in_time_zone, b ] }
18
+ contain_exactly(*items)
19
+ end
18
20
  end
19
21
  end
20
22
 
metadata CHANGED
@@ -1,113 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: event-counter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Orel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-18 00:00:00.000000000 Z
11
+ date: 2014-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3'
27
27
  - !ruby/object:Gem::Dependency
28
- name: pg
28
+ name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: bundler
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.7'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1.7'
55
- - !ruby/object:Gem::Dependency
56
- name: database_cleaner
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rspec
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
31
+ - - ">="
74
32
  - !ruby/object:Gem::Version
75
33
  version: '3'
76
- type: :development
34
+ type: :runtime
77
35
  prerelease: false
78
36
  version_requirements: !ruby/object:Gem::Requirement
79
37
  requirements:
80
- - - "~>"
38
+ - - ">="
81
39
  - !ruby/object:Gem::Version
82
40
  version: '3'
83
41
  - !ruby/object:Gem::Dependency
84
- name: fabrication
42
+ name: pg
85
43
  requirement: !ruby/object:Gem::Requirement
86
44
  requirements:
87
45
  - - "~>"
88
46
  - !ruby/object:Gem::Version
89
47
  version: '0'
90
- type: :development
48
+ type: :runtime
91
49
  prerelease: false
92
50
  version_requirements: !ruby/object:Gem::Requirement
93
51
  requirements:
94
52
  - - "~>"
95
53
  - !ruby/object:Gem::Version
96
54
  version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rake
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '10.0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '10.0'
111
55
  description: Database based event counter with throttling per time intervals
112
56
  email:
113
57
  - eagle.anton@gmail.com
@@ -117,20 +61,34 @@ extra_rdoc_files: []
117
61
  files:
118
62
  - ".gitignore"
119
63
  - ".rubocop.yml"
64
+ - ".travis.yml"
65
+ - Appraisals
66
+ - CHANGELOG.md
120
67
  - Gemfile
121
68
  - LICENSE.txt
122
69
  - README.md
123
70
  - Rakefile
124
71
  - config/database.ci.yml
125
72
  - event-counter.gemspec
73
+ - gemfiles/pg_ar_30.gemfile
74
+ - gemfiles/pg_ar_30.gemfile.lock
75
+ - gemfiles/pg_ar_31.gemfile
76
+ - gemfiles/pg_ar_31.gemfile.lock
77
+ - gemfiles/pg_ar_32.gemfile
78
+ - gemfiles/pg_ar_32.gemfile.lock
79
+ - gemfiles/pg_ar_40.gemfile
80
+ - gemfiles/pg_ar_40.gemfile.lock
81
+ - gemfiles/pg_ar_41.gemfile
82
+ - gemfiles/pg_ar_41.gemfile.lock
126
83
  - lib/event-counter.rb
127
84
  - lib/event_counter.rb
128
85
  - lib/event_counter/active_record_extension.rb
129
86
  - lib/event_counter/version.rb
87
+ - log/.gitkeep
88
+ - spec/fixtures/.gitkeep
130
89
  - spec/lib/event_counter_spec.rb
131
90
  - spec/lib/performance_spec.rb
132
91
  - spec/spec_helper.rb
133
- - spec/support/fabrications.rb
134
92
  - spec/support/matchers.rb
135
93
  homepage: https://github.com/skyeagle/event-counter
136
94
  licenses:
@@ -157,9 +115,9 @@ signing_key:
157
115
  specification_version: 4
158
116
  summary: Event counter with throttling per time interval
159
117
  test_files:
118
+ - spec/fixtures/.gitkeep
160
119
  - spec/lib/event_counter_spec.rb
161
120
  - spec/lib/performance_spec.rb
162
121
  - spec/spec_helper.rb
163
- - spec/support/fabrications.rb
164
122
  - spec/support/matchers.rb
165
123
  has_rdoc: