omega-tariffs-base 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'init'))
2
+
3
+ describe 'Settings' do
4
+ before do
5
+ @settings = Settings.new({ :life => "is shit",
6
+ :water => "is wet",
7
+ :usama => { :bin => :laden, :loves => [ :bombing ] }
8
+ })
9
+ end
10
+
11
+ it 'should create object with a valid hash' do
12
+ @settings.should_not == nil
13
+ end
14
+
15
+ it 'should not create object without a valid hash' do
16
+ lambda {
17
+ Settings.new("zadnica")
18
+ }.should raise_error(ArgumentError)
19
+ end
20
+
21
+ it 'should convert first level values of hash to function calls' do
22
+ @settings.life.should == "is shit"
23
+ @settings.water.should == "is wet"
24
+ end
25
+
26
+ it 'should return proxy for the second and more levels' do
27
+ @settings.usama.should be_a_kind_of(Settings::Proxy)
28
+ end
29
+
30
+ it 'should allow any reasonable level of the deepness' do
31
+ @settings.usama.bin.should == :laden
32
+ @settings.usama.loves.should == [ :bombing ]
33
+ end
34
+
35
+ it 'should correctly compare with hashes' do
36
+ @settings.usama.should == { :bin => :laden, :loves => [ :bombing ] }
37
+
38
+ @settings.usama.should_not == { :roga => :kopyta }
39
+ end
40
+
41
+ it 'should correctly compare with the other settings objects' do
42
+ @other_settings = Settings.new({ :bin => :laden, :loves => [ :bombing ] })
43
+ @settings.usama.should == @other_settings
44
+
45
+ @different_settings = Settings.new({ :zhopa => :kedy })
46
+ @settings.usama.should_not == @different_settings
47
+ end
48
+
49
+ it 'should raise exceptions when being compared to something stupid' do
50
+ lambda {
51
+ @settings.usama == 3
52
+ }.should raise_error
53
+ end
54
+
55
+ it 'should correctly return hash' do
56
+ @settings.to_hash.should == HashWithIndifferentAccess.new({ :life => "is shit",
57
+ :water => "is wet",
58
+ :usama => { :bin => :laden, :loves => [ :bombing ] }
59
+ })
60
+ end
61
+ end
62
+
@@ -0,0 +1,122 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'init'))
2
+
3
+ describe "SingleTimeFilterRepository" do
4
+ it "should return false for payments before any has been added" do
5
+ SingleTimeFilterRepository.had_single_payment?(1, 2, 3).should == false
6
+ end
7
+
8
+ it "should return true for registered payments and false for the others" do
9
+ SingleTimeFilterRepository.register_single_payment(1, 2, 3)
10
+ SingleTimeFilterRepository.register_single_payment(1, 2, 7)
11
+ SingleTimeFilterRepository.had_single_payment?(1, 2, 3).should == true
12
+ SingleTimeFilterRepository.had_single_payment?(1, 2, 4).should == false
13
+ SingleTimeFilterRepository.had_single_payment?(1, 5, 3).should == false
14
+ SingleTimeFilterRepository.had_single_payment?(7, 2, 3).should == false
15
+ SingleTimeFilterRepository.had_single_payment?(1, 2, 7).should == true
16
+ end
17
+ end
18
+
19
+ describe "SingleTimeFilter" do
20
+ PRICE = 120
21
+ GUY_WITH_CASH = 1
22
+ GUY_WITHOUT_CASH = 2
23
+ DUMMY = nil
24
+
25
+ before do
26
+ @settings = Settings.new({ :price => PRICE })
27
+ @filter = SingleTimeFilter.new(@settings, 0)
28
+ Login.set_login_balance(GUY_WITH_CASH, 666)
29
+
30
+ FinTransaction.reset_transactions
31
+
32
+ SingleTimeFilterRepository.class_eval { @payments = [ ] }
33
+
34
+ @ft = FinTransaction.new
35
+ @ft.author_id, @ft.club_id = 1, 2
36
+ end
37
+
38
+ it "should return default values when no one-time payment has been made and we have no money" do
39
+ options = { :period => (0...3600) }
40
+ activity = Activity.new(:login_id => GUY_WITHOUT_CASH)
41
+
42
+ @filter.permitted?(DUMMY, GUY_WITHOUT_CASH, options).should == false
43
+ @filter.calculate_cost(DUMMY, GUY_WITHOUT_CASH, DUMMY, DUMMY, options).should == PRICE
44
+ @filter.process_activity(activity, @ft, options).should == false
45
+ @filter.start_permitted?(DUMMY, GUY_WITHOUT_CASH, options).should == false
46
+ end
47
+
48
+ it "should deny resource usage when we haven't logged even, even though we have money" do
49
+ options = { :period => (0...3600) }
50
+ @filter.permitted?(DUMMY, DUMMY, options).should == false
51
+ end
52
+
53
+ it "should allow logging in and using the resource when we have money" do
54
+ options = { :period => (0...3600) }
55
+
56
+ # before charge
57
+ @filter.start_permitted?(DUMMY, GUY_WITH_CASH, options).should == true
58
+ @filter.permitted?(DUMMY, GUY_WITH_CASH, options).should == true
59
+ @filter.calculate_cost(DUMMY, GUY_WITH_CASH, DUMMY, DUMMY, options).should == PRICE
60
+
61
+ # charge
62
+ activity = Activity.new(:login_id => GUY_WITH_CASH, :created_at => Time.at(10), :amount => 30)
63
+ @filter.process_activity(activity, @ft, options).should == true
64
+
65
+ # after
66
+ @filter.start_permitted?(DUMMY, GUY_WITH_CASH, options).should == true
67
+ @filter.permitted?(DUMMY, GUY_WITH_CASH, options).should == true
68
+ @filter.calculate_cost(DUMMY, GUY_WITH_CASH, DUMMY, DUMMY, options).should == 0
69
+
70
+ # ... and even with no balance
71
+ Login.set_login_balance(GUY_WITH_CASH, 0)
72
+ @filter.start_permitted?(DUMMY, GUY_WITH_CASH, options).should == true
73
+ @filter.permitted?(DUMMY, GUY_WITH_CASH, options).should == true
74
+ @filter.calculate_cost(DUMMY, GUY_WITH_CASH, DUMMY, DUMMY, options).should == 0
75
+ end
76
+
77
+ it "should distinguish periods" do
78
+ options = { :period => (0...3600) }
79
+
80
+ # charge
81
+ activity = Activity.new(:login_id => GUY_WITH_CASH, :created_at => Time.at(10), :amount => 30)
82
+ @filter.process_activity(activity, @ft, options).should == true
83
+
84
+ # ok for the initial period ...
85
+ @filter.start_permitted?(DUMMY, GUY_WITH_CASH, options).should == true
86
+ @filter.permitted?(DUMMY, GUY_WITH_CASH, options).should == true
87
+ @filter.calculate_cost(DUMMY, GUY_WITH_CASH, DUMMY, DUMMY, options).should == 0
88
+
89
+ # ... but fail for the other one (unless the guy's got the money o'course)
90
+ options = { :period => (3600...7200) }
91
+ Login.set_login_balance(GUY_WITH_CASH, 0)
92
+ @filter.start_permitted?(DUMMY, GUY_WITH_CASH, options).should == false
93
+ @filter.permitted?(DUMMY, GUY_WITH_CASH, options).should == false
94
+ @filter.calculate_cost(DUMMY, GUY_WITH_CASH, DUMMY, DUMMY, options).should == PRICE
95
+ end
96
+
97
+ it "does charge once within a period" do
98
+ options = [ { :period => (0...3600) } ,
99
+ { :period => (3600...7200) } ]
100
+
101
+ # no transactions before
102
+ FinTransaction.transactions.should == [ ]
103
+
104
+ # charge
105
+ (0..1000).step(30).each do |offset|
106
+ activity = Activity.new(:login_id => GUY_WITH_CASH, :created_at => Time.at(offset), :amount => 30)
107
+ @filter.process_activity(activity, @ft, options[0]).should == true
108
+ end
109
+
110
+ # only ONE transaction after
111
+ FinTransaction.transactions.should == [120]
112
+
113
+ # charge another one
114
+ (0..1000).step(30).each do |offset|
115
+ activity = Activity.new(:login_id => GUY_WITH_CASH, :created_at => Time.at(offset), :amount => 30)
116
+ @filter.process_activity(activity, @ft, options[1]).should == true
117
+ end
118
+
119
+ # ... TWO transactions after
120
+ FinTransaction.transactions.should == [120, 120]
121
+ end
122
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'init'))
2
+
3
+ class TarifBuilderMockClass
4
+ attr :settings
5
+ attr :tarif_id
6
+
7
+ def initialize(settings, tarif_id)
8
+ @settings = settings
9
+ @tarif_id = tarif_id
10
+ end
11
+ end
12
+
13
+ describe "TarifBuilder" do
14
+ it "should deny instantination" do
15
+ lambda {
16
+ TarifBuilder.new
17
+ }.should raise_error
18
+ end
19
+
20
+ it "build a first level filter" do
21
+ child_settings = { :a => 1, :b => 2 }
22
+ settings_hash = {
23
+ :klass => "TarifBuilderMockClass",
24
+ :settings => child_settings
25
+ }
26
+ settings = Settings.new(settings_hash)
27
+
28
+ tarif = TarifBuilder.build(settings, 0)
29
+
30
+ tarif.should be_an_instance_of TarifBuilderMockClass
31
+ tarif.settings.should == child_settings
32
+ end
33
+
34
+ it "should propagate tarif_id" do
35
+ settings_hash = {
36
+ :klass => "TarifBuilderMockClass",
37
+ :settings => { :a => 1, :b => 2 }
38
+ }
39
+ settings = Settings.new(settings_hash)
40
+ tarif = TarifBuilder.build(settings, 123)
41
+ tarif.tarif_id.should == 123
42
+ end
43
+ end
@@ -0,0 +1,144 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'init'))
2
+ require 'mathn'
3
+
4
+ class WeekdayMockFilter1 < Filter
5
+ def calculate_cost(computer_id, login_id, started_at, amount, options={})
6
+ Rational(amount.to_i*100, 3600)
7
+ end
8
+
9
+ def process_activity(unprocessed_activity, ft, options={})
10
+ ft = ft.dup
11
+ ft.volume = Rational(unprocessed_activity.amount.to_i*100, 3600)
12
+ ft.save!
13
+ true
14
+ end
15
+ end
16
+
17
+ class WeekdayMockFilter2 < Filter
18
+ def calculate_cost(computer_id, login_id, started_at, amount, options={})
19
+ Rational(amount.to_i*200, 3600)
20
+ end
21
+
22
+ def process_activity(unprocessed_activity, ft, options={})
23
+ ft = ft.dup
24
+ ft.volume = Rational(unprocessed_activity.amount.to_i*200, 3600)
25
+ ft.save!
26
+ true
27
+ end
28
+ end
29
+
30
+ class WeekdayMockFilter3 < Filter
31
+ def calculate_cost(computer_id, login_id, started_at, amount, options={})
32
+ Rational(amount.to_i*300, 3600)
33
+ end
34
+
35
+ def process_activity(unprocessed_activity, ft, options={})
36
+ ft = ft.dup
37
+ ft.volume = Rational(unprocessed_activity.amount.to_i*300, 3600)
38
+ ft.save!
39
+ true
40
+ end
41
+ end
42
+
43
+ describe "WeekdayFilter" do
44
+ before do
45
+ @settings = Settings.new({
46
+ (0..2) => { :klass => "WeekdayMockFilter1", :settings => { :vasya => "pupkin" } },
47
+ (3..4) => { :klass => "WeekdayMockFilter2", :settings => { :vasya => "vanin" } },
48
+ (5..6) => { :klass => "WeekdayMockFilter3", :settings => { :vanya => "vasin" } }
49
+ })
50
+
51
+ @filter = WeekdayFilter.new(@settings, 0)
52
+ end
53
+
54
+ it "should fail to instantinate with missing days in settings" do
55
+ invalid_settings = Settings.new({
56
+ (0..2) => { :klass => "Filter", :settings => { :vasya => "pupkin" } },
57
+ (3..3) => { :klass => "Filter", :settings => { :vasya => "vanin" } },
58
+ (5..6) => { :klass => "Filter", :settings => { :vanya => "vasin" } }
59
+ })
60
+
61
+ lambda {
62
+ WeekdayFilter.new(invalid_settings, 0)
63
+ }.should raise_error
64
+ end
65
+
66
+ it "should fail to instantinate with repeating days in settings" do
67
+ invalid_settings = Settings.new({
68
+ (0..2) => { :klass => "Filter", :settings => { :vasya => "pupkin" } },
69
+ (3..5) => { :klass => "Filter", :settings => { :vasya => "vanin" } },
70
+ (5..6) => { :klass => "Filter", :settings => { :vanya => "vasin" } }
71
+ })
72
+
73
+ lambda {
74
+ WeekdayFilter.new(invalid_settings, 0)
75
+ }.should raise_error
76
+ end
77
+
78
+ it "should direct methods calls to a certain child Filter and pass options" do
79
+ # verify that we are testing all the available methods
80
+ Filter.public_instance_methods(false).size.should == 4
81
+
82
+ variants = [
83
+ { :moment => Time.local(2010, 8, 10, 17, 30, 0), :klass => WeekdayMockFilter1 },
84
+ { :moment => Time.local(2010, 8, 11, 17, 30, 0), :klass => WeekdayMockFilter2 },
85
+ { :moment => Time.local(2010, 8, 14, 17, 30, 0), :klass => WeekdayMockFilter3 }
86
+ ]
87
+
88
+ variants.each do |variant|
89
+ Timecop.freeze(variant[:moment]) do
90
+ options = { :my => :options }
91
+
92
+ now = Time.now
93
+ activity_stub, ft_stub = Activity.new, FinTransaction.new
94
+ activity_stub.stubs(:created_at).returns(Time.now)
95
+ activity_stub.stubs(:amount).returns(4)
96
+
97
+ # set expectations
98
+ variant[:klass].any_instance.expects(:start_permitted?).with(2, 3, options).returns(1)
99
+ variant[:klass].any_instance.expects(:permitted?).with(2, 3, options).returns(2)
100
+ variant[:klass].any_instance.expects(:calculate_cost).with(1, 2, now, 4, options).returns(3)
101
+ variant[:klass].any_instance.expects(:process_activity).with(kind_of(Activity), ft_stub, options).returns(4)
102
+
103
+ # satisfy them
104
+ @filter.start_permitted?(2, 3, options).should == 1
105
+ @filter.permitted?(2, 3, options).should == 2
106
+ @filter.calculate_cost(1, 2, now, 4, options).should == 3
107
+ @filter.process_activity(activity_stub, ft_stub, options).should == true
108
+ end
109
+ end
110
+ end
111
+
112
+ it "should correctly split periods of time and perform calculations among them" do
113
+ @filter.calculate_cost(1, 2, Time.local(2010, 8, 11, 12, 00, 0), 86400*2).should == 10800
114
+ @filter.calculate_cost(1, 2, Time.local(2010, 8, 11, 13, 5, 5), 86400*7).should == 31200
115
+ end
116
+
117
+ it "should process activities correctly spanning them" do
118
+ unprocessed_activity = Activity.new
119
+ unprocessed_activity.expects(:created_at).returns(Time.at(0)).at_least_once
120
+ unprocessed_activity.expects(:amount).returns(7*24*3600).at_least_once
121
+
122
+ ft = FinTransaction.template
123
+ ft.author_id = 1
124
+ ft.club_id = 2
125
+
126
+ FinTransaction.reset_transactions
127
+ @filter.process_activity(unprocessed_activity, ft).should == true
128
+ FinTransaction.transactions.inject(&:+).should == 31200
129
+ end
130
+
131
+ it "should process activities correctly spanning them (strict check)" do
132
+ unprocessed_activity = Activity.new
133
+ unprocessed_activity.expects(:created_at).returns(Time.utc(2010, 8, 15, 00, 00, 0)).at_least_once
134
+ unprocessed_activity.expects(:amount).returns(7*24*3600).at_least_once
135
+
136
+ ft = FinTransaction.template
137
+ ft.author_id = 1
138
+ ft.club_id = 2
139
+
140
+ FinTransaction.reset_transactions
141
+ @filter.process_activity(unprocessed_activity, ft).should == true
142
+ FinTransaction.transactions.should == [ 2400, 2400, 2400, 4800, 4800, 7200, 7200 ]
143
+ end
144
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omega-tariffs-base
3
+ version: !ruby/object:Gem::Version
4
+ hash: 17
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 5
10
+ version: 0.1.5
11
+ platform: ruby
12
+ authors:
13
+ - Uniq Systems
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-23 00:00:00 +04: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: 19
30
+ segments:
31
+ - 2
32
+ - 3
33
+ - 8
34
+ version: 2.3.8
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: activesupport
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - "="
44
+ - !ruby/object:Gem::Version
45
+ hash: 19
46
+ segments:
47
+ - 2
48
+ - 3
49
+ - 8
50
+ version: 2.3.8
51
+ type: :development
52
+ version_requirements: *id002
53
+ description: Omega Sector base tariffs
54
+ email: ivan@uniqsystems.ru
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files:
60
+ - CHANGELOG
61
+ - README.rdoc
62
+ - lib/computer_class_filter.rb
63
+ - lib/deny_filter.rb
64
+ - lib/filter.rb
65
+ - lib/omega-tariffs-base.rb
66
+ - lib/packet_filter.rb
67
+ - lib/rate_filter.rb
68
+ - lib/regioned_calculation.rb
69
+ - lib/repeating_filter.rb
70
+ - lib/settings.rb
71
+ - lib/single_time_filter.rb
72
+ - lib/tarif_builder.rb
73
+ - lib/weekday_filter.rb
74
+ files:
75
+ - CHANGELOG
76
+ - Manifest
77
+ - README.rdoc
78
+ - Rakefile
79
+ - lib/computer_class_filter.rb
80
+ - lib/deny_filter.rb
81
+ - lib/filter.rb
82
+ - lib/omega-tariffs-base.rb
83
+ - lib/packet_filter.rb
84
+ - lib/rate_filter.rb
85
+ - lib/regioned_calculation.rb
86
+ - lib/repeating_filter.rb
87
+ - lib/settings.rb
88
+ - lib/single_time_filter.rb
89
+ - lib/tarif_builder.rb
90
+ - lib/weekday_filter.rb
91
+ - spec/complex_tarif_spec.rb
92
+ - spec/computer_class_filter_spec.rb
93
+ - spec/deny_filter_spec.rb
94
+ - spec/filter_spec.rb
95
+ - spec/lib/active_record_classes_stub.rb
96
+ - spec/lib/init.rb
97
+ - spec/lib/spec_helper.rb
98
+ - spec/packet_filter_spec.rb
99
+ - spec/rate_filter_spec.rb
100
+ - spec/repeating_filter_spec.rb
101
+ - spec/settings_spec.rb
102
+ - spec/single_time_filter_spec.rb
103
+ - spec/tarif_builder_spec.rb
104
+ - spec/weekday_filter_spec.rb
105
+ - omega-tariffs-base.gemspec
106
+ has_rdoc: true
107
+ homepage: http://uniqsys.ru/
108
+ licenses: []
109
+
110
+ post_install_message:
111
+ rdoc_options:
112
+ - --line-numbers
113
+ - --inline-source
114
+ - --title
115
+ - Omega-tariffs-base
116
+ - --main
117
+ - README.rdoc
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ hash: 3
126
+ segments:
127
+ - 0
128
+ version: "0"
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ hash: 11
135
+ segments:
136
+ - 1
137
+ - 2
138
+ version: "1.2"
139
+ requirements: []
140
+
141
+ rubyforge_project: omega-tariffs-base
142
+ rubygems_version: 1.3.7
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: Omega Sector base tariffs
146
+ test_files: []
147
+