#!/usr/bin/env pytest

#testreq: personal
"""<<CONDOR_TESTREQ_CONFIG
	# make sure that file transfer plugins are enabled (might be disabled by default)
	ENABLE_URL_TRANSFERS = true
	FILETRANSFER_PLUGINS = $(FILETRANSFER_PLUGINS) $(LIBEXEC)/curl_plugin $(LIBEXEC)/data_plugin
"""
#endtestreq


import logging
import classad2 as classad
import re
from ornithology import *

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

PLUGIN_EXIT_CODE = 17

@action
def submitJobInputFailureAP(default_condor):
    return default_condor.submit(
        {
           "log": "job_ap_input.log",
           "executable": "/bin/sleep",
           "arguments": "0",
           "transfer_executable": "false",
           "should_transfer_files": "yes",
           "transfer_input_files": "not_there_in",
        }
    )


@action
def jobInputFailureAP(submitJobInputFailureAP):
   assert submitJobInputFailureAP.wait(condition=ClusterState.all_held,timeout=60)
   return submitJobInputFailureAP.query()[0]


@action
def submitJobOutputFailureAP(default_condor):
   return default_condor.submit(
        {
           "log": "job_ap_output.log",
           "executable": "/bin/sleep",
           "arguments": "0",
           "transfer_executable": "false",
           "should_transfer_files": "yes",
           "transfer_input_files": "/bin/date",
           "transfer_output_files": "date",
           "transfer_output_remaps": classad.quote("date=/not_there_dir/blah"),
        }
    )


@action
def jobOutputFailureAP(submitJobOutputFailureAP):
   assert submitJobOutputFailureAP.wait(condition=ClusterState.all_held,timeout=60)
   return submitJobOutputFailureAP.query()[0]


@action
def submitJobInputFailureEP(default_condor):
   return default_condor.submit(
        {
           "log": "job_ep_input.log",
           "executable": "/bin/sleep",
           "arguments": "0",
           "transfer_executable": "false",
           "should_transfer_files": "yes",
           "transfer_input_files": "http://nonexistent.invalid/index.html",
        }
    )


@action
def jobInputFailureEP(submitJobInputFailureEP):
   assert submitJobInputFailureEP.wait(condition=ClusterState.all_held,timeout=180)
   return submitJobInputFailureEP.query()[0]


@action
def submitJobOutputFailureEP(default_condor):
   return default_condor.submit(
        {
           "log": "job_ep_output.log",
           "executable": "/bin/sleep",
           "arguments": "0",
           "transfer_executable": "false",
           "should_transfer_files": "yes",
           "transfer_output_files": "not_there_out",
        }
    )


@action
def jobOutputFailureEP(submitJobOutputFailureEP):
   assert submitJobOutputFailureEP.wait(condition=ClusterState.all_held,timeout=60)
   return submitJobOutputFailureEP.query()[0]


@action
def submitJobPluginInputFailureEP(default_condor, test_dir, path_to_sleep):
   return default_condor.submit(
        {
           "log": "job_ep_output_plugin.log",
           "executable": path_to_sleep,
           "arguments": "0",
           "transfer_executable": "false",
           "should_transfer_files": "yes",

           "transfer_input_files": f"debug://exit/{PLUGIN_EXIT_CODE}",
        }
    )


@action
def jobPluginInputFailureEP(submitJobPluginInputFailureEP):
   assert submitJobPluginInputFailureEP.wait(condition=ClusterState.all_held,timeout=60)
   return submitJobPluginInputFailureEP.query()[0]


@action
def submitJobPluginOutputFailureEP(default_condor, test_dir, path_to_sleep):
   return default_condor.submit(
        {
           "log": "job_ep_output_plugin.log",
           "executable": path_to_sleep,
           "arguments": "0",
           "transfer_executable": "false",
           "should_transfer_files": "yes",

           "transfer_output_files": "foo",
           "transfer_output_remaps": f'"foo=debug://exit/{PLUGIN_EXIT_CODE}"',
        }
    )


@action
def jobPluginOutputFailureEP(submitJobPluginOutputFailureEP):
   assert submitJobPluginOutputFailureEP.wait(condition=ClusterState.all_held,timeout=60)
   return submitJobPluginOutputFailureEP.query()[0]


@action
def submitJobCredFailureAP(default_condor):
   return default_condor.submit(
        {
           "log": "job_ap_cred.log",
           "executable": "/bin/sleep",
           "arguments": "0",
           "transfer_executable": "false",
           "MY.OAuthServicesNeeded": classad.quote("broken_token"),
        }
    )


@action
def jobCredFailureAP(submitJobCredFailureAP):
   assert submitJobCredFailureAP.wait(condition=ClusterState.all_held,timeout=60)
   return submitJobCredFailureAP.query()[0]


def check_reason_string(reason: str, direction: str, source: str):
    assert re.search(rf"Transfer {direction} files failure at (?:the )?{source}", reason)


class TestXferHoldCodes:
   def test_submit_all(self,
      submitJobInputFailureAP, submitJobOutputFailureAP,
      submitJobInputFailureEP, submitJobOutputFailureEP,
      submitJobCredFailureAP,
      submitJobPluginOutputFailureEP, submitJobPluginInputFailureEP
   ):
       assert True


   def test_jobInputFailureAP(self, jobInputFailureAP):
      assert jobInputFailureAP["HoldReasonCode"] == 13
      check_reason_string(jobInputFailureAP["HoldReason"], "input", "access point")


   def test_jobOutputFailureAP(self, jobOutputFailureAP):
      assert jobOutputFailureAP["HoldReasonCode"] == 12
      check_reason_string(jobOutputFailureAP["HoldReason"], "output", "access point")


   def test_jobInputFailureEP(self, jobInputFailureEP):
      assert jobInputFailureEP["HoldReasonCode"] == 13
      assert jobInputFailureEP["HoldReasonSubCode"] == (1 << 8)
      check_reason_string(jobInputFailureEP["HoldReason"], "input", "execution point")


   def test_jobOutputFailureEP(self, jobOutputFailureEP):
      assert jobOutputFailureEP["HoldReasonCode"] == 12
      assert jobOutputFailureEP["HoldReasonSubCode"] == 2
      check_reason_string(jobOutputFailureEP["HoldReason"], "output", "execution point")


   def test_jobCredFailureAP(self, jobCredFailureAP):
      assert jobCredFailureAP["HoldReasonCode"] == 4
      assert "Job credentials are not available" in jobCredFailureAP["HoldReason"]


   def test_jobPluginOutputFailureEP(self, jobPluginOutputFailureEP):
      assert jobPluginOutputFailureEP["HoldReasonCode"] == 12
      assert jobPluginOutputFailureEP["HoldReasonSubCode"] == (PLUGIN_EXIT_CODE << 8)
      check_reason_string(jobPluginOutputFailureEP["HoldReason"], "output", "execution point")


   def test_jobPluginInputFailureEP(self, jobPluginInputFailureEP):
      assert jobPluginInputFailureEP["HoldReasonCode"] == 13
      assert jobPluginInputFailureEP["HoldReasonSubCode"] == (PLUGIN_EXIT_CODE << 8)
      check_reason_string(jobPluginInputFailureEP["HoldReason"], "input", "execution point")
