win32-taskscheduler 1.0.2 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/spec/spec_helper.rb CHANGED
@@ -1 +1,224 @@
1
- $LOAD_PATH.unshift File.expand_path('../lib/win32', __dir__)
1
+ libx = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(libx) unless $LOAD_PATH.include?(libx)
3
+
4
+ require 'date'
5
+
6
+ # In order to test some dummy task and folder, we are creating
7
+ # 'Test' folder and consider it as 'root'.
8
+ # After the test case, all the above created elements
9
+ # i.e, 'Test', Tasks and nested folders will be deleted.
10
+ # It will ensure No Harm be caused to any existing tasks at root
11
+
12
+ # Creating folder 'Test'; This will be treated as root
13
+ def create_test_folder
14
+ @service ||= service
15
+ @root_path = '\\'
16
+ @test_path = '\\Test'
17
+ @root_folder = @service.GetFolder(@root_path)
18
+ @test_folder = @root_folder.CreateFolder(@test_path)
19
+ @ts.instance_variable_set(:@root, @test_folder) if @ts
20
+ end
21
+
22
+ # Deleting the test folder its nested folder(if any)
23
+ # And the tasks within(if any)
24
+ def clear_them
25
+ if @test_folder
26
+ delete_all(@test_folder)
27
+ else
28
+ @test_folder = nil
29
+ end
30
+ end
31
+
32
+ # Logic to delete tasks and folder using Win32OLE methods
33
+ def delete_all(folder)
34
+ delete_tasks_in(folder)
35
+ folder.GetFolders(0).each do |nested_folder|
36
+ delete_all(nested_folder)
37
+ end
38
+ @root_folder.DeleteFolder(folder.Path, 0)
39
+ end
40
+
41
+ # Deleting the task in specified folder using Win32OLE methods
42
+ def delete_tasks_in(folder)
43
+ folder.GetTasks(0).each do |task|
44
+ folder.DeleteTask(task.Name, 0)
45
+ end
46
+ end
47
+
48
+ # Returns Win32 Service object
49
+ def service
50
+ service = WIN32OLE.new('Schedule.Service')
51
+ service.Connect
52
+ service
53
+ end
54
+
55
+ # Returns no of task in the specified folder
56
+ def no_of_tasks(folder = @test_folder)
57
+ if folder.is_a?(String)
58
+ folder = @test_path + folder
59
+ folder = @service.GetFolder(folder)
60
+ end
61
+ folder.GetTasks(0).Count
62
+ end
63
+
64
+ # Steps to create (Register) a task
65
+ # This is an example activity to test
66
+ # the related functionalities over a task in RSpecs
67
+ def create_task
68
+ return nil unless @service
69
+ @task_definition = @service.NewTask(0)
70
+ task_registration
71
+ task_prinicipals
72
+ task_settings
73
+ task_triggers
74
+ task_action
75
+ register_task
76
+ end
77
+
78
+ def task_registration
79
+ reg_info = @task_definition.RegistrationInfo
80
+ reg_info.Description = 'Sample task for testing purpose'
81
+ reg_info.Author = 'Rspec'
82
+ end
83
+
84
+ def task_prinicipals
85
+ principal = @task_definition.Principal
86
+ principal.LogonType = 3 # Interactive Logon
87
+ end
88
+
89
+ def task_settings
90
+ settings = @task_definition.Settings
91
+ settings.Enabled = true
92
+ settings.StartWhenAvailable = true
93
+ settings.Hidden = false
94
+ end
95
+
96
+ def task_triggers
97
+ triggers = @task_definition.Triggers
98
+ trigger = triggers.Create(1) # Time
99
+ start_time, end_time = start_end_time
100
+ trigger.StartBoundary = start_time
101
+ trigger.EndBoundary = end_time
102
+ trigger.ExecutionTimeLimit = 'PT5M' # Five minutes
103
+ trigger.Id = 'TimeTriggerId'
104
+ trigger.Enabled = true
105
+ end
106
+
107
+ def task_action
108
+ action = @task_definition.Actions.Create(0)
109
+ action.Path = @app
110
+ end
111
+
112
+ # Registering(Creating) a task in test folder
113
+ def register_task
114
+ @current_task = @test_folder.RegisterTaskDefinition(
115
+ @task, # Name of the task
116
+ @task_definition, # Definition
117
+ 6, # Flag: TASK_CREATE_OR_UPDATE
118
+ nil, # UserId
119
+ nil, # Password
120
+ 3
121
+ )
122
+ @ts.instance_variable_set(:@task, @current_task) if @ts
123
+ end
124
+
125
+ def start_end_time
126
+ t = Date.new(2010)
127
+ start_time = t.strftime('%FT%T')
128
+ end_time = (t + 5).strftime('%FT%T') # 5 Days
129
+ [start_time, end_time]
130
+ end
131
+
132
+ def tasksch_err
133
+ Win32::TaskScheduler::Error
134
+ end
135
+
136
+ # Methods to build all types of triggers and their values
137
+
138
+ def all_triggers
139
+ all_triggers = {}
140
+
141
+ %w[ONCE DAILY WEEKLY MONTHLYDATE MONTHLYDOW
142
+ ON_IDLE AT_SYSTEMSTART AT_LOGON].each do |trig_type|
143
+ trigger = {}
144
+ trigger[:trigger_type] = Win32::TaskScheduler.class_eval(trig_type)
145
+ start_end_params(trigger)
146
+ other_trigger_params(trig_type, trigger)
147
+ all_triggers[trig_type] = trigger
148
+ end
149
+
150
+ all_triggers
151
+ end
152
+
153
+ def start_end_params(trigger)
154
+ %i[start_year end_year].each do |t|
155
+ trigger[t] = '2030'
156
+ end
157
+
158
+ %i[start_month start_day start_hour start_minute].each do |t|
159
+ trigger[t] = '02'
160
+ end
161
+
162
+ %i[end_day end_month].each do |t|
163
+ trigger[t] = '03'
164
+ end
165
+
166
+ %i[minutes_duration minutes_interval].each do |t|
167
+ trigger[t] = 2
168
+ end
169
+ end
170
+
171
+ def other_trigger_params(trig_type, trigger)
172
+ type = {}
173
+ case trig_type
174
+ when 'ONCE'
175
+ trigger[:type] = type
176
+ type[:once] = nil
177
+ trigger[:random_minutes_interval] = 2
178
+ when 'DAILY'
179
+ trigger[:type] = type
180
+ type[:days_interval] = 2
181
+ trigger[:random_minutes_interval] = 2
182
+ when 'WEEKLY'
183
+ trigger[:type] = type
184
+ type[:weeks_interval] = 2
185
+ type[:days_of_week] = sunday
186
+ trigger[:random_minutes_interval] = 2
187
+ when 'MONTHLYDATE'
188
+ trigger[:type] = type
189
+ type[:months] = january
190
+ type[:days] = first_day
191
+ trigger[:run_on_last_day_of_month] = false
192
+ trigger[:random_minutes_interval] = 2
193
+ when 'MONTHLYDOW'
194
+ trigger[:type] = type
195
+ type[:months] = january
196
+ type[:days_of_week] = sunday
197
+ type[:weeks_of_month] = first_week
198
+ trigger[:run_on_last_week_of_month] = false
199
+ trigger[:random_minutes_interval] = 2
200
+ when 'ON_IDLE'
201
+ trigger[:execution_time_limit] = 2
202
+ when 'AT_SYSTEMSTART'
203
+ trigger[:delay_duration] = 2
204
+ when 'AT_LOGON'
205
+ trigger[:user_id] = 'SYSTEM'
206
+ trigger[:delay_duration] = 2
207
+ end
208
+ end
209
+
210
+ def sunday
211
+ Win32::TaskScheduler::SUNDAY
212
+ end
213
+
214
+ def january
215
+ Win32::TaskScheduler::JANUARY
216
+ end
217
+
218
+ def first_day
219
+ Win32::TaskScheduler::FIRST
220
+ end
221
+
222
+ def first_week
223
+ Win32::TaskScheduler::FIRST_WEEK
224
+ end
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+ require 'win32ole'
3
+ require 'win32/taskscheduler'
4
+
5
+ RSpec.describe Win32::TaskScheduler, :windows_only do
6
+ before { create_test_folder }
7
+ after { clear_them }
8
+ before { load_task_variables }
9
+
10
+ describe '#Constructor' do
11
+ let(:ts) { Win32::TaskScheduler }
12
+ context 'no of arguments' do
13
+ it 'zero' do
14
+ expect(ts.new).to be_a(ts)
15
+ expect(no_of_tasks).to eq(0)
16
+ end
17
+
18
+ it 'one: task' do
19
+ expect(ts.new(@task)).to be_a(ts)
20
+ expect(no_of_tasks).to eq(0)
21
+ end
22
+
23
+ it 'two: task, trigger; trigger_type is blank' do
24
+ @trigger[:trigger_type] = nil
25
+ expect { ts.new(@task, @trigger) }.to raise_error(ArgumentError)
26
+ expect(no_of_tasks).to eq(0)
27
+ end
28
+
29
+ it 'two: task, trigger; trigger_type is not blank; Creates a task' do
30
+ expect(ts.new(@task, @trigger)).to be_a(ts)
31
+ expect(no_of_tasks).to eq(1)
32
+ end
33
+
34
+ it 'three: task, trigger, folder; Creates a task' do
35
+ expect(ts.new(@task, @trigger, @folder)).to be_a(ts)
36
+ expect(no_of_tasks).to eq(1)
37
+ end
38
+
39
+ it 'four: task, trigger, folder, force; Creates a task' do
40
+ expect(ts.new(@task, @trigger, @folder, @force)).to be_a(ts)
41
+ expect(no_of_tasks).to eq(1)
42
+ end
43
+
44
+ it 'raises an error for more than four arguments' do
45
+ expect { ts.new(@task, @trigger, @folder, @force, 1) }.to raise_error(ArgumentError)
46
+ expect { ts.new(@task, @trigger, @folder, @force, 'abc') }.to raise_error(ArgumentError)
47
+ expect(no_of_tasks).to eq(0)
48
+ end
49
+ end
50
+ end
51
+
52
+ describe '#Tasks' do
53
+ before { create_task }
54
+ it 'Returns an Array' do
55
+ expect(@ts.tasks).to be_a(Array)
56
+ end
57
+
58
+ it 'Returns an Empty Array if no task is present' do
59
+ delete_tasks_in(@test_folder)
60
+ expect(@ts.tasks).to be_empty
61
+ end
62
+ end
63
+
64
+ describe '#exists?' do
65
+ let(:folder) { '\\Foo' }
66
+ let(:force) { true }
67
+ before { create_task }
68
+
69
+ context 'At Root' do
70
+ it 'Requires only task name' do
71
+ expect(@ts.exists?(@task)).to be_truthy
72
+ end
73
+
74
+ it 'Does not require root to be appended' do
75
+ task = @folder + '\\' + @task
76
+ expect(@ts.exists?(task)).to be_falsey
77
+ end
78
+ end
79
+
80
+ context 'At Nested folder' do
81
+ it 'Returns false for non existing folder' do
82
+ task = folder + '\\' + @task
83
+ expect(@ts.exists?(task)).to be_falsey
84
+ end
85
+
86
+ it 'Returns true for existing folder' do
87
+ @ts = Win32::TaskScheduler.new(@task, @trigger, folder, force)
88
+ task = folder + '\\' + @task
89
+ expect(@ts.exists?(task)).to be_truthy
90
+ end
91
+ end
92
+ end
93
+
94
+ describe '#get_task' do
95
+ before { create_task }
96
+ it 'Requires a string: Task Name' do
97
+ expect { @ts.get_task(0) }.to raise_error(TypeError)
98
+ end
99
+ end
100
+
101
+ describe '#activate' do
102
+ before { create_task }
103
+ it 'Requires a string: Task Name' do
104
+ expect { @ts.activate(0) }.to raise_error(TypeError)
105
+ end
106
+ end
107
+
108
+ describe '#delete' do
109
+ before { create_task }
110
+ it 'Requires a string: Task Name' do
111
+ expect { @ts.delete(0) }.to raise_error(TypeError)
112
+ end
113
+ end
114
+
115
+ private
116
+
117
+ def load_task_variables
118
+ time = Time.now
119
+ # Ensuring root path will be test path
120
+ allow_any_instance_of(Win32::TaskScheduler).to receive(:root_path).and_return(@test_path)
121
+ @app = 'notepad.exe'
122
+ @task = 'test_task'
123
+ @folder = @test_path
124
+ @force = false
125
+ @trigger = { start_year: time.year, start_month: time.month,
126
+ start_day: time.day, start_hour: time.hour,
127
+ start_minute: time.min,
128
+ # Will update this in test cases when required
129
+ trigger_type: Win32::TaskScheduler::ONCE }
130
+ @ts = Win32::TaskScheduler.new
131
+ end
132
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'win32/taskscheduler'
3
+ require 'win32/windows/constants'
4
+
5
+ RSpec.describe Win32::TaskScheduler, :windows_only do
6
+ describe 'Ensuring trigger constants' do
7
+ subject(:ts) { Win32::TaskScheduler }
8
+ describe 'to handle scheduled tasks' do
9
+ [:ONCE, :DAILY, :WEEKLY, :MONTHLYDATE, :MONTHLYDOW].each do |const|
10
+ it { should be_const_defined(const) }
11
+ end
12
+ end
13
+
14
+ describe 'to handle other types' do
15
+ [:AT_LOGON, :AT_SYSTEMSTART, :ON_IDLE].each do |const|
16
+ it { should be_const_defined(const) }
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,217 @@
1
+ require 'spec_helper'
2
+ require 'win32/windows/time_calc_helper'
3
+
4
+ RSpec.describe Windows::TimeCalcHelper do
5
+ let(:object) { klass.new }
6
+ let(:klass) do
7
+ Class.new do
8
+ include Windows::TimeCalcHelper
9
+ end
10
+ end
11
+
12
+ describe '#is_leap_year?' do
13
+ it 'require an year in integer format' do
14
+ expect { object.is_leap_year? }.to raise_error(ArgumentError)
15
+ expect { object.is_leap_year?('year') }.to raise_error(NoMethodError)
16
+ end
17
+
18
+ it 'returns true for leap years' do
19
+ year = 2000
20
+ expect(object.is_leap_year?(year)).to be_truthy
21
+ year = 2004
22
+ expect(object.is_leap_year?(year)).to be_truthy
23
+ end
24
+
25
+ it 'returns false for non-leap years' do
26
+ year = 1900
27
+ expect(object.is_leap_year?(year)).to be_falsy
28
+ year = 2001
29
+ expect(object.is_leap_year?(year)).to be_falsy
30
+ end
31
+ end
32
+
33
+ describe '#days_in_month' do
34
+ it 'require month and year in integer format' do
35
+ expect { object.days_in_month }.to raise_error(ArgumentError)
36
+ expect { object.days_in_month('month', 'year') }.to raise_error(TypeError)
37
+ end
38
+
39
+ context 'leap year' do
40
+ year = 2000
41
+ it 'January will have 31 days' do
42
+ month = 1
43
+ expect(object.days_in_month(month, year)).to eql(31)
44
+ end
45
+
46
+ it 'February will have 29 days' do
47
+ month = 2
48
+ expect(object.days_in_month(month, year)).to eql(29)
49
+ end
50
+
51
+ it 'November will have 30 days' do
52
+ month = 11
53
+ expect(object.days_in_month(month, year)).to eql(30)
54
+ end
55
+ end
56
+
57
+ context 'non-leap year' do
58
+ year = 2003
59
+ it 'January will have 31 days' do
60
+ month = 1
61
+ expect(object.days_in_month(month, year)).to eql(31)
62
+ end
63
+
64
+ it 'February will have 28 days' do
65
+ month = 2
66
+ expect(object.days_in_month(month, year)).to eql(28)
67
+ end
68
+
69
+ it 'November will have 30 days' do
70
+ month = 11
71
+ expect(object.days_in_month(month, year)).to eql(30)
72
+ end
73
+ end
74
+ end
75
+
76
+ describe '#time_details' do
77
+ it 'require a time string in String format' do
78
+ expect { object.time_details }.to raise_error(ArgumentError)
79
+ expect { object.time_details(1234) }.to raise_error(TypeError)
80
+ end
81
+
82
+ it 'returns an empty hash if no string is passed' do
83
+ expect(object.time_details(nil)).to be_a(Hash)
84
+ expect(object.time_details(nil)).to be_empty
85
+ end
86
+
87
+ context 'of MSDN time string' do
88
+ it 'returns hash with date' do
89
+ time_str = 'P10Y10M10D'
90
+ time_hsh = { year: '10', month: '10', day: '10' }
91
+ expect(object.time_details(time_str)).to eq(time_hsh)
92
+ end
93
+
94
+ it 'returns hash with time' do
95
+ time_str = 'PT10H10M10S'
96
+ time_hsh = { hour: '10', min: '10', sec: '10' }
97
+ expect(object.time_details(time_str)).to eq(time_hsh)
98
+ end
99
+
100
+ it 'returns hash with date-time' do
101
+ time_str = 'P10Y10M10DT10H10M10S'
102
+ time_hsh = { year: '10', month: '10', day: '10',
103
+ hour: '10', min: '10', sec: '10' }
104
+ expect(object.time_details(time_str)).to eq(time_hsh)
105
+ end
106
+ end
107
+ end
108
+
109
+ describe '#time_in_seconds' do
110
+ it 'require a time string in String format' do
111
+ expect { object.time_in_seconds }.to raise_error(ArgumentError)
112
+ expect { object.time_in_seconds(1234) }.to raise_error(TypeError)
113
+ end
114
+
115
+ it 'returns zero if no string is passed' do
116
+ expect(object.time_in_seconds(nil)).to be_zero
117
+ end
118
+
119
+ context 'in leap year' do
120
+ before do
121
+ time_now = Time.new(2004)
122
+ allow(Time).to receive(:now).and_return(time_now)
123
+ end
124
+
125
+ it 'returns seconds for date' do
126
+ time_str = 'P10Y10M10D'
127
+ expect(object.time_in_seconds(time_str)).to eq(342_748_800)
128
+ end
129
+
130
+ it 'returns seconds for time' do
131
+ time_str = 'PT10H10M10S'
132
+ expect(object.time_in_seconds(time_str)).to eq(36_610)
133
+ end
134
+
135
+ it 'returns seconds for date-time' do
136
+ time_str = 'P10Y10M10DT10H10M10S'
137
+ expect(object.time_in_seconds(time_str)).to eq(342_785_410)
138
+ end
139
+ end
140
+ context 'in non-leap year' do
141
+ before do
142
+ time_now = Time.new(2003)
143
+ allow(Time).to receive(:now).and_return(time_now)
144
+ end
145
+
146
+ it 'returns seconds for date' do
147
+ time_str = 'P10Y10M10D'
148
+ expect(object.time_in_seconds(time_str)).to eq(342_748_800)
149
+ end
150
+
151
+ it 'returns seconds for time' do
152
+ time_str = 'PT10H10M10S'
153
+ expect(object.time_in_seconds(time_str)).to eq(36_610)
154
+ end
155
+
156
+ it 'returns seconds for date-time' do
157
+ time_str = 'P10Y10M10DT10H10M10S'
158
+ expect(object.time_in_seconds(time_str)).to eq(342_785_410)
159
+ end
160
+ end
161
+ end
162
+
163
+ describe '#time_in_minutes' do
164
+ it 'require a time string in String format' do
165
+ expect { object.time_in_minutes }.to raise_error(ArgumentError)
166
+ expect { object.time_in_minutes(1234) }.to raise_error(TypeError)
167
+ end
168
+
169
+ it 'returns zero if no string is passed' do
170
+ expect(object.time_in_minutes(nil)).to be_zero
171
+ end
172
+
173
+ context 'in leap year' do
174
+ before do
175
+ time_now = Time.new(2004)
176
+ allow(Time).to receive(:now).and_return(time_now)
177
+ end
178
+
179
+ it 'returns minutes for date' do
180
+ time_str = 'P10Y10M10D'
181
+ expect(object.time_in_minutes(time_str)).to eq(5_712_480)
182
+ end
183
+
184
+ it 'returns minutes for time' do
185
+ time_str = 'PT10H10M10S'
186
+ expect(object.time_in_minutes(time_str)).to eq(610)
187
+ end
188
+
189
+ it 'returns minutes for date-time' do
190
+ time_str = 'P10Y10M10DT10H10M10S'
191
+ expect(object.time_in_minutes(time_str)).to eq(5_713_090)
192
+ end
193
+ end
194
+
195
+ context 'in non-leap year' do
196
+ before do
197
+ time_now = Time.new(2003)
198
+ allow(Time).to receive(:now).and_return(time_now)
199
+ end
200
+
201
+ it 'returns minutes for date' do
202
+ time_str = 'P10Y10M10D'
203
+ expect(object.time_in_minutes(time_str)).to eq(5_712_480)
204
+ end
205
+
206
+ it 'returns minutes for time' do
207
+ time_str = 'PT10H10M10S'
208
+ expect(object.time_in_minutes(time_str)).to eq(610)
209
+ end
210
+
211
+ it 'returns minutes for date-time' do
212
+ time_str = 'P10Y10M10DT10H10M10S'
213
+ expect(object.time_in_minutes(time_str)).to eq(5_713_090)
214
+ end
215
+ end
216
+ end
217
+ end