omega-tariffs-base 0.1.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.
@@ -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
+