def test_list(self, batch_p, get_p): batch_p.return_value = V1JobList( items=[V1Pod(metadata=V1ObjectMeta(name='drwho-cate-sdav'))]) get_p.return_value = { 'cubegen_id': 'id', 'status': 'Ready', 'output': ['bla'], 'progress': 100 } res = cubegens.list('drwho') self.assertEqual(1, len(res)) self.assertDictEqual( { 'cubegen_id': 'id', 'status': 'Ready', 'output': ['bla'], 'progress': 100 }, res[0]) batch_p.side_effect = ApiException(401, 'Unauthorized') with self.assertRaises(api.ApiError) as e: cubegens.list(user_id='drwho') self.assertIn("Reason: Unauthorized", str(e.exception)) self.assertIn("401", str(e.exception)) self.assertEqual(400, e.exception.status_code)
def test_fetch_jobs_continue(self, mock_batch_client): _continue = "xyz" mock_batch_client.list_namespaced_job.side_effect = [ V1JobList( items=[V1Job(metadata=V1ObjectMeta(name="1"))], metadata=V1ListMeta(_continue=_continue), ), V1JobList( items=[V1Job(metadata=V1ObjectMeta(name="2"))], metadata=V1ListMeta() ), ] namespace = "blech" manager = JobManager( namespace=namespace, signer=Mock(), register=StaticJobDefinitionsRegister() ) assert len(list(manager.fetch_jobs())) == 2 assert mock_batch_client.list_namespaced_job.call_count == 2 mock_batch_client.list_namespaced_job.assert_called_with( namespace=namespace, _continue=_continue )
def test_fetch_jobs_filters(self, mock_batch_client): mock_batch_client.list_namespaced_job.return_value = V1JobList( items=[V1Job(metadata=V1ObjectMeta(name="1"))], metadata=V1ListMeta() ) namespace = "hellomoto" signer = JobSigner("foo") manager = JobManager( namespace=namespace, signer=signer, register=StaticJobDefinitionsRegister() ) assert len(list(manager.fetch_jobs(extra="filter"))) == 1 mock_batch_client.list_namespaced_job.assert_called_once_with( namespace=namespace, label_selector=signer.label_selector(extra="filter") )
def test_fetch_jobs_job_definition_name(self, mock_batch_client): namespace = "phd" signer = JobSigner("school") manager = JobManager( namespace=namespace, signer=signer, register=StaticJobDefinitionsRegister() ) job_definition_name = "jd" mock_batch_client.list_namespaced_job.return_value = V1JobList( items=[], metadata=V1ListMeta() ) list(manager.fetch_jobs(job_definition_name)) mock_batch_client.list_namespaced_job.assert_called_once_with( namespace=namespace, label_selector=signer.label_selector(job_definition_name), )
def test_logs(self, pod_read_p, pod_p): pod_p.return_value = V1JobList( items=[V1Pod(metadata=V1ObjectMeta(name='drwho-cate-sdav'))]) pod_read_p.return_value = 'bla' res = cubegens.logs('drwho') self.assertEqual(1, len(res)) self.assertEqual([ 'bla', ], res) pod_p.side_effect = ApiException(401, 'Unauthorized') with self.assertRaises(api.ApiError) as e: cubegens.logs('drwho', raises=True) self.assertIn("Reason: Unauthorized", str(e.exception)) self.assertIn("401", str(e.exception)) self.assertEqual(400, e.exception.status_code)
def test_delete_complete_jobs_raises_server_error(api: MagicMock, batch_api: MagicMock): batch_api.list_namespaced_job.return_value = V1JobList(items=[ # delete because complete V1Job( metadata=V1ObjectMeta( name="flush-pv-1", uid="uid-flush-pv-1", resource_version="1"), status=V1JobStatus( conditions=[V1JobCondition(status="", type="Complete")]), ), ]) def delete_job(name, namespace, body): raise ApiException(reason="Server Error") batch_api.delete_namespaced_job.side_effect = delete_job with pytest.raises(ApiException): delete_complete_jobs(api, batch_api, "namespace") batch_api.list_namespaced_job.called_once_with("namespace")
def test_flush_released_pvs(api: MagicMock, batch_api: MagicMock): api.list_persistent_volume.return_value = V1PersistentVolumeList( items=[ # don't flush because job exists V1PersistentVolume(metadata=V1ObjectMeta(name="pv-0")), # don't flush because wrong namespace V1PersistentVolume( metadata=V1ObjectMeta(name="pv-4"), spec=V1PersistentVolumeSpec( claim_ref=V1ObjectReference(namespace="other"), persistent_volume_reclaim_policy="Retain", ), status=V1PersistentVolumeStatus(phase="Released"), ), # don't flush because it's already done V1PersistentVolume( metadata=V1ObjectMeta(name="pv-5"), spec=V1PersistentVolumeSpec( claim_ref=V1ObjectReference(namespace="namespace"), persistent_volume_reclaim_policy="Delete", ), status=V1PersistentVolumeStatus(phase="Released"), ), # don't flush because it's in use V1PersistentVolume( metadata=V1ObjectMeta(name="pv-6"), spec=V1PersistentVolumeSpec( claim_ref=V1ObjectReference( name="queue-web-0", namespace="namespace" ), persistent_volume_reclaim_policy="Retain", ), status=V1PersistentVolumeStatus(phase="Bound"), ), # try to flush because pvc is bound but job was created after jobs were listed V1PersistentVolume( metadata=V1ObjectMeta(name="pv-7"), spec=V1PersistentVolumeSpec( claim_ref=V1ObjectReference( name="flush-pv-7", namespace="namespace" ), persistent_volume_reclaim_policy="Retain", ), status=V1PersistentVolumeStatus(phase="Bound"), ), # flush because pvc is bound but job does not exist V1PersistentVolume( metadata=V1ObjectMeta(name="pv-8"), spec=V1PersistentVolumeSpec( claim_ref=V1ObjectReference( name="flush-pv-8", namespace="namespace" ), persistent_volume_reclaim_policy="Retain", ), status=V1PersistentVolumeStatus(phase="Bound"), ), # flush because pvc is not yet bound and job does not exist V1PersistentVolume( metadata=V1ObjectMeta(name="pv-9"), spec=V1PersistentVolumeSpec( claim_ref=V1ObjectReference( name="queue-web-0", namespace="namespace" ), persistent_volume_reclaim_policy="Retain", ), status=V1PersistentVolumeStatus(phase="Released"), ), # flush because pvc and job both do not exist V1PersistentVolume( metadata=V1ObjectMeta(name="pv-A"), spec=V1PersistentVolumeSpec( claim_ref=V1ObjectReference( name="queue-web-0", namespace="namespace" ), persistent_volume_reclaim_policy="Retain", ), status=V1PersistentVolumeStatus(phase="Released"), ), ] ) def create_pvc(namespace: str, body: V1PersistentVolumeClaim): if body.metadata.name == "flush-pv-9": exc = ApiException(status=409, reason="Conflict") exc.body = '{"reason":"AlreadyExists"}' raise exc body.metadata.uid = "uid-" + body.metadata.name body.metadata.resource_version = "1" return body api.create_namespaced_persistent_volume_claim.side_effect = create_pvc def read_pvc(name: str, namespace: str): return V1PersistentVolumeClaim( metadata=V1ObjectMeta( name=name, namespace=namespace, uid="uid-" + name, resource_version="2" ) ) api.read_namespaced_persistent_volume_claim.side_effect = read_pvc batch_api.list_namespaced_job.return_value = V1JobList( items=[V1Job(metadata=V1ObjectMeta(name="flush-pv-0"))] ) def create_job(namespace, body): if body.metadata.name == "flush-pv-7": exc = ApiException(status=409, reason="Conflict") exc.body = '{"reason":"AlreadyExists"}' raise exc batch_api.create_namespaced_job.side_effect = create_job flush_released_pvs(api, batch_api, "command", "env", "image", "namespace") api.list_persistent_volume.assert_called_once_with() batch_api.list_namespaced_job.assert_called_once_with("namespace") assert [f"flush-pv-{i}" for i in "9A"] == [ call.kwargs["body"].metadata.name for call in api.create_namespaced_persistent_volume_claim.call_args_list ] api.read_namespaced_persistent_volume_claim.assert_called_once_with( "flush-pv-9", "namespace" ) assert [("pv-9", "flush-pv-9"), ("pv-A", "flush-pv-A"),] == [ ( call.kwargs["name"], call.kwargs["body"].spec.claim_ref and call.kwargs["body"].spec.claim_ref.name, ) for call in api.patch_persistent_volume.call_args_list ] assert [f"flush-pv-{i}" for i in "789A"] == [ call.kwargs["body"].metadata.name for call in batch_api.create_namespaced_job.call_args_list ] batch_api.read_namespaced_job.assert_called_once_with("flush-pv-7", "namespace")
def test_delete_complete_jobs(api: MagicMock, batch_api: MagicMock): batch_api.list_namespaced_job.return_value = V1JobList(items=[ # delete because complete *(V1Job( metadata=V1ObjectMeta( name=f"flush-pv-{i}", uid=f"uid-flush-pv-{i}", resource_version=f"{i}", ), status=V1JobStatus( conditions=[V1JobCondition(status="", type="Complete")]), ) for i in range(3)), # don't delete because already deleted V1Job( metadata=V1ObjectMeta( name="flush-pv-3", deletion_timestamp=datetime.utcnow(), ), status=V1JobStatus( conditions=[V1JobCondition(status="", type="Complete")]), ), # don't delete because not complete V1Job( metadata=V1ObjectMeta(name="flush-pv-4"), status=V1JobStatus( conditions=[V1JobCondition(status="", type="Pending")]), ), # don't delete because status does not contain conditions V1Job(metadata=V1ObjectMeta(name="flush-pv-5"), status=V1JobStatus()), # don't delete because not a flush job V1Job( metadata=V1ObjectMeta(name="cron-1"), status=V1JobStatus( conditions=[V1JobCondition(status="", type="Complete")]), ), ]) def delete_job(name, namespace, body): if name == "flush-pv-1": raise ApiException(reason="Conflict") if name == "flush-pv-2": raise ApiException(reason="Not Found") batch_api.delete_namespaced_job.side_effect = delete_job delete_complete_jobs(api, batch_api, "namespace") batch_api.list_namespaced_job.assert_called_once_with("namespace") assert [(f"pv-{i}", "Delete") for i in range(3)] == [( call.kwargs["name"], call.kwargs["body"].spec.persistent_volume_reclaim_policy, ) for call in api.patch_persistent_volume.call_args_list] assert [(f"flush-pv-{i}", "namespace", [ ("Job", f"flush-pv-{i}") ]) for i in range(3)] == [( call.kwargs["name"], call.kwargs["namespace"], [(ref.kind, ref.name) for ref in call.kwargs["body"].metadata.owner_references], ) for call in api.patch_namespaced_persistent_volume_claim.call_args_list] assert [(f"flush-pv-{i}", "namespace", f"uid-flush-pv-{i}", f"{i}") for i in range(3)] == [( call.kwargs["name"], call.kwargs["namespace"], call.kwargs["body"].preconditions.uid, call.kwargs["body"].preconditions.resource_version, ) for call in batch_api.delete_namespaced_job.call_args_list]