panda-server-source 0.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- panda_server_source-0.8.0.dist-info/METADATA +55 -0
- panda_server_source-0.8.0.dist-info/RECORD +375 -0
- panda_server_source-0.8.0.dist-info/WHEEL +4 -0
- panda_server_source-0.8.0.dist-info/licenses/LICENSE.txt +202 -0
- pandajedi/__init__.py +0 -0
- pandajedi/jedibrokerage/AtlasAnalJobBroker.py +2343 -0
- pandajedi/jedibrokerage/AtlasBrokerUtils.py +1292 -0
- pandajedi/jedibrokerage/AtlasProdJobBroker.py +2064 -0
- pandajedi/jedibrokerage/AtlasProdTaskBroker.py +629 -0
- pandajedi/jedibrokerage/GenJobBroker.py +381 -0
- pandajedi/jedibrokerage/JobBrokerBase.py +133 -0
- pandajedi/jedibrokerage/TaskBrokerBase.py +15 -0
- pandajedi/jedibrokerage/__init__.py +0 -0
- pandajedi/jediconfig/__init__.py +0 -0
- pandajedi/jediconfig/jedi_config.py +40 -0
- pandajedi/jedicore/FactoryBase.py +182 -0
- pandajedi/jedicore/Interaction.py +433 -0
- pandajedi/jedicore/JediDBProxy.py +56 -0
- pandajedi/jedicore/JediDBProxyPool.py +37 -0
- pandajedi/jedicore/JediDBSchemaInfo.py +17 -0
- pandajedi/jedicore/JediException.py +13 -0
- pandajedi/jedicore/JediTaskBuffer.py +984 -0
- pandajedi/jedicore/JediTaskBufferInterface.py +50 -0
- pandajedi/jedicore/MsgWrapper.py +124 -0
- pandajedi/jedicore/ProcessUtils.py +34 -0
- pandajedi/jedicore/SiteCandidate.py +90 -0
- pandajedi/jedicore/ThreadUtils.py +205 -0
- pandajedi/jedicore/__init__.py +0 -0
- pandajedi/jediddm/AtlasDDMClient.py +1708 -0
- pandajedi/jediddm/DDMClientBase.py +16 -0
- pandajedi/jediddm/DDMInterface.py +83 -0
- pandajedi/jediddm/GenDDMClient.py +17 -0
- pandajedi/jediddm/__init__.py +0 -0
- pandajedi/jedidog/AtlasAnalWatchDog.py +648 -0
- pandajedi/jedidog/AtlasDataCarouselWatchDog.py +189 -0
- pandajedi/jedidog/AtlasDataLocalityUpdaterWatchDog.py +215 -0
- pandajedi/jedidog/AtlasProdWatchDog.py +443 -0
- pandajedi/jedidog/AtlasQueueFillerWatchDog.py +800 -0
- pandajedi/jedidog/AtlasTaskWithholderWatchDog.py +245 -0
- pandajedi/jedidog/AtlasWorkflowManagerWatchDog.py +63 -0
- pandajedi/jedidog/GenWatchDog.py +21 -0
- pandajedi/jedidog/JumboWatchDog.py +147 -0
- pandajedi/jedidog/TypicalWatchDogBase.py +122 -0
- pandajedi/jedidog/WatchDogBase.py +53 -0
- pandajedi/jedidog/__init__.py +0 -0
- pandajedi/jediexec/reniceJEDI.py +25 -0
- pandajedi/jedigen/AtlasTaskGenerator.py +110 -0
- pandajedi/jedigen/TaskGeneratorBase.py +15 -0
- pandajedi/jedigen/__init__.py +0 -0
- pandajedi/jedimsgprocessor/__init__.py +0 -0
- pandajedi/jedimsgprocessor/ai_parameter_adjuster_msg_processor +71 -0
- pandajedi/jedimsgprocessor/atlas_idds_msg_processor.py +66 -0
- pandajedi/jedimsgprocessor/base_msg_processor.py +33 -0
- pandajedi/jedimsgprocessor/forwarding_msg_processor.py +29 -0
- pandajedi/jedimsgprocessor/hpo_msg_processor.py +93 -0
- pandajedi/jedimsgprocessor/jedi_contents_feeder_msg_processor.py +63 -0
- pandajedi/jedimsgprocessor/jedi_job_generator_msg_processor.py +185 -0
- pandajedi/jedimsgprocessor/jedi_post_processor_msg_processor.py +82 -0
- pandajedi/jedimsgprocessor/kafka_msg_processor.py +44 -0
- pandajedi/jedimsgprocessor/panda_callback_msg_processor.py +182 -0
- pandajedi/jedimsgprocessor/panda_to_jedi_msg_processor.py +74 -0
- pandajedi/jedimsgprocessor/processing_msg_processor.py +134 -0
- pandajedi/jedimsgprocessor/status_report_msg_processor.py +129 -0
- pandajedi/jedimsgprocessor/tape_carousel_msg_processor.py +118 -0
- pandajedi/jedimsgprocessor/workflow_manager_msg_processor.py +89 -0
- pandajedi/jediorder/ContentsFeeder.py +785 -0
- pandajedi/jediorder/JediDaemon.py +27 -0
- pandajedi/jediorder/JediKnight.py +55 -0
- pandajedi/jediorder/JediMaster.py +238 -0
- pandajedi/jediorder/JediMsgProcessor.py +32 -0
- pandajedi/jediorder/JobBroker.py +33 -0
- pandajedi/jediorder/JobGenerator.py +2763 -0
- pandajedi/jediorder/JobSplitter.py +308 -0
- pandajedi/jediorder/JobThrottler.py +28 -0
- pandajedi/jediorder/PostProcessor.py +166 -0
- pandajedi/jediorder/TaskBroker.py +268 -0
- pandajedi/jediorder/TaskCommando.py +334 -0
- pandajedi/jediorder/TaskGenerator.py +17 -0
- pandajedi/jediorder/TaskRefiner.py +611 -0
- pandajedi/jediorder/TaskSetupper.py +17 -0
- pandajedi/jediorder/WatchDog.py +79 -0
- pandajedi/jediorder/__init__.py +0 -0
- pandajedi/jedipprocess/AtlasAnalPostProcessor.py +404 -0
- pandajedi/jedipprocess/AtlasPostProcessorUtils.py +50 -0
- pandajedi/jedipprocess/AtlasProdPostProcessor.py +178 -0
- pandajedi/jedipprocess/GenPostProcessor.py +35 -0
- pandajedi/jedipprocess/MailTemplates.py +185 -0
- pandajedi/jedipprocess/PostProcessorBase.py +269 -0
- pandajedi/jedipprocess/__init__.py +0 -0
- pandajedi/jedirefine/AtlasAnalTaskRefiner.py +259 -0
- pandajedi/jedirefine/AtlasProdTaskRefiner.py +162 -0
- pandajedi/jedirefine/GenTaskRefiner.py +61 -0
- pandajedi/jedirefine/RefinerUtils.py +154 -0
- pandajedi/jedirefine/TaskRefinerBase.py +996 -0
- pandajedi/jedirefine/__init__.py +0 -0
- pandajedi/jedisetup/AtlasTaskSetupper.py +309 -0
- pandajedi/jedisetup/GenTaskSetupper.py +16 -0
- pandajedi/jedisetup/SimpleTaskSetupper.py +152 -0
- pandajedi/jedisetup/TaskSetupperBase.py +15 -0
- pandajedi/jedisetup/__init__.py +0 -0
- pandajedi/jeditest/SchemaChecker.py +41 -0
- pandajedi/jeditest/addContWoSoTask.py +54 -0
- pandajedi/jeditest/addDataCarouselRequest.py +47 -0
- pandajedi/jeditest/addEventServiceTask.py +101 -0
- pandajedi/jeditest/addHpoTask.py +81 -0
- pandajedi/jeditest/addIDDSStageInRequest.py +56 -0
- pandajedi/jeditest/addNonAtlasTask.py +71 -0
- pandajedi/jeditest/addNonAtlasTaskEnc.py +64 -0
- pandajedi/jeditest/addTestTask.py +124 -0
- pandajedi/jeditest/addTestTaskParamToDEFT.py +70 -0
- pandajedi/jeditest/addTestTaskWithMerger.py +97 -0
- pandajedi/jeditest/brokerTest.py +78 -0
- pandajedi/jeditest/cancelDataCarouselRequest.py +35 -0
- pandajedi/jeditest/contentsFeederTest.py +28 -0
- pandajedi/jeditest/contentsFeederTestWithTask.py +18 -0
- pandajedi/jeditest/ddmTest.py +4 -0
- pandajedi/jeditest/jobGenForOneTask.py +38 -0
- pandajedi/jeditest/jobGeneratorTest.py +43 -0
- pandajedi/jeditest/jobSplitterTest.py +104 -0
- pandajedi/jeditest/jobThrottlerTest.py +22 -0
- pandajedi/jeditest/msgProcessorTest.py +9 -0
- pandajedi/jeditest/postProcessorTest.py +18 -0
- pandajedi/jeditest/resubmitDataCarouselRequest.py +35 -0
- pandajedi/jeditest/resubmitTaskParam.py +20 -0
- pandajedi/jeditest/taskBrokerTest.py +22 -0
- pandajedi/jeditest/taskBrokerTestWithTask.py +38 -0
- pandajedi/jeditest/taskBufferTest.py +5 -0
- pandajedi/jeditest/taskCommandoTest.py +28 -0
- pandajedi/jeditest/taskRefinerTest.py +30 -0
- pandajedi/jeditest/testOneTaskToRefine.py +49 -0
- pandajedi/jeditest/testOneTaskToTaskBroker.py +42 -0
- pandajedi/jeditest/testPandaDDMMap.py +62 -0
- pandajedi/jeditest/updateDataCarouselRequestParams.py +50 -0
- pandajedi/jeditest/watchDogTest.py +25 -0
- pandajedi/jeditest/workQueueTest.py +22 -0
- pandajedi/jedithrottle/AtlasAnalJobThrottler.py +19 -0
- pandajedi/jedithrottle/AtlasProdJobThrottler.py +18 -0
- pandajedi/jedithrottle/GenJobThrottler.py +26 -0
- pandajedi/jedithrottle/JobThrottlerBase.py +496 -0
- pandajedi/jedithrottle/__init__.py +0 -0
- pandaserver/__init__.py +0 -0
- pandaserver/api/__init__.py +0 -0
- pandaserver/api/v1/__init__.py +0 -0
- pandaserver/api/v1/common.py +339 -0
- pandaserver/api/v1/credential_management_api.py +372 -0
- pandaserver/api/v1/data_carousel_api.py +264 -0
- pandaserver/api/v1/event_api.py +269 -0
- pandaserver/api/v1/file_server_api.py +942 -0
- pandaserver/api/v1/harvester_api.py +445 -0
- pandaserver/api/v1/http_client.py +166 -0
- pandaserver/api/v1/idds_api.py +180 -0
- pandaserver/api/v1/job_api.py +463 -0
- pandaserver/api/v1/metaconfig_api.py +122 -0
- pandaserver/api/v1/pilot_api.py +895 -0
- pandaserver/api/v1/statistics_api.py +207 -0
- pandaserver/api/v1/system_api.py +186 -0
- pandaserver/api/v1/task_api.py +1520 -0
- pandaserver/api/v1/tests/__init__.py +0 -0
- pandaserver/api/v1/tests/credential_management_api_tests.py +116 -0
- pandaserver/api/v1/tests/data_carousel_api_tests.py +82 -0
- pandaserver/api/v1/tests/harvester_api_tests.py +188 -0
- pandaserver/api/v1/tests/idds_api_tests.py +45 -0
- pandaserver/api/v1/tests/job_api_tests.py +112 -0
- pandaserver/api/v1/tests/pilot_api_tests.py +154 -0
- pandaserver/api/v1/tests/statistics_api_tests.py +104 -0
- pandaserver/api/v1/tests/system_api_tests.py +58 -0
- pandaserver/api/v1/tests/task_api_tests.py +590 -0
- pandaserver/api/v1/version.py +2 -0
- pandaserver/api/v1/workflow_api.py +136 -0
- pandaserver/brokerage/SiteMapper.py +406 -0
- pandaserver/brokerage/__init__.py +0 -0
- pandaserver/brokerage/broker.py +272 -0
- pandaserver/config/__init__.py +0 -0
- pandaserver/config/config_utils.py +15 -0
- pandaserver/config/daemon_config.py +29 -0
- pandaserver/config/mcp_config.py +38 -0
- pandaserver/config/panda_config.py +233 -0
- pandaserver/configurator/Carbon.py +65 -0
- pandaserver/configurator/Configurator.py +908 -0
- pandaserver/configurator/__init__.py +0 -0
- pandaserver/configurator/aux.py +73 -0
- pandaserver/daemons/__init__.py +0 -0
- pandaserver/daemons/master.py +110 -0
- pandaserver/daemons/master_systemd.py +79 -0
- pandaserver/daemons/scripts/__init__.py +0 -0
- pandaserver/daemons/scripts/add_main.py +264 -0
- pandaserver/daemons/scripts/add_sub.py +221 -0
- pandaserver/daemons/scripts/cache_pilots.py +47 -0
- pandaserver/daemons/scripts/cache_schedconfig.py +286 -0
- pandaserver/daemons/scripts/carbon.py +50 -0
- pandaserver/daemons/scripts/configurator.py +94 -0
- pandaserver/daemons/scripts/copyArchive.py +1387 -0
- pandaserver/daemons/scripts/datasetManager.py +1154 -0
- pandaserver/daemons/scripts/dummy_test.py +25 -0
- pandaserver/daemons/scripts/evpPD2P.py +144 -0
- pandaserver/daemons/scripts/hs_scrapers.py +264 -0
- pandaserver/daemons/scripts/metric_collector.py +927 -0
- pandaserver/daemons/scripts/panda_activeusers_query.py +80 -0
- pandaserver/daemons/scripts/pilotStreaming.py +109 -0
- pandaserver/daemons/scripts/process_workflow_files_daemon.py +166 -0
- pandaserver/daemons/scripts/recover_lost_files_daemon.py +177 -0
- pandaserver/daemons/scripts/task_evaluator.py +405 -0
- pandaserver/daemons/scripts/tmpwatch.py +70 -0
- pandaserver/daemons/scripts/worker_synchronization.py +97 -0
- pandaserver/daemons/utils.py +753 -0
- pandaserver/dataservice/DataServiceUtils.py +323 -0
- pandaserver/dataservice/ErrorCode.py +25 -0
- pandaserver/dataservice/RecoverLostFilesCore.py +322 -0
- pandaserver/dataservice/__init__.py +0 -0
- pandaserver/dataservice/activator.py +79 -0
- pandaserver/dataservice/adder_atlas_plugin.py +1106 -0
- pandaserver/dataservice/adder_dummy_plugin.py +31 -0
- pandaserver/dataservice/adder_gen.py +954 -0
- pandaserver/dataservice/adder_plugin_base.py +27 -0
- pandaserver/dataservice/adder_result.py +75 -0
- pandaserver/dataservice/adder_simple_plugin.py +160 -0
- pandaserver/dataservice/closer.py +247 -0
- pandaserver/dataservice/closer_atlas_plugin.py +90 -0
- pandaserver/dataservice/ddm.py +1381 -0
- pandaserver/dataservice/ddm_handler.py +95 -0
- pandaserver/dataservice/dyn_data_distributer.py +824 -0
- pandaserver/dataservice/event_lookup_client_ei.py +77 -0
- pandaserver/dataservice/event_picker.py +268 -0
- pandaserver/dataservice/finisher.py +194 -0
- pandaserver/dataservice/setupper.py +225 -0
- pandaserver/dataservice/setupper_atlas_plugin.py +1851 -0
- pandaserver/dataservice/setupper_dummy_plugin.py +47 -0
- pandaserver/dataservice/setupper_plugin_base.py +67 -0
- pandaserver/jobdispatcher/DispatcherUtils.py +35 -0
- pandaserver/jobdispatcher/ErrorCode.py +19 -0
- pandaserver/jobdispatcher/JobDispatcher.py +1625 -0
- pandaserver/jobdispatcher/Protocol.py +443 -0
- pandaserver/jobdispatcher/Watcher.py +186 -0
- pandaserver/jobdispatcher/__init__.py +0 -0
- pandaserver/pandamcp/__init__.py +0 -0
- pandaserver/pandamcp/mcp_main.py +56 -0
- pandaserver/pandamcp/mcp_test_client.py +95 -0
- pandaserver/pandamcp/mcp_utils.py +74 -0
- pandaserver/proxycache/__init__.py +0 -0
- pandaserver/proxycache/panda_proxy_cache.py +240 -0
- pandaserver/proxycache/token_cache.py +141 -0
- pandaserver/server/.gacl +6 -0
- pandaserver/server/panda.py +539 -0
- pandaserver/srvcore/CoreUtils.py +572 -0
- pandaserver/srvcore/MailUtils.py +106 -0
- pandaserver/srvcore/__init__.py +0 -0
- pandaserver/srvcore/allowed_methods.py +100 -0
- pandaserver/srvcore/oidc_utils.py +152 -0
- pandaserver/srvcore/panda_request.py +196 -0
- pandaserver/srvcore/srv_msg_utils.py +42 -0
- pandaserver/taskbuffer/ConBridge.py +513 -0
- pandaserver/taskbuffer/DBProxyPool.py +95 -0
- pandaserver/taskbuffer/DataCarousel.py +3053 -0
- pandaserver/taskbuffer/DatasetSpec.py +137 -0
- pandaserver/taskbuffer/DdmSpec.py +201 -0
- pandaserver/taskbuffer/ErrorCode.py +87 -0
- pandaserver/taskbuffer/EventServiceUtils.py +396 -0
- pandaserver/taskbuffer/FileSpec.py +290 -0
- pandaserver/taskbuffer/GlobalShares.py +244 -0
- pandaserver/taskbuffer/HarvesterMetricsSpec.py +92 -0
- pandaserver/taskbuffer/Initializer.py +82 -0
- pandaserver/taskbuffer/InputChunk.py +1080 -0
- pandaserver/taskbuffer/JediCacheSpec.py +57 -0
- pandaserver/taskbuffer/JediDatasetSpec.py +588 -0
- pandaserver/taskbuffer/JediFileSpec.py +242 -0
- pandaserver/taskbuffer/JediTaskSpec.py +1687 -0
- pandaserver/taskbuffer/JobSpec.py +1006 -0
- pandaserver/taskbuffer/JobUtils.py +232 -0
- pandaserver/taskbuffer/NucleusSpec.py +116 -0
- pandaserver/taskbuffer/OraDBProxy.py +174 -0
- pandaserver/taskbuffer/PanDAMsgProcessor.py +8 -0
- pandaserver/taskbuffer/PandaDBSchemaInfo.py +18 -0
- pandaserver/taskbuffer/ParseJobXML.py +350 -0
- pandaserver/taskbuffer/PickleFileSpec.py +18 -0
- pandaserver/taskbuffer/PickleJobSpec.py +25 -0
- pandaserver/taskbuffer/PrioUtil.py +40 -0
- pandaserver/taskbuffer/ProcessGroups.py +111 -0
- pandaserver/taskbuffer/ResourceSpec.py +175 -0
- pandaserver/taskbuffer/SQLDumper.py +37 -0
- pandaserver/taskbuffer/SQLManager.py +60 -0
- pandaserver/taskbuffer/SiteSpec.py +304 -0
- pandaserver/taskbuffer/SupErrors.py +10 -0
- pandaserver/taskbuffer/TaskBuffer.py +2882 -0
- pandaserver/taskbuffer/TaskBufferInterface.py +163 -0
- pandaserver/taskbuffer/Utils.py +848 -0
- pandaserver/taskbuffer/WorkQueue.py +227 -0
- pandaserver/taskbuffer/WorkQueueMapper.py +203 -0
- pandaserver/taskbuffer/WorkerSpec.py +143 -0
- pandaserver/taskbuffer/WrappedCursor.py +487 -0
- pandaserver/taskbuffer/WrappedPickle.py +88 -0
- pandaserver/taskbuffer/WrappedPostgresConn.py +24 -0
- pandaserver/taskbuffer/__init__.py +0 -0
- pandaserver/taskbuffer/db_proxy_mods/OraDBProxy_structure.png +0 -0
- pandaserver/taskbuffer/db_proxy_mods/__init__.py +7 -0
- pandaserver/taskbuffer/db_proxy_mods/base_module.py +841 -0
- pandaserver/taskbuffer/db_proxy_mods/data_carousel_module.py +772 -0
- pandaserver/taskbuffer/db_proxy_mods/entity_module.py +3804 -0
- pandaserver/taskbuffer/db_proxy_mods/job_complex_module.py +5661 -0
- pandaserver/taskbuffer/db_proxy_mods/job_standalone_module.py +2640 -0
- pandaserver/taskbuffer/db_proxy_mods/metrics_module.py +874 -0
- pandaserver/taskbuffer/db_proxy_mods/misc_standalone_module.py +4272 -0
- pandaserver/taskbuffer/db_proxy_mods/task_complex_module.py +6172 -0
- pandaserver/taskbuffer/db_proxy_mods/task_event_module.py +4953 -0
- pandaserver/taskbuffer/db_proxy_mods/task_standalone_module.py +4999 -0
- pandaserver/taskbuffer/db_proxy_mods/task_utils_module.py +2063 -0
- pandaserver/taskbuffer/db_proxy_mods/worker_module.py +1944 -0
- pandaserver/taskbuffer/db_proxy_mods/workflow_module.py +832 -0
- pandaserver/taskbuffer/retryModule.py +552 -0
- pandaserver/taskbuffer/task_split_rules.py +308 -0
- pandaserver/taskbuffer/workflow_processor.py +249 -0
- pandaserver/taskbuffer/wrapped_oracle_conn.py +18 -0
- pandaserver/test/SchemaChecker.py +40 -0
- pandaserver/test/__init__.py +0 -0
- pandaserver/test/banUser.py +43 -0
- pandaserver/test/boostPrio.py +19 -0
- pandaserver/test/boostUser.py +35 -0
- pandaserver/test/callbackDDM.py +11 -0
- pandaserver/test/daod_on_demand.py +95 -0
- pandaserver/test/finishJob.py +184 -0
- pandaserver/test/finishTaskJEDI.py +11 -0
- pandaserver/test/getJobs.py +53 -0
- pandaserver/test/killJob.py +79 -0
- pandaserver/test/killJobLowPrio.py +99 -0
- pandaserver/test/killJobsInTask.py +56 -0
- pandaserver/test/killTask.py +80 -0
- pandaserver/test/killTaskJEDI.py +11 -0
- pandaserver/test/killUser.py +83 -0
- pandaserver/test/lsst/README.txt +7 -0
- pandaserver/test/lsst/lsstSubmit.py +139 -0
- pandaserver/test/lsst/lsstSubmitMERGEtest.py +141 -0
- pandaserver/test/lsst/lsstSubmitPhosim332.py +53 -0
- pandaserver/test/lsst/prepare-client-tarball-from-bigpanda-server.sh +41 -0
- pandaserver/test/reassignJobs.py +17 -0
- pandaserver/test/reassignSite.py +82 -0
- pandaserver/test/reassignTask.py +117 -0
- pandaserver/test/reassignWaiting.py +39 -0
- pandaserver/test/recoverLostFiles.py +7 -0
- pandaserver/test/reloadInputDS.py +51 -0
- pandaserver/test/sendCommandToJob.py +26 -0
- pandaserver/test/setDebugMode.py +38 -0
- pandaserver/test/setPriority.py +28 -0
- pandaserver/test/testEvgen.py +60 -0
- pandaserver/test/testEvgen17.py +58 -0
- pandaserver/test/testG4sim.py +81 -0
- pandaserver/test/testG4sim17.py +90 -0
- pandaserver/test/testGlobalShares.py +131 -0
- pandaserver/test/testReco.py +103 -0
- pandaserver/test/testSimulReco14.py +98 -0
- pandaserver/test/testSiteMap.py +26 -0
- pandaserver/test/testUpdateWorkerPilotStatus.py +9 -0
- pandaserver/userinterface/Client.py +1686 -0
- pandaserver/userinterface/UserIF.py +1799 -0
- pandaserver/userinterface/__init__.py +0 -0
- pandaserver/workflow/__init__.py +0 -0
- pandaserver/workflow/data_handler_plugins/base_data_handler.py +48 -0
- pandaserver/workflow/data_handler_plugins/ddm_collection_data_handler.py +100 -0
- pandaserver/workflow/data_handler_plugins/panda_task_data_handler.py +140 -0
- pandaserver/workflow/pcwl_test.py +122 -0
- pandaserver/workflow/pcwl_utils.py +384 -0
- pandaserver/workflow/psnakemake_container.json +68 -0
- pandaserver/workflow/psnakemake_task.json +62 -0
- pandaserver/workflow/psnakemake_test.py +60 -0
- pandaserver/workflow/snakeparser/__init__.py +3 -0
- pandaserver/workflow/snakeparser/extensions.py +74 -0
- pandaserver/workflow/snakeparser/log.py +53 -0
- pandaserver/workflow/snakeparser/names.py +3 -0
- pandaserver/workflow/snakeparser/parser.py +332 -0
- pandaserver/workflow/snakeparser/utils.py +29 -0
- pandaserver/workflow/step_handler_plugins/base_step_handler.py +85 -0
- pandaserver/workflow/step_handler_plugins/panda_task_step_handler.py +280 -0
- pandaserver/workflow/workflow_base.py +531 -0
- pandaserver/workflow/workflow_core.py +1974 -0
- pandaserver/workflow/workflow_core_smoketest.py +388 -0
- pandaserver/workflow/workflow_parser.py +222 -0
- pandaserver/workflow/workflow_utils.py +1047 -0
|
File without changes
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# TODO: the result of the tests depend on the cert/token used for the call. These particular results are for running with user pandasv1
|
|
2
|
+
|
|
3
|
+
import unittest
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
|
|
6
|
+
from pandaserver.api.v1.http_client import HttpClient, api_url, api_url_ssl
|
|
7
|
+
|
|
8
|
+
# Get current UTC time with microseconds. The format needs to be compatible with the one used in the database
|
|
9
|
+
now_utc = datetime.now(timezone.utc)
|
|
10
|
+
formatted_time = now_utc.strftime("%d.%m.%y %H:%M:%S") + f".{now_utc.microsecond // 1000:02d}"
|
|
11
|
+
|
|
12
|
+
KEY = "test_key"
|
|
13
|
+
VALUE = "test_value"
|
|
14
|
+
|
|
15
|
+
NO_SSL_RESPONSE = {"success": False, "message": "SSL secure connection is required", "data": None}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TestSecretManagementAPI(unittest.TestCase):
|
|
19
|
+
def setUp(self):
|
|
20
|
+
self.http_client = HttpClient()
|
|
21
|
+
self.urls = [api_url, api_url_ssl] # Run tests with both base URLs
|
|
22
|
+
|
|
23
|
+
def test_set_user_secrets(self):
|
|
24
|
+
for url in self.urls:
|
|
25
|
+
with self.subTest(base_url=url):
|
|
26
|
+
full_url = f"{url}/creds/set_user_secrets"
|
|
27
|
+
print(f"Testing URL: {full_url}")
|
|
28
|
+
data = {"key": KEY, "value": VALUE}
|
|
29
|
+
status, output = self.http_client.post(full_url, data)
|
|
30
|
+
print(output)
|
|
31
|
+
if url.startswith(api_url):
|
|
32
|
+
expected_response = NO_SSL_RESPONSE
|
|
33
|
+
else:
|
|
34
|
+
expected_response = {"success": True, "message": "OK", "data": None}
|
|
35
|
+
self.assertEqual(output, expected_response)
|
|
36
|
+
|
|
37
|
+
def test_get_user_secrets(self):
|
|
38
|
+
for url in self.urls:
|
|
39
|
+
with self.subTest(base_url=url):
|
|
40
|
+
full_url = f"{url}/creds/get_user_secrets"
|
|
41
|
+
print(f"Testing URL: {full_url}")
|
|
42
|
+
data = {"keys": KEY}
|
|
43
|
+
status, output = self.http_client.get(full_url, data)
|
|
44
|
+
print(output)
|
|
45
|
+
if url.startswith(api_url):
|
|
46
|
+
expected_response = NO_SSL_RESPONSE
|
|
47
|
+
else:
|
|
48
|
+
expected_response = {"success": True, "message": "", "data": '{"test_key": "test_value"}'}
|
|
49
|
+
self.assertEqual(output, expected_response)
|
|
50
|
+
|
|
51
|
+
def test_get_key_pair(self):
|
|
52
|
+
for url in self.urls:
|
|
53
|
+
with self.subTest(base_url=url):
|
|
54
|
+
full_url = f"{url}/creds/get_key_pair"
|
|
55
|
+
print(f"Testing URL: {full_url}")
|
|
56
|
+
data = {"public_key_name": "a", "private_key_name": "b"}
|
|
57
|
+
status, output = self.http_client.get(full_url, data)
|
|
58
|
+
print(output)
|
|
59
|
+
if url.startswith(api_url):
|
|
60
|
+
expected_response = NO_SSL_RESPONSE
|
|
61
|
+
else:
|
|
62
|
+
expected_response = {
|
|
63
|
+
"success": False,
|
|
64
|
+
"message": "Failed since 'pandasv1' not authorized with 'k' in ATLAS_PANDAMETA.USERS.GRIDPREF",
|
|
65
|
+
"data": None,
|
|
66
|
+
}
|
|
67
|
+
self.assertEqual(output, expected_response)
|
|
68
|
+
|
|
69
|
+
def test_get_proxy(self):
|
|
70
|
+
for url in self.urls:
|
|
71
|
+
with self.subTest(base_url=url):
|
|
72
|
+
full_url = f"{url}/creds/get_proxy"
|
|
73
|
+
print(f"Testing URL: {full_url}")
|
|
74
|
+
data = {"role": "atlas", "dn": "atlpilo2"}
|
|
75
|
+
status, output = self.http_client.get(full_url, data)
|
|
76
|
+
print(output)
|
|
77
|
+
if url.startswith(api_url):
|
|
78
|
+
expected_response = NO_SSL_RESPONSE
|
|
79
|
+
else:
|
|
80
|
+
expected_response = {"success": False, "message": "'proxy' not found for atlpilo2", "data": None}
|
|
81
|
+
self.assertEqual(output, expected_response)
|
|
82
|
+
|
|
83
|
+
def test_get_access_token(self):
|
|
84
|
+
for url in self.urls:
|
|
85
|
+
with self.subTest(base_url=url):
|
|
86
|
+
full_url = f"{url}/creds/get_access_token"
|
|
87
|
+
print(f"Testing URL: {full_url}")
|
|
88
|
+
data = {"client_name": "pilot_server"}
|
|
89
|
+
status, output = self.http_client.get(full_url, data)
|
|
90
|
+
print(output)
|
|
91
|
+
if url.startswith(api_url):
|
|
92
|
+
expected_response = NO_SSL_RESPONSE
|
|
93
|
+
else:
|
|
94
|
+
expected_response = {"success": False, "message": "failed since token key is invalid for pilot_server", "data": None}
|
|
95
|
+
self.assertEqual(output, expected_response)
|
|
96
|
+
|
|
97
|
+
def test_get_token_key(self):
|
|
98
|
+
for url in self.urls:
|
|
99
|
+
with self.subTest(base_url=url):
|
|
100
|
+
full_url = f"{url}/creds/get_token_key"
|
|
101
|
+
print(f"Testing URL: {full_url}")
|
|
102
|
+
data = {"client_name": "pilot_server"}
|
|
103
|
+
status, output = self.http_client.get(full_url, data)
|
|
104
|
+
print(output)
|
|
105
|
+
if url.startswith(api_url):
|
|
106
|
+
expected_response = NO_SSL_RESPONSE
|
|
107
|
+
else:
|
|
108
|
+
del output["data"]
|
|
109
|
+
del output["message"]
|
|
110
|
+
expected_response = {"success": True}
|
|
111
|
+
self.assertEqual(output, expected_response)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# Run tests
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
unittest.main()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Description: Unit tests for the Data Carousel API methods
|
|
2
|
+
import os
|
|
3
|
+
import unittest
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
|
+
|
|
6
|
+
from pandaserver.api.v1.http_client import HttpClient, api_url_ssl
|
|
7
|
+
|
|
8
|
+
# to run the tests with a real Data Carousel request ID or dataset name by setting the environment variable
|
|
9
|
+
REQUEST_ID = int(os.environ.get("REQUEST_ID", None))
|
|
10
|
+
DATASET = str(os.environ.get("DATASET", None))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestDataCarouselAPI(unittest.TestCase):
|
|
14
|
+
def setUp(self):
|
|
15
|
+
self.http_client = HttpClient()
|
|
16
|
+
|
|
17
|
+
def test_change_staging_destination_by_request_id(self):
|
|
18
|
+
url = f"{api_url_ssl}/data_carousel/change_staging_destination"
|
|
19
|
+
print(f"Testing URL: {url}")
|
|
20
|
+
data = {"request_id": REQUEST_ID}
|
|
21
|
+
status, output = self.http_client.post(url, data)
|
|
22
|
+
print(status, output)
|
|
23
|
+
if status == 0 and output.get("data"):
|
|
24
|
+
self.assertEqual(output["data"].get("request_id"), REQUEST_ID)
|
|
25
|
+
self.assertIsInstance(output["data"].get("new_request_id"), int)
|
|
26
|
+
|
|
27
|
+
def test_change_staging_destination_by_dataset(self):
|
|
28
|
+
url = f"{api_url_ssl}/data_carousel/change_staging_destination"
|
|
29
|
+
print(f"Testing URL: {url}")
|
|
30
|
+
data = {"dataset": DATASET}
|
|
31
|
+
status, output = self.http_client.post(url, data)
|
|
32
|
+
print(status, output)
|
|
33
|
+
if status == 0 and output.get("data"):
|
|
34
|
+
self.assertEqual(output["data"].get("dataset"), DATASET)
|
|
35
|
+
self.assertIsInstance(output["data"].get("new_request_id"), int)
|
|
36
|
+
|
|
37
|
+
def test_change_staging_source_by_request_id(self):
|
|
38
|
+
url = f"{api_url_ssl}/data_carousel/change_staging_source"
|
|
39
|
+
print(f"Testing URL: {url}")
|
|
40
|
+
data = {"request_id": REQUEST_ID}
|
|
41
|
+
status, output = self.http_client.post(url, data)
|
|
42
|
+
print(status, output)
|
|
43
|
+
if status == 0 and output.get("data"):
|
|
44
|
+
self.assertEqual(output["data"].get("request_id"), REQUEST_ID)
|
|
45
|
+
self.assertIsInstance(output["data"].get("ddm_rule_id"), str)
|
|
46
|
+
|
|
47
|
+
def test_change_staging_source_by_dataset(self):
|
|
48
|
+
url = f"{api_url_ssl}/data_carousel/change_staging_source"
|
|
49
|
+
print(f"Testing URL: {url}")
|
|
50
|
+
data = {"dataset": DATASET}
|
|
51
|
+
status, output = self.http_client.post(url, data)
|
|
52
|
+
print(status, output)
|
|
53
|
+
if status == 0 and output.get("data"):
|
|
54
|
+
self.assertEqual(output["data"].get("dataset"), DATASET)
|
|
55
|
+
self.assertIsInstance(output["data"].get("ddm_rule_id"), str)
|
|
56
|
+
|
|
57
|
+
def test_force_to_staging_by_request_id(self):
|
|
58
|
+
url = f"{api_url_ssl}/data_carousel/force_to_staging"
|
|
59
|
+
print(f"Testing URL: {url}")
|
|
60
|
+
data = {"request_id": REQUEST_ID}
|
|
61
|
+
status, output = self.http_client.post(url, data)
|
|
62
|
+
print(status, output)
|
|
63
|
+
if status == 0 and output.get("data"):
|
|
64
|
+
self.assertEqual(output["data"].get("request_id"), REQUEST_ID)
|
|
65
|
+
self.assertEqual(output["data"].get("status"), "staging")
|
|
66
|
+
self.assertIsInstance(output["data"].get("ddm_rule_id"), str)
|
|
67
|
+
|
|
68
|
+
def test_force_to_staging_by_dataset(self):
|
|
69
|
+
url = f"{api_url_ssl}/data_carousel/force_to_staging"
|
|
70
|
+
print(f"Testing URL: {url}")
|
|
71
|
+
data = {"dataset": DATASET}
|
|
72
|
+
status, output = self.http_client.post(url, data)
|
|
73
|
+
print(status, output)
|
|
74
|
+
if status == 0 and output.get("data"):
|
|
75
|
+
self.assertEqual(output["data"].get("dataset"), DATASET)
|
|
76
|
+
self.assertEqual(output["data"].get("status"), "staging")
|
|
77
|
+
self.assertIsInstance(output["data"].get("ddm_rule_id"), str)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Run tests
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
unittest.main()
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import unittest
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
|
|
5
|
+
from pandaserver.api.v1.http_client import HttpClient, api_url_ssl
|
|
6
|
+
|
|
7
|
+
# Get current UTC time with microseconds. The format needs to be compatible with the one used in the database
|
|
8
|
+
now_utc = datetime.now(timezone.utc)
|
|
9
|
+
formatted_time = now_utc.strftime("%d.%m.%y %H:%M:%S") + f".{now_utc.microsecond // 1000:02d}"
|
|
10
|
+
|
|
11
|
+
HARVESTER_ID = "test_fbarreir"
|
|
12
|
+
HARVESTER_HOST = "test_fbarreir.cern.ch"
|
|
13
|
+
PANDA_QUEUE = "test_queue"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestHarvesterAPI(unittest.TestCase):
|
|
17
|
+
def setUp(self):
|
|
18
|
+
self.http_client = HttpClient()
|
|
19
|
+
|
|
20
|
+
def test_update_service_metrics(self):
|
|
21
|
+
url = f"{api_url_ssl}/harvester/update_service_metrics"
|
|
22
|
+
print(f"Testing URL: {url}")
|
|
23
|
+
harvester_id = HARVESTER_ID
|
|
24
|
+
harvester_host = HARVESTER_HOST
|
|
25
|
+
creation_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
|
|
26
|
+
metric = {
|
|
27
|
+
"rss_mib": 2737.36,
|
|
28
|
+
"memory_pc": 39.19,
|
|
29
|
+
"cpu_pc": 15.23,
|
|
30
|
+
"volume_data_pc": 20.0,
|
|
31
|
+
"cert_lifetime": {
|
|
32
|
+
"/data/atlpan/proxy/x509up_u25606_prod": 81,
|
|
33
|
+
"/data/atlpan/proxy/x509up_u25606_pilot": 81,
|
|
34
|
+
"/cephfs/atlpan/harvester/proxy/x509up_u25606_prod": 96,
|
|
35
|
+
"/cephfs/atlpan/harvester/proxy/x509up_u25606_pilot": 96,
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# DBProxy expects the metrics in json format and stores them directly in the database
|
|
40
|
+
metrics = [[creation_time, harvester_host, json.dumps(metric)]]
|
|
41
|
+
|
|
42
|
+
data = {"harvester_id": harvester_id, "metrics": metrics}
|
|
43
|
+
status, output = self.http_client.post(url, data)
|
|
44
|
+
print(output)
|
|
45
|
+
expected_response = {"success": True, "message": "", "data": [True]}
|
|
46
|
+
self.assertEqual(output, expected_response)
|
|
47
|
+
|
|
48
|
+
def test_add_dialogs(self):
|
|
49
|
+
url = f"{api_url_ssl}/harvester/add_dialogs"
|
|
50
|
+
print(f"Testing URL: {url}")
|
|
51
|
+
harvester_id = HARVESTER_ID
|
|
52
|
+
|
|
53
|
+
dialog = {
|
|
54
|
+
"diagID": 1,
|
|
55
|
+
"moduleName": "test_module",
|
|
56
|
+
"identifier": "test identifier",
|
|
57
|
+
"creationTime": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"),
|
|
58
|
+
"messageLevel": "INFO",
|
|
59
|
+
"diagMessage": "test message",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
dialogs = [dialog]
|
|
63
|
+
|
|
64
|
+
data = {"harvester_id": harvester_id, "dialogs": dialogs}
|
|
65
|
+
status, output = self.http_client.post(url, data)
|
|
66
|
+
print(output)
|
|
67
|
+
expected_response = {"success": True, "message": "", "data": None}
|
|
68
|
+
self.assertEqual(output, expected_response)
|
|
69
|
+
|
|
70
|
+
def test_heartbeat(self):
|
|
71
|
+
url = f"{api_url_ssl}/harvester/heartbeat"
|
|
72
|
+
print(f"Testing URL: {url}")
|
|
73
|
+
harvester_id = HARVESTER_ID
|
|
74
|
+
data = {"harvester_id": harvester_id, "data": []}
|
|
75
|
+
status, output = self.http_client.post(url, data)
|
|
76
|
+
|
|
77
|
+
expected_response = {"success": True, "message": "", "data": None}
|
|
78
|
+
self.assertEqual(output, expected_response)
|
|
79
|
+
|
|
80
|
+
def test_get_worker_statistics(self):
|
|
81
|
+
url = f"{api_url_ssl}/harvester/get_worker_statistics"
|
|
82
|
+
print(f"Testing URL: {url}")
|
|
83
|
+
data = {}
|
|
84
|
+
status, output = self.http_client.get(url, data)
|
|
85
|
+
print(output)
|
|
86
|
+
# the statistics can't be predicted, so we just check the type of the response
|
|
87
|
+
self.assertEqual(True, output["success"])
|
|
88
|
+
self.assertEqual(dict, type(output["data"]))
|
|
89
|
+
|
|
90
|
+
def test_get_current_worker_id(self):
|
|
91
|
+
url = f"{api_url_ssl}/harvester/get_current_worker_id"
|
|
92
|
+
print(f"Testing URL: {url}")
|
|
93
|
+
data = {"harvester_id": HARVESTER_ID}
|
|
94
|
+
status, output = self.http_client.get(url, data)
|
|
95
|
+
print(output)
|
|
96
|
+
# the current/max worker id can't be predicted, so we just check the type of the response
|
|
97
|
+
self.assertEqual(True, output["success"])
|
|
98
|
+
self.assertEqual(int, type(output["data"]))
|
|
99
|
+
|
|
100
|
+
def test_report_worker_statistics(self):
|
|
101
|
+
url = f"{api_url_ssl}/harvester/report_worker_statistics"
|
|
102
|
+
print(f"Testing URL: {url}")
|
|
103
|
+
harvester_id = HARVESTER_ID
|
|
104
|
+
panda_queue = PANDA_QUEUE
|
|
105
|
+
# the json loads is done in DBProxy
|
|
106
|
+
statistics = json.dumps({"user": {"SCORE": {"running": 1, "submitted": 1}}, "managed": {"MCORE": {"running": 1, "submitted": 1}}})
|
|
107
|
+
data = {"harvester_id": harvester_id, "panda_queue": panda_queue, "statistics": statistics}
|
|
108
|
+
status, output = self.http_client.post(url, data)
|
|
109
|
+
print(output)
|
|
110
|
+
expected_response = {"success": True, "message": "OK", "data": None}
|
|
111
|
+
self.assertEqual(output, expected_response)
|
|
112
|
+
|
|
113
|
+
def test_update_workers(self):
|
|
114
|
+
url = f"{api_url_ssl}/harvester/update_workers"
|
|
115
|
+
print(f"Testing URL: {url}")
|
|
116
|
+
worker = {
|
|
117
|
+
"workerID": 1,
|
|
118
|
+
"batchID": 1,
|
|
119
|
+
"queueName": "queue1",
|
|
120
|
+
"status": "running",
|
|
121
|
+
"computingSite": "site1",
|
|
122
|
+
"nCore": 1,
|
|
123
|
+
"nodeID": None,
|
|
124
|
+
"submitTime": "02-NOV-24 00:02:18",
|
|
125
|
+
"startTime": "02-NOV-24 00:02:18",
|
|
126
|
+
"endTime": None,
|
|
127
|
+
"jobType": "managed",
|
|
128
|
+
"resourceType": "SCORE",
|
|
129
|
+
"nativeExitCode": None,
|
|
130
|
+
"nativeStatus": None,
|
|
131
|
+
"diagMessage": None,
|
|
132
|
+
"nJobs": 1,
|
|
133
|
+
"computingElement": "ce1",
|
|
134
|
+
"syncLevel": 0,
|
|
135
|
+
"submissionHost": "submissionhost1",
|
|
136
|
+
"harvesterHost": "harvesterhost1",
|
|
137
|
+
"errorCode": None,
|
|
138
|
+
"minRamCount": 2000,
|
|
139
|
+
}
|
|
140
|
+
workers = [worker]
|
|
141
|
+
|
|
142
|
+
harvester_id = HARVESTER_ID
|
|
143
|
+
data = {"harvester_id": harvester_id, "workers": workers}
|
|
144
|
+
|
|
145
|
+
status, output = self.http_client.post(url, data)
|
|
146
|
+
print(output)
|
|
147
|
+
expected_response = {"success": True, "message": "", "data": [True]}
|
|
148
|
+
|
|
149
|
+
self.assertEqual(output, expected_response)
|
|
150
|
+
|
|
151
|
+
def test_acquire_commands(self):
|
|
152
|
+
url = f"{api_url_ssl}/harvester/acquire_commands"
|
|
153
|
+
print(f"Testing URL: {url}")
|
|
154
|
+
|
|
155
|
+
harvester_id = HARVESTER_ID
|
|
156
|
+
n_commands = 1
|
|
157
|
+
data = {"harvester_id": harvester_id, "n_commands": n_commands}
|
|
158
|
+
status, output = self.http_client.post(url, data)
|
|
159
|
+
print(output)
|
|
160
|
+
# the commands can't be predicted, so we just check the type of the response
|
|
161
|
+
self.assertEqual(True, output["success"])
|
|
162
|
+
self.assertEqual(list, type(output["data"]))
|
|
163
|
+
|
|
164
|
+
def test_acknowledge_commands(self):
|
|
165
|
+
url = f"{api_url_ssl}/harvester/acknowledge_commands"
|
|
166
|
+
print(f"Testing URL: {url}")
|
|
167
|
+
command_ids = [1]
|
|
168
|
+
data = {"command_ids": command_ids}
|
|
169
|
+
status, output = self.http_client.post(url, data)
|
|
170
|
+
print(output)
|
|
171
|
+
expected_response = {"success": True, "message": "", "data": None}
|
|
172
|
+
self.assertEqual(output, expected_response)
|
|
173
|
+
|
|
174
|
+
def test_add_target_slots(self):
|
|
175
|
+
url = f"{api_url_ssl}/harvester/add_target_slots"
|
|
176
|
+
print(f"Testing URL: {url}")
|
|
177
|
+
panda_queue = PANDA_QUEUE
|
|
178
|
+
slots = 0
|
|
179
|
+
data = {"panda_queue": panda_queue, "slots": slots}
|
|
180
|
+
status, output = self.http_client.post(url, data)
|
|
181
|
+
print(output)
|
|
182
|
+
self.assertEqual(True, output["success"])
|
|
183
|
+
self.assertEqual(None, output["data"])
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# Run tests
|
|
187
|
+
if __name__ == "__main__":
|
|
188
|
+
unittest.main()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Description: Unit tests for the IDDS API methods
|
|
2
|
+
# TODO: These tests are placeholders and need to be completed
|
|
3
|
+
import unittest
|
|
4
|
+
|
|
5
|
+
from pandaserver.api.v1.http_client import HttpClient, api_url_ssl
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestIDDSAPI(unittest.TestCase):
|
|
9
|
+
def setUp(self):
|
|
10
|
+
self.http_client = HttpClient()
|
|
11
|
+
|
|
12
|
+
def test_relay_idds_command(self):
|
|
13
|
+
url = f"{api_url_ssl}/idds/relay_idds_command"
|
|
14
|
+
print(f"Testing URL: {url}")
|
|
15
|
+
data = {}
|
|
16
|
+
status, output = self.http_client.get(url, data)
|
|
17
|
+
print(output)
|
|
18
|
+
output["status"] = status
|
|
19
|
+
|
|
20
|
+
# Remove the data field from the response for comparison
|
|
21
|
+
del output["data"]
|
|
22
|
+
|
|
23
|
+
expected_response = {"success": True, "message": "", "status": 0}
|
|
24
|
+
|
|
25
|
+
self.assertEqual(output, expected_response)
|
|
26
|
+
|
|
27
|
+
def test_execute_idds_workflow_command(self):
|
|
28
|
+
url = f"{api_url_ssl}/statistics/execute_idds_workflow_command"
|
|
29
|
+
print(f"Testing URL: {url}")
|
|
30
|
+
data = {}
|
|
31
|
+
status, output = self.http_client.get(url, data)
|
|
32
|
+
print(output)
|
|
33
|
+
output["status"] = status
|
|
34
|
+
|
|
35
|
+
# Remove the data field from the response for comparison
|
|
36
|
+
del output["data"]
|
|
37
|
+
|
|
38
|
+
expected_response = {"success": True, "message": "", "status": 0}
|
|
39
|
+
|
|
40
|
+
self.assertEqual(output, expected_response)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# Run tests
|
|
44
|
+
if __name__ == "__main__":
|
|
45
|
+
unittest.main()
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Description: Unit tests for the Job API methods
|
|
2
|
+
import os
|
|
3
|
+
import unittest
|
|
4
|
+
|
|
5
|
+
from pandaserver.api.v1.http_client import HttpClient, api_url_ssl
|
|
6
|
+
|
|
7
|
+
# To run tests with real IDs, set environment variables:
|
|
8
|
+
# PANDA_JOB_ID_TEST=<job_id> JEDI_TASK_ID_TEST=<task_id>
|
|
9
|
+
PANDA_JOB_ID = int(os.environ.get("PANDA_JOB_ID_TEST", -1))
|
|
10
|
+
JEDI_TASK_ID = int(os.environ.get("JEDI_TASK_ID_TEST", -1))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestJobAPI(unittest.TestCase):
|
|
14
|
+
def setUp(self):
|
|
15
|
+
self.http_client = HttpClient()
|
|
16
|
+
|
|
17
|
+
def test_get_status(self):
|
|
18
|
+
# def get_status(req: PandaRequest, job_ids: List[int], timeout: int = 60) -> Dict:
|
|
19
|
+
url = f"{api_url_ssl}/job/get_status"
|
|
20
|
+
print(f"Testing URL: {url}")
|
|
21
|
+
data = {"job_ids": [PANDA_JOB_ID]}
|
|
22
|
+
status, output = self.http_client.get(url, data)
|
|
23
|
+
print(output)
|
|
24
|
+
output["status"] = status
|
|
25
|
+
del output["data"]
|
|
26
|
+
del output["message"]
|
|
27
|
+
|
|
28
|
+
# Returns success=True regardless of whether job exists (returns empty or None entries)
|
|
29
|
+
expected_response = {"status": 0, "success": True}
|
|
30
|
+
self.assertEqual(output, expected_response)
|
|
31
|
+
|
|
32
|
+
def test_get_description(self):
|
|
33
|
+
# def get_description(req: PandaRequest, job_ids: List[int]) -> Dict:
|
|
34
|
+
url = f"{api_url_ssl}/job/get_description"
|
|
35
|
+
print(f"Testing URL: {url}")
|
|
36
|
+
data = {"job_ids": [PANDA_JOB_ID]}
|
|
37
|
+
status, output = self.http_client.get(url, data)
|
|
38
|
+
print(output)
|
|
39
|
+
output["status"] = status
|
|
40
|
+
del output["data"]
|
|
41
|
+
del output["message"]
|
|
42
|
+
|
|
43
|
+
# Returns success=True regardless (returns [None] for unknown job IDs)
|
|
44
|
+
expected_response = {"status": 0, "success": True}
|
|
45
|
+
self.assertEqual(output, expected_response)
|
|
46
|
+
|
|
47
|
+
def test_get_description_incl_archive(self):
|
|
48
|
+
# def get_description_incl_archive(req: PandaRequest, job_ids: List[int]) -> Dict:
|
|
49
|
+
url = f"{api_url_ssl}/job/get_description_incl_archive"
|
|
50
|
+
print(f"Testing URL: {url}")
|
|
51
|
+
data = {"job_ids": [PANDA_JOB_ID]}
|
|
52
|
+
status, output = self.http_client.get(url, data)
|
|
53
|
+
print(output)
|
|
54
|
+
output["status"] = status
|
|
55
|
+
del output["data"]
|
|
56
|
+
del output["message"]
|
|
57
|
+
|
|
58
|
+
# Returns success=True regardless (returns [None] for unknown job IDs)
|
|
59
|
+
expected_response = {"status": 0, "success": True}
|
|
60
|
+
self.assertEqual(output, expected_response)
|
|
61
|
+
|
|
62
|
+
def test_get_metadata_for_analysis_jobs(self):
|
|
63
|
+
# def get_metadata_for_analysis_jobs(req: PandaRequest, task_id: int) -> Dict:
|
|
64
|
+
url = f"{api_url_ssl}/job/get_metadata_for_analysis_jobs"
|
|
65
|
+
print(f"Testing URL: {url}")
|
|
66
|
+
data = {"task_id": JEDI_TASK_ID}
|
|
67
|
+
status, output = self.http_client.get(url, data)
|
|
68
|
+
print(output)
|
|
69
|
+
output["status"] = status
|
|
70
|
+
del output["data"]
|
|
71
|
+
|
|
72
|
+
if JEDI_TASK_ID == -1:
|
|
73
|
+
# Fake task returns success=True with "No metadata found" message
|
|
74
|
+
expected_response = {"status": 0, "success": True, "message": "No metadata found"}
|
|
75
|
+
else:
|
|
76
|
+
# Real task
|
|
77
|
+
expected_response = {"status": 0, "success": True, "message": ""}
|
|
78
|
+
output["message"] = ""
|
|
79
|
+
self.assertEqual(output, expected_response)
|
|
80
|
+
|
|
81
|
+
def test_kill(self):
|
|
82
|
+
# def kill(req, job_ids: List[int], code: int = None, ...) -> Dict:
|
|
83
|
+
url = f"{api_url_ssl}/job/kill"
|
|
84
|
+
print(f"Testing URL: {url}")
|
|
85
|
+
data = {"job_ids": [PANDA_JOB_ID]}
|
|
86
|
+
status, output = self.http_client.post(url, data)
|
|
87
|
+
print(output)
|
|
88
|
+
output["status"] = status
|
|
89
|
+
del output["data"]
|
|
90
|
+
del output["message"]
|
|
91
|
+
|
|
92
|
+
# killJobs always returns success=True
|
|
93
|
+
expected_response = {"status": 0, "success": True}
|
|
94
|
+
self.assertEqual(output, expected_response)
|
|
95
|
+
|
|
96
|
+
def test_reassign(self):
|
|
97
|
+
# def reassign(req: PandaRequest, job_ids: List[int]) -> Dict:
|
|
98
|
+
url = f"{api_url_ssl}/job/reassign"
|
|
99
|
+
print(f"Testing URL: {url}")
|
|
100
|
+
data = {"job_ids": [PANDA_JOB_ID]}
|
|
101
|
+
status, output = self.http_client.post(url, data)
|
|
102
|
+
print(output)
|
|
103
|
+
output["status"] = status
|
|
104
|
+
del output["message"]
|
|
105
|
+
|
|
106
|
+
# reassignJobs always returns success=True
|
|
107
|
+
expected_response = {"status": 0, "success": True, "data": None}
|
|
108
|
+
self.assertEqual(output, expected_response)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if __name__ == "__main__":
|
|
112
|
+
unittest.main()
|