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.
- 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
|