end
def queue
- return send_error("Unsupported legacy jobs API",
- status: 400)
+ @objects = []
+ index
end
def queue_size
- return send_error("Unsupported legacy jobs API",
- status: 400)
+ render :json => {:queue_size => 0}
end
def self._create_requires_parameters
class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
fixtures :repositories, :users, :jobs, :links, :collections
- # See git_setup.rb for the commit log for test.git.tar
- include GitTestHelper
-
setup do
@controller = Arvados::V1::JobsController.new
authorize_with :active
end
- test "reuse job with no_reuse=false" do
- post :create, params: {
- job: {
- no_reuse: false,
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- an_integer: '1',
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45'
- }
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "reuse job with find_or_create=true" do
- post :create, params: {
- job: {
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- },
- find_or_create: true
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "no reuse job with null log" do
- post :create, params: {
- job: {
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '3'
- }
- },
- find_or_create: true
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqq3', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "reuse job with symbolic script_version" do
- post :create, params: {
- job: {
- script: "hash",
- script_version: "tag1",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- },
- find_or_create: true
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "do not reuse job because no_reuse=true" do
- post :create, params: {
- job: {
- no_reuse: true,
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- [false, "false"].each do |whichfalse|
- test "do not reuse job because find_or_create=#{whichfalse.inspect}" do
- post :create, params: {
- job: {
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- },
- find_or_create: whichfalse
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
- end
-
- test "do not reuse job because output is not readable by user" do
- authorize_with :job_reader
- post :create, params: {
- job: {
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- },
- find_or_create: true
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "test_cannot_reuse_job_no_output" do
- post :create, params: {
- job: {
- no_reuse: false,
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '2'
- }
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykppp', new_job['uuid']
- end
-
- test "test_reuse_job_range" do
- post :create, params: {
- job: {
- no_reuse: false,
- script: "hash",
- minimum_script_version: "tag1",
- script_version: "master",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "cannot_reuse_job_no_minimum_given_so_must_use_specified_commit" do
- post :create, params: {
- job: {
- no_reuse: false,
- script: "hash",
- script_version: "master",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '077ba2ad3ea24a929091a9e6ce545c93199b8e57', new_job['script_version']
- end
-
- test "test_cannot_reuse_job_different_input" do
- post :create, params: {
- job: {
- no_reuse: false,
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '2'
- }
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "test_cannot_reuse_job_different_version" do
- post :create, params: {
- job: {
- no_reuse: false,
- script: "hash",
- script_version: "master",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '2'
- }
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '077ba2ad3ea24a929091a9e6ce545c93199b8e57', new_job['script_version']
- end
-
- test "test_can_reuse_job_submitted_nondeterministic" do
- post :create, params: {
- job: {
- no_reuse: false,
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- },
- nondeterministic: true
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "test_cannot_reuse_job_past_nondeterministic" do
- post :create, params: {
- job: {
- no_reuse: false,
- script: "hash2",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykyyy', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "test_cannot_reuse_job_no_permission" do
- authorize_with :spectator
- post :create, params: {
- job: {
- no_reuse: false,
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "test_cannot_reuse_job_excluded" do
- post :create, params: {
- job: {
- no_reuse: false,
- script: "hash",
- minimum_script_version: "31ce37fe365b3dc204300a3e4c396ad333ed0556",
- script_version: "master",
- repository: "active/foo",
- exclude_script_versions: ["tag1"],
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_not_equal('4fe459abe02d9b365932b8f5dc419439ab4e2577',
- new_job['script_version'])
- end
-
- test "cannot reuse job with find_or_create but excluded version" do
- post :create, params: {
- job: {
- script: "hash",
- script_version: "master",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- },
- find_or_create: true,
- minimum_script_version: "31ce37fe365b3dc204300a3e4c396ad333ed0556",
- exclude_script_versions: ["tag1"],
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_not_equal('4fe459abe02d9b365932b8f5dc419439ab4e2577',
- new_job['script_version'])
- end
-
- test "cannot reuse job when hash-like branch includes newer commit" do
- check_new_job_created_from({job: {script_version: "738783"}},
- :previous_job_run_superseded_by_hash_branch)
- end
-
BASE_FILTERS = {
'repository' => ['=', 'active/foo'],
'script' => ['=', 'hash'],
hash.each_pair.map { |name, filter| [name] + filter }
end
- test "can reuse a Job based on filters" do
- filters_hash = BASE_FILTERS.
- merge('script_version' => ['in git', 'tag1'])
- post(:create, params: {
- job: {
- script: "hash",
- script_version: "master",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- },
- filters: filters_from_hash(filters_hash),
- find_or_create: true,
- })
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "can not reuse a Job based on filters" do
- filters = filters_from_hash(BASE_FILTERS
- .reject { |k| k == 'script_version' })
- filters += [["script_version", "in git",
- "31ce37fe365b3dc204300a3e4c396ad333ed0556"],
- ["script_version", "not in git", ["tag1"]]]
- post(:create, params: {
- job: {
- script: "hash",
- script_version: "master",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- },
- filters: filters,
- find_or_create: true,
- })
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '077ba2ad3ea24a929091a9e6ce545c93199b8e57', new_job['script_version']
- end
-
- test "can not reuse a Job based on arbitrary filters" do
- filters_hash = BASE_FILTERS.
- merge("created_at" => ["<", "2010-01-01T00:00:00Z"])
- post(:create, params: {
- job: {
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- },
- filters: filters_from_hash(filters_hash),
- find_or_create: true,
- })
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_equal 'zzzzz-8i9sb-cjs4pklxxjykqqq', new_job['uuid']
- assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
- end
-
- test "can reuse a Job with a Docker image" do
- post(:create, params: {
- job: {
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- },
- runtime_constraints: {
- docker_image: 'arvados/apitestfixture',
- }
- },
- find_or_create: true,
- })
- assert_response :success
- new_job = assigns(:object)
- assert_not_nil new_job
- target_job = jobs(:previous_docker_job_run)
- [:uuid, :script_version, :docker_image_locator].each do |attr|
- assert_equal(target_job.send(attr), new_job.send(attr))
- end
- end
-
- test "can reuse a Job with a Docker image hash filter" do
- filters_hash = BASE_FILTERS.
- merge("script_version" =>
- ["=", "4fe459abe02d9b365932b8f5dc419439ab4e2577"],
- "docker_image_locator" =>
- ["in docker", links(:docker_image_collection_hash).name])
- post(:create, params: {
- job: {
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- },
- },
- filters: filters_from_hash(filters_hash),
- find_or_create: true,
- })
- assert_response :success
- new_job = assigns(:object)
- assert_not_nil new_job
- target_job = jobs(:previous_docker_job_run)
- [:uuid, :script_version, :docker_image_locator].each do |attr|
- assert_equal(target_job.send(attr), new_job.send(attr))
- end
- end
-
- test "reuse Job with Docker image repo+tag" do
- filters_hash = BASE_FILTERS.
- merge("script_version" =>
- ["=", "4fe459abe02d9b365932b8f5dc419439ab4e2577"],
- "docker_image_locator" =>
- ["in docker", links(:docker_image_collection_tag2).name])
- post(:create, params: {
- job: {
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- },
- },
- filters: filters_from_hash(filters_hash),
- find_or_create: true,
- })
- assert_response :success
- new_job = assigns(:object)
- assert_not_nil new_job
- target_job = jobs(:previous_docker_job_run)
- [:uuid, :script_version, :docker_image_locator].each do |attr|
- assert_equal(target_job.send(attr), new_job.send(attr))
- end
- end
-
- test "new job with unknown Docker image filter" do
- filters_hash = BASE_FILTERS.
- merge("docker_image_locator" => ["in docker", "_nonesuchname_"])
- post(:create, params: {
- job: {
- script: "hash",
- script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- },
- },
- filters: filters_from_hash(filters_hash),
- find_or_create: true,
- })
- assert_response :success
- new_job = assigns(:object)
- assert_not_nil new_job
- assert_not_equal(jobs(:previous_docker_job_run).uuid, new_job.uuid)
- end
-
- test "don't reuse job using older Docker image of same name" do
- jobspec = {runtime_constraints: {
- docker_image: "arvados/apitestfixture",
- }}
- check_new_job_created_from({job: jobspec},
- :previous_ancient_docker_image_job_run)
- end
-
- test "reuse job with Docker image that has hash name" do
- jobspec = {runtime_constraints: {
- docker_image: "a" * 64,
- }}
- check_job_reused_from(jobspec, :previous_docker_job_run)
- end
-
- ["repository", "script"].each do |skip_key|
- test "missing #{skip_key} filter raises an error" do
- filters = filters_from_hash(BASE_FILTERS.reject { |k| k == skip_key })
- post(:create, params: {
- job: {
- script: "hash",
- script_version: "master",
- repository: "active/foo",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- },
- filters: filters,
- find_or_create: true,
- })
- assert_includes(405..599, @response.code.to_i,
- "bad status code with missing #{skip_key} filter")
- end
- end
-
test "find Job with script version range" do
get :index, params: {
filters: [["repository", "=", "active/foo"],
jobs(:previous_docker_job_run).uuid)
end
- JOB_SUBMIT_KEYS = [:script, :script_parameters, :script_version, :repository]
- DEFAULT_START_JOB = :previous_job_run
-
- def create_job_params(params, start_from=DEFAULT_START_JOB)
- if not params.has_key?(:find_or_create)
- params[:find_or_create] = true
- end
- job_attrs = params.delete(:job) || {}
- start_job = jobs(start_from)
- params[:job] = Hash[JOB_SUBMIT_KEYS.map do |key|
- [key, start_job.send(key)]
- end]
- params[:job][:runtime_constraints] =
- job_attrs.delete(:runtime_constraints) || {}
- { arvados_sdk_version: :arvados_sdk_version,
- docker_image_locator: :docker_image }.each do |method, constraint_key|
- if constraint_value = start_job.send(method)
- params[:job][:runtime_constraints][constraint_key] ||= constraint_value
- end
- end
- params[:job].merge!(job_attrs)
- params
- end
-
- def create_job_from(params, start_from)
- post(:create, params: create_job_params(params, start_from))
- assert_response :success
- new_job = assigns(:object)
- assert_not_nil new_job
- new_job
- end
-
- def check_new_job_created_from(params, start_from=DEFAULT_START_JOB)
- start_time = Time.now
- new_job = create_job_from(params, start_from)
- assert_operator(start_time, :<=, new_job.created_at)
- new_job
- end
-
- def check_job_reused_from(params, start_from)
- new_job = create_job_from(params, start_from)
- assert_equal(jobs(start_from).uuid, new_job.uuid)
- end
-
- def check_errors_from(params, start_from=DEFAULT_START_JOB)
- post(:create, params: create_job_params(params, start_from))
- assert_includes(405..499, @response.code.to_i)
- errors = json_response.fetch("errors", [])
- assert(errors.any?, "no errors assigned from #{params}")
- refute(errors.any? { |msg| msg =~ /^#<[A-Za-z]+: / },
- "errors include raw exception: #{errors.inspect}")
- errors
- end
-
- # 1de84a8 is on the b1 branch, after master's tip.
- test "new job created from unsatisfiable minimum version filter" do
- filters_hash = BASE_FILTERS.merge("script_version" => ["in git", "1de84a8"])
- check_new_job_created_from(filters: filters_from_hash(filters_hash))
- end
-
- test "new job created from unsatisfiable minimum version parameter" do
- check_new_job_created_from(minimum_script_version: "1de84a8")
- end
-
- test "new job created from unsatisfiable minimum version attribute" do
- check_new_job_created_from(job: {minimum_script_version: "1de84a8"})
- end
-
- test "graceful error from nonexistent minimum version filter" do
- filters_hash = BASE_FILTERS.merge("script_version" =>
- ["in git", "__nosuchbranch__"])
- errors = check_errors_from(filters: filters_from_hash(filters_hash))
- assert(errors.any? { |msg| msg.include? "__nosuchbranch__" },
- "bad refspec not mentioned in error message")
- end
-
- test "graceful error from nonexistent minimum version parameter" do
- errors = check_errors_from(minimum_script_version: "__nosuchbranch__")
- assert(errors.any? { |msg| msg.include? "__nosuchbranch__" },
- "bad refspec not mentioned in error message")
- end
-
- test "graceful error from nonexistent minimum version attribute" do
- errors = check_errors_from(job: {minimum_script_version: "__nosuchbranch__"})
- assert(errors.any? { |msg| msg.include? "__nosuchbranch__" },
- "bad refspec not mentioned in error message")
- end
-
- test "don't reuse job with older Arvados SDK version specified by branch" do
- jobspec = {runtime_constraints: {
- arvados_sdk_version: "master",
- }}
- check_new_job_created_from({job: jobspec},
- :previous_job_run_with_arvados_sdk_version)
- end
-
- test "don't reuse job with older Arvados SDK version specified by commit" do
- jobspec = {runtime_constraints: {
- arvados_sdk_version: "ca68b24e51992e790f29df5cc4bc54ce1da4a1c2",
- }}
- check_new_job_created_from({job: jobspec},
- :previous_job_run_with_arvados_sdk_version)
- end
-
- test "don't reuse job with newer Arvados SDK version specified by commit" do
- jobspec = {runtime_constraints: {
- arvados_sdk_version: "436637c87a1d2bdbf4b624008304064b6cf0e30c",
- }}
- check_new_job_created_from({job: jobspec},
- :previous_job_run_with_arvados_sdk_version)
- end
-
- test "reuse job from arvados_sdk_version git filters" do
- prev_job = jobs(:previous_job_run_with_arvados_sdk_version)
- filters_hash = BASE_FILTERS.
- merge("arvados_sdk_version" => ["in git", "commit2"],
- "docker_image_locator" => ["=", prev_job.docker_image_locator])
- filters_hash.delete("script_version")
- params = create_job_params(filters: filters_from_hash(filters_hash))
- post(:create, params: params)
- assert_response :success
- assert_equal(prev_job.uuid, assigns(:object).uuid)
- end
-
- test "create new job because of arvados_sdk_version 'not in git' filters" do
- filters_hash = BASE_FILTERS.reject { |k| k == "script_version" }
- filters = filters_from_hash(filters_hash)
- # Allow anything from the root commit, but before commit 2.
- filters += [["arvados_sdk_version", "in git", "436637c8"],
- ["arvados_sdk_version", "not in git", "00634b2b"]]
- check_new_job_created_from(filters: filters)
- end
end
class Arvados::V1::JobsControllerTest < ActionController::TestCase
- include GitTestHelper
-
- test "submit a job" do
- authorize_with :active
- post :create, params: {
- job: {
- script: "hash",
- script_version: "master",
- repository: "active/foo",
- script_parameters: {}
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = JSON.parse(@response.body)
- assert_not_nil new_job['uuid']
- assert_not_nil new_job['script_version'].match(/^[0-9a-f]{40}$/)
- assert_equal 0, new_job['priority']
- end
-
- test "normalize output and log uuids when creating job" do
- authorize_with :active
- post :create, params: {
- job: {
- script: "hash",
- script_version: "master",
- script_parameters: {},
- repository: "active/foo",
- started_at: Time.now,
- finished_at: Time.now,
- running: false,
- success: true,
- output: 'd41d8cd98f00b204e9800998ecf8427e+0+K@xyzzy',
- log: 'd41d8cd98f00b204e9800998ecf8427e+0+K@xyzzy'
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- new_job = assigns(:object)
- assert_equal 'd41d8cd98f00b204e9800998ecf8427e+0', new_job['log']
- assert_equal 'd41d8cd98f00b204e9800998ecf8427e+0', new_job['output']
- version = new_job['script_version']
-
- # Make sure version doesn't get mangled by normalize
- assert_not_nil version.match(/^[0-9a-f]{40}$/)
- assert_equal 'master', json_response['supplied_script_version']
- end
-
- test "normalize output and log uuids when updating job" do
- authorize_with :active
-
- foobar_job = jobs(:foobar)
-
- new_output = 'd41d8cd98f00b204e9800998ecf8427e+0+K@xyzzy'
- new_log = 'd41d8cd98f00b204e9800998ecf8427e+0+K@xyzzy'
- put :update, params: {
- id: foobar_job['uuid'],
- job: {
- output: new_output,
- log: new_log
- }
- }
-
- updated_job = json_response
- assert_not_equal foobar_job['log'], updated_job['log']
- assert_not_equal new_log, updated_job['log'] # normalized during update
- assert_equal new_log[0,new_log.rindex('+')], updated_job['log']
- assert_not_equal foobar_job['output'], updated_job['output']
- assert_not_equal new_output, updated_job['output'] # normalized during update
- assert_equal new_output[0,new_output.rindex('+')], updated_job['output']
- end
-
- test "cancel a running job" do
- # We need to verify that "cancel" creates a trigger file, so first
- # let's make sure there is no stale trigger file.
- begin
- File.unlink(Rails.configuration.Containers.JobsAPI.CrunchRefreshTrigger)
- rescue Errno::ENOENT
- end
-
- authorize_with :active
- put :update, params: {
- id: jobs(:running).uuid,
- job: {
- cancelled_at: 4.day.ago
- }
- }
- assert_response :success
- assert_not_nil assigns(:object)
- job = JSON.parse(@response.body)
- assert_not_nil job['uuid']
- assert_not_nil job['cancelled_at']
- assert_not_nil job['cancelled_by_user_uuid']
- assert_not_nil job['cancelled_by_client_uuid']
- assert_equal(true, Time.parse(job['cancelled_at']) > 1.minute.ago,
- 'server should correct bogus cancelled_at ' +
- job['cancelled_at'])
- assert_equal(true,
- File.exist?(Rails.configuration.Containers.JobsAPI.CrunchRefreshTrigger),
- 'trigger file should be created when job is cancelled')
- end
-
- [
- [:put, :update, {job:{cancelled_at: Time.now}}, :success],
- [:put, :update, {job:{cancelled_at: nil}}, :unprocessable_entity],
- [:put, :update, {job:{state: 'Cancelled'}}, :success],
- [:put, :update, {job:{state: 'Queued'}}, :unprocessable_entity],
- [:put, :update, {job:{state: 'Running'}}, :unprocessable_entity],
- [:put, :update, {job:{state: 'Failed'}}, :unprocessable_entity],
- [:put, :update, {job:{state: 'Complete'}}, :unprocessable_entity],
- [:post, :cancel, {}, :success],
- ].each do |http_method, action, params, expected_response|
- test "cancelled job stays cancelled after #{[http_method, action, params].inspect}" do
- # We need to verify that "cancel" creates a trigger file, so first
- # let's make sure there is no stale trigger file.
- begin
- File.unlink(Rails.configuration.Containers.JobsAPI.CrunchRefreshTrigger)
- rescue Errno::ENOENT
- end
-
- authorize_with :active
- self.send http_method, action, params: { id: jobs(:cancelled).uuid }.merge(params)
- assert_response expected_response
- if expected_response == :success
- job = json_response
- assert_not_nil job['cancelled_at'], 'job cancelled again using #{attribute}=#{value} did not have cancelled_at value'
- assert_equal job['state'], 'Cancelled', 'cancelled again job state changed when updated using using #{attribute}=#{value}'
- end
- # Verify database record still says Cancelled
- assert_equal 'Cancelled', Job.find(jobs(:cancelled).id).state, 'job was un-cancelled'
- end
- end
-
- test "cancelled job updated to any other state change results in error" do
- # We need to verify that "cancel" creates a trigger file, so first
- # let's make sure there is no stale trigger file.
- begin
- File.unlink(Rails.configuration.Containers.JobsAPI.CrunchRefreshTrigger)
- rescue Errno::ENOENT
- end
-
- authorize_with :active
- put :update, params: {
- id: jobs(:running_cancelled).uuid,
- job: {
- cancelled_at: nil
- }
- }
- assert_response 422
- end
-
- ['abc.py', 'hash.py'].each do |script|
- test "update job script attribute to #{script} without failing script_version check" do
- authorize_with :admin
- put :update, params: {
- id: jobs(:uses_nonexistent_script_version).uuid,
- job: {
- script: script
- }
- }
- assert_response :success
- resp = assigns(:object)
- assert_equal jobs(:uses_nonexistent_script_version).script_version, resp['script_version']
- end
- end
-
test "search jobs by uuid with >= query" do
authorize_with :active
get :index, params: {
assert_response 422
end
- test "finish a job" do
- authorize_with :active
- put :update, params: {
- id: jobs(:nearly_finished_job).uuid,
- job: {
- output: '551392cc37a317abf865b95f66f4ef94+101',
- log: '9215de2a951a721f5f156bc08cf63ad7+93',
- tasks_summary: {done: 1, running: 0, todo: 0, failed: 0},
- success: true,
- running: false,
- finished_at: Time.now.to_s
- }
- }
- assert_response :success
- end
-
[:spectator, :admin].each_with_index do |which_token, i|
test "get job queue as #{which_token} user" do
authorize_with which_token
get :queue
assert_response :success
- assert_equal i, assigns(:objects).count
- end
- end
-
- test "get job queue as with a = filter" do
- authorize_with :admin
- get :queue, params: { filters: [['script','=','foo']] }
- assert_response :success
- assert_equal ['foo'], assigns(:objects).collect(&:script).uniq
- assert_equal 0, assigns(:objects)[0].queue_position
- end
-
- test "get job queue as with a != filter" do
- authorize_with :admin
- get :queue, params: { filters: [['script','!=','foo']] }
- assert_response :success
- assert_equal 0, assigns(:objects).count
- end
-
- [:spectator, :admin].each do |which_token|
- test "get queue_size as #{which_token} user" do
- authorize_with which_token
- get :queue_size
- assert_response :success
- assert_equal 1, JSON.parse(@response.body)["queue_size"]
+ assert_equal 0, assigns(:objects).count
end
end
assert_equal([nodes(:busy).uuid], json_response["node_uuids"])
end
- test "job lock success" do
- authorize_with :active
- post :lock, params: {id: jobs(:queued).uuid}
- assert_response :success
- job = Job.where(uuid: jobs(:queued).uuid).first
- assert_equal "Running", job.state
- end
-
- test "job lock conflict" do
- authorize_with :active
- post :lock, params: {id: jobs(:running).uuid}
- assert_response 422 # invalid state transition
- end
-
- test 'reject invalid commit in remote repository' do
- authorize_with :active
- url = "http://localhost:1/fake/fake.git"
- fetch_remote_from_local_repo url, :foo
- post :create, params: {
- job: {
- script: "hash",
- script_version: "abc123",
- repository: url,
- script_parameters: {}
- }
- }
- assert_response 422
- end
-
- test 'tag remote commit in internal repository' do
- authorize_with :active
- url = "http://localhost:1/fake/fake.git"
- fetch_remote_from_local_repo url, :foo
- post :create, params: {
- job: {
- script: "hash",
- script_version: "master",
- repository: url,
- script_parameters: {}
- }
- }
- assert_response :success
- assert_equal('077ba2ad3ea24a929091a9e6ce545c93199b8e57',
- internal_tag(json_response['uuid']))
- end
-
- test 'tag local commit in internal repository' do
- authorize_with :active
- post :create, params: {
- job: {
- script: "hash",
- script_version: "master",
- repository: "active/foo",
- script_parameters: {}
- }
- }
- assert_response :success
- assert_equal('077ba2ad3ea24a929091a9e6ce545c93199b8e57',
- internal_tag(json_response['uuid']))
- end
-
test 'get job with components' do
authorize_with :active
get :show, params: {id: jobs(:running_job_with_components).uuid}
assert_not_nil json_response["components"]
assert_equal ["component1", "component2"], json_response["components"].keys
end
-
- [
- [:active, :success],
- [:system_user, :success],
- [:admin, 403],
- ].each do |user, expected|
- test "add components to job locked by active user as #{user} user and expect #{expected}" do
- authorize_with user
- put :update, params: {
- id: jobs(:running).uuid,
- job: {
- components: {"component1" => "value1", "component2" => "value2"}
- }
- }
- assert_response expected
- if expected == :success
- assert_not_nil json_response["components"]
- keys = json_response["components"].keys
- assert_equal ["component1", "component2"], keys
- assert_equal "value1", json_response["components"][keys[0]]
- end
- end
- end
-
- test 'jobs.create disabled in config' do
- Rails.configuration.API.DisabledAPIs = {"jobs.create"=>{},
- "pipeline_instances.create"=>{}}
- authorize_with :active
- post :create, params: {
- job: {
- script: "hash",
- script_version: "master",
- repository: "active/foo",
- script_parameters: {}
- }
- }
- assert_response 404
- end
end
require 'test_helper'
class Arvados::V1::PipelineInstancesControllerTest < ActionController::TestCase
-
- test 'create pipeline with components copied from template' do
- authorize_with :active
- post :create, params: {
- pipeline_instance: {
- pipeline_template_uuid: pipeline_templates(:two_part).uuid
- }
- }
- assert_response :success
- assert_equal(pipeline_templates(:two_part).components.to_json,
- assigns(:object).components.to_json)
- end
-
- test 'create pipeline with no template' do
- authorize_with :active
- post :create, params: {
- pipeline_instance: {
- components: {}
- }
- }
- assert_response :success
- assert_equal({}, assigns(:object).components)
- end
-
- [
- true,
- false
- ].each do |cascade|
- test "cancel a pipeline instance with cascade=#{cascade}" do
- authorize_with :active
- pi_uuid = pipeline_instances(:job_child_pipeline_with_components_at_level_2).uuid
-
- post :cancel, params: {id: pi_uuid, cascade: cascade}
- assert_response :success
-
- pi = PipelineInstance.where(uuid: pi_uuid).first
- assert_equal "Paused", pi.state
-
- children = Job.where(uuid: ['zzzzz-8i9sb-job1atlevel3noc', 'zzzzz-8i9sb-job2atlevel3noc'])
- children.each do |child|
- assert_equal ("Cancelled" == child.state), cascade
- end
- end
- end
end
+++ /dev/null
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: AGPL-3.0
-
-require 'test_helper'
-require 'helpers/git_test_helper'
-
-class CrunchDispatchIntegrationTest < ActionDispatch::IntegrationTest
- include GitTestHelper
-
- fixtures :all
-
- @@crunch_dispatch_pid = nil
-
- def launch_crunch_dispatch
- @@crunch_dispatch_pid = Process.fork {
- ENV['PATH'] = ENV['HOME'] + '/arvados/services/crunch:' + ENV['PATH']
- exec(ENV['HOME'] + '/arvados/services/api/script/crunch-dispatch.rb')
- }
- end
-
- teardown do
- if @@crunch_dispatch_pid
- Process.kill "TERM", @@crunch_dispatch_pid
- Process.wait
- @@crunch_dispatch_pid = nil
- end
- end
-
- test "job runs" do
- post "/arvados/v1/jobs",
- params: {
- format: "json",
- job: {
- script: "log",
- repository: "active/crunchdispatchtest",
- script_version: "f35f99b7d32bac257f5989df02b9f12ee1a9b0d6",
- script_parameters: {
- input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
- an_integer: '1'
- }
- }
- },
- headers: auth(:admin)
- assert_response :success
- end
-end
require 'test_helper'
class JobsApiTest < ActionDispatch::IntegrationTest
- fixtures :all
-
- test "cancel job" do
- post "/arvados/v1/jobs/#{jobs(:running).uuid}/cancel",
- params: {:format => :json},
- headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:active).api_token}"}
- assert_response :success
- assert_equal "arvados#job", json_response['kind']
- assert_not_nil json_response['cancelled_at']
- end
-
- test "cancel someone else's visible job" do
- post "/arvados/v1/jobs/#{jobs(:runningbarbaz).uuid}/cancel",
- params: {:format => :json},
- headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:spectator).api_token}"}
- assert_response 403
- end
-
- test "cancel someone else's invisible job" do
- post "/arvados/v1/jobs/#{jobs(:running).uuid}/cancel",
- params: {:format => :json},
- headers: {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:spectator).api_token}"}
- assert_response 404
- end
-
- test "task qsequence values automatically increase monotonically" do
- post_args = ["/arvados/v1/job_tasks",
- params: {job_task: {
- job_uuid: jobs(:running).uuid,
- sequence: 1,
- }},
- headers: auth(:active)]
- last_qsequence = -1
- (1..3).each do |task_num|
- @response = nil
- post(*post_args)
- assert_response :success
- qsequence = json_response["qsequence"]
- assert_not_nil(qsequence, "task not assigned qsequence")
- assert_operator(qsequence, :>, last_qsequence,
- "qsequence did not increase between tasks")
- last_qsequence = qsequence
- end
- end
-
- test 'get_delete components_get again for job with components' do
- authorize_with :active
- get "/arvados/v1/jobs/#{jobs(:running_job_with_components).uuid}",
- headers: auth(:active)
- assert_response 200
- assert_not_nil json_response["components"]
- assert_equal ["component1", "component2"], json_response["components"].keys
-
- # delete second component
- put "/arvados/v1/jobs/#{jobs(:running_job_with_components).uuid}", params: {
- job: {
- components: {"component1" => "zzzzz-8i9sb-jobuuid00000001"}
- },
- limit: 1000
- }, headers: auth(:active)
- assert_response 200
-
- get "/arvados/v1/jobs/#{jobs(:running_job_with_components).uuid}",
- headers: auth(:active)
- assert_response 200
- assert_not_nil json_response["components"]
- assert_equal ["component1"], json_response["components"].keys
-
- # delete all components
- put "/arvados/v1/jobs/#{jobs(:running_job_with_components).uuid}", params: {
- job: {
- components: nil
- },
- limit: 1000
- }, headers: auth(:active)
- assert_response 200
-
- get "/arvados/v1/jobs/#{jobs(:running_job_with_components).uuid}",
- headers: auth(:active)
- assert_response 200
- assert_not_nil json_response["components"]
- assert_equal [], json_response["components"].keys
- end
end
require 'test_helper'
class PipelineIntegrationTest < ActionDispatch::IntegrationTest
- # These tests simulate the workflow of arv-run-pipeline-instance
- # and other pipeline-running code.
-
- def check_component_match(comp_key, comp_hash)
- assert_response :success
- built_json = json_response
- built_component = built_json["components"][comp_key]
- comp_hash.each_pair do |key, expected|
- assert_equal(expected, built_component[key.to_s],
- "component's #{key} field changed")
- end
- end
-
- test "creating a pipeline instance preserves required component parameters" do
- comp_name = "test_component"
- component = {
- repository: "test_repo",
- script: "test_script",
- script_version: "test_refspec",
- script_parameters: {},
- }
-
- post("/arvados/v1/pipeline_instances",
- params: {
- pipeline_instance: {
- components: {comp_name => component}
- }.to_json
- },
- headers: auth(:active))
- check_component_match(comp_name, component)
- pi_uuid = json_response["uuid"]
-
- @response = nil
- get("/arvados/v1/pipeline_instances/#{pi_uuid}", params: {}, headers: auth(:active))
- check_component_match(comp_name, component)
- end
end
human: {properties: {eye_color: 'gray'}},
- job: {
- repository: 'active/foo',
- runtime_constraints: {docker_image: 'arvados/apitestfixture'},
- script: 'hash',
- script_version: 'master',
- script_parameters: {pattern: 'foobar'},
- tasks_summary: {todo: 0},
- },
-
- job_task: {parameters: {pattern: 'foo'}},
-
link: {link_class: 'test', name: 'test', properties: {foo: :bar}},
node: {info: {uptime: 1234}},
- pipeline_instance: {
- components: {"job1" => {parameters: {pattern: "xyzzy"}}},
- components_summary: {todo: 0},
- properties: {test: true},
- },
-
- pipeline_template: {
- components: {"job1" => {parameters: {pattern: "xyzzy"}}},
- },
-
specimen: {properties: {eye_color: 'meringue'}},
trait: {properties: {eye_color: 'brown'}},
+++ /dev/null
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: AGPL-3.0
-
-require 'test_helper'
-require 'crunch_dispatch'
-require 'helpers/git_test_helper'
-
-class CrunchDispatchTest < ActiveSupport::TestCase
- include GitTestHelper
-
- test 'choose cheaper nodes first' do
- act_as_system_user do
- # Replace test fixtures with a set suitable for testing dispatch
- Node.destroy_all
-
- # Idle nodes with different prices
- [['compute1', 3.20, 32],
- ['compute2', 1.60, 16],
- ['compute3', 0.80, 8]].each do |hostname, price, cores|
- Node.create!(hostname: hostname,
- info: {
- 'slurm_state' => 'idle',
- },
- properties: {
- 'cloud_node' => {
- 'price' => price,
- },
- 'total_cpu_cores' => cores,
- 'total_ram_mb' => cores*1024,
- 'total_scratch_mb' => cores*10000,
- })
- end
-
- # Node with no price information
- Node.create!(hostname: 'compute4',
- info: {
- 'slurm_state' => 'idle',
- },
- properties: {
- 'total_cpu_cores' => 8,
- 'total_ram_mb' => 8192,
- 'total_scratch_mb' => 80000,
- })
-
- # Cheap but busy node
- Node.create!(hostname: 'compute5',
- info: {
- 'slurm_state' => 'alloc',
- },
- properties: {
- 'cloud_node' => {
- 'price' => 0.10,
- },
- 'total_cpu_cores' => 32,
- 'total_ram_mb' => 32768,
- 'total_scratch_mb' => 320000,
- })
- end
-
- dispatch = CrunchDispatch.new
- [[1, 16384, ['compute2']],
- [2, 16384, ['compute2', 'compute1']],
- [2, 8000, ['compute4', 'compute3']],
- ].each do |min_nodes, min_ram, expect_nodes|
- job = Job.new(uuid: 'zzzzz-8i9sb-382lhiizavzhqlp',
- runtime_constraints: {
- 'min_nodes' => min_nodes,
- 'min_ram_mb_per_node' => min_ram,
- })
- nodes = dispatch.nodes_available_for_job_now job
- assert_equal expect_nodes, nodes
- end
- end
-
- test 'respond to TERM' do
- lockfile = Rails.root.join 'tmp', 'dispatch.lock'
- ENV['CRUNCH_DISPATCH_LOCKFILE'] = lockfile.to_s
- begin
- pid = Process.fork do
- begin
- dispatch = CrunchDispatch.new
- dispatch.stubs(:did_recently).returns true
- dispatch.run []
- ensure
- Process.exit!
- end
- end
- assert_with_timeout 5, "Dispatch did not lock #{lockfile}" do
- !can_lock(lockfile)
- end
- ensure
- Process.kill("TERM", pid)
- end
- assert_with_timeout 20, "Dispatch did not unlock #{lockfile}" do
- can_lock(lockfile)
- end
- end
-
- test 'override --cgroup-root with CRUNCH_CGROUP_ROOT' do
- ENV['CRUNCH_CGROUP_ROOT'] = '/path/to/cgroup'
- Rails.configuration.Containers.JobsAPI.CrunchJobWrapper = "none"
- act_as_system_user do
- j = Job.create(repository: 'active/foo',
- script: 'hash',
- script_version: '4fe459abe02d9b365932b8f5dc419439ab4e2577',
- script_parameters: {})
- ok = false
- Open3.expects(:popen3).at_least_once.with do |*args|
- if args.index(j.uuid)
- ok = ((i = args.index '--cgroup-root') and
- (args[i+1] == '/path/to/cgroup'))
- end
- true
- end.raises(StandardError.new('all is well'))
- dispatch = CrunchDispatch.new
- dispatch.parse_argv ['--jobs']
- dispatch.refresh_todo
- dispatch.start_jobs
- assert ok
- end
- end
-
- def assert_with_timeout timeout, message
- t = 0
- while (t += 0.1) < timeout
- if yield
- return
- end
- sleep 0.1
- end
- assert false, message + " (waited #{timeout} seconds)"
- end
-
- def can_lock lockfile
- lockfile.open(File::RDWR|File::CREAT, 0644) do |f|
- return f.flock(File::LOCK_EX|File::LOCK_NB)
- end
- end
-
- test 'rate limit of partial line segments' do
- act_as_system_user do
- Rails.configuration.Containers.Logging.LogPartialLineThrottlePeriod = 1
-
- job = {}
- job[:bytes_logged] = 0
- job[:log_throttle_bytes_so_far] = 0
- job[:log_throttle_lines_so_far] = 0
- job[:log_throttle_bytes_skipped] = 0
- job[:log_throttle_is_open] = true
- job[:log_throttle_partial_line_last_at] = Time.new(0)
- job[:log_throttle_first_partial_line] = true
-
- dispatch = CrunchDispatch.new
-
- line = "first log line"
- limit = dispatch.rate_limit(job, line)
- assert_equal true, limit
- assert_equal "first log line", line
- assert_equal 1, job[:log_throttle_lines_so_far]
-
- # first partial line segment is skipped and counted towards skipped lines
- now = Time.now.strftime('%Y-%m-%d-%H:%M:%S')
- line = "#{now} localhost 100 0 stderr [...] this is first partial line segment [...]"
- limit = dispatch.rate_limit(job, line)
- assert_equal true, limit
- assert_includes line, "Rate-limiting partial segments of long lines", line
- assert_equal 2, job[:log_throttle_lines_so_far]
-
- # next partial line segment within throttle interval is skipped but not counted towards skipped lines
- line = "#{now} localhost 100 0 stderr [...] second partial line segment within the interval [...]"
- limit = dispatch.rate_limit(job, line)
- assert_equal false, limit
- assert_equal 2, job[:log_throttle_lines_so_far]
-
- # next partial line after interval is counted towards skipped lines
- sleep(1)
- line = "#{now} localhost 100 0 stderr [...] third partial line segment after the interval [...]"
- limit = dispatch.rate_limit(job, line)
- assert_equal false, limit
- assert_equal 3, job[:log_throttle_lines_so_far]
-
- # this is not a valid line segment
- line = "#{now} localhost 100 0 stderr [...] does not end with [...] and is not a partial segment"
- limit = dispatch.rate_limit(job, line)
- assert_equal true, limit
- assert_equal "#{now} localhost 100 0 stderr [...] does not end with [...] and is not a partial segment", line
- assert_equal 4, job[:log_throttle_lines_so_far]
-
- # this also is not a valid line segment
- line = "#{now} localhost 100 0 stderr does not start correctly but ends with [...]"
- limit = dispatch.rate_limit(job, line)
- assert_equal true, limit
- assert_equal "#{now} localhost 100 0 stderr does not start correctly but ends with [...]", line
- assert_equal 5, job[:log_throttle_lines_so_far]
- end
- end
-
- test 'scancel orphaned job nodes' do
- Rails.configuration.Containers.JobsAPI.CrunchJobWrapper = "slurm_immediate"
- act_as_system_user do
- dispatch = CrunchDispatch.new
-
- squeue_resp = IO.popen("echo zzzzz-8i9sb-pshmckwoma9plh7\necho thisisnotvalidjobuuid\necho zzzzz-8i9sb-4cf0abc123e809j\necho zzzzz-dz642-o04e3r651turtdr\n")
- scancel_resp = IO.popen("true")
-
- IO.expects(:popen).
- with(['squeue', '-a', '-h', '-o', '%j']).
- returns(squeue_resp)
-
- IO.expects(:popen).
- with(dispatch.sudo_preface + ['scancel', '-n', 'zzzzz-8i9sb-4cf0abc123e809j']).
- returns(scancel_resp)
-
- dispatch.check_orphaned_slurm_jobs
- end
- end
-end
+++ /dev/null
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: AGPL-3.0
-
-require 'test_helper'
-require 'crunch_dispatch'
-
-class FailJobsTest < ActiveSupport::TestCase
- include DbCurrentTime
-
- BOOT_TIME = 1448378837
-
- setup do
- @job = {}
- act_as_user users(:admin) do
- @job[:before_reboot] = Job.create!(state: 'Running',
- running: true,
- started_at: Time.at(BOOT_TIME - 300))
- @job[:after_reboot] = Job.create!(state: 'Running',
- running: true,
- started_at: Time.at(BOOT_TIME + 300))
- @job[:complete] = Job.create!(state: 'Running',
- running: true,
- started_at: Time.at(BOOT_TIME - 300))
- @job[:complete].update_attributes(state: 'Complete')
- @job[:complete].update_attributes(finished_at: Time.at(BOOT_TIME + 100))
- @job[:queued] = jobs(:queued)
-
- @job.values.each do |job|
- # backdate timestamps
- Job.where(uuid: job.uuid).
- update_all(created_at: Time.at(BOOT_TIME - 330),
- modified_at: (job.finished_at ||
- job.started_at ||
- Time.at(BOOT_TIME - 300)))
- end
- end
- @dispatch = CrunchDispatch.new
- @test_start_time = db_current_time
- end
-
- test 'cancel slurm jobs' do
- Rails.configuration.Containers.JobsAPI.CrunchJobWrapper = "slurm_immediate"
- Rails.configuration.Containers.JobsAPI.CrunchJobUser = 'foobar'
- fake_squeue = IO.popen("echo #{@job[:before_reboot].uuid}")
- fake_scancel = IO.popen("true")
- IO.expects(:popen).
- with(['squeue', '-a', '-h', '-o', '%j']).
- returns(fake_squeue)
- IO.expects(:popen).
- with(includes('sudo', '-u', 'foobar', 'scancel', '-n', @job[:before_reboot].uuid)).
- returns(fake_scancel)
- @dispatch.fail_jobs(before: Time.at(BOOT_TIME).to_s)
- assert_end_states
- end
-
- test 'use reboot time' do
- Rails.configuration.Containers.JobsAPI.CrunchJobWrapper = nil
- @dispatch.expects(:open).once.with('/proc/stat').
- returns open(Rails.root.join('test/fixtures/files/proc_stat'))
- @dispatch.fail_jobs(before: 'reboot')
- assert_end_states
- end
-
- test 'command line help' do
- cmd = Rails.root.join('script/fail-jobs.rb').to_s
- assert_match(/Options:.*--before=/m, File.popen([cmd, '--help']).read)
- end
-
- protected
-
- def assert_end_states
- @job.values.map(&:reload)
- assert_equal 'Failed', @job[:before_reboot].state
- assert_equal false, @job[:before_reboot].running
- assert_equal false, @job[:before_reboot].success
- assert_operator @job[:before_reboot].finished_at, :>=, @test_start_time
- assert_operator @job[:before_reboot].finished_at, :<=, db_current_time
- assert_equal 'Running', @job[:after_reboot].state
- assert_equal 'Complete', @job[:complete].state
- assert_equal 'Queued', @job[:queued].state
- end
-end