From 1ad6deca89b6b747819f83e10893ead81bc191e6 Mon Sep 17 00:00:00 2001 From: Jeremy Nicklas Date: Fri, 20 Apr 2018 10:41:56 -0400 Subject: [PATCH] Torque adapter takes native arrays Fixes #65 --- CHANGELOG.md | 3 + lib/ood_core/job/adapters/torque.rb | 116 +++++++---- ood_core.gemspec | 2 +- spec/job/adapters/torque_spec.rb | 291 +++++++++++++++++++++++----- 4 files changed, 328 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb07c4649..032f82460 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- Updated Torque adapter to take into account the new `Script#native` format + allowing for arrays. [#65](https://github.com/OSC/ood_core/issues/65) ## [0.3.0] - 2018-04-05 ### Added diff --git a/lib/ood_core/job/adapters/torque.rb b/lib/ood_core/job/adapters/torque.rb index fb90163b5..5034ac7e7 100644 --- a/lib/ood_core/job/adapters/torque.rb +++ b/lib/ood_core/job/adapters/torque.rb @@ -71,54 +71,94 @@ def submit(script, after: [], afterok: [], afternotok: [], afterany: []) afternotok = Array(afternotok).map(&:to_s) afterany = Array(afterany).map(&:to_s) - # Set headers - headers = {} - headers.merge!(job_arguments: script.args.join(' ')) unless script.args.nil? - headers.merge!(Hold_Types: :u) if script.submit_as_hold - headers.merge!(Rerunable: script.rerunnable ? 'y' : 'n') unless script.rerunnable.nil? - headers.merge!(init_work_dir: script.workdir) unless script.workdir.nil? - headers.merge!(Mail_Users: script.email.join(',')) unless script.email.nil? - mail_points = '' - mail_points += 'b' if script.email_on_started - mail_points += 'e' if script.email_on_terminated - headers.merge!(Mail_Points: mail_points) unless mail_points.empty? - headers.merge!(Job_Name: script.job_name) unless script.job_name.nil? - headers.merge!(Shell_Path_List: script.shell_path) unless script.shell_path.nil? - # ignore input_path (not defined in Torque) - headers.merge!(Output_Path: script.output_path) unless script.output_path.nil? - headers.merge!(Error_Path: script.error_path) unless script.error_path.nil? - # If error_path is not specified we join stdout & stderr (as this - # mimics what the other resource managers do) - headers.merge!(Join_Path: 'oe') if script.error_path.nil? - headers.merge!(reservation_id: script.reservation_id) unless script.reservation_id.nil? - headers.merge!(Priority: script.priority) unless script.priority.nil? - headers.merge!(Execution_Time: script.start_time.localtime.strftime("%C%y%m%d%H%M.%S")) unless script.start_time.nil? - headers.merge!(Account_Name: script.accounting_id) unless script.accounting_id.nil? - # Set dependencies depend = [] depend << "after:#{after.join(':')}" unless after.empty? depend << "afterok:#{afterok.join(':')}" unless afterok.empty? depend << "afternotok:#{afternotok.join(':')}" unless afternotok.empty? depend << "afterany:#{afterany.join(':')}" unless afterany.empty? - headers.merge!(depend: depend.join(',')) unless depend.empty? - # Set resources - resources = {} - resources.merge!(walltime: seconds_to_duration(script.wall_time)) unless script.wall_time.nil? + # Set mailing options + mail_points = "" + mail_points += "b" if script.email_on_started + mail_points += "e" if script.email_on_terminated - # Set environment variables - envvars = script.job_environment || {} + # FIXME: Remove the Hash option once all Interactive Apps are + # converted to Array format + if script.native.is_a?(Hash) + # Set headers + headers = {} + headers.merge!(job_arguments: script.args.join(' ')) unless script.args.nil? + headers.merge!(Hold_Types: :u) if script.submit_as_hold + headers.merge!(Rerunable: script.rerunnable ? 'y' : 'n') unless script.rerunnable.nil? + headers.merge!(init_work_dir: script.workdir) unless script.workdir.nil? + headers.merge!(Mail_Users: script.email.join(',')) unless script.email.nil? + headers.merge!(Mail_Points: mail_points) unless mail_points.empty? + headers.merge!(Job_Name: script.job_name) unless script.job_name.nil? + headers.merge!(Shell_Path_List: script.shell_path) unless script.shell_path.nil? + # ignore input_path (not defined in Torque) + headers.merge!(Output_Path: script.output_path) unless script.output_path.nil? + headers.merge!(Error_Path: script.error_path) unless script.error_path.nil? + # If error_path is not specified we join stdout & stderr (as this + # mimics what the other resource managers do) + headers.merge!(Join_Path: 'oe') if script.error_path.nil? + headers.merge!(reservation_id: script.reservation_id) unless script.reservation_id.nil? + headers.merge!(Priority: script.priority) unless script.priority.nil? + headers.merge!(Execution_Time: script.start_time.localtime.strftime("%C%y%m%d%H%M.%S")) unless script.start_time.nil? + headers.merge!(Account_Name: script.accounting_id) unless script.accounting_id.nil? + headers.merge!(depend: depend.join(',')) unless depend.empty? - # Set native options - if script.native - headers.merge! script.native.fetch(:headers, {}) - resources.merge! script.native.fetch(:resources, {}) - envvars.merge! script.native.fetch(:envvars, {}) - end + # Set resources + resources = {} + resources.merge!(walltime: seconds_to_duration(script.wall_time)) unless script.wall_time.nil? + + # Set environment variables + envvars = script.job_environment || {} + + # Set native options + if script.native + headers.merge! script.native.fetch(:headers, {}) + resources.merge! script.native.fetch(:resources, {}) + envvars.merge! script.native.fetch(:envvars, {}) + end - # Submit job - @pbs.submit_string(script.content, queue: script.queue_name, headers: headers, resources: resources, envvars: envvars) + # Submit job + @pbs.submit_string(script.content, queue: script.queue_name, headers: headers, resources: resources, envvars: envvars) + else + # Set qsub arguments + args = [] + args += ["-F", script.args.join(" ")] unless script.args.nil? + args += ["-h"] if script.submit_as_hold + args += ["-r", script.rerunnable ? "y" : "n"] unless script.rerunnable.nil? + args += ["-M", script.email.join(",")] unless script.email.nil? + args += ["-m", mail_points] unless mail_points.empty? + args += ["-N", script.job_name] unless script.job_name.nil? + args += ["-S", script.shell_path] unless script.shell_path.nil? + # ignore input_path (not defined in Torque) + args += ["-o", script.output_path] unless script.output_path.nil? + args += ["-e", script.error_path] unless script.error_path.nil? + args += ["-W", "x=advres:#{script.reservation_id}"] unless script.reservation_id.nil? + args += ["-q", script.queue_name] unless script.queue_name.nil? + args += ["-p", script.priority] unless script.priority.nil? + args += ["-a", script.start_time.localtime.strftime("%C%y%m%d%H%M.%S")] unless script.start_time.nil? + args += ["-A", script.accounting_id] unless script.accounting_id.nil? + args += ["-W", "depend=#{depend.join(",")}"] unless depend.empty? + args += ["-l", "walltime=#{seconds_to_duration(script.wall_time)}"] unless script.wall_time.nil? + + # Set environment variables + env = script.job_environment.to_h + args += ["-v", env.keys.join(",")] unless env.empty? + + # If error_path is not specified we join stdout & stderr (as this + # mimics what the other resource managers do) + args += ["-j", "oe"] if script.error_path.nil? + + # Set native options + args += script.native if script.native + + # Submit job + @pbs.submit(script.content, args: args, env: env, chdir: script.workdir) + end rescue PBS::Error => e raise JobAdapterError, e.message end diff --git a/ood_core.gemspec b/ood_core.gemspec index 1df419f92..6bbd1c46c 100644 --- a/ood_core.gemspec +++ b/ood_core.gemspec @@ -23,7 +23,7 @@ Gem::Specification.new do |spec| spec.required_ruby_version = ">= 2.2.0" spec.add_runtime_dependency "ood_support", "~> 0.0.2" - spec.add_development_dependency "pbs", "~> 2.1", ">= 2.1.0" + spec.add_development_dependency "pbs", "~> 2.1", ">= 2.2.0" spec.add_development_dependency "bundler", "~> 1.7" spec.add_development_dependency "rake", "~> 10.0" spec.add_development_dependency "rspec", "~> 3.0" diff --git a/spec/job/adapters/torque_spec.rb b/spec/job/adapters/torque_spec.rb index 8b81fc992..60b88fb63 100644 --- a/spec/job/adapters/torque_spec.rb +++ b/spec/job/adapters/torque_spec.rb @@ -36,7 +36,7 @@ def build_script(opts = {}) ) end - let(:pbs) { double(submit_string: "job.123") } + let(:pbs) { double(submit: "job.123") } let(:content) { "my batch script" } context "when script not defined" do @@ -49,32 +49,32 @@ def build_script(opts = {}) it "returns job id" do is_expected.to eq("job.123") - expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {}) + expect(pbs).to have_received(:submit).with(content, args: ["-j", "oe"], env: {}, chdir: nil) end context "with :queue_name" do before { adapter.submit(build_script(queue_name: "queue")) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: "queue", headers: {Join_Path: "oe"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-q", "queue", "-j", "oe"], env: {}, chdir: nil) } end context "with :args" do before { adapter.submit(build_script(args: ["arg1", "arg2"])) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", job_arguments: "arg1 arg2"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-F", "arg1 arg2", "-j", "oe"], env: {}, chdir: nil) } end context "with :submit_as_hold" do context "as true" do before { adapter.submit(build_script(submit_as_hold: true)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Hold_Types: :u}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-h", "-j", "oe"], env: {}, chdir: nil) } end context "as false" do before { adapter.submit(build_script(submit_as_hold: false)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-j", "oe"], env: {}, chdir: nil) } end end @@ -82,45 +82,45 @@ def build_script(opts = {}) context "as true" do before { adapter.submit(build_script(rerunnable: true)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Rerunable: "y"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-r", "y", "-j", "oe"], env: {}, chdir: nil) } end context "as false" do before { adapter.submit(build_script(rerunnable: false)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Rerunable: "n"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-r", "n", "-j", "oe"], env: {}, chdir: nil) } end end context "with :job_environment" do before { adapter.submit(build_script(job_environment: {"key" => "value"})) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {"key" => "value"}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-v", "key", "-j", "oe"], env: {"key" => "value"}, chdir: nil) } end context "with :workdir" do before { adapter.submit(build_script(workdir: "/path/to/workdir")) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", init_work_dir: Pathname.new("/path/to/workdir")}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-j", "oe"], env: {}, chdir: Pathname.new("/path/to/workdir")) } end context "with :email" do before { adapter.submit(build_script(email: ["email1", "email2"])) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Mail_Users: "email1,email2"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-M", "email1,email2", "-j", "oe"], env: {}, chdir: nil) } end context "with :email_on_started" do context "as true" do before { adapter.submit(build_script(email_on_started: true)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Mail_Points: "b"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-m", "b", "-j", "oe"], env: {}, chdir: nil) } end context "as false" do before { adapter.submit(build_script(email_on_started: false)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-j", "oe"], env: {}, chdir: nil) } end end @@ -128,123 +128,324 @@ def build_script(opts = {}) context "as true" do before { adapter.submit(build_script(email_on_terminated: true)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Mail_Points: "e"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-m", "e", "-j", "oe"], env: {}, chdir: nil) } end context "as false" do before { adapter.submit(build_script(email_on_terminated: false)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-j", "oe"], env: {}, chdir: nil) } end end context "with :email_on_started and :email_on_terminated" do before { adapter.submit(build_script(email_on_started: true, email_on_terminated: true)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Mail_Points: "be"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-m", "be", "-j", "oe"], env: {}, chdir: nil) } end context "with :job_name" do before { adapter.submit(build_script(job_name: "my_job")) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Job_Name: "my_job"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-N", "my_job", "-j", "oe"], env: {}, chdir: nil) } end context "with :shell_path" do before { adapter.submit(build_script(shell_path: "/path/to/shell")) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Shell_Path_List: Pathname.new("/path/to/shell")}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-S", Pathname.new("/path/to/shell"), "-j", "oe"], env: {}, chdir: nil) } end context "with :input_path" do before { adapter.submit(build_script(input_path: "/path/to/input")) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-j", "oe"], env: {}, chdir: nil) } end context "with :output_path" do before { adapter.submit(build_script(output_path: "/path/to/output")) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Output_Path: Pathname.new("/path/to/output")}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-o", Pathname.new("/path/to/output"), "-j", "oe"], env: {}, chdir: nil) } end context "with :error_path" do before { adapter.submit(build_script(error_path: "/path/to/error")) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Error_Path: Pathname.new("/path/to/error")}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-e", Pathname.new("/path/to/error")], env: {}, chdir: nil) } end context "with :reservation_id" do before { adapter.submit(build_script(reservation_id: "my_rsv")) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", reservation_id: "my_rsv"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-W", "x=advres:my_rsv", "-j", "oe"], env: {}, chdir: nil) } end context "with :priority" do before { adapter.submit(build_script(priority: 123)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Priority: 123}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-p", 123, "-j", "oe"], env: {}, chdir: nil) } end context "with :start_time" do before { adapter.submit(build_script(start_time: Time.new(2016, 11, 8, 13, 53, 54).to_i)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Execution_Time: "201611081353.54"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-a", "201611081353.54", "-j", "oe"], env: {}, chdir: nil) } end context "with :accounting_id" do before { adapter.submit(build_script(accounting_id: "my_account")) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Account_Name: "my_account"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-A", "my_account", "-j", "oe"], env: {}, chdir: nil) } end context "with :wall_time" do before { adapter.submit(build_script(wall_time: 94534)) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {walltime: "26:15:34"}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-l", "walltime=26:15:34", "-j", "oe"], env: {}, chdir: nil) } end context "with :native" do - context "with :headers" do - before { adapter.submit(build_script(native: {headers: {check: "this"}})) } - - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", check: "this"}, resources: {}, envvars: {}) } - end - - context "with :resources" do - before { adapter.submit(build_script(native: {resources: {check: "this"}})) } - - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {check: "this"}, envvars: {}) } - end + before { adapter.submit(build_script(native: ["A", "B", "C"])) } - context "with :envvars" do - before { adapter.submit(build_script(native: {envvars: {check: "this"}})) } - - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {check: "this"}) } - end + it { expect(pbs).to have_received(:submit).with(content, args: ["-j", "oe", "A", "B", "C"], env: {}, chdir: nil) } end %i(after afterok afternotok afterany).each do |after| context "and :#{after} is defined as a single job id" do before { adapter.submit(build_script, after => "job_id") } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", depend: "#{after}:job_id"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-W", "depend=#{after}:job_id", "-j", "oe"], env: {}, chdir: nil) } end context "and :#{after} is defined as multiple job ids" do before { adapter.submit(build_script, after => ["job1", "job2"]) } - it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", depend: "#{after}:job1:job2"}, resources: {}, envvars: {}) } + it { expect(pbs).to have_received(:submit).with(content, args: ["-W", "depend=#{after}:job1:job2", "-j", "oe"], env: {}, chdir: nil) } end end context "when PBS::Error is raised" do - before { expect(pbs).to receive(:submit_string).and_raise(PBS::Error) } + before { expect(pbs).to receive(:submit).and_raise(PBS::Error) } it "raises OodCore::JobAdapterError" do expect { subject }.to raise_error(OodCore::JobAdapterError) end end + + # FIXME: Remove this when all Interactive Apps are updated to use an Array + # for native + context "when native is a Hash" do + def build_script(opts = {}) + OodCore::Job::Script.new( + { + content: content, + native: {} + }.merge opts + ) + end + + let(:pbs) { double(submit_string: "job.123") } + let(:content) { "my batch script" } + + context "when script not defined" do + it "raises ArgumentError" do + expect { adapter.submit }.to raise_error(ArgumentError) + end + end + + subject { adapter.submit(build_script) } + + it "returns job id" do + is_expected.to eq("job.123") + expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {}) + end + + context "with :queue_name" do + before { adapter.submit(build_script(queue_name: "queue")) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: "queue", headers: {Join_Path: "oe"}, resources: {}, envvars: {}) } + end + + context "with :args" do + before { adapter.submit(build_script(args: ["arg1", "arg2"])) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", job_arguments: "arg1 arg2"}, resources: {}, envvars: {}) } + end + + context "with :submit_as_hold" do + context "as true" do + before { adapter.submit(build_script(submit_as_hold: true)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Hold_Types: :u}, resources: {}, envvars: {}) } + end + + context "as false" do + before { adapter.submit(build_script(submit_as_hold: false)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {}) } + end + end + + context "with :rerunnable" do + context "as true" do + before { adapter.submit(build_script(rerunnable: true)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Rerunable: "y"}, resources: {}, envvars: {}) } + end + + context "as false" do + before { adapter.submit(build_script(rerunnable: false)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Rerunable: "n"}, resources: {}, envvars: {}) } + end + end + + context "with :job_environment" do + before { adapter.submit(build_script(job_environment: {"key" => "value"})) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {"key" => "value"}) } + end + + context "with :workdir" do + before { adapter.submit(build_script(workdir: "/path/to/workdir")) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", init_work_dir: Pathname.new("/path/to/workdir")}, resources: {}, envvars: {}) } + end + + context "with :email" do + before { adapter.submit(build_script(email: ["email1", "email2"])) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Mail_Users: "email1,email2"}, resources: {}, envvars: {}) } + end + + context "with :email_on_started" do + context "as true" do + before { adapter.submit(build_script(email_on_started: true)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Mail_Points: "b"}, resources: {}, envvars: {}) } + end + + context "as false" do + before { adapter.submit(build_script(email_on_started: false)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {}) } + end + end + + context "with :email_on_terminated" do + context "as true" do + before { adapter.submit(build_script(email_on_terminated: true)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Mail_Points: "e"}, resources: {}, envvars: {}) } + end + + context "as false" do + before { adapter.submit(build_script(email_on_terminated: false)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {}) } + end + end + + context "with :email_on_started and :email_on_terminated" do + before { adapter.submit(build_script(email_on_started: true, email_on_terminated: true)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Mail_Points: "be"}, resources: {}, envvars: {}) } + end + + context "with :job_name" do + before { adapter.submit(build_script(job_name: "my_job")) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Job_Name: "my_job"}, resources: {}, envvars: {}) } + end + + context "with :shell_path" do + before { adapter.submit(build_script(shell_path: "/path/to/shell")) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Shell_Path_List: Pathname.new("/path/to/shell")}, resources: {}, envvars: {}) } + end + + context "with :input_path" do + before { adapter.submit(build_script(input_path: "/path/to/input")) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {}) } + end + + context "with :output_path" do + before { adapter.submit(build_script(output_path: "/path/to/output")) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Output_Path: Pathname.new("/path/to/output")}, resources: {}, envvars: {}) } + end + + context "with :error_path" do + before { adapter.submit(build_script(error_path: "/path/to/error")) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Error_Path: Pathname.new("/path/to/error")}, resources: {}, envvars: {}) } + end + + context "with :reservation_id" do + before { adapter.submit(build_script(reservation_id: "my_rsv")) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", reservation_id: "my_rsv"}, resources: {}, envvars: {}) } + end + + context "with :priority" do + before { adapter.submit(build_script(priority: 123)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Priority: 123}, resources: {}, envvars: {}) } + end + + context "with :start_time" do + before { adapter.submit(build_script(start_time: Time.new(2016, 11, 8, 13, 53, 54).to_i)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Execution_Time: "201611081353.54"}, resources: {}, envvars: {}) } + end + + context "with :accounting_id" do + before { adapter.submit(build_script(accounting_id: "my_account")) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", Account_Name: "my_account"}, resources: {}, envvars: {}) } + end + + context "with :wall_time" do + before { adapter.submit(build_script(wall_time: 94534)) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {walltime: "26:15:34"}, envvars: {}) } + end + + context "with :native" do + context "with :headers" do + before { adapter.submit(build_script(native: {headers: {check: "this"}})) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", check: "this"}, resources: {}, envvars: {}) } + end + + context "with :resources" do + before { adapter.submit(build_script(native: {resources: {check: "this"}})) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {check: "this"}, envvars: {}) } + end + + context "with :envvars" do + before { adapter.submit(build_script(native: {envvars: {check: "this"}})) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe"}, resources: {}, envvars: {check: "this"}) } + end + end + + %i(after afterok afternotok afterany).each do |after| + context "and :#{after} is defined as a single job id" do + before { adapter.submit(build_script, after => "job_id") } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", depend: "#{after}:job_id"}, resources: {}, envvars: {}) } + end + + context "and :#{after} is defined as multiple job ids" do + before { adapter.submit(build_script, after => ["job1", "job2"]) } + + it { expect(pbs).to have_received(:submit_string).with(content, queue: nil, headers: {Join_Path: "oe", depend: "#{after}:job1:job2"}, resources: {}, envvars: {}) } + end + end + end end describe "#info_all" do