lucid_works 0.6.14 → 0.6.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,19 @@
1
1
  require 'active_support/core_ext/numeric/time.rb'
2
2
  module LucidWorks
3
- class Collection < Base
3
+ class Collection
4
4
  class Activity < Base
5
5
  TYPES = %w{ optimize spelling click autocomplete}
6
6
 
7
+ # Unlike Datasource schedules, the API allows multiples of these
8
+ # So, to be honest with gem users, we can't really say this:
9
+ # self.singleton = true
7
10
  belongs_to :collection
8
11
  has_many :histories, :class_name => :history
9
12
  has_one :status
10
13
 
11
14
  schema do
12
- attributes :start_time, :period
15
+ attribute :period
16
+ attribute :start_time, :iso8601
13
17
  attribute :active, :boolean
14
18
  attribute :type, :string, :values => TYPES, :omit_during_update => true
15
19
  end
@@ -17,6 +21,151 @@ module LucidWorks
17
21
  validates_presence_of :type, :start_time
18
22
  validates_numericality_of :period, :allow_blank => true
19
23
 
24
+ def frequency
25
+ case period
26
+ when 1.weeks.seconds then 'weekly'
27
+ when 1.days.seconds then 'daily'
28
+ when 1.hours.seconds then 'hourly'
29
+ when 0 then nil
30
+ else 'custom'
31
+ end
32
+ end
33
+
34
+ #
35
+ # accepts hourly, daily, weekly, and sets period to respective # of seconds
36
+ #
37
+ def frequency=(frequency)
38
+ self.period = case frequency
39
+ when 'hourly' then 1.hours.seconds
40
+ when 'daily' then 1.days.seconds
41
+ when 'weekly' then 1.weeks.seconds
42
+ else raise "unknown frequency"
43
+ end
44
+ end
45
+
46
+ #
47
+ # predict when action will occur next if active at that time
48
+ #
49
+ def next_start
50
+ return start_time if (now = Time.now) <= start_time
51
+ # require 'ruby-debug'; debugger
52
+ time_since_start = now - start_time
53
+ last_interval_num = (time_since_start / period).to_i
54
+ next_interval_num = if (time_since_start % period) == 0
55
+ # this is sort of a stupid condition b/c time precision is millisecond or less
56
+ # for human purposes we wouldn't care if the result were as though the call
57
+ # happened a millisecond later. But whatever.
58
+ last_interval_num # the next interval *is* the last interval if it is exactly now
59
+ else
60
+ last_interval_num + 1
61
+ end
62
+ start_time + period * next_interval_num
63
+ end
64
+
65
+ #
66
+ # phantom attribute for compiling real start time and frequency from appropriate form data
67
+ # Allows the user to specify a schedule simply with repeat interval (hourly, daily, weekly)
68
+ # and time within the interval to run (e.g 5 past, or Tuesdays at 2:15)
69
+ #
70
+ # We have to figure out when the actual start time will be because we are not asking
71
+ # the user for this. It needs to be:
72
+ # * at the requested time relative to the interval chosen
73
+ # * as soon as possible
74
+ # * in the future
75
+ #
76
+ # This is obvious to humans, but when computing it, you run into the following problem. It
77
+ # happens with all interval sizes, but for the sake of example, we'll use weekly:
78
+ #
79
+ # Problem 1) If today is Thursday, and the user asks for "weekly on Wednesdays," Wednesday has
80
+ # already happened this week. We have to make sure we pick the nearest wednesday that is in
81
+ # the future
82
+ #
83
+ # Problem 2) If today is Tuesday, and the user asks for "weekly on Wednesdays,", the simple solution
84
+ # to problem 1 (start next week instead of this week) causes you to skip this Tuesday, even though
85
+ # it is valid and is what the user would expect
86
+ #
87
+ # The algorith to solve both problems at once is this:
88
+ # * From Time.now, back up to the beginning of the interval even if it is in the past.
89
+ # * Fast forward to the requested siimple start time
90
+ # * If you are still in the past, advance by one interval
91
+ #
92
+ def schedule=(all_attributes)
93
+ # convert to format accepted by Time.advance
94
+ if all_attributes['start']
95
+ all_attributes['start'].to_options!
96
+ all_attributes['start'].each{|k,v| all_attributes['start'][k]=v.to_i}
97
+ end
98
+
99
+ self.active = all_attributes['active'] if all_attributes.keys.include?('active')
100
+
101
+ now = Time.now
102
+ self.frequency = all_attributes['frequency']
103
+ self.start_time =
104
+ case all_attributes['frequency']
105
+ when 'weekly'
106
+ # require 'ruby-debug'; debugger
107
+ start = now.beginning_of_week.advance(all_attributes['start'])
108
+ start < now ? start.advance(:weeks => 1) : start
109
+ when 'daily'
110
+ start = now.beginning_of_day.advance(all_attributes['start'])
111
+ start < now ? start.advance(:days => 1) : start
112
+ when 'hourly'
113
+ start = now.change(:min => 0).advance(all_attributes['start'])
114
+ start < now ? start.advance(:hours => 1) : start
115
+ else
116
+ puts "*** frequency: <#{all_attributes[:frequency]}>"
117
+ raise "unexpected frequency encountered"
118
+ end
119
+ end
120
+
121
+ #
122
+ # convenince method for setting the current value in a view selector
123
+ #
124
+ def hour
125
+ self.start_time.localtime.hour rescue nil
126
+ end
127
+
128
+ #
129
+ # convenince method for setting the current value in a view selector
130
+ #
131
+ def min
132
+ self.start_time.localtime.min rescue nil
133
+ end
134
+
135
+ #
136
+ # convenince method for setting the current value in a view selector
137
+ #
138
+ def day_of_week
139
+ # subract 1 because '%u' returns 1-7, and this is working with zero-indexed ruby arrays
140
+ self.start_time.localtime.strftime('%u').to_i - 1 rescue nil
141
+ end
142
+
143
+ def start_is_more_than_one_period_in_the_future?
144
+ # This works fine with start times that are multiple periods in the past
145
+ # because that gives a negative difference, and period is always >= 0
146
+ (self.start_time - Time.now) > self.period
147
+ end
148
+
149
+ #
150
+ # convenience method for detecting whether schedule can be represented in simple format
151
+ # or should be described as custom (meaning it is beyond the capabilities of the convenience methods)
152
+ #
153
+ def custom?
154
+ return false unless self.start_time
155
+ return true if self.frequency == 'custom'
156
+ return true if self.start_is_more_than_one_period_in_the_future?
157
+ return false
158
+ end
159
+
160
+ #
161
+ # convenience method for setting defaults in a UI that make sense for a user
162
+ #
163
+ def ui_appropriate_defaults!
164
+ if self.start_time.blank? || self.period == 0
165
+ self.active = true
166
+ end
167
+ end
168
+
20
169
  def t_type
