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.
- data/lib/lucid_works/collection/activity.rb +151 -2
- data/lib/lucid_works/collection.rb +2 -1
- data/lib/lucid_works/version.rb +1 -1
- data/spec/lib/lucid_works/collection/activity_spec.rb +476 -86
- data/spec/lib/lucid_works/collection_spec.rb +58 -0
- data/spec/lib/lucid_works/datasource/schedule_spec.rb +1 -1
- metadata +2 -2
@@ -1,15 +1,19 @@
|
|
1
1
|
require 'active_support/core_ext/numeric/time.rb'
|
2
2
|
module LucidWorks
|
3
|
-
class Collection
|
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
|
-
|
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
|
-
|
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
|
data/lib/lucid_works/version.rb
CHANGED
@@ -1,125 +1,515 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
11
|
-
|
10
|
+
class Time
|
11
|
+
def weekday
|
12
|
+
self.strftime('%A')
|
13
|
+
end
|
12
14
|
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
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
|
-
@
|
73
|
+
@now = Time.iso8601(Time.now.utc.iso8601)
|
25
74
|
end
|
26
75
|
|
27
|
-
it
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
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
|
-
|
109
|
-
|
110
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
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
|
-
|
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
|
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.
|
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-
|
13
|
+
date: 2011-06-08 00:00:00 -04:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|