lucid_works 0.6.14 → 0.6.15

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