21
170
  I18n.t(type, :scope => 'activemodel.models.lucid_works.collection.activity.type')
22
171
  end
@@ -65,7 +65,8 @@ module LucidWorks
65
65
  act
66
66
  else
67
67
  num_created += 1
68
- self.create_activity(:type => type, :active => true, 'start_time' => 3600*num_created)
68
+ start_time = Time.now.change(:min => 0) + num_created.hours
69
+ self.create_activity(:type => type, :active => true, :start_time => start_time, :period => 1.days.seconds)
69
70
  end
70
71
  end
71
72
  self.activities! if num_created > 0
@@ -1,5 +1,5 @@
1
1
  module LucidWorks
2
- VERSION = "0.6.14"
2
+ VERSION = "0.6.15"
3
3
 
4
4
  class Version < Base
5
5
  end
@@ -1,125 +1,515 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe LucidWorks::Collection::Activity do
4
- before :all do
5
- @server = connect_to_live_server
6
- @server.reset_collections!
7
- @collection = @server.collections!.first
3
+ # convenience methods for readability of these tests themselves
4
+ class String
5
+ def weekday
6
+ Time.iso8601(self).strftime('%A')
7
+ end
8
8
  end
9
9
 
10
- def activity_count
11
- @collection.activities!.size
10
+ class Time
11
+ def weekday
12
+ self.strftime('%A')
13
+ end
12
14
  end
13
15
 
14
- class LucidWorks::Collection::Activity
15
- def history_size
16
- self.histories!.size
16
+
17
+ describe LucidWorks::Collection::Activity do
18
+ context "Functionality shared with Datasource scheduling" do
19
+ before :all do
20
+ ENV['TZ'] = 'UTC'
17
21
  end
18
- end
19
22
 
