From bc1947e4aef52fe5f3aebc10dc2ea74cad86672d Mon Sep 17 00:00:00 2001 From: Peter Amstutz Date: Wed, 7 Aug 2019 16:39:55 -0400 Subject: [PATCH 1/1] 15133: API tests passing Arvados-DCO-1.1-Signed-off-by: Peter Amstutz --- .../controllers/arvados/v1/jobs_controller.rb | 7 +- .../arvados/v1/job_reuse_controller_test.rb | 702 ------------------ .../arvados/v1/jobs_controller_test.rb | 307 +------- .../v1/pipeline_instances_controller_test.rb | 44 -- .../test/integration/crunch_dispatch_test.rb | 47 -- .../api/test/integration/jobs_api_test.rb | 83 --- .../api/test/integration/pipeline_test.rb | 36 - .../integration/serialized_encoding_test.rb | 21 - .../api/test/unit/crunch_dispatch_test.rb | 218 ------ services/api/test/unit/fail_jobs_test.rb | 83 --- 10 files changed, 4 insertions(+), 1544 deletions(-) delete mode 100644 services/api/test/integration/crunch_dispatch_test.rb delete mode 100644 services/api/test/unit/crunch_dispatch_test.rb delete mode 100644 services/api/test/unit/fail_jobs_test.rb diff --git a/services/api/app/controllers/arvados/v1/jobs_controller.rb b/services/api/app/controllers/arvados/v1/jobs_controller.rb index f6308c528f..58a3fd168d 100644 --- a/services/api/app/controllers/arvados/v1/jobs_controller.rb +++ b/services/api/app/controllers/arvados/v1/jobs_controller.rb @@ -28,13 +28,12 @@ class Arvados::V1::JobsController < ApplicationController 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 diff --git a/services/api/test/functional/arvados/v1/job_reuse_controller_test.rb b/services/api/test/functional/arvados/v1/job_reuse_controller_test.rb index d10ab6a71b..02c5c6892c 100644 --- a/services/api/test/functional/arvados/v1/job_reuse_controller_test.rb +++ b/services/api/test/functional/arvados/v1/job_reuse_controller_test.rb @@ -8,370 +8,11 @@ require 'helpers/git_test_helper' 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'], @@ -384,217 +25,6 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase 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"], @@ -673,136 +103,4 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase 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 diff --git a/services/api/test/functional/arvados/v1/jobs_controller_test.rb b/services/api/test/functional/arvados/v1/jobs_controller_test.rb index 3803a0dc45..9298f23d54 100644 --- a/services/api/test/functional/arvados/v1/jobs_controller_test.rb +++ b/services/api/test/functional/arvados/v1/jobs_controller_test.rb @@ -7,172 +7,6 @@ require 'helpers/git_test_helper' 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: { @@ -331,52 +165,12 @@ class Arvados::V1::JobsControllerTest < ActionController::TestCase 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 @@ -387,67 +181,6 @@ class Arvados::V1::JobsControllerTest < ActionController::TestCase 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} @@ -455,42 +188,4 @@ class Arvados::V1::JobsControllerTest < ActionController::TestCase 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 diff --git a/services/api/test/functional/arvados/v1/pipeline_instances_controller_test.rb b/services/api/test/functional/arvados/v1/pipeline_instances_controller_test.rb index a76151150f..e455354c11 100644 --- a/services/api/test/functional/arvados/v1/pipeline_instances_controller_test.rb +++ b/services/api/test/functional/arvados/v1/pipeline_instances_controller_test.rb @@ -5,48 +5,4 @@ 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 diff --git a/services/api/test/integration/crunch_dispatch_test.rb b/services/api/test/integration/crunch_dispatch_test.rb deleted file mode 100644 index 6ac127087e..0000000000 --- a/services/api/test/integration/crunch_dispatch_test.rb +++ /dev/null @@ -1,47 +0,0 @@ -# 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 diff --git a/services/api/test/integration/jobs_api_test.rb b/services/api/test/integration/jobs_api_test.rb index f5fb920b46..76d4fff59e 100644 --- a/services/api/test/integration/jobs_api_test.rb +++ b/services/api/test/integration/jobs_api_test.rb @@ -5,87 +5,4 @@ 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 diff --git a/services/api/test/integration/pipeline_test.rb b/services/api/test/integration/pipeline_test.rb index d4f7eba302..4d8f88248a 100644 --- a/services/api/test/integration/pipeline_test.rb +++ b/services/api/test/integration/pipeline_test.rb @@ -5,40 +5,4 @@ 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 diff --git a/services/api/test/integration/serialized_encoding_test.rb b/services/api/test/integration/serialized_encoding_test.rb index 16d43e6f3c..f41c033b39 100644 --- a/services/api/test/integration/serialized_encoding_test.rb +++ b/services/api/test/integration/serialized_encoding_test.rb @@ -15,31 +15,10 @@ class SerializedEncodingTest < ActionDispatch::IntegrationTest 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'}}, diff --git a/services/api/test/unit/crunch_dispatch_test.rb b/services/api/test/unit/crunch_dispatch_test.rb deleted file mode 100644 index 3a8f90a66b..0000000000 --- a/services/api/test/unit/crunch_dispatch_test.rb +++ /dev/null @@ -1,218 +0,0 @@ -# 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 diff --git a/services/api/test/unit/fail_jobs_test.rb b/services/api/test/unit/fail_jobs_test.rb deleted file mode 100644 index 304335c6f0..0000000000 --- a/services/api/test/unit/fail_jobs_test.rb +++ /dev/null @@ -1,83 +0,0 @@ -# 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 -- 2.30.2