4651: Merge branch 'master' into 4651-boolean-params
[arvados.git] / services / api / test / functional / arvados / v1 / job_reuse_controller_test.rb
index b00fbf11c66f49a7799da07ed296535331f69aa0..9b66851d7e0dc8885876b0b7b179c7e063782ed8 100644 (file)
@@ -1,11 +1,11 @@
 require 'test_helper'
-load 'test/functional/arvados/v1/git_setup.rb'
+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 GitSetup
+  include GitTestHelper
 
   setup do
     @controller = Arvados::V1::JobsController.new
@@ -50,6 +50,26 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
     assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
   end
 
+  test "reuse job with symbolic script_version" do
+    post :create, {
+      job: {
+        script: "hash",
+        script_version: "tag1",
+        repository: "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, {
       job: {
@@ -70,7 +90,30 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
     assert_equal '4fe459abe02d9b365932b8f5dc419439ab4e2577', new_job['script_version']
   end
 
-  test "do not reuse job because find_or_create=false" do
+  [false, "false"].each do |whichfalse|
+    test "do not reuse job because find_or_create=#{whichfalse.inspect}" do
+      post :create, {
+        job: {
+          script: "hash",
+          script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
+          repository: "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, {
       job: {
         script: "hash",
@@ -81,7 +124,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
           an_integer: '1'
         }
       },
-      find_or_create: false
+      find_or_create: true
     }
     assert_response :success
     assert_not_nil assigns(:object)
@@ -253,7 +296,8 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
     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']
+    assert_not_equal('4fe459abe02d9b365932b8f5dc419439ab4e2577',
+                     new_job['script_version'])
   end
 
   test "cannot reuse job with find_or_create but excluded version" do
@@ -275,7 +319,8 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
     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']
+    assert_not_equal('4fe459abe02d9b365932b8f5dc419439ab4e2577',
+                     new_job['script_version'])
   end
 
   BASE_FILTERS = {
@@ -283,6 +328,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
     'script' => ['=', 'hash'],
     'script_version' => ['in git', 'master'],
     'docker_image_locator' => ['=', nil],
+    'arvados_sdk_version' => ['=', nil],
   }
 
   def filters_from_hash(hash)
@@ -290,7 +336,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
   end
 
   test "can reuse a Job based on filters" do
-    filter_h = BASE_FILTERS.
+    filters_hash = BASE_FILTERS.
       merge('script_version' => ['in git', 'tag1'])
     post(:create, {
            job: {
@@ -302,7 +348,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
                an_integer: '1'
              }
            },
-           filters: filters_from_hash(filter_h),
+           filters: filters_from_hash(filters_hash),
            find_or_create: true,
          })
     assert_response :success
@@ -313,10 +359,11 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
   end
 
   test "can not reuse a Job based on filters" do
-    filter_a = filters_from_hash(BASE_FILTERS.reject { |k| k == 'script_version' })
-    filter_a += [["script_version", "in git",
-                  "31ce37fe365b3dc204300a3e4c396ad333ed0556"],
-                 ["script_version", "not in git", ["tag1"]]]
+    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, {
            job: {
              script: "hash",
@@ -327,7 +374,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
                an_integer: '1'
              }
            },
-           filters: filter_a,
+           filters: filters,
            find_or_create: true,
          })
     assert_response :success
@@ -338,7 +385,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
   end
 
   test "can not reuse a Job based on arbitrary filters" do
-    filter_h = BASE_FILTERS.
+    filters_hash = BASE_FILTERS.
       merge("created_at" => ["<", "2010-01-01T00:00:00Z"])
     post(:create, {
            job: {
@@ -350,7 +397,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
                an_integer: '1'
              }
            },
-           filters: filters_from_hash(filter_h),
+           filters: filters_from_hash(filters_hash),
            find_or_create: true,
          })
     assert_response :success
@@ -386,7 +433,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
   end
 
   test "can reuse a Job with a Docker image hash filter" do