20
- describe "CRUD" do
21
- describe ".create"do
22
- context "with invalid parameters" do
23
+ before do
24
+ @server = connect_to_live_server
25
+ @schedule = LucidWorks::Datasource::Schedule.new(:parent => @server)
26
+ end
27
+
28
+ describe '#frequency' do
29
+ it "should return 'weekly' when period == num of seconds in a week" do
30
+ @schedule.period = 604800
31
+ @schedule.frequency.should == 'weekly'
32
+ end
33
+
34
+ it "should return 'daily' when period == num of seconds in a day" do
35
+ @schedule.period = 86400
36
+ @schedule.frequency.should == 'daily'
37
+ end
38
+
39
+ it "should return 'hourly' when period == num of seconds in an hour" do
40
+ @schedule.period = 3600
41
+ @schedule.frequency.should == 'hourly'
42
+ end
43
+
44
+ it "should return 'custom' when period does not correspond to a common number of seconds" do
45
+ @schedule.period = 1
46
+ @schedule.frequency.should == 'custom'
47
+ end
48
+
49
+ it "should return nil when the period is zero" do
50
+ @schedule.period = 0
51
+ @schedule.frequency.should == nil
52
+ end
53
+ end
54
+
55
+ describe '#next_start' do
56
+ context 'start_time is in the future' do
57
+ it 'should return start_time' do
58
+ Timecop.freeze(now = Time.now.utc) do
59
+ @schedule.start_time = now + 30.minutes
60
+ @schedule.next_start.should == @schedule.start_time
61
+ end
62
+ end
63
+ end
64
+
65
+ #
66
+ # some of these are a little sketchy b/c comparing time equality is tricky
67
+ # Time objects are precise to the millisecond
68
+ # we cheat by converting to string, which is only accurate to the second
69
+ # but if these test are run on a second boundary, they might wrongly fail
70
+ #
71
+ context 'start_time is in the past' do
23
72
  before do
24
- @activity_params = {:type => 'bogus', :start_time => 8600}
73
+ @now = Time.iso8601(Time.now.utc.iso8601)
25
74
  end
26
75
 
27
- it "should not create, and should add errors to model" do
28
- a = nil
29
- lambda {
30
- a = LucidWorks::Collection::Activity.create(@activity_params.merge(:parent => @collection))
31
- }.should_not change(self, :activity_count)
32
- a.should_not be_persisted
33
- a.errors[:type].should_not be_blank
76
+ describe 'and it is an exact multiple of self.periods until now' do
77
+ it 'should return now' do
78
+ # get current time after rounding error
79
+ Timecop.freeze(@now) do
80
+ @schedule.start_time = @now - 30.minutes
81
+ @schedule.period = 10.minutes
82
+ @schedule.next_start.should == @now
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'Time since self.start_time is not even multiple of self.period' do
88
+ describe 'one interval has passed' do
89
+ before do
90
+ @i = the_interval = 10.minutes
91
+ @a = a_little_more_than_an_interval_ago = @now - the_interval - 1.minutes
92
+
93
+ @schedule.period = the_interval
94
+ @schedule.start_time = a_little_more_than_an_interval_ago
95
+ end
96
+
97
+ it 'should return a time less than one interval in the future' do
98
+ one_interval_in_the_future = @now + @schedule.period
99
+ @schedule.next_start.should < one_interval_in_the_future
100
+ end
101
+
102
+ it 'should return a time one interval from the start_time' do
103
+ # TODO: this should be in terms of start time & period, not @now
104
+ @schedule.next_start.to_s.should == (@now + 9.minutes).to_s
105
+ end
106
+ end
107
+
108
+ describe 'several (e.g. 4) intervals have passed' do
109
+ before do
110
+ @schedule.start_time = @now - 45.minutes
111
+ @schedule.period = 10.minutes
112
+ end
113
+
114
+ it 'should return a time between 4 and 6 intervals from start_time' do
115
+ @schedule.next_start.should > @schedule.start_time + (4 * @schedule.period)
116
+ end
117
+
118
+ it 'should return a start time within 1 period from now' do
119
+ @schedule.next_start.should < @now + @schedule.period
120
+ end
121
+ end
34
122
  end
35
123
  end
124
+ end
36
125
 
37
- context "with valid parameters" do
38
- before do
39
- @activity_params = {:type => 'optimize', :start_time => 8600}
126
+ describe '#active, #active=' do
127
+ it 'should maintain specified value' do
128
+ @schedule.active = true
129
+ @schedule.active.should == true
130
+ @schedule.active = false
131
+ @schedule.active.should == false
132
+ # make sure the first true wasn't luck
133
+ @schedule.active = true
134
+ @schedule.active.should == true
135
+ end
136
+ end
137
+
138
+ describe '#schedule=' do
139
+ context 'active attribute supplied' do
140
+ describe 'updates the "active" attribute in the model' do
141
+ it 'should update the "active" attribute in the model' do
142
+ @schedule.active = true
143
+ attributes = {"frequency"=>"hourly", "start"=>{"minutes"=>"15"}, "active" => 'false'}
144
+ @schedule.schedule = attributes
145
+ @schedule.active.should == false
146
+
147
+ attributes = {"frequency"=>"hourly", "start"=>{"minutes"=>"15"}, "active" => 'true'}
148
+ @schedule.schedule = attributes
149
+ @schedule.active.should == true
150
+ end
40
151
  end
