def test_batch_jobs(self, **kwargs):
        client = self.create_sharedkey_client(**kwargs)
        # Test Create Job
        auto_pool = models.AutoPoolSpecification(
            pool_lifetime_option=models.PoolLifetimeOption.job,
            pool=models.PoolSpecification(
                vm_size='small',
                cloud_service_configuration=models.CloudServiceConfiguration(
                    os_family='5'
                )
            )
        )
        job_prep = models.JobPreparationTask(command_line="cmd /c \"echo hello world\"")
        job_release = models.JobReleaseTask(command_line="cmd /c \"echo goodbye world\"")
        job_param = models.JobAddParameter(
            id=self.get_resource_name('batch_job1_'),
            pool_info=models.PoolInformation(
                auto_pool_specification=auto_pool
            ),
            job_preparation_task=job_prep,
            job_release_task=job_release
        )
        response = client.job.add(job_param)
        self.assertIsNone(response)

        # Test Update Job
        constraints = models.JobConstraints(max_task_retry_count=3)
        options = models.JobUpdateParameter(
            priority=500,
            constraints=constraints,
            pool_info=models.PoolInformation(
                auto_pool_specification=auto_pool
            )
        )
        response = client.job.update(job_param.id, options)
        self.assertIsNone(response)

        # Test Patch Job
        options = models.JobPatchParameter(priority=900)
        response = client.job.patch(job_param.id, options)
        self.assertIsNone(response)

        job = client.job.get(job_param.id)
        self.assertIsInstance(job, models.CloudJob)
        self.assertEqual(job.id, job_param.id)
        self.assertEqual(job.constraints.max_task_retry_count, 3)
        self.assertEqual(job.priority, 900)

        # Test Create Job with Auto Complete
        job_auto_param = models.JobAddParameter(
            id=self.get_resource_name('batch_job2_'),
            on_all_tasks_complete=models.OnAllTasksComplete.terminate_job,
            on_task_failure=models.OnTaskFailure.perform_exit_options_job_action,
            pool_info=models.PoolInformation(
                auto_pool_specification=auto_pool
            )
        )
        response = client.job.add(job_auto_param)
        self.assertIsNone(response)
        job = client.job.get(job_auto_param.id)
        self.assertIsInstance(job, models.CloudJob)
        self.assertEqual(job.on_all_tasks_complete, models.OnAllTasksComplete.terminate_job)
        self.assertEqual(job.on_task_failure, models.OnTaskFailure.perform_exit_options_job_action)

        # Test List Jobs
        jobs = client.job.list()
        self.assertIsInstance(jobs, models.CloudJobPaged)
        self.assertEqual(len(list(jobs)), 2)

        # Test Disable Job
        response = client.job.disable(job_param.id, models.DisableJobOption.requeue)
        self.assertIsNone(response)

        # Test Enable Job
        response = client.job.enable(job_param.id)
        self.assertIsNone(response)

        # Prep and release task status
        task_status = client.job.list_preparation_and_release_task_status(job_param.id)
        self.assertIsInstance(task_status, models.JobPreparationAndReleaseTaskExecutionInformationPaged)
        self.assertEqual(list(task_status), [])

        # Test Terminate Job
        response = client.job.terminate(job_param.id)
        self.assertIsNone(response)

        # Test Delete Job
        response = client.job.delete(job_auto_param.id)
        self.assertIsNone(response)

        # Test Job Lifetime Statistics
        stats = client.job.get_all_lifetime_statistics()
        self.assertIsInstance(stats, models.JobStatistics)
        self.assertEqual(stats.num_succeeded_tasks, 0)
        self.assertEqual(stats.num_failed_tasks, 0)
def retarget_job_to_new_pool(batch_service_client: batch.BatchExtensionsClient,
                             job_id: str, new_pool_id: str):
    """ Disables a job with task requeue, then patches it to target a new pool.
    
    :param batch_service_client: The batch client used for making batch operations
    :type batch_service_client: `azure.batch.BatchExtensionsClient`
    :param job_id: The job to retarget
    :type job_id: str
    :param new_pool_id: The id of the new pool
    :type new_pool_id: str
    """
    logger.info("Retargeting job [{}] to new pool [{}]".format(
        job_id, new_pool_id))

    try:

        batch_service_client.job.disable(job_id, "requeue")

    except batchmodels.BatchErrorException as batch_exception:
        # potential race condition where the nodes have gone idle and the job has 'Completed' between our internal
        # node-idle-timeout check and the call to disable the job. Just return in this case
        if expected_exception(batch_exception,
                              "The specified job does not exist"):
            logger.info(
                "The specified Job [{}] did not exist when we tried to delete it."
                .format(job_id))
            raise ex.JobAlreadyCompleteException(
                job_id, "Job already complete and deleted.")

        if expected_exception(
                batch_exception,
                "The specified job is already in a completed state"):
            logger.info(
                "The specified Job [{}] was already in completed state when we tried to delete it."
                .format(job_id))
            raise ex.JobAlreadyCompleteException(job_id,
                                                 "Job already complete.")
        raise

    # give the job time to move to disabled state before we try Patch it
    time.sleep(service_state_transition_seconds)

    looping_job_patch = True
    job_patch_retry_count = 0
    while looping_job_patch:
        try:
            batch_service_client.job.patch(
                job_id,
                batchmodels.JobPatchParameter(
                    pool_info=batchmodels.PoolInformation(
                        pool_id=new_pool_id)))
            looping_job_patch = False
        except batchmodels.BatchErrorException as batch_exception:
            if expected_exception(
                    batch_exception,
                    "The specified operation is not valid for the current state of the resource"
            ):
                if job_patch_retry_count > 10:
                    logger.error(
                        "Exhausted retries and Failed to patch job [{}] due to the current state of the resource"
                        .format(job_id))
                    raise
                logger.info(
                    "Failed to patch job [{}] due to the current state of the resource, retrying...."
                    .format(job_id))
                time.sleep(5)
                job_patch_retry_count = job_patch_retry_count + 1

    logger.info("Successfully retargeted job [{}] to pool [{}]".format(
        job_id, new_pool_id))