-    filter_h = BASE_FILTERS.
+    filters_hash = BASE_FILTERS.
       merge("script_version" =>
               ["=", "4fe459abe02d9b365932b8f5dc419439ab4e2577"],
             "docker_image_locator" =>
@@ -401,7 +448,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
                an_integer: '1'
              },
            },
-           filters: filters_from_hash(filter_h),
+           filters: filters_from_hash(filters_hash),
            find_or_create: true,
          })
     assert_response :success
@@ -414,7 +461,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
   end
 
   test "reuse Job with Docker image repo+tag" do
-    filter_h = BASE_FILTERS.
+    filters_hash = BASE_FILTERS.
       merge("script_version" =>
               ["=", "4fe459abe02d9b365932b8f5dc419439ab4e2577"],
             "docker_image_locator" =>
@@ -429,7 +476,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
                an_integer: '1'
              },
            },
-           filters: filters_from_hash(filter_h),
+           filters: filters_from_hash(filters_hash),
            find_or_create: true,
          })
     assert_response :success
@@ -442,7 +489,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
   end
 
   test "new job with unknown Docker image filter" do
-    filter_h = BASE_FILTERS.
+    filters_hash = BASE_FILTERS.
       merge("docker_image_locator" => ["in docker", "_nonesuchname_"])
     post(:create, {
            job: {
@@ -454,7 +501,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
                an_integer: '1'
              },
            },
-           filters: filters_from_hash(filter_h),
+           filters: filters_from_hash(filters_hash),
            find_or_create: true,
          })
     assert_response :success
@@ -465,7 +512,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
 
   ["repository", "script"].each do |skip_key|
     test "missing #{skip_key} filter raises an error" do
-      filter_a = filters_from_hash(BASE_FILTERS.reject { |k| k == skip_key })
+      filters = filters_from_hash(BASE_FILTERS.reject { |k| k == skip_key })
       post(:create, {
              job: {
                script: "hash",
@@ -476,7 +523,7 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
                  an_integer: '1'
                }
              },
-             filters: filter_a,
+             filters: filters,
              find_or_create: true,
            })
       assert_includes(405..599, @response.code.to_i,
@@ -551,4 +598,107 @@ class Arvados::V1::JobReuseControllerTest < ActionController::TestCase
     refute_includes(assigns(:objects).map { |job| job.uuid },
                     jobs(:previous_docker_job_run).uuid)
   end
+
+  def create_foo_hash_job_params(params)
+    if not params.has_key?(:find_or_create)
+      params[:find_or_create] = true
+    end
+    job_attrs = params.delete(:job) || {}
+    params[:job] = {
+      script: "hash",
+      script_version: "4fe459abe02d9b365932b8f5dc419439ab4e2577",
+      repository: "foo",
+      script_parameters: {
+        input: 'fa7aeb5140e2848d39b416daeef4ffc5+45',
+        an_integer: '1',
+      },
+    }.merge(job_attrs)
+    params
+  end
+
+  def check_new_job_created_from(params)
+    start_time = Time.now
+    post(:create, create_foo_hash_job_params(params))
+    assert_response :success
+    new_job = assigns(:object)
+    assert_not_nil new_job
+    assert_operator(start_time, :<=, new_job.created_at)
+    new_job
+  end
+
+  def check_errors_from(params)
+    post(:create, create_foo_hash_job_params(params))
+    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
+  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 "can't reuse job with older Arvados SDK version" do
+    params = {
+      script_version: "31ce37fe365b3dc204300a3e4c396ad333ed0556",
+      runtime_constraints: {
+        "arvados_sdk_version" => "master",
+        "docker_image" => links(:docker_image_collection_tag).name,
+      },
+    }
+    check_new_job_created_from(job: params)
+  end
+
+  test "reuse job from arvados_sdk_version git filters" do
+    filters_hash = BASE_FILTERS.
+      merge("arvados_sdk_version" => ["in git", "commit2"])
+    filters_hash.delete("script_version")
+    params = create_foo_hash_job_params(filters:
+                                        filters_from_hash(filters_hash))
+    post(:create, params)
+    assert_response :success
+    assert_equal(jobs(:previous_job_run_with_arvados_sdk_version).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