41
- it "should create a new activity" do
42
- a = nil
43
- lambda {
44
- a = LucidWorks::Collection::Activity.create(@activity_params.merge(:parent => @collection))
45
- }.should change(self, :activity_count).by(1)
46
- a.should be_persisted
47
- a.errors[:type].should be_blank
152
+
153
+ describe 'with active attribute not supplied' do
154
+ it 'should not change the attribute in the model' do
155
+ attributes = {"frequency"=>"hourly", "start"=>{"minutes"=>"15"}}
156
+ @schedule.active= true
157
+ @schedule.schedule = attributes
158
+ @schedule.active.should == true
159
+
160
+ @schedule.active= false
161
+ @schedule.schedule = attributes
162
+ @schedule.active.should == false
163
+ end
164
+
48
165
  end
49
166
  end
50
167
 
51
- describe ".find" do
52
- before do
53
- @activity = LucidWorks::Collection::Activity.create(
54
- :type => 'optimize',
55
- :start_time => 8600,
56
- :collection => @collection
57
- )
58
- @activity.should be_persisted
59
- end
60
-
61
- it "should return a valid activity" do
62
- a = LucidWorks::Collection::Activity.find(@activity.id, :parent => @collection)
63
- a.should be_a(LucidWorks::Collection::Activity)
64
- end
65
-
66
- %w{ type period start_time }.each do |attr|
67
- it "should have a value for #{attr}" do
68
- @activity.send(attr.to_sym).should_not be_nil
168
+ context 'supplied start time has elapsed w/rt current interval' do
169
+ describe 'with hourly frequency' do
170
+ it "should advance the start time" do
171
+ half_past_midnight = Time.iso8601("2011-05-09T00:30:00Z").in_time_zone('Eastern Time (US & Canada)')
172
+ hourly_at_quarter_past = {"frequency"=>"hourly", "start"=>{"minutes"=>"15"}}
173
+ quarter_past_1_am = Time.iso8601('2011-05-09T01:15:00Z').in_time_zone('Eastern Time (US & Canada)')
174
+
175
+ Timecop.freeze half_past_midnight do
176
+ @schedule.start_time.should_not == quarter_past_1_am
177
+
178
+ @schedule.schedule = hourly_at_quarter_past
179
+ @schedule.start_time.should == quarter_past_1_am
180
+ end
181
+ end
182
+ end
183
+
184
+ describe 'with daily frequency' do
185
+ it "should advance the start time" do
186
+ today_at_noon = Time.iso8601("2011-05-09T12:00:00Z").in_time_zone('Eastern Time (US & Canada)')
187
+ tomorrow_at_eleven_am = Time.iso8601('2011-05-10T11:00:00Z').in_time_zone('Eastern Time (US & Canada)')
188
+ daily_at_11_am = {"frequency"=>"daily", "start"=>{"hours" => "11", "minutes"=>"00"}}
189
+ Timecop.freeze today_at_noon do
190
+ @schedule.start_time.should_not == tomorrow_at_eleven_am
191
+
192
+ @schedule.schedule = daily_at_11_am
193
+ @schedule.start_time.should == tomorrow_at_eleven_am
194
+ end
195
+ end
196
+ end
197
+
198
+ describe 'with weekly frequency' do
199
+ it "should advance the start time" do
200
+ # note: Rails week starts on Monday
201
+ friday_of_this_week = Time.iso8601("2011-05-13T00:00:00Z")
202
+ wednesday_of_next_week = Time.iso8601('2011-05-18T00:00:00Z')
203
+ weekly_on_wednesday = {"frequency"=>"weekly", "start"=>{"days" => "2", "hours" => "0", "minutes"=>"00"}}
204
+
205
+ # just make sure I'm not on crack
206
+ friday_of_this_week.weekday.should == 'Friday'
207
+ wednesday_of_next_week.weekday.should == 'Wednesday'
208
+
209
+ Timecop.freeze friday_of_this_week do
210
+ @schedule.start_time.should_not == wednesday_of_next_week
211
+
212
+ @schedule.schedule = weekly_on_wednesday
213
+ @schedule.start_time.should == wednesday_of_next_week
214
+ end
69
215
  end
