osc-machete 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/CHANGELOG.md +87 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +194 -0
- data/Rakefile +23 -0
- data/lib/osc/machete.rb +18 -0
- data/lib/osc/machete/job.rb +239 -0
- data/lib/osc/machete/job_dir.rb +56 -0
- data/lib/osc/machete/location.rb +91 -0
- data/lib/osc/machete/process.rb +32 -0
- data/lib/osc/machete/status.rb +190 -0
- data/lib/osc/machete/torque_helper.rb +190 -0
- data/lib/osc/machete/user.rb +72 -0
- data/lib/osc/machete/version.rb +6 -0
- data/osc-machete.gemspec +30 -0
- data/test/fixtures/app-params.yml +8 -0
- data/test/fixtures/app-template-rendered/job.sh +40 -0
- data/test/fixtures/app-template-rendered/params.yml +8 -0
- data/test/fixtures/app-template-rendered/test/job.sh +40 -0
- data/test/fixtures/app-template/job.sh.mustache +40 -0
- data/test/fixtures/app-template/params.yml.mustache +8 -0
- data/test/fixtures/app-template/test/job.sh.mustache +40 -0
- data/test/fixtures/oakley.sh +14 -0
- data/test/fixtures/quick.sh +14 -0
- data/test/fixtures/ruby.sh +14 -0
- data/test/test_job.rb +179 -0
- data/test/test_job_dir.rb +39 -0
- data/test/test_location.rb +97 -0
- data/test/test_status.rb +99 -0
- data/test/test_torque_helper.rb +209 -0
- data/test/test_torque_helper_live.rb +174 -0
- metadata +177 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'osc/machete'
|
3
|
+
|
4
|
+
class TestJobDir < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@data_root = Dir.mktmpdir
|
7
|
+
@parent = Pathname.new(@data_root).join("containers")
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
FileUtils.remove_entry @data_root
|
12
|
+
end
|
13
|
+
|
14
|
+
# test and verify if we create a JobDir helper
|
15
|
+
# with a parent directory that doesn't yet exist
|
16
|
+
# new_jobdir returns /path/to/parent/1
|
17
|
+
def test_job_dir_with_missing_parent_dir
|
18
|
+
dirhelper = OSC::Machete::JobDir.new(@parent)
|
19
|
+
|
20
|
+
assert_equal [], dirhelper.jobdirs
|
21
|
+
assert_equal [], dirhelper.targetdirs
|
22
|
+
assert_equal @parent.join("1"), dirhelper.new_jobdir
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_new_jobdir_succeeds_with_numbered_directories
|
26
|
+
FileUtils.mkdir_p @parent
|
27
|
+
|
28
|
+
# Initialize app directory with multiple jobs
|
29
|
+
# and a file with a larger number
|
30
|
+
Dir.mkdir("#{@parent}/1")
|
31
|
+
Dir.mkdir("#{@parent}/5")
|
32
|
+
FileUtils.touch("#{@parent}/8")
|
33
|
+
|
34
|
+
# Create unique directory
|
35
|
+
new_jobdir = OSC::Machete::JobDir.new(@parent).new_jobdir
|
36
|
+
Dir.mkdir(new_jobdir)
|
37
|
+
assert Dir.exists?("#{@parent}/9"), "Directory was not created: #{@parent}/9"
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'osc/machete'
|
3
|
+
|
4
|
+
class TestLocation < Minitest::Test
|
5
|
+
|
6
|
+
def setup
|
7
|
+
# tmp directory
|
8
|
+
# and we are making a location object that wraps that directory
|
9
|
+
# we add mustache templates and test rendering
|
10
|
+
# we add another tmp directory/location and we test copy to
|
11
|
+
@dir1 = Dir.mktmpdir("location")
|
12
|
+
@dir2 = Dir.mktmpdir("location")
|
13
|
+
@location1 = OSC::Machete::Location.new(@dir1)
|
14
|
+
@location2 = OSC::Machete::Location.new(@dir2)
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
FileUtils.remove_entry @dir1
|
19
|
+
FileUtils.remove_entry @dir2
|
20
|
+
end
|
21
|
+
|
22
|
+
# Location.render(params, options = {})
|
23
|
+
|
24
|
+
def test_render_default_replace_template
|
25
|
+
setup_render
|
26
|
+
@location1.render("")
|
27
|
+
assert_equal true, File.exists?("#{@dir1}/file.txt")
|
28
|
+
assert_equal false, File.exists?("#{@dir1}/file.txt.mustache")
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_render_user_replace_template
|
32
|
+
setup_render
|
33
|
+
@location1.render("", {replace: true})
|
34
|
+
assert_equal true, File.exists?("#{@dir1}/file.txt")
|
35
|
+
assert_equal false, File.exists?("#{@dir1}/file.txt.mustache")
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_render_user_doesnt_replace_template
|
39
|
+
setup_render
|
40
|
+
@location1.render("", {replace: false})
|
41
|
+
assert_equal true, File.exists?("#{@dir1}/file.txt")
|
42
|
+
assert_equal true, File.exists?("#{@dir1}/file.txt.mustache")
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_copy_to_shouldnt_copy_developer_files
|
46
|
+
setup_copy_to
|
47
|
+
|
48
|
+
@location1.copy_to(@dir2)
|
49
|
+
assert_equal true, Dir.exists?("#{@dir2}")
|
50
|
+
assert_equal false, Dir.exists?("#{@dir2}/.git")
|
51
|
+
assert_equal false, Dir.exists?("#{@dir2}/.svn")
|
52
|
+
assert_equal false, Dir.exists?("#{@dir2}/test.dir.1")
|
53
|
+
assert_equal true, Dir.exists?("#{@dir2}/test.dir.2")
|
54
|
+
assert_equal true, File.exists?("#{@dir2}/test.1")
|
55
|
+
assert_equal false, File.exists?("#{@dir2}/test.2")
|
56
|
+
assert_equal true, File.exists?("#{@dir2}/test.3")
|
57
|
+
assert_equal false, File.exists?("#{@dir2}/test.4")
|
58
|
+
assert_equal false, File.exists?("#{@dir2}/test.dir.2/test.1")
|
59
|
+
assert_equal false, File.exists?("#{@dir2}/test.dir.2/test.2")
|
60
|
+
assert_equal true, File.exists?("#{@dir2}/test.dir.2/test.4")
|
61
|
+
assert_equal false, File.exists?("#{@dir2}/.gitignore")
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def setup_render
|
68
|
+
FileUtils.touch("#{@dir1}/file.txt.mustache")
|
69
|
+
end
|
70
|
+
|
71
|
+
def setup_copy_to
|
72
|
+
# Example directory/file structure of developer
|
73
|
+
Dir.mkdir("#{@dir1}/.git")
|
74
|
+
Dir.mkdir("#{@dir1}/.svn")
|
75
|
+
Dir.mkdir("#{@dir1}/test.dir.1")
|
76
|
+
Dir.mkdir("#{@dir1}/test.dir.2")
|
77
|
+
FileUtils.touch("#{@dir1}/test.1")
|
78
|
+
FileUtils.touch("#{@dir1}/test.2")
|
79
|
+
FileUtils.touch("#{@dir1}/test.3")
|
80
|
+
FileUtils.touch("#{@dir1}/test.4")
|
81
|
+
FileUtils.touch("#{@dir1}/test.dir.2/test.1")
|
82
|
+
FileUtils.touch("#{@dir1}/test.dir.2/test.2")
|
83
|
+
FileUtils.touch("#{@dir1}/test.dir.2/test.4")
|
84
|
+
|
85
|
+
# Make example .gitignore
|
86
|
+
gitignore = <<-END.gsub(/^ {20}/, '')
|
87
|
+
# All files here will be ignored
|
88
|
+
test.2
|
89
|
+
#test.3
|
90
|
+
/test.4
|
91
|
+
test.dir.1
|
92
|
+
test.dir.2/test.1
|
93
|
+
END
|
94
|
+
|
95
|
+
File.open("#{@dir1}/.gitignore", 'w') {|f| f.write(gitignore) }
|
96
|
+
end
|
97
|
+
end
|
data/test/test_status.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'osc/machete'
|
3
|
+
|
4
|
+
class TestStatus < Minitest::Test
|
5
|
+
include OSC::Machete
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@passed = Status.passed
|
9
|
+
@running = Status.running
|
10
|
+
@held = Status.held
|
11
|
+
@queued = Status.queued
|
12
|
+
@failed = Status.failed
|
13
|
+
@new = Status.not_submitted
|
14
|
+
@suspended = Status.suspended
|
15
|
+
@undetermined = Status.undetermined
|
16
|
+
end
|
17
|
+
|
18
|
+
def teardown
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_status_equality
|
22
|
+
assert Status.new(:F).eql?(Status.new("F"))
|
23
|
+
assert_equal Status.new(:F), Status.new("F")
|
24
|
+
assert_equal @failed, Status.new("F")
|
25
|
+
assert_equal @passed, Status.new("C")
|
26
|
+
|
27
|
+
#FIXME: is supporting comparisons between Status values and Strings a good idea?
|
28
|
+
assert_equal @passed, "C"
|
29
|
+
|
30
|
+
# default value is
|
31
|
+
assert_equal Status.new(""), @new
|
32
|
+
assert_equal Status.new(nil), @new
|
33
|
+
assert_nil @new.char
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_to_s
|
37
|
+
assert_equal "Passed", @passed.to_s
|
38
|
+
assert_equal "Not Submitted", @new.to_s
|
39
|
+
assert_equal "Running", @running.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_create_status_value_from_status_value
|
43
|
+
assert_equal @passed, OSC::Machete::Status.new(@passed)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_helpers
|
47
|
+
assert_equal false, @passed.active?
|
48
|
+
assert_equal true, @passed.completed?
|
49
|
+
assert_equal true, @passed.passed?
|
50
|
+
assert_equal true, @queued.queued?
|
51
|
+
assert_equal true, @queued.active?
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_max
|
55
|
+
assert_equal @passed, [@passed, @passed].max
|
56
|
+
assert_equal @passed, [@new, @passed].max
|
57
|
+
assert_equal @running, [@running, @queued].max
|
58
|
+
assert_equal @failed, [@passed, @failed].max
|
59
|
+
assert_equal @running, [@passed, @running].max
|
60
|
+
assert_equal @running, [@running, @queued].max
|
61
|
+
assert_equal @queued, [@new, @queued].max
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_add
|
65
|
+
assert_equal @passed, @passed + @passed
|
66
|
+
assert_equal @passed, @new + @passed
|
67
|
+
assert_equal @running, @running + @queued
|
68
|
+
assert_equal @failed, @passed + @failed
|
69
|
+
assert_equal @running, @passed + @running
|
70
|
+
assert_equal @running, @running + @queued
|
71
|
+
assert_equal @queued, @new + @queued
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_undetermined
|
75
|
+
assert_equal Status.new("X"), Status.undetermined
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_submitted
|
79
|
+
assert @passed.submitted?
|
80
|
+
assert @running.submitted?
|
81
|
+
assert @queued.submitted?
|
82
|
+
assert @failed.submitted?
|
83
|
+
assert @passed.submitted?
|
84
|
+
assert ! @new.submitted?
|
85
|
+
assert ! Status.undetermined.submitted?
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_active_status_values
|
89
|
+
assert_equal Status.values.sort, [@undetermined, @new, @passed, @failed, @held, @queued, @running, @suspended].sort
|
90
|
+
assert_equal Status.active_values.sort, [@running, @queued, @held, @suspended].sort
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_completed
|
94
|
+
assert_equal Status.completed_values.sort, [@passed, @failed]
|
95
|
+
assert @passed.completed?
|
96
|
+
assert @failed.completed?
|
97
|
+
assert ! @running.completed?
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'osc/machete'
|
3
|
+
require 'pbs'
|
4
|
+
require 'mocha/setup'
|
5
|
+
|
6
|
+
# test helper class
|
7
|
+
class TestTorqueHelper < Minitest::Test
|
8
|
+
|
9
|
+
# FIXME:
|
10
|
+
# will be replacing with programmatic access to torque
|
11
|
+
# however... we should have our tests actually submit tiny jobs on a queue that can respond immediately,
|
12
|
+
# run for a minute, and die
|
13
|
+
# perhaps using the Oxymoron cluster for this purpose?
|
14
|
+
#
|
15
|
+
# 2016/01/08 Implemented this in `test_qsub_oakley` and `test_qsub_ruby`. The test only runs when rake
|
16
|
+
# is called on the correct submit host. On all other systems, only the stubs are used.
|
17
|
+
|
18
|
+
def setup
|
19
|
+
# FIXME: Torque only works from websvsc02
|
20
|
+
# This raises an issue mentioning that it is not being submitted on the
|
21
|
+
# correct host, comment out the raise to skip the live tests.
|
22
|
+
# Maybe this would be better accomplished with a separate rake task.
|
23
|
+
@submit_host = "websvcs02.osc.edu"
|
24
|
+
|
25
|
+
@job_state_queued = OSC::Machete::Status.queued
|
26
|
+
@job_state_completed = OSC::Machete::Status.passed
|
27
|
+
@job_state_running = OSC::Machete::Status.running
|
28
|
+
@job_state_undetermined = OSC::Machete::Status.undetermined
|
29
|
+
|
30
|
+
@shell = OSC::Machete::TorqueHelper.new
|
31
|
+
|
32
|
+
# test staging using HSP template
|
33
|
+
#@params = YAML.load(File.read('test/fixtures/app-params.yml'))
|
34
|
+
#@template = 'test/fixtures/app-template'
|
35
|
+
#@expected = 'test/fixtures/app-template-rendered'
|
36
|
+
|
37
|
+
# directory where to create jobs
|
38
|
+
#@target = Dir.mktmpdir
|
39
|
+
#@script = 'GLO_job'
|
40
|
+
|
41
|
+
@script_oakley = 'test/fixtures/oakley.sh'
|
42
|
+
@script_ruby = 'test/fixtures/ruby.sh'
|
43
|
+
end
|
44
|
+
|
45
|
+
# FIXME: what is the purpose of these tests?
|
46
|
+
# # Test qstat parameters for completed job.
|
47
|
+
# def test_qsub_oakley_stub
|
48
|
+
# PBS::Job.any_instance.stubs(:submit).with(file: @script_oakley, headers: {}, qsub: true).returns(PBS::Job.new(conn: 'oakley', id: '1234598.oak-batch.osc.edu'))
|
49
|
+
# assert_equal "1234598.oak-batch.osc.edu", @shell.qsub(@script_oakley)
|
50
|
+
# PBS::Job.any_instance.unstub(:submit)
|
51
|
+
# end
|
52
|
+
|
53
|
+
# # Test job state parser when returning queued
|
54
|
+
# def test_qsub_ruby_stub
|
55
|
+
# PBS::Job.any_instance.stubs(:submit).with(file: @script_ruby, headers: {}, qsub: true).returns(PBS::Job.new(conn: 'ruby', id: '1234598'))
|
56
|
+
# assert_equal "1234598", @shell.qsub(@script_ruby)
|
57
|
+
# PBS::Job.any_instance.unstub(:submit)
|
58
|
+
# end
|
59
|
+
|
60
|
+
def test_qstat_state_no_job
|
61
|
+
PBS::Job.any_instance.stubs(:status).raises(PBS::UnkjobidError, "Unknown Job Id")
|
62
|
+
assert_equal @job_state_completed, @shell.qstat("")
|
63
|
+
assert_equal @job_state_completed, @shell.qstat(nil)
|
64
|
+
PBS::Job.any_instance.unstub(:status)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Test that qstat returns Running job StatusValue
|
68
|
+
def test_qstat_state_running_oakley
|
69
|
+
PBS::Job.any_instance.stubs(:status).returns({ :attribs => { :job_state => "R" }})
|
70
|
+
assert_equal @job_state_running, @shell.qstat("123.oak-batch.osc.edu")
|
71
|
+
PBS::Job.any_instance.unstub(:status)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Test that qstat returns Queued job StatusValue
|
75
|
+
def test_qstat_state_queued_oakley
|
76
|
+
PBS::Job.any_instance.stubs(:status).returns({ :attribs => { :job_state => "Q" }})
|
77
|
+
assert_equal @job_state_queued, @shell.qstat("123.oak-batch.osc.edu")
|
78
|
+
PBS::Job.any_instance.unstub(:status)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Test that qstat returns Queued job StatusValue
|
82
|
+
def test_qstat_state_running_ruby
|
83
|
+
PBS::Job.any_instance.stubs(:status).returns({ :attribs => { :job_state => "Q" }})
|
84
|
+
assert_equal @job_state_queued, @shell.qstat("12398765")
|
85
|
+
PBS::Job.any_instance.unstub(:status)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Test that qstat returns Completed job StatusValue when state is nil.
|
89
|
+
def test_qstat_state_completed_oakley
|
90
|
+
PBS::Job.any_instance.stubs(:status).raises(PBS::UnkjobidError, "Unknown Job Id Error")
|
91
|
+
assert_equal @job_state_completed, @shell.qstat("123.oak-batch.osc.edu")
|
92
|
+
PBS::Job.any_instance.unstub(:status)
|
93
|
+
|
94
|
+
PBS::Job.any_instance.stubs(:status).raises(PBS::UnkjobidError, "Unknown Job Id")
|
95
|
+
assert_equal @job_state_completed, @shell.qstat("123.oak-batch.osc.edu")
|
96
|
+
PBS::Job.any_instance.unstub(:status)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Test that qdel works for oakley
|
100
|
+
def test_qdel_oakley_ok
|
101
|
+
PBS::Job.any_instance.stubs(:delete).returns(true)
|
102
|
+
assert_equal true, @shell.qdel("123.oak-batch.osc.edu")
|
103
|
+
PBS::Job.any_instance.unstub(:delete)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Test that qdel works for quick batch
|
107
|
+
def test_qdel_quick
|
108
|
+
PBS::Job.any_instance.stubs(:delete).returns(true)
|
109
|
+
assert_equal true, @shell.qdel("123.quick-batch.osc.edu")
|
110
|
+
PBS::Job.any_instance.unstub(:delete)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Test that qdel works for Ruby cluster
|
114
|
+
def test_qdel_ruby
|
115
|
+
PBS::Job.any_instance.stubs(:delete).returns(true)
|
116
|
+
assert_equal true, @shell.qdel("12365478")
|
117
|
+
PBS::Job.any_instance.unstub(:delete)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Test that qdel throws exception on PBS exception
|
121
|
+
def test_qdel_throws_exception
|
122
|
+
PBS::Job.any_instance.stubs(:delete).raises(PBS::Error)
|
123
|
+
assert_raises(PBS::Error) { @shell.qdel("123.quick-batch.osc.edu") }
|
124
|
+
PBS::Job.any_instance.unstub(:delete)
|
125
|
+
|
126
|
+
PBS::Job.any_instance.stubs(:delete).raises(PBS::SystemError)
|
127
|
+
assert_raises(PBS::SystemError) { @shell.qdel("123.quick-batch.osc.edu") }
|
128
|
+
PBS::Job.any_instance.unstub(:delete)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Test that qdel doesn't throw exception if Unknown Job Id exception
|
132
|
+
def test_qdel_doesnt_throw_exception_on_unknown_job_id
|
133
|
+
PBS::Job.any_instance.stubs(:delete).raises(PBS::UnkjobidError)
|
134
|
+
@shell.qdel("123.quick-batch.osc.edu")
|
135
|
+
PBS::Job.any_instance.unstub(:delete)
|
136
|
+
end
|
137
|
+
|
138
|
+
def assert_qsub_dependency_list(dependency_list, dependencies, host=nil)
|
139
|
+
assert_equal dependency_list, @shell.qsub_dependencies_header(dependencies)
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_qsub_afterany
|
143
|
+
assert_qsub_dependency_list("afterany:1234.oak-batch.osc.edu", { afterany: ["1234.oak-batch.osc.edu"] })
|
144
|
+
assert_qsub_dependency_list("afterany:1234.oakbatch.osc.edu", { afterany: "1234.oakbatch.osc.edu" })
|
145
|
+
assert_qsub_dependency_list("afterany:1234.oakbatch.osc.edu:2345.oakbatch.osc.edu", { afterany: ["1234.oakbatch.osc.edu", "2345.oakbatch.osc.edu"] })
|
146
|
+
return true
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
def test_qsub_afterok
|
151
|
+
assert_qsub_dependency_list("afterok:1234.oakbatch.osc.edu", { afterok: ["1234.oakbatch.osc.edu"] })
|
152
|
+
assert_qsub_dependency_list("afterok:1234.oakbatch.osc.edu:2345.oakbatch.osc.edu", { afterok: ["1234.oakbatch.osc.edu", "2345.oakbatch.osc.edu"] })
|
153
|
+
return true
|
154
|
+
end
|
155
|
+
|
156
|
+
# With multiple dependency types, is formatted:
|
157
|
+
# type[:argument[:argument...][,type:argument...]
|
158
|
+
# i.e.
|
159
|
+
# -W depend=afterany:1234.oakbatch.osc.edu,afterok:2345.oakbatch.osc.edu"
|
160
|
+
#
|
161
|
+
# See qsub manpage for details
|
162
|
+
def test_qsub_afterok_and_afterany
|
163
|
+
assert_qsub_dependency_list("afterany:1234.oakbatch.osc.edu,afterok:2345.oakbatch.osc.edu", { afterany: "1234.oakbatch.osc.edu", afterok: "2345.oakbatch.osc.edu" } )
|
164
|
+
return true
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_qsub_other
|
168
|
+
assert_qsub_dependency_list("after:1234.oakbatch.osc.edu", { after: ["1234.oakbatch.osc.edu"] })
|
169
|
+
assert_qsub_dependency_list("afternotok:1234.oakbatch.osc.edu:2345.oakbatch.osc.edu", { afternotok: ["1234.oakbatch.osc.edu", "2345.oakbatch.osc.edu"] })
|
170
|
+
return true
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_qsub_all_dependencies
|
174
|
+
dependencies = {
|
175
|
+
afterany: "1234.oakbatch.osc.edu",
|
176
|
+
afterok: "2345.oakbatch.osc.edu",
|
177
|
+
after: ["2347.oakbatch.osc.edu", "2348.oakbatch.osc.edu"],
|
178
|
+
afternotok: ["2349.oakbatch.osc.edu", "2350.oakbatch.osc.edu", "2351.oakbatch.osc.edu"]
|
179
|
+
}
|
180
|
+
|
181
|
+
depencencies_str = "afterany:1234.oakbatch.osc.edu"
|
182
|
+
depencencies_str += ",afterok:2345.oakbatch.osc.edu"
|
183
|
+
depencencies_str += ",after:2347.oakbatch.osc.edu:2348.oakbatch.osc.edu"
|
184
|
+
depencencies_str += ",afternotok:2349.oakbatch.osc.edu:2350.oakbatch.osc.edu:2351.oakbatch.osc.edu"
|
185
|
+
|
186
|
+
assert_qsub_dependency_list(depencencies_str, dependencies)
|
187
|
+
return true
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_account_string_passed_into_qsub_used_during_submit_call
|
191
|
+
PBS::Job.any_instance.expects(:submit).with(has_entry(headers: {Account_Name: "XXX"})).returns(PBS::Job.new(conn: 'oakley', id: '1234598.oak-batch.osc.edu'))
|
192
|
+
@shell.qsub(@script_oakley, account_string: "XXX")
|
193
|
+
PBS::Job.any_instance.unstub(:submit)
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_default_account_string_used_in_qsub_during_submit_call
|
197
|
+
@shell.stubs(:default_account_string).returns("PZS3000")
|
198
|
+
|
199
|
+
PBS::Job.any_instance.expects(:submit).with(has_entry(headers: {Account_Name: @shell.default_account_string})).returns(PBS::Job.new(conn: 'oakley', id: '1234598.oak-batch.osc.edu'))
|
200
|
+
@shell.qsub(@script_oakley)
|
201
|
+
|
202
|
+
@shell.stubs(:default_account_string).returns("appl")
|
203
|
+
PBS::Job.any_instance.expects(:submit).with(has_entry(headers: {})).returns(PBS::Job.new(conn: 'oakley', id: '1234598.oak-batch.osc.edu'))
|
204
|
+
@shell.qsub(@script_oakley)
|
205
|
+
|
206
|
+
PBS::Job.any_instance.unstub(:submit)
|
207
|
+
@shell.unstub(:default_account_string)
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'osc/machete'
|
3
|
+
require 'pbs'
|
4
|
+
require 'mocha/setup'
|
5
|
+
|
6
|
+
# test helper class
|
7
|
+
class TestTorqueHelperLive < Minitest::Test
|
8
|
+
|
9
|
+
# FIXME:
|
10
|
+
# All of our tests here are broken after updating to PBS
|
11
|
+
# Everything will need to be revisited.
|
12
|
+
|
13
|
+
# FIXME:
|
14
|
+
# will be replacing with programmatic access to torque
|
15
|
+
# however... we should have our tests actually submit tiny jobs on a queue that can respond immediately,
|
16
|
+
# run for a minute, and die
|
17
|
+
# perhaps using the Oxymoron cluster for this purpose?
|
18
|
+
#
|
19
|
+
# 2016/01/08 Implemented this in `test_qsub_oakley` and `test_qsub_ruby`. The test only runs when rake
|
20
|
+
# is called on the correct submit host. On all other systems, only the stubs are used.
|
21
|
+
#
|
22
|
+
def live_test_enabled?
|
23
|
+
! ENV['LIVETEST'].nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def setup
|
27
|
+
|
28
|
+
# FIXME: Torque only works from websvsc02
|
29
|
+
# This raises an issue mentioning that it is not being submitted on the
|
30
|
+
# correct host, comment out the raise to skip the live tests.
|
31
|
+
# Maybe this would be better accomplished with a separate rake task.
|
32
|
+
@submit_host = "websvcs02.osc.edu"
|
33
|
+
|
34
|
+
@job_state_queued = OSC::Machete::Status.queued
|
35
|
+
@job_state_completed = OSC::Machete::Status.passed
|
36
|
+
@job_state_running = OSC::Machete::Status.running
|
37
|
+
|
38
|
+
@shell = OSC::Machete::TorqueHelper.new
|
39
|
+
|
40
|
+
# test staging using HSP template
|
41
|
+
#@params = YAML.load(File.read('test/fixtures/app-params.yml'))
|
42
|
+
#@template = 'test/fixtures/app-template'
|
43
|
+
#@expected = 'test/fixtures/app-template-rendered'
|
44
|
+
|
45
|
+
# directory where to create jobs
|
46
|
+
#@target = Dir.mktmpdir
|
47
|
+
#@script = 'GLO_job'
|
48
|
+
|
49
|
+
@script_oakley = 'test/fixtures/oakley.sh'
|
50
|
+
@script_ruby = 'test/fixtures/ruby.sh'
|
51
|
+
@script_quick = 'test/fixtures/quick.sh'
|
52
|
+
end
|
53
|
+
|
54
|
+
# This tests an actual live workflow by
|
55
|
+
# submitting a job to oakley,
|
56
|
+
# checking it's status, and
|
57
|
+
# deleting it.
|
58
|
+
#
|
59
|
+
# Only works on the current submit host.
|
60
|
+
def test_qsub_oakley
|
61
|
+
return unless live_test_enabled?
|
62
|
+
|
63
|
+
torque = OSC::Machete::TorqueHelper.new
|
64
|
+
|
65
|
+
# Don't run the tests if the host doesn't match.
|
66
|
+
if Socket.gethostname == @submit_host
|
67
|
+
# Submit a small job.
|
68
|
+
live_job = torque.qsub(@script_oakley)
|
69
|
+
assert_match(/\d+.oak-batch.osc.edu/, live_job)
|
70
|
+
|
71
|
+
# Qstat it to make sure it's queued.
|
72
|
+
live_status = torque.qstat(live_job)
|
73
|
+
assert_equal @job_state_queued, live_status
|
74
|
+
|
75
|
+
# Delete it and assert true returned.
|
76
|
+
live_delete_status = torque.qdel(live_job)
|
77
|
+
assert_equal nil, live_delete_status
|
78
|
+
else
|
79
|
+
puts "Run test 'test_qsub_oakley' on the batch system from #{@submit_host}."
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
# This tests an actual live workflow by
|
85
|
+
# submitting a job to ruby with an oakley script,
|
86
|
+
# checking it's status, and
|
87
|
+
# deleting it.
|
88
|
+
#
|
89
|
+
# Only works on the current submit host.
|
90
|
+
def test_qsub_ruby_with_oakley_script
|
91
|
+
return unless live_test_enabled?
|
92
|
+
|
93
|
+
torque = OSC::Machete::TorqueHelper.new
|
94
|
+
|
95
|
+
# Don't run the tests if the host doesn't match.
|
96
|
+
if Socket.gethostname == @submit_host
|
97
|
+
# Submit a small job to ruby using an Oakley script,
|
98
|
+
# ensuring that we are no longer evaluating the headers.
|
99
|
+
live_job = torque.qsub(@script_oakley, host: "ruby")
|
100
|
+
assert_match(/\d+$/, live_job)
|
101
|
+
|
102
|
+
# Qstat it to make sure it's queued.
|
103
|
+
live_status = torque.qstat(live_job)
|
104
|
+
assert_equal @job_state_queued, live_status
|
105
|
+
|
106
|
+
# Delete it and assert true returned.
|
107
|
+
live_delete_status = torque.qdel(live_job)
|
108
|
+
assert_equal nil, live_delete_status
|
109
|
+
else
|
110
|
+
puts "Run test 'test_qsub_ruby_with_oakley_script' on the batch system from #{@submit_host}."
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
# This tests an actual live workflow by
|
116
|
+
# submitting a job to ruby,
|
117
|
+
# checking it's status, and
|
118
|
+
# deleting it.
|
119
|
+
#
|
120
|
+
# Only works on the current submit host.
|
121
|
+
def test_qsub_ruby
|
122
|
+
return unless live_test_enabled?
|
123
|
+
|
124
|
+
torque = OSC::Machete::TorqueHelper.new
|
125
|
+
|
126
|
+
# Don't run the tests if the host doesn't match.
|
127
|
+
if Socket.gethostname == @submit_host
|
128
|
+
# Submit a small job.
|
129
|
+
live_job = torque.qsub(@script_ruby)
|
130
|
+
assert_match /^\d+$/, live_job
|
131
|
+
|
132
|
+
# Qstat it to make sure it's queued.
|
133
|
+
live_status = torque.qstat(live_job)
|
134
|
+
assert_equal @job_state_queued, live_status
|
135
|
+
|
136
|
+
# Delete it and assert true returned.
|
137
|
+
live_delete_status = torque.qdel(live_job)
|
138
|
+
assert_equal nil, live_delete_status
|
139
|
+
else
|
140
|
+
puts "Run test 'test_qsub_ruby' on the batch system from #{@submit_host}."
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# This tests an actual live workflow by
|
145
|
+
# submitting a job to quick,
|
146
|
+
# checking it's status, and
|
147
|
+
# deleting it.
|
148
|
+
#
|
149
|
+
# Only works on the current submit host.
|
150
|
+
def test_qsub_quick
|
151
|
+
return unless live_test_enabled?
|
152
|
+
|
153
|
+
torque = OSC::Machete::TorqueHelper.new
|
154
|
+
|
155
|
+
# Don't run the tests if the host doesn't match.
|
156
|
+
if Socket.gethostname == @submit_host
|
157
|
+
# Submit a small job.
|
158
|
+
live_job = torque.qsub(@script_quick, host: 'quick')
|
159
|
+
assert_match /\d+.quick-batch.osc.edu/, live_job
|
160
|
+
|
161
|
+
# Qstat it to make sure it's queued.
|
162
|
+
live_status = torque.qstat(live_job)
|
163
|
+
assert_equal @job_state_queued, live_status
|
164
|
+
|
165
|
+
# Delete it and assert true returned.
|
166
|
+
live_delete_status = torque.qdel(live_job)
|
167
|
+
assert_equal nil, live_delete_status
|
168
|
+
else
|
169
|
+
puts "Run test 'test_qsub_quick' on the batch system from #{@submit_host}."
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
end
|