omega-tariffs-base 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/Manifest +30 -0
- data/README.rdoc +10 -0
- data/Rakefile +14 -0
- data/lib/computer_class_filter.rb +37 -0
- data/lib/deny_filter.rb +24 -0
- data/lib/filter.rb +43 -0
- data/lib/omega-tariffs-base.rb +13 -0
- data/lib/packet_filter.rb +111 -0
- data/lib/rate_filter.rb +31 -0
- data/lib/regioned_calculation.rb +61 -0
- data/lib/repeating_filter.rb +188 -0
- data/lib/settings.rb +42 -0
- data/lib/single_time_filter.rb +67 -0
- data/lib/tarif_builder.rb +16 -0
- data/lib/weekday_filter.rb +53 -0
- data/omega-tariffs-base.gemspec +36 -0
- data/spec/complex_tarif_spec.rb +54 -0
- data/spec/computer_class_filter_spec.rb +82 -0
- data/spec/deny_filter_spec.rb +23 -0
- data/spec/filter_spec.rb +36 -0
- data/spec/lib/active_record_classes_stub.rb +151 -0
- data/spec/lib/init.rb +5 -0
- data/spec/lib/spec_helper.rb +9 -0
- data/spec/packet_filter_spec.rb +287 -0
- data/spec/rate_filter_spec.rb +36 -0
- data/spec/repeating_filter_spec.rb +250 -0
- data/spec/settings_spec.rb +62 -0
- data/spec/single_time_filter_spec.rb +122 -0
- data/spec/tarif_builder_spec.rb +43 -0
- data/spec/weekday_filter_spec.rb +144 -0
- metadata +147 -0
data/spec/lib/init.rb
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'init'))
|
2
|
+
|
3
|
+
describe "PacketFilterRepository" do
|
4
|
+
before do
|
5
|
+
PacketFilterRepository.reset
|
6
|
+
@now = Time.now
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return nothing for non-existent regions" do
|
10
|
+
# yet unregistered region ...
|
11
|
+
PacketFilterRepository.region_registered?(1, 2).should == false
|
12
|
+
PacketFilterRepository.region_paid?(1, 2).should == false
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should register regions" do
|
16
|
+
# register region
|
17
|
+
PacketFilterRepository.register_region(1, 2, @now, 3600)
|
18
|
+
|
19
|
+
# registered but not yet paid region ...
|
20
|
+
PacketFilterRepository.region_registered?(1, 2).should == true
|
21
|
+
PacketFilterRepository.region_paid?(1, 2).should == false
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should register and commit payments" do
|
25
|
+
# register region
|
26
|
+
PacketFilterRepository.register_region(1, 2, @now, 3600)
|
27
|
+
|
28
|
+
# pay for the region ...
|
29
|
+
PacketFilterRepository.pay_region(1, 2)
|
30
|
+
|
31
|
+
# registered and paid region ...
|
32
|
+
PacketFilterRepository.region_registered?(1, 2).should == true
|
33
|
+
PacketFilterRepository.region_paid?(1, 2).should == true
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return false for other regions when current is paid" do
|
37
|
+
# register region
|
38
|
+
PacketFilterRepository.register_region(1, 2, @now, 3600)
|
39
|
+
|
40
|
+
# pay for the region ...
|
41
|
+
PacketFilterRepository.pay_region(1, 2)
|
42
|
+
|
43
|
+
# this is not the region ...
|
44
|
+
PacketFilterRepository.region_registered?(1, 2, @now-1).should == false
|
45
|
+
PacketFilterRepository.region_paid?(1, 2, @now-1).should == false
|
46
|
+
|
47
|
+
# this is still the region ...
|
48
|
+
PacketFilterRepository.region_registered?(1, 2, @now+1).should == true
|
49
|
+
PacketFilterRepository.region_paid?(1, 2, @now+1).should == true
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should report spanning regions" do
|
53
|
+
# register region
|
54
|
+
PacketFilterRepository.register_region(1, 2, @now, 3600)
|
55
|
+
|
56
|
+
# check spanning
|
57
|
+
PacketFilterRepository.region_spans?(1, 2, @now, 1000).should == false
|
58
|
+
PacketFilterRepository.region_spans?(1, 2, @now, 3599).should == false
|
59
|
+
PacketFilterRepository.region_spans?(1, 2, @now, 3600).should == true
|
60
|
+
PacketFilterRepository.region_spans?(1, 2, @now, 5000).should == true
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should not end by default" do
|
64
|
+
PacketFilterRepository.should_end?(1, 2).should == false
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should_end call should return true" do
|
68
|
+
PacketFilterRepository.set_should_end(1, 2, @now+60).should == true
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should end when it's scheduled" do
|
72
|
+
PacketFilterRepository.set_should_end(1, 2, @now+60)
|
73
|
+
PacketFilterRepository.should_end?(1, 2).should == false
|
74
|
+
Timecop.freeze(@now + 60) { PacketFilterRepository.should_end?(1, 2).should == false }
|
75
|
+
Timecop.freeze(@now + 61) { PacketFilterRepository.should_end?(1, 2).should == true }
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should not interfere with the other users and tariffs" do
|
79
|
+
PacketFilterRepository.set_should_end(1, 2, @now-1)
|
80
|
+
PacketFilterRepository.should_end?(1, 2).should == true
|
81
|
+
PacketFilterRepository.should_end?(1, 3).should == false
|
82
|
+
PacketFilterRepository.should_end?(8, 2).should == false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "PacketFilter" do
|
87
|
+
before do
|
88
|
+
@settings = stub()
|
89
|
+
@settings.expects(:price).returns(100)
|
90
|
+
@settings.expects(:length).returns(3600)
|
91
|
+
@filter = PacketFilter.new(@settings, 1)
|
92
|
+
|
93
|
+
FinTransaction.reset_transactions
|
94
|
+
PacketFilterRepository.reset
|
95
|
+
Login.set_login_balance(1, 0)
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "start_permitted?" do
|
99
|
+
it "should permit login if I have got close to enough money" do
|
100
|
+
Login.set_login_balance(1, 100)
|
101
|
+
@filter.start_permitted?(2, 1).should == true
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should permit login if I have got enough money" do
|
105
|
+
Login.set_login_balance(1, 101)
|
106
|
+
@filter.start_permitted?(2, 1).should == true
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should permit login if I haven't got enough money" do
|
110
|
+
Login.set_login_balance(1, 99)
|
111
|
+
@filter.start_permitted?(2, 1).should == false
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "permitted?" do
|
116
|
+
it "should permit work if I have got close to enough money" do
|
117
|
+
Login.set_login_balance(1, 100)
|
118
|
+
@filter.permitted?(2, 1).should == true
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should permit work if I have got enough money" do
|
122
|
+
Login.set_login_balance(1, 101)
|
123
|
+
@filter.permitted?(2, 1).should == true
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should permit work if I haven't got enough money" do
|
127
|
+
Login.set_login_balance(1, 99)
|
128
|
+
@filter.permitted?(2, 1).should == false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def make_single_activity_processed
|
133
|
+
activity = Activity.new
|
134
|
+
activity.created_at = Time.now
|
135
|
+
activity.login_id = 1
|
136
|
+
activity.amount = 3600
|
137
|
+
|
138
|
+
ft = FinTransaction.template
|
139
|
+
ft.club_id, ft.author_id, ft.src_account_id, ft.dst_account_id = 1, 2, 3, 4
|
140
|
+
|
141
|
+
@filter.process_activity(activity, ft)
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "calculate_cost" do
|
145
|
+
it "should return the price of the region unless paid" do
|
146
|
+
@filter.calculate_cost(2, 1, Time.now, 10).should == 100
|
147
|
+
@filter.calculate_cost(2, 1, Time.now, 3599).should == 100
|
148
|
+
@filter.calculate_cost(2, 1, Time.now, 3600).should == 100
|
149
|
+
@filter.calculate_cost(2, 1, Time.now, 3601).should == 100
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should return the zero price of the region if paid and Integer::MAX out of the region" do
|
153
|
+
Login.set_login_balance(1, 100)
|
154
|
+
|
155
|
+
make_single_activity_processed.should == true
|
156
|
+
|
157
|
+
@filter.calculate_cost(2, 1, Time.now, 10).should == 0
|
158
|
+
@filter.calculate_cost(2, 1, Time.now, 3599).should == 0
|
159
|
+
@filter.calculate_cost(2, 1, Time.now, 3600).should == Integer::MAX
|
160
|
+
@filter.calculate_cost(2, 1, Time.now, 3605).should == Integer::MAX
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "process_activity" do
|
165
|
+
it "should return unsuccessful activity processing if no money" do
|
166
|
+
Login.set_login_balance(1, 99)
|
167
|
+
make_single_activity_processed.should == false
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "packet life time" do
|
172
|
+
def actualize_balance!
|
173
|
+
Login.set_login_balance(1, Login.find(1).balance - FinTransaction.transactions.sum)
|
174
|
+
FinTransaction.reset_transactions
|
175
|
+
end
|
176
|
+
|
177
|
+
def do_several_activities(offsets=[0])
|
178
|
+
ft = FinTransaction.template
|
179
|
+
ft.club_id, ft.author_id, ft.src_account_id, ft.dst_account_id = 1, 2, 3, 4
|
180
|
+
|
181
|
+
offsets.each do |offset|
|
182
|
+
activity = Activity.new
|
183
|
+
activity.created_at = Time.now + offset
|
184
|
+
activity.login_id = 1
|
185
|
+
activity.amount = 30
|
186
|
+
@filter.process_activity(activity, ft).should == true
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should allow the packet to be opened once, if there's exact amount of money on the account as needed" do
|
191
|
+
now = Time.now
|
192
|
+
|
193
|
+
Timecop.freeze(now) do
|
194
|
+
Login.set_login_balance(1, 100)
|
195
|
+
|
196
|
+
@filter.start_permitted?(2, 1).should == true
|
197
|
+
@filter.permitted?(2, 1).should == true
|
198
|
+
|
199
|
+
Login.find(1).balance.should == 100
|
200
|
+
do_several_activities [ 0, 30, 60 ]
|
201
|
+
actualize_balance!
|
202
|
+
Login.find(1).balance.should == 0
|
203
|
+
end
|
204
|
+
|
205
|
+
[ [now + 1, true, true], [now + 3598, true, true], [now + 3599, false, false], [now + 3699, false, false]].each do |variant|
|
206
|
+
Timecop.freeze(variant[0]) do
|
207
|
+
@filter.start_permitted?(2, 1).should == variant[1]
|
208
|
+
@filter.permitted?(2, 1).should == variant[2]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should allow the packet to be opened once even if there's slightly more money on the account than needed" do
|
214
|
+
now = Time.now
|
215
|
+
|
216
|
+
Timecop.freeze(now) do
|
217
|
+
Login.set_login_balance(1, 105)
|
218
|
+
|
219
|
+
@filter.start_permitted?(2, 1).should == true
|
220
|
+
@filter.permitted?(2, 1).should == true
|
221
|
+
|
222
|
+
Login.find(1).balance.should == 105
|
223
|
+
do_several_activities [ 0, 30, 60 ]
|
224
|
+
actualize_balance!
|
225
|
+
Login.find(1).balance.should == 5
|
226
|
+
end
|
227
|
+
|
228
|
+
[ [now + 1, true, true], [now + 3598, true, true], [now + 3599, false, false], [now + 3699, false, false]].each do |variant|
|
229
|
+
Timecop.freeze(variant[0]) do
|
230
|
+
@filter.start_permitted?(2, 1).should == variant[1]
|
231
|
+
@filter.permitted?(2, 1).should == variant[2]
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should allow the packet to be opened twice if there is enough money, and the user should be charged twice" do
|
237
|
+
now = Time.now
|
238
|
+
|
239
|
+
Timecop.freeze(now) do
|
240
|
+
Login.set_login_balance(1, 205)
|
241
|
+
|
242
|
+
@filter.start_permitted?(2, 1).should == true
|
243
|
+
@filter.permitted?(2, 1).should == true
|
244
|
+
|
245
|
+
Login.find(1).balance.should == 205
|
246
|
+
do_several_activities [ 0, 30, 60 ]
|
247
|
+
actualize_balance!
|
248
|
+
Login.find(1).balance.should == 105
|
249
|
+
end
|
250
|
+
|
251
|
+
# check end of the single session
|
252
|
+
[ [now + 1, true], [now + 3600, true], [now + 3601, false], [now + 3699, false]].each do |variant|
|
253
|
+
Timecop.freeze(variant[0]) do
|
254
|
+
@filter.permitted?(2, 1).should == variant[1]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
# check if start_permitted? resets permitted? flag
|
259
|
+
[ [now + 1, true, true], [now + 3599, true, true], [now + 3600, true, true], [now + 3699, true, true]].each do |variant|
|
260
|
+
Timecop.freeze(variant[0]) do
|
261
|
+
@filter.start_permitted?(2, 1).should == variant[1]
|
262
|
+
@filter.permitted?(2, 1).should == variant[2]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
now += 3610
|
267
|
+
|
268
|
+
Timecop.freeze(now) do
|
269
|
+
@filter.start_permitted?(2, 1).should == true
|
270
|
+
@filter.permitted?(2, 1).should == true
|
271
|
+
|
272
|
+
Login.find(1).balance.should == 105
|
273
|
+
do_several_activities [ 0, 30, 60 ]
|
274
|
+
actualize_balance!
|
275
|
+
Login.find(1).balance.should == 5
|
276
|
+
end
|
277
|
+
|
278
|
+
# check if permitted? and start_permitted? are in the correct state
|
279
|
+
[ [now + 1, true, true], [now + 3598, true, true], [now + 3599, false, false], [now + 3699, false, false]].each do |variant|
|
280
|
+
Timecop.freeze(variant[0]) do
|
281
|
+
@filter.start_permitted?(2, 1).should == variant[1]
|
282
|
+
@filter.permitted?(2, 1).should == variant[2]
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'init'))
|
2
|
+
|
3
|
+
describe "RateFilter" do
|
4
|
+
RATE = 123
|
5
|
+
|
6
|
+
before do
|
7
|
+
settings = mock()
|
8
|
+
settings.expects(:rate).returns(RATE)
|
9
|
+
@filter = RateFilter.new(settings, 0)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should permit start" do
|
13
|
+
@filter.start_permitted?(1, 2, 3).should == true
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should permit going on" do
|
17
|
+
@filter.permitted?(1, 2, 3).should == true
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should calculate the correct amount" do
|
21
|
+
@filter.calculate_cost(1, 2, 3, 3600).should == RATE
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should process activity correctly" do
|
25
|
+
activity = mock()
|
26
|
+
activity.expects(:amount).returns(3600)
|
27
|
+
|
28
|
+
ft = FinTransaction.template
|
29
|
+
ft.club_id, ft.author_id, ft.src_account_id, ft.dst_account_id = 1, 2, 3, 4
|
30
|
+
|
31
|
+
FinTransaction.any_instance.expects(:volume=).with(RATE)
|
32
|
+
FinTransaction.any_instance.expects(:valid?).returns(true)
|
33
|
+
|
34
|
+
@filter.process_activity(activity, ft).should == true
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'init'))
|
2
|
+
|
3
|
+
class RepeatingMockFilter1 < Filter
|
4
|
+
def calculate_cost(computer_id, login_id, started_at, amount, options={})
|
5
|
+
Rational(amount.to_i*100, 3600)
|
6
|
+
end
|
7
|
+
|
8
|
+
def process_activity(unprocessed_activity, ft, options={})
|
9
|
+
ft = ft.dup
|
10
|
+
ft.volume = Rational(unprocessed_activity.amount.to_i*100, 3600)
|
11
|
+
ft.save!
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class RepeatingMockFilter2 < Filter
|
17
|
+
def calculate_cost(computer_id, login_id, started_at, amount, options={})
|
18
|
+
Rational(amount.to_i*200, 3600)
|
19
|
+
end
|
20
|
+
|
21
|
+
def process_activity(unprocessed_activity, ft, options={})
|
22
|
+
ft = ft.dup
|
23
|
+
ft.volume = Rational(unprocessed_activity.amount.to_i*200, 3600)
|
24
|
+
ft.save!
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class RepeatingMockFilter3 < Filter
|
30
|
+
def calculate_cost(computer_id, login_id, started_at, amount, options={})
|
31
|
+
Rational(amount.to_i*300, 3600)
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_activity(unprocessed_activity, ft, options={})
|
35
|
+
ft = ft.dup
|
36
|
+
ft.volume = Rational(unprocessed_activity.amount.to_i*300, 3600)
|
37
|
+
ft.save!
|
38
|
+
true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class RepeatingMockFilterWithOptionsExpectations < Filter
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
describe "RepeatingFilterPeriod" do
|
47
|
+
it "should not allow to create invalid period" do
|
48
|
+
lambda {
|
49
|
+
RepeatingFilterPeriod.new(Time.now, 300, 200, stub())
|
50
|
+
}.should raise_error
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should allow valid period creation" do
|
54
|
+
RepeatingFilterPeriod.new(Time.now, 300, 300, stub())
|
55
|
+
RepeatingFilterPeriod.new(Time.now, 123, 200, stub())
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should set filter value" do
|
59
|
+
filtah = stub()
|
60
|
+
RepeatingFilterPeriod.new(Time.now, 300, 300, filtah).filter.should == filtah
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should delegate filter value when generating ranges" do
|
64
|
+
filtah, now = stub(), Time.now
|
65
|
+
periods = RepeatingFilterPeriod.new(now, 100, 200, filtah).generate_in_range(now-1, now + 410)
|
66
|
+
periods.each { |p| p.filter.should == filtah }
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should recur correctly" do
|
70
|
+
test_start_time = Time.now
|
71
|
+
|
72
|
+
period = RepeatingFilterPeriod.new(test_start_time, 2*3600, 86400, stub())
|
73
|
+
|
74
|
+
# today
|
75
|
+
period.includes?(test_start_time).should == true
|
76
|
+
period.includes?(test_start_time+123).should == true
|
77
|
+
period.includes?(test_start_time+7199).should == true
|
78
|
+
period.includes?(test_start_time+7200).should == false
|
79
|
+
period.includes?(test_start_time+56124).should == false
|
80
|
+
period.includes?(test_start_time+86399).should == false
|
81
|
+
|
82
|
+
# tomorrow
|
83
|
+
period.includes?(test_start_time+86400).should == true
|
84
|
+
period.includes?(test_start_time+86400+123).should == true
|
85
|
+
period.includes?(test_start_time+86400+7199).should == true
|
86
|
+
period.includes?(test_start_time+86400+7200).should == false
|
87
|
+
period.includes?(test_start_time+86400+56124).should == false
|
88
|
+
period.includes?(test_start_time+86400+86399).should == false
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should support === operator to behave exactly like includes?" do
|
92
|
+
period = RepeatingFilterPeriod.new(Time.now, 2*3600, 86400, stub())
|
93
|
+
period.expects(:includes?).with(1024).returns(:thats_what_include_returns)
|
94
|
+
(period === 1024).should == :thats_what_include_returns
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should generate correct ranges array" do
|
98
|
+
test_start_time = Time.now
|
99
|
+
|
100
|
+
period = RepeatingFilterPeriod.new(test_start_time, 2*3600, 86400, stub())
|
101
|
+
|
102
|
+
ranges = period.generate_in_range(test_start_time, test_start_time+86400).map { |r| r.as_range }
|
103
|
+
ranges.should == [ (test_start_time.to_i ... test_start_time.to_i+2*3600) ]
|
104
|
+
|
105
|
+
ranges = period.generate_in_range(test_start_time, test_start_time+45000).map { |r| r.as_range }
|
106
|
+
ranges.should == [ (test_start_time.to_i ... test_start_time.to_i+2*3600) ]
|
107
|
+
|
108
|
+
ranges = period.generate_in_range(test_start_time, test_start_time+2*86400).map { |r| r.as_range }
|
109
|
+
ranges.should == [ (test_start_time.to_i ... test_start_time.to_i+2*3600), (test_start_time.to_i+86400 ... test_start_time.to_i+86400+2*3600) ]
|
110
|
+
|
111
|
+
ranges = period.generate_in_range(test_start_time, test_start_time+1024*86400).map { |r| r.as_range }
|
112
|
+
ranges.size.should == 1024
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should return correct variant of the localized period" do
|
116
|
+
test_start_time = Time.now
|
117
|
+
period = RepeatingFilterPeriod.new(test_start_time, 2*3600, 86400, stub())
|
118
|
+
period.local_period(test_start_time+30.days+10.seconds).as_range.should ==
|
119
|
+
((test_start_time+30*86400).to_i ... (test_start_time+2*3600+30*86400).to_i)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "SortableRange" do
|
124
|
+
it "should sort the correct way" do
|
125
|
+
r_1_3 = SortableRange.new(1, 3)
|
126
|
+
r_5_9 = SortableRange.new(5, 9)
|
127
|
+
r_16_18= SortableRange.new(16, 18)
|
128
|
+
[ r_5_9, r_1_3, r_16_18 ].sort.should == [ r_1_3, r_5_9, r_16_18 ]
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should return corresponding Range object" do
|
132
|
+
SortableRange.new(10, 13).as_range.should == Range.new(10,13)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should have filter field" do
|
136
|
+
r = SortableRange.new(10, 13)
|
137
|
+
r.filter = 123
|
138
|
+
r.filter.should == 123
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "RepeatingFilter" do
|
143
|
+
before do
|
144
|
+
now = Time.at(0)
|
145
|
+
@settings = Settings.new({
|
146
|
+
{ :starts_at => now, :length => 3600, :period => 10800 } => { :klass => "RepeatingMockFilter1", :settings => { :vasya => "pupkin" } },
|
147
|
+
{ :starts_at => now+3600, :length => 3600, :period => 10800 } => { :klass => "RepeatingMockFilter2", :settings => { :vasya => "vanin" } },
|
148
|
+
{ :starts_at => now+7200, :length => 3600, :period => 10800 } => { :klass => "RepeatingMockFilter3", :settings => { :vasya => "vanin" } }
|
149
|
+
})
|
150
|
+
@filter = RepeatingFilter.new(@settings, 0)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should not instantinate when periods are not cosistent" do
|
154
|
+
now = Time.at(0)
|
155
|
+
settings = Settings.new({
|
156
|
+
{ :starts_at => now, :length => 100, :period => 300 } => { :klass => "RepeatingMockFilter1", :settings => { :vasya => "pupkin" } },
|
157
|
+
{ :starts_at => now+100, :length => 100, :period => 300 } => { :klass => "RepeatingMockFilter2", :settings => { :vasya => "vanin" } }
|
158
|
+
})
|
159
|
+
|
160
|
+
lambda {
|
161
|
+
filter = RepeatingFilter.new(settings, 0)
|
162
|
+
}.should raise_error(Exception, /Inconsistent periods/)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should not instantinate when periods are intersecting" do
|
166
|
+
now = Time.at(0)
|
167
|
+
settings = Settings.new({
|
168
|
+
{ :starts_at => now, :length => 95, :period => 301 } => { :klass => "RepeatingMockFilter1", :settings => { :vasya => "pupkin" } },
|
169
|
+
{ :starts_at => now+100, :length => 100, :period => 300 } => { :klass => "RepeatingMockFilter2", :settings => { :vasya => "vanin" } },
|
170
|
+
{ :starts_at => now+200, :length => 100, :period => 300 } => { :klass => "RepeatingMockFilter3", :settings => { :vasya => "vanin" } },
|
171
|
+
})
|
172
|
+
|
173
|
+
lambda {
|
174
|
+
filter = RepeatingFilter.new(settings, 0)
|
175
|
+
}.should raise_error(Exception, /Intersectings periods/)
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should calculate cost correctly" do
|
179
|
+
@filter.calculate_cost(1, 2, Time.at(0), 3600).should == 100
|
180
|
+
@filter.calculate_cost(1, 2, Time.at(3600), 3600).should == 200
|
181
|
+
@filter.calculate_cost(1, 2, Time.at(7200), 3600).should == 300
|
182
|
+
|
183
|
+
@filter.calculate_cost(1, 2, Time.at(0), 7*24*3600).should == 33600
|
184
|
+
@filter.calculate_cost(1, 2, Time.at(3600+1800), 7*24*3600).should == 33600
|
185
|
+
|
186
|
+
@filter.calculate_cost(1, 2, Time.at(3600+1800), 3600+1800).should == 400
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should process activities correctly spanning them" do
|
190
|
+
unprocessed_activity = Activity.new
|
191
|
+
unprocessed_activity.expects(:created_at).returns(Time.at(0)).at_least_once
|
192
|
+
unprocessed_activity.expects(:amount).returns(7*24*3600).at_least_once
|
193
|
+
|
194
|
+
ft = FinTransaction.template
|
195
|
+
ft.author_id = 1
|
196
|
+
ft.club_id = 2
|
197
|
+
|
198
|
+
FinTransaction.reset_transactions
|
199
|
+
@filter.process_activity(unprocessed_activity, ft).should == true
|
200
|
+
FinTransaction.transactions.inject(&:+).should == 33600
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should process activities correctly spanning them (strict check)" do
|
204
|
+
unprocessed_activity = Activity.new
|
205
|
+
unprocessed_activity.expects(:created_at).returns(Time.at(0)).at_least_once
|
206
|
+
unprocessed_activity.expects(:amount).returns(3600*4+1800).at_least_once
|
207
|
+
|
208
|
+
ft = FinTransaction.template
|
209
|
+
ft.author_id = 1
|
210
|
+
ft.club_id = 2
|
211
|
+
|
212
|
+
FinTransaction.reset_transactions
|
213
|
+
@filter.process_activity(unprocessed_activity, ft).should == true
|
214
|
+
FinTransaction.transactions.should == [ 100, 200, 300, 100, 100 ]
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should pass on the options to the underlying filter and add its own" do
|
218
|
+
doesnt_matter = nil
|
219
|
+
now = Time.at(0)
|
220
|
+
settings = Settings.new({
|
221
|
+
{ :starts_at => now, :length => 3600, :period => 10800 } => { :klass => "RepeatingMockFilterWithOptionsExpectations", :settings => { :vasya => "pupkin" } },
|
222
|
+
{ :starts_at => now+3600, :length => 3600, :period => 10800 } => { :klass => "RepeatingMockFilter2", :settings => { :vasya => "vanin" } },
|
223
|
+
{ :starts_at => now+7200, :length => 3600, :period => 10800 } => { :klass => "RepeatingMockFilter3", :settings => { :vasya => "vanin" } }
|
224
|
+
})
|
225
|
+
|
226
|
+
filter = RepeatingFilter.new(settings, 0)
|
227
|
+
|
228
|
+
[ 0, 3600*3 ].each do |offset|
|
229
|
+
RepeatingMockFilterWithOptionsExpectations.any_instance.tap do |it|
|
230
|
+
it.expects(:calculate_cost).with(anything, anything, anything, anything, equals({:my => :options, :period => (0+offset...3600+offset)})).returns(0)
|
231
|
+
it.expects(:start_permitted?).with(anything, anything, equals({:my => :options, :period => (0+offset...3600+offset)})).returns(true)
|
232
|
+
it.expects(:permitted?).with(anything, anything, equals({:my => :options, :period => (0+offset...3600+offset)})).returns(true)
|
233
|
+
it.expects(:process_activity).with(anything, anything, equals({:my => :options, :period => (0+offset...3600+offset)})).returns(true)
|
234
|
+
end
|
235
|
+
|
236
|
+
Timecop.freeze(now + offset) do
|
237
|
+
ft_doesnt_matter = stub_everything()
|
238
|
+
|
239
|
+
activity_doesnt_matter = Activity.new
|
240
|
+
activity_doesnt_matter.stubs(:created_at).returns(Time.now + 30.seconds).at_least_once
|
241
|
+
activity_doesnt_matter.stubs(:amount).returns(3600).at_least_once
|
242
|
+
|
243
|
+
filter.calculate_cost(doesnt_matter, doesnt_matter, Time.now + 30.seconds, 3600, { :my => :options })
|
244
|
+
filter.start_permitted?(doesnt_matter, doesnt_matter, { :my => :options })
|
245
|
+
filter.permitted?(doesnt_matter, doesnt_matter, { :my => :options })
|
246
|
+
filter.process_activity(activity_doesnt_matter, ft_doesnt_matter, { :my => :options })
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|