70
216
  end
71
217
  end
72
218
 
73
- describe "#start" do
74
- before do
75
- @activity = LucidWorks::Collection::Activity.first(:parent => @collection)
219
+ context 'supplied time has not elapsed w/rt current interval' do
220
+ describe 'with hourly frequency' do
221
+ it "should not advance the start time" do
222
+ half_past_midnight = Time.iso8601("2011-05-09T00:30:00Z")
223
+ three_quarters_past_midnight = Time.iso8601('2011-05-09T00:45:00Z')
224
+ hourly_at_three_quarters_past = {"frequency"=>"hourly", "start"=>{"minutes"=>"45"}}
225
+
226
+ Timecop.freeze half_past_midnight do
227
+ @schedule.start_time.should_not == three_quarters_past_midnight
228
+ @schedule.frequency.should_not == 'hourly'
229
+
230
+ @schedule.schedule = hourly_at_three_quarters_past
231
+ @schedule.start_time.should == three_quarters_past_midnight
232
+ @schedule.frequency.should == 'hourly'
233
+ end
234
+ end
76
235
  end
77
236
 
78
- # can't check #running? b/c w/out a big index, operation is done faster than we can check
237
+ describe 'with daily frequency' do
238
+ it "should not advance the start time" do
239
+ today_at_noon = Time.iso8601("2011-05-09T12:00:00Z")
240
+ today_at_1pm = Time.iso8601('2011-05-09T13:00:00Z')
241
+ daily_at_1pm = {"frequency"=>"daily", "start"=>{"hours" => "13", "minutes"=>"00"}}
242
+
243
+ Timecop.freeze today_at_noon do
244
+ @schedule.start_time.should_not == today_at_1pm
245
+ @schedule.frequency.should_not == 'daily'
79
246
 
80
- it "should create a new history" do
81
- lambda {
82
- @collection.activities!.first.start
83
- }.should change(@activity, :history_size).by(1)
247
+ @schedule.schedule = daily_at_1pm
248
+ @schedule.start_time.should == today_at_1pm
249
+ @schedule.frequency.should == 'daily'
250
+ end
251
+ end
252
+ end
253
+
254
+ describe 'with weekly frequency' do
255
+ it "should not advance the start time" do
256
+ # note: Rails week starts on Monday
257
+ wednesday_of_this_week = Time.iso8601("2011-05-11T00:00:00Z")
258
+ thursday_of_this_week = Time.iso8601('2011-05-12T00:00:00Z')
259
+ weekly_on_thursday = {"frequency"=>"weekly", "start"=>{"days" => "3", "hours" => "0", "minutes"=>"00"}}
260
+
261
+ # just make sure I'm not on crack
262
+ wednesday_of_this_week.weekday.should == 'Wednesday'
263
+ thursday_of_this_week.weekday.should == 'Thursday'
264
+
265
+ Timecop.freeze wednesday_of_this_week do
266
+ @schedule.start_time.should_not == thursday_of_this_week
267
+ @schedule.frequency.should_not == 'weekly'
268
+
269
+ @schedule.schedule = weekly_on_thursday
270
+ @schedule.start_time.should == thursday_of_this_week
271
+ @schedule.frequency.should == 'weekly'
272
+ end
273
+ end
84
274
  end
85
275
  end
276
+ end
86
277
 
87
- describe "#human_readable_period" do
88
- it "should return hours if divisible by 1.hours but not by 1.days or 1.weeks" do
89
- activity = LucidWorks::Collection::Activity.new(:period => 3600*2, :parent => @collection)
90
- activity.human_readable_period.should == [2, 'hours']
278
+ context 'sub-time convenience accessors' do
279
+ describe '#hour' do
280
+ it 'should return the hour component of the time' do
281
+ @schedule.start_time = Time.new(2011, 4, 15, 13, 11, 56)
282
+ @schedule.hour.should == 13
91
283
  end
92
- it "should return nearest hours if not divisible by 1.hours"do
93
- activity = LucidWorks::Collection::Activity.new(:period => 3600*2.4, :parent => @collection)
94
- activity.human_readable_period.should == [2, 'hours']
95
- activity = LucidWorks::Collection::Activity.new(:period => 3600*4.6, :parent => @collection)
96
- activity.human_readable_period.should == [5, 'hours']
97
- activity = LucidWorks::Collection::Activity.new(:period => 3600*10.01, :parent => @collection)
98
- activity.human_readable_period.should == [10, 'hours']
284
+
285
+ it 'should return nil if start_time == nil' do
286
+ @schedule.start_time = nil
287
+ @schedule.hour.should == nil
99
288
  end
100
- it "should return 1 hours if < 1.hours"do
101
- activity = LucidWorks::Collection::Activity.new(:period => 3599, :parent => @collection)
102
- activity.human_readable_period.should == [1, 'hours']
289
+ end
290
+
291
+ describe '#min' do
292
+ it 'should return the minute component of the time' do
293
+ @schedule.start_time = Time.new(2011, 4, 15, 13, 11, 56)
294
+ @schedule.min.should == 11
103
295
  end
104
- it "should return days if divisible by 1.days but not 1.weeks" do
105
- activity = LucidWorks::Collection::Activity.new(:period => 3600*48, :parent => @collection)
106
- activity.human_readable_period.should == [2, 'days']
296
+
297
+ it 'should return nil if start_time == nil' do
298
+ @schedule.start_time = nil
299
+ @schedule.min.should == nil
107
300
  end
108
- it "should return weeks if divisible by 1.weeks" do
109
- activity = LucidWorks::Collection::Activity.new(:period => 3600*24*7, :parent => @collection)
110
- activity.human_readable_period.should == [1, 'weeks']
301
+ end
302
+
303
+ describe '#day_of_week' do
304
+ it 'should return the week component of the time' do
305
+ @schedule.start_time = Time.new(2011, 4, 15, 13, 11, 56)
306
+ @schedule.day_of_week.should == 4
307
+ end
308
+
309
+ it 'should return nil if start_time == nil' do
310
+ @schedule.start_time = nil
311
+ @schedule.day_of_week.should == nil
111
312
  end
112
313
  end
314
+ end
113
315
 
114
- describe "#human_readable_period=" do
115
- it "should set correct period if given a number and hours/days/weeks" do
116
- activity = LucidWorks::Collection::Activity.new(:parent => @collection)
117
- activity.human_readable_period = [2, 'hours']
118
- activity.period.should == 3600*2
119
- activity.human_readable_period = [2, 'days']
120
- activity.period.should == 3600*2*24
316
+ describe '#custom?' do
317
+ context 'schedule can not be represent as simple weekly/daily/hourly' do
318
+ it 'should be true if frequency is non-standard' do
319
+ @schedule.period = 1
320
+ @schedule.should be_custom
121
321
  end
322
+
323
+ it 'should be true if period is standard but start_time is > 1 period from now' do
324
+ some_random_time = Time.new(2011, 4, 15, 13, 11, 56)
325
+ more_than_a_day_later = some_random_time.advance(:days => 2)
326
+
327
+ Timecop.freeze some_random_time do
328
+ @schedule.frequency = 'daily'
329
+ @schedule.start_time = more_than_a_day_later
330
+
331
+ @schedule.should be_custom
332
+ end
333
+ end
334
+ end
335
+
336
+ context 'schedule can be represent as simple weekly/daily/hourly' do
337
+ it 'should be false if period is standard and start_time is within period from now' do
338
+ half_past_midnight = Time.iso8601("2011-05-09T00:30:00Z")
339
+ a_standard_schedule = {"frequency"=>"hourly", "start"=>{"minutes"=>"15"}}
340
+ some_random_specific_time = Time.iso8601('2011-05-09T01:15:00Z')
341
+
342
+ Timecop.freeze some_random_specific_time do
343
+ @schedule.schedule = a_standard_schedule
344
+
345
+ @schedule.should_not be_custom
346
+ end
347
+ end
348
+
349
+ it 'should be false if period is standard and start time is > 1 period in the past' do
350
+ some_random_time = Time.new(2011, 4, 15, 13, 11, 56)
351
+ more_than_a_day_ago = some_random_time.advance(:days => -2)
352
+ Timecop.freeze some_random_time do
353
+ @schedule.frequency = 'daily'
354
+ @schedule.start_time = more_than_a_day_ago
355
+
356
+ @schedule.should_not be_custom
357
+ end
358
+ end
359
+
360
+ end
361
+
362
+ it 'should be false if the start_time is nil and frequency is standard' do
363
+ @schedule.start_time = nil
364
+ @schedule.frequency = 'weekly'
365
+ @schedule.should_not be_custom
366
+ end
367
+ end
368
+
369
+ describe '#ui_appropriate_defaults!' do
370
+ it "should set active to true if start_time is defaulted" do
371
+ @schedule.start_time = nil
372
+ @schedule.period = 1.hours.seconds
373
+ @schedule.active = false
374
+
375
+ @schedule.ui_appropriate_defaults!
376
+
377
+ @schedule.active.should == true
378
+ end
379
+
380
+ it "should set active to true if period is defaulted" do
381
+ @schedule.start_time = Time.now
382
+ @schedule.period = 0
383
+ @schedule.active = false
384
+
385
+ @schedule.ui_appropriate_defaults!
386
+
387
+ @schedule.active.should == true
122
388
  end
123
389
  end
124
390
  end
125
- end
391
+
392
+ # context "Custom Activity schedule functionality" do
393
+ # before :all do
394
+ # @server = connect_to_live_server
395
+ # @server.reset_collections!
396
+ # @collection = @server.collections!.first
397
+ # end
398
+ #
399
+ # def activity_count
400
+ # @collection.activities!.size
401
+ # end
402
+ #
403
+ # class LucidWorks::Collection::Activity
404
+ # def history_size
405
+ # self.histories!.size
406
+ # end
407
+ # end
408
+ #
409
+ # describe "CRUD" do
410
+ # describe ".create"do
411
+ # context "with invalid parameters" do
412
+ # before do
413
+ # @activity_params = {:type => 'bogus', :start_time => 8600}
414
+ # end
415
+ #
416
+ # it "should not create, and should add errors to model" do
417
+ # a = nil
418
+ # lambda {
419
+ # a = LucidWorks::Collection::Activity.create(@activity_params.merge(:parent => @collection))
420
+ # }.should_not change(self, :activity_count)
421
+ # a.should_not be_persisted
422
+ # a.errors[:type].should_not be_blank
423
+ # end
424
+ # end
425
+ #
426
+ # context "with valid parameters" do
427
+ # before do
428
+ # @activity_params = {:type => 'optimize', :start_time => 8600}
429
+ # end
430
+ # it "should create a new activity" do
431
+ # a = nil
432
+ # lambda {
433
+ # a = LucidWorks::Collection::Activity.create(@activity_params.merge(:parent => @collection))
434
+ # }.should change(self, :activity_count).by(1)
435
+ # a.should be_persisted
436
+ # a.errors[:type].should be_blank
437
+ # end
438
+ # end
439
+ #
440
+ # describe ".find" do
441
+ # before do
442
+ # @activity = LucidWorks::Collection::Activity.create(
443
+ # :type => 'optimize',
444
+ # :start_time => 8600,
445
+ # :collection => @collection
446
+ # )
447
+ # @activity.should be_persisted
448
+ # end
449
+ #
450
+ # it "should return a valid activity" do
451
+ # a = LucidWorks::Collection::Activity.find(@activity.id, :parent => @collection)
452
+ # a.should be_a(LucidWorks::Collection::Activity)
453
+ # end
454
+ #
455
+ # %w{ type period start_time }.each do |attr|
456
+ # it "should have a value for #{attr}" do
457
+ # @activity.send(attr.to_sym).should_not be_nil
458
+ # end
459
+ # end
460
+ # end
461
+ #
462
+ # describe "#start" do
463
+ # before do
464
+ # @activity = LucidWorks::Collection::Activity.first(:parent => @collection)
465
+ # end
466
+ #
467
+ # # can't check #running? b/c w/out a big index, operation is done faster than we can check
468
+ #
469
+ # it "should create a new history" do
470
+ # lambda {
471
+ # @collection.activities!.first.start
472
+ # }.should change(@activity, :history_size).by(1)
473
+ # end
474
+ # end
475
+ #
476
+ # describe "#human_readable_period" do
477
+ # it "should return hours if divisible by 1.hours but not by 1.days or 1.weeks" do
478
+ # activity = LucidWorks::Collection::Activity.new(:period => 3600*2, :parent => @collection)
479
+ # activity.human_readable_period.should == [2, 'hours']
480
+ # end
481
+ # it "should return nearest hours if not divisible by 1.hours"do
482
+ # activity = LucidWorks::Collection::Activity.new(:period => 3600*2.4, :parent => @collection)
483
+ # activity.human_readable_period.should == [2, 'hours']
484
+ # activity = LucidWorks::Collection::Activity.new(:period => 3600*4.6, :parent => @collection)
485
+ # activity.human_readable_period.should == [5, 'hours']
486
+ # activity = LucidWorks::Collection::Activity.new(:period => 3600*10.01, :parent => @collection)
487
+ # activity.human_readable_period.should == [10, 'hours']
488
+ # end
489
+ # it "should return 1 hours if < 1.hours"do
490
+ # activity = LucidWorks::Collection::Activity.new(:period => 3599, :parent => @collection)
491
+ # activity.human_readable_period.should == [1, 'hours']
492
+ # end
493
+ # it "should return days if divisible by 1.days but not 1.weeks" do
494
+ # activity = LucidWorks::Collection::Activity.new(:period => 3600*48, :parent => @collection)
495
+ # activity.human_readable_period.should == [2, 'days']
496
+ # end
497
+ # it "should return weeks if divisible by 1.weeks" do
498
+ # activity = LucidWorks::Collection::Activity.new(:period => 3600*24*7, :parent => @collection)
499
+ # activity.human_readable_period.should == [1, 'weeks']
500
+ # end
501
+ # end
502
+ #
503
+ # describe "#human_readable_period=" do
504
+ # it "should set correct period if given a number and hours/days/weeks" do
505
+ # activity = LucidWorks::Collection::Activity.new(:parent => @collection)
506
+ # activity.human_readable_period = [2, 'hours']
507
+ # activity.period.should == 3600*2
508
+ # activity.human_readable_period = [2, 'days']
509
+ # activity.period.should == 3600*2*24
510
+ # end
511
+ # end
512
+ # end
513
+ # end
514
+ # end
515
+ end
@@ -117,6 +117,64 @@ describe LucidWorks::Collection do
117
117
  end
118
118
  end
119
119
  end
120
+
121
+ describe "#prime_activities" do
122
+ before do
123
+ @collection = @server.collection('collection1')
124
+ # require 'ruby-debug'; debugger
125
+ # activity = LucidWorks::Collection::Activity.create(
126
+ # :type => 'optimize',
127
+ # :start_time => 8600,
128
+ # :collection => @collection
129
+ # )
130
+ # activity.should be_persisted
131
+ end
132
+
133
+ it "should not create activities that already exist" do
134
+ activity_params = {:type => 'optimize', :start_time => 8600}
135
+ c = LucidWorks::Collection.create(:name => "a_collection_for_prime_activities_non_redundancy",
136
+ :instance_dir => @instance_dir,
137
+ :template => @template,
138
+ :parent => @server)
139
+
140
+ LucidWorks::Collection::Activity.create(activity_params.merge(:parent => c))
141
+ c.activities.size.should == 1
142
+ c.prime_activities
143
+ c.activities.size.should == 4
144
+ end
145
+
146
+ context "with a new collection with no activities" do
147
+ before :all do
148
+ @collection2 = LucidWorks::Collection.create(:name => "a_collection_for_prime_activities",
149
+ :instance_dir => @instance_dir,
150
+ :template => @template,
151
+ :parent => @server)
152
+
153
+ @collection2.activities.size.should == 0
154
+ @collection2.prime_activities
155
+ @collection2.activities.size.should == 4
156
+ end
157
+
158
+ it "should ensure at least one of each activity" do
159
+ %w(optimize spelling click autocomplete).each do |type|
160
+ @collection2.activities.find_all{|a| a.type == type}.size.should == 1
161
+ end
162
+ end
163
+
164
+ it "should give start_times divisible by 5 minutes for created activities" do
165
+ @collection2.activities!.each do |activity|
166
+ (activity.start_time.min % 5).should == 0
167
+ end
168
+ end
169
+
170
+ it "should schedule reasonable repeat intervals for each activity" do
171
+ @collection2.activities!.each do |activity|
172
+ (activity.period % 1.hours).should == 0
173
+ (activity.period / 1.hours).should > 0
174
+ end
175
+ end
176
+ end
177
+ end
120
178
 
121
179
  describe "#synonyms" do
122
180
  before do
@@ -44,7 +44,7 @@ describe LucidWorks::Datasource::Schedule do
44
44
  @schedule.frequency.should == 'custom'
45
45
  end
46
46
 
47
- it "should return nil" do
47
+ it "should return nil when the period is zero" do
48
48
  @schedule.period = 0
49
49
  @schedule.frequency.should == nil
50
50
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: lucid_works
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.6.14
5
+ version: 0.6.15
6
6
  platform: ruby
7
7
  authors:
8
8
  - Sam Pierson
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-06-03 00:00:00 +01:00
13
+ date: 2011-06-08 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency