rucio-clients 38.4.0__tar.gz → 38.5.0__tar.gz

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.

Potentially problematic release.


This version of rucio-clients might be problematic. Click here for more details.

Files changed (202) hide show
  1. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/PKG-INFO +1 -1
  2. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/etc/rucio.cfg.template +2 -3
  3. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/bin_legacy/rucio.py +12 -7
  4. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/bin_legacy/rucio_admin.py +9 -2
  5. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/replica.py +6 -2
  6. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/rule.py +0 -1
  7. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/scope.py +9 -0
  8. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/utils.py +11 -0
  9. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/downloadclient.py +3 -1
  10. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/scopeclient.py +40 -1
  11. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/didtype.py +18 -11
  12. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/vcsversion.py +3 -3
  13. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_bin_rucio.py +79 -0
  14. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_cli_client_structure.py +13 -4
  15. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_conveyor.py +22 -15
  16. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_did_meta_plugins.py +21 -0
  17. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_gateway_external_representation.py +1 -1
  18. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_multi_vo.py +2 -2
  19. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_policy_package.py +41 -0
  20. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse.py +14 -0
  21. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_scope.py +64 -2
  22. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/AUTHORS.rst +0 -0
  23. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/ChangeLog +0 -0
  24. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/LICENSE +0 -0
  25. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/MANIFEST.in +0 -0
  26. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/README.md +0 -0
  27. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/bin/rucio +0 -0
  28. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/bin/rucio-admin +0 -0
  29. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/etc/rse-accounts.cfg.template +0 -0
  30. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/etc/rucio.cfg.atlas.client.template +0 -0
  31. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/__init__.py +0 -0
  32. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/alembicrevision.py +0 -0
  33. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/__init__.py +0 -0
  34. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/account.py +0 -0
  35. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/bin_legacy/__init__.py +0 -0
  36. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/command.py +0 -0
  37. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/config.py +0 -0
  38. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/did.py +0 -0
  39. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/download.py +0 -0
  40. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/lifetime_exception.py +0 -0
  41. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/opendata.py +0 -0
  42. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/rse.py +0 -0
  43. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/subscription.py +0 -0
  44. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/cli/upload.py +0 -0
  45. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/__init__.py +0 -0
  46. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/accountclient.py +0 -0
  47. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/accountlimitclient.py +0 -0
  48. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/baseclient.py +0 -0
  49. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/client.py +0 -0
  50. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/configclient.py +0 -0
  51. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/credentialclient.py +0 -0
  52. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/didclient.py +0 -0
  53. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/diracclient.py +0 -0
  54. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/exportclient.py +0 -0
  55. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/importclient.py +0 -0
  56. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/lifetimeclient.py +0 -0
  57. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/lockclient.py +0 -0
  58. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/metaconventionsclient.py +0 -0
  59. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/opendataclient.py +0 -0
  60. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/pingclient.py +0 -0
  61. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/replicaclient.py +0 -0
  62. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/requestclient.py +0 -0
  63. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/richclient.py +0 -0
  64. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/rseclient.py +0 -0
  65. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/ruleclient.py +0 -0
  66. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/subscriptionclient.py +0 -0
  67. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/touchclient.py +0 -0
  68. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/client/uploadclient.py +0 -0
  69. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/__init__.py +0 -0
  70. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/bittorrent.py +0 -0
  71. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/cache.py +0 -0
  72. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/checksum.py +0 -0
  73. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/client.py +0 -0
  74. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/config.py +0 -0
  75. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/constants.py +0 -0
  76. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/constraints.py +0 -0
  77. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/exception.py +0 -0
  78. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/extra.py +0 -0
  79. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/logging.py +0 -0
  80. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/pcache.py +0 -0
  81. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/plugins.py +0 -0
  82. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/policy.py +0 -0
  83. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/schema/__init__.py +0 -0
  84. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/schema/generic.py +0 -0
  85. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/schema/generic_multi_vo.py +0 -0
  86. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/stomp_utils.py +0 -0
  87. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/stopwatch.py +0 -0
  88. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/test_rucio_server.py +0 -0
  89. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/types.py +0 -0
  90. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/common/utils.py +0 -0
  91. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/__init__.py +0 -0
  92. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/__init__.py +0 -0
  93. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/bittorrent.py +0 -0
  94. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/cache.py +0 -0
  95. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/dummy.py +0 -0
  96. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/gfal.py +0 -0
  97. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/globus.py +0 -0
  98. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/http_cache.py +0 -0
  99. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/mock.py +0 -0
  100. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/ngarc.py +0 -0
  101. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/posix.py +0 -0
  102. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/protocol.py +0 -0
  103. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/rclone.py +0 -0
  104. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/rfio.py +0 -0
  105. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/srm.py +0 -0
  106. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/ssh.py +0 -0
  107. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/storm.py +0 -0
  108. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/webdav.py +0 -0
  109. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/protocols/xrootd.py +0 -0
  110. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/rsemanager.py +0 -0
  111. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/rse/translation.py +0 -0
  112. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio/version.py +0 -0
  113. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/lib/rucio_clients.egg-info/SOURCES.txt +0 -0
  114. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/pyproject.toml +0 -0
  115. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/requirements/requirements.client.txt +0 -0
  116. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/setup.cfg +0 -0
  117. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/setup.py +0 -0
  118. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/setuputil.py +0 -0
  119. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_abacus_account.py +0 -0
  120. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_abacus_collection_replica.py +0 -0
  121. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_abacus_rse.py +0 -0
  122. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_account.py +0 -0
  123. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_account_limits.py +0 -0
  124. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_archive.py +0 -0
  125. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_auditor.py +0 -0
  126. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_auditor_hdfs.py +0 -0
  127. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_auditor_srmdumps.py +0 -0
  128. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_authentication.py +0 -0
  129. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_automatix.py +0 -0
  130. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_bad_replica.py +0 -0
  131. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_bb8.py +0 -0
  132. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_belleii.py +0 -0
  133. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_boolean.py +0 -0
  134. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_clients.py +0 -0
  135. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_config.py +0 -0
  136. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_conveyor_submitter.py +0 -0
  137. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_counter.py +0 -0
  138. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_credential.py +0 -0
  139. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_curl.py +0 -0
  140. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_daemons.py +0 -0
  141. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_dataset_replicas.py +0 -0
  142. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_db.py +0 -0
  143. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_did.py +0 -0
  144. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_download.py +0 -0
  145. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_dumper.py +0 -0
  146. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_filter_engine.py +0 -0
  147. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_heartbeat.py +0 -0
  148. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_hermes.py +0 -0
  149. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_identity.py +0 -0
  150. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_impl_upload_download.py +0 -0
  151. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_import_export.py +0 -0
  152. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_judge_cleaner.py +0 -0
  153. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_judge_evaluator.py +0 -0
  154. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_judge_injector.py +0 -0
  155. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_judge_repairer.py +0 -0
  156. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_lifetime.py +0 -0
  157. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_message.py +0 -0
  158. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_meta_conventions.py +0 -0
  159. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_meta_did.py +0 -0
  160. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_module_import.py +0 -0
  161. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_monitor.py +0 -0
  162. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_naming_convention.py +0 -0
  163. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_oauthmanager.py +0 -0
  164. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_oidc.py +0 -0
  165. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_opendata.py +0 -0
  166. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_permission.py +0 -0
  167. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_pfns.py +0 -0
  168. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_ping.py +0 -0
  169. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_preparer.py +0 -0
  170. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_qos.py +0 -0
  171. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_quarantined_replica.py +0 -0
  172. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_reaper.py +0 -0
  173. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_redirect.py +0 -0
  174. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_replica.py +0 -0
  175. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_replica_recoverer.py +0 -0
  176. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_replica_sorting.py +0 -0
  177. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_request.py +0 -0
  178. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_root_proxy.py +0 -0
  179. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_expression_parser.py +0 -0
  180. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_lfn2path.py +0 -0
  181. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_protocol_gfal2.py +0 -0
  182. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_protocol_gfal2_impl.py +0 -0
  183. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_protocol_posix.py +0 -0
  184. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_protocol_rclone.py +0 -0
  185. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_protocol_rsync.py +0 -0
  186. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_protocol_srm.py +0 -0
  187. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_protocol_ssh.py +0 -0
  188. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_protocol_webdav.py +0 -0
  189. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_protocol_xrootd.py +0 -0
  190. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rse_selector.py +0 -0
  191. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rucio_server.py +0 -0
  192. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_rule.py +0 -0
  193. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_subscription.py +0 -0
  194. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_throttler.py +0 -0
  195. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_tpc.py +0 -0
  196. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_trace.py +0 -0
  197. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_transfer.py +0 -0
  198. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_transfer_plugins.py +0 -0
  199. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_undertaker.py +0 -0
  200. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_upload.py +0 -0
  201. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tests/test_utils.py +0 -0
  202. {rucio_clients-38.4.0 → rucio_clients-38.5.0}/tools/merge_rucio_configs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rucio-clients
3
- Version: 38.4.0
3
+ Version: 38.5.0
4
4
  Summary: Rucio Client Lite Package
5
5
  Home-page: https://rucio.cern.ch/
6
6
  Author: Rucio
@@ -121,8 +121,8 @@ usercert = /opt/rucio/tools/x509up
121
121
 
122
122
  [messaging-fts3]
123
123
  port = 61123
124
- ssl_key_file = /home/mario/.ssh/hostkey.pem
125
- ssl_cert_file = /home/mario/.ssh/hostcert.pem
124
+ ssl_key_file = /etc/grid-security/hostkey.pem
125
+ ssl_cert_file = /etc/grid-security/hostcert.pem
126
126
  destination = /topic/transfer.fts_monitoring_queue_state
127
127
  brokers = dashb-test-mb.cern.ch
128
128
  voname = atlas
@@ -199,7 +199,6 @@ account = cache_mb
199
199
  cacert = /opt/rucio/etc/web/ca.crt
200
200
  #cacert = /etc/pki/tls/certs/CERN-bundle.pem
201
201
  usercert = /opt/rucio/etc/web/usercert.pem
202
- #usercert = /home/mario/.ssh/usercert_with_key.pem
203
202
 
204
203
  [nagios]
205
204
  proxy = /opt/rucio/etc/ddmadmin.proxy.nagios
@@ -36,7 +36,7 @@ from tabulate import tabulate
36
36
 
37
37
  # rucio module has the same name as this executable module, so this rule fails. pylint: disable=no-name-in-module
38
38
  from rucio import version
39
- from rucio.cli.utils import exception_handler, get_client, setup_gfal2_logger, signal_handler
39
+ from rucio.cli.utils import exception_handler, get_client, scope_exists, setup_gfal2_logger, signal_handler
40
40
  from rucio.client.richclient import MAX_TRACEBACK_WIDTH, MIN_CONSOLE_WIDTH, CLITheme, generate_table, get_cli_config, get_pager, print_output, setup_rich_logger
41
41
  from rucio.common.client import detect_client_location
42
42
  from rucio.common.config import config_get, config_get_float
@@ -48,7 +48,6 @@ from rucio.common.exception import (
48
48
  InvalidType,
49
49
  RSENotFound,
50
50
  RucioException,
51
- ScopeNotFound,
52
51
  UnsupportedOperation,
53
52
  )
54
53
  from rucio.common.extra import import_extras
@@ -459,8 +458,7 @@ def list_dids(args, client, logger, console, spinner):
459
458
  scope = args.did[0]
460
459
  name = '*'
461
460
 
462
- if scope not in client.list_scopes():
463
- raise ScopeNotFound
461
+ scope_exists(client, scope)
464
462
 
465
463
  if args.recursive and '*' in name:
466
464
  raise InputValidationError('Option recursive cannot be used with wildcards.')
@@ -522,12 +520,19 @@ def list_scopes(args, client, logger, console, spinner):
522
520
  scopes = client.list_scopes()
523
521
  if (cli_config == 'rich') and (not args.csv):
524
522
  scopes = [[scope] for scope in sorted(scopes)]
525
- table = generate_table(scopes, headers=['SCOPE'], col_alignments=['left'])
523
+ table = generate_table(scopes, headers=['SCOPE', 'ACCOUNT'], col_alignments=['left'])
526
524
  spinner.stop()
527
525
  print_output(table, console=console, no_pager=args.no_pager)
528
526
  else:
529
- for scope in scopes:
530
- print(scope)
527
+ if isinstance(scopes[0], str): # TODO: Backwards compatibility - remove in v40 issue #8125
528
+ for scope in scopes:
529
+ print(scope)
530
+ elif args.csv:
531
+ for scope in scopes:
532
+ print(scope['scope'])
533
+ else:
534
+ scopes = [[s['scope'], s['account']] for s in scopes]
535
+ print(tabulate(scopes, tablefmt=tablefmt, headers=['SCOPE', 'ACCOUNT'], disable_numparse=True))
531
536
  return SUCCESS
532
537
 
533
538
 
@@ -780,8 +780,15 @@ def list_scopes(args, client, logger, console, spinner):
780
780
  spinner.stop()
781
781
  print_output(table, console=console, no_pager=args.no_pager)
782
782
  else:
783
- for scope in scopes:
784
- print(scope)
783
+ if isinstance(scopes[0], str): # TODO: Backwards compatibility - remove in v40 issue #8125
784
+ for scope in scopes:
785
+ print(scope)
786
+ elif args.csv:
787
+ for scope in scopes:
788
+ print(scope['scope'])
789
+ else:
790
+ scopes = [[s['scope'], s['account']] for s in scopes]
791
+ print(tabulate(scopes, tablefmt=tablefmt, headers=['SCOPE', 'ACCOUNT'], disable_numparse=True))
785
792
  return SUCCESS
786
793
 
787
794
 
@@ -129,11 +129,15 @@ def update_bad(ctx, replicas, reason, as_file, collection, lfn, scope, rse):
129
129
  """Mark a replica bad"""
130
130
  args = {"reason": reason, "allow_collection": collection, "scope": scope, "rse": rse}
131
131
  if as_file:
132
- args["inputfile"] = replicas
132
+ if len(replicas) != 1:
133
+ raise ValueError("Exactly one positional argument expected in case as-file")
134
+ args["inputfile"] = replicas[0]
133
135
  elif lfn:
134
136
  if (scope is None) or (rse is None):
135
137
  raise ValueError("Scope and RSE are required when using LFNs")
136
- args["lfns"] = replicas
138
+ if len(replicas) != 1:
139
+ raise ValueError("Exactly one positional argument expected in case of LFN list")
140
+ args["lfns"] = replicas[0]
137
141
  else:
138
142
  args["listbadfiles"] = replicas
139
143
  declare_bad_file_replicas(Arguments(args), ctx.obj.client, ctx.obj.logger, ctx.obj.console, ctx.obj.spinner)
@@ -118,7 +118,6 @@ def move(ctx, rule_id, rses, activity, source_rses):
118
118
  @click.option("--account", help="The account owning the rule")
119
119
  @click.option("--stuck", is_flag=True, default=False, help="Set state to STUCK.")
120
120
  @click.option('--suspend', is_flag=True, default=None, help='Set state to SUSPENDED.')
121
- @click.option("--activity", help="Activity of the rule.")
122
121
  @click.option("--cancel-requests", is_flag=True, default=False, help="Cancel requests when setting rules to stuck.")
123
122
  @click.option("--priority", help="Priority of the requests of the rule.")
124
123
  @click.option("--child-rule-id", help='Child rule id of the rule. Use "None" to remove an existing parent/child relationship.')
@@ -39,3 +39,12 @@ def add_(ctx, account, scope_name):
39
39
  def list_(ctx: click.Context, account: str, csv: bool):
40
40
  """List existing scopes"""
41
41
  list_scopes(Arguments({"no_pager": ctx.obj.no_pager, "account": account, "csv": csv}), ctx.obj.client, ctx.obj.logger, ctx.obj.console, ctx.obj.spinner)
42
+
43
+
44
+ @scope.command("update")
45
+ @click.argument('scope-name')
46
+ @click.option('-a', '--account', help="New account to associate with the scope", required=True)
47
+ @click.pass_context
48
+ def update(ctx: click.Context, scope_name: str, account: str):
49
+ """Update the ownership of a [SCOPE-NAME]"""
50
+ ctx.obj.client.update_scope_ownership(account=account, scope=scope_name)
@@ -41,6 +41,7 @@ from rucio.common.exception import (
41
41
  RSENotFound,
42
42
  RucioException,
43
43
  RuleNotFound,
44
+ ScopeNotFound,
44
45
  UnsupportedOperation,
45
46
  )
46
47
  from rucio.common.utils import setup_logger
@@ -260,3 +261,13 @@ class JSONType(click.ParamType):
260
261
  return json.loads(value)
261
262
  except json.JSONDecodeError as e:
262
263
  self.fail(f"Invalid JSON: {e}", param, ctx)
264
+
265
+
266
+ def scope_exists(client: 'Client', scope: str) -> None:
267
+ possible_scopes = client.list_scopes()
268
+ if isinstance(possible_scopes[0], str): # type: ignore #TODO Backwards Compat - Remove in v40, #8125
269
+ scopes = possible_scopes
270
+ else:
271
+ scopes = [s['scope'] for s in possible_scopes] # type: ignore
272
+ if scope not in scopes: # type: ignore - handled by the if isinstance
273
+ raise ScopeNotFound
@@ -1856,7 +1856,9 @@ class DownloadClient:
1856
1856
  did_name = did[1]
1857
1857
  elif len(did) == 1:
1858
1858
  if self.extract_scope_convention == 'belleii':
1859
- scopes = [scope for scope in self.client.list_scopes()]
1859
+ scopes = self.client.list_scopes()
1860
+ if not isinstance(scopes, list):
1861
+ scopes = [scope['scope'] for scope in scopes]
1860
1862
  did_scope, did_name = extract_scope(did[0], scopes)
1861
1863
  else:
1862
1864
  did = did_str.split('.')
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  from json import loads
16
+ from typing import TYPE_CHECKING, Any, Literal, Union
16
17
  from urllib.parse import quote_plus
17
18
 
18
19
  from requests.status_codes import codes
@@ -21,6 +22,9 @@ from rucio.client.baseclient import BaseClient, choice
21
22
  from rucio.common.constants import HTTPMethod
22
23
  from rucio.common.utils import build_url
23
24
 
25
+ if TYPE_CHECKING:
26
+ from collections.abc import Iterator
27
+
24
28
 
25
29
  class ScopeClient(BaseClient):
26
30
 
@@ -64,7 +68,7 @@ class ScopeClient(BaseClient):
64
68
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
65
69
  raise exc_cls(exc_msg)
66
70
 
67
- def list_scopes(self) -> list[str]:
71
+ def list_scopes(self) -> "Union[list[str], Iterator[dict[Literal['scope', 'account'], Any]]]":
68
72
  """
69
73
  Sends the request to list all scopes.
70
74
 
@@ -83,6 +87,41 @@ class ScopeClient(BaseClient):
83
87
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
84
88
  raise exc_cls(exc_msg)
85
89
 
90
+ def update_scope_ownership(self, account: str, scope: str) -> bool:
91
+ """
92
+ Change the ownership of a scope
93
+
94
+ Parameters
95
+ ----------
96
+ account :
97
+ New account to assign as scope owner
98
+ scope :
99
+ Scope to change ownership of
100
+
101
+ Returns
102
+ -------
103
+ bool
104
+ True if the operation was successful
105
+
106
+ Raises
107
+ ------
108
+ AccountNotFound
109
+ If account doesn't exist.
110
+ ScopeNotFound
111
+ If scope doesn't exist.
112
+ CannotAuthenticate, AccessDenied
113
+ Insufficient permission/incorrect credentials to change ownership.
114
+ """
115
+
116
+ path = '/'.join(['scopes', account, scope])
117
+ url = build_url(choice(self.list_hosts), path=path)
118
+ r = self._send_request(url, method=HTTPMethod.PUT)
119
+ if r.status_code == codes.ok:
120
+ return True
121
+ else:
122
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
123
+ raise exc_cls(exc_msg)
124
+
86
125
  def list_scopes_for_account(self, account: str) -> list[str]:
87
126
  """
88
127
  Sends the request to list all scopes for a rucio account.
@@ -15,10 +15,12 @@
15
15
  """
16
16
  DID type to represent a DID and to simplify operations on it
17
17
  """
18
-
18
+ import logging
19
+ from configparser import NoSectionError
19
20
  from typing import Any, Union
20
21
 
21
- from rucio.common.exception import DIDError
22
+ from rucio.common.exception import ConfigNotFound, DIDError, InvalidAlgorithmName
23
+ from rucio.common.utils import extract_scope
22
24
 
23
25
 
24
26
  class DID:
@@ -126,15 +128,20 @@ class DID:
126
128
  Construct the DID from a string.
127
129
  :param did: string containing the DID information
128
130
  """
129
- did_parts = did.split(DID.SCOPE_SEPARATOR, 1)
130
- if len(did_parts) == 1:
131
- self.name = did
132
- self._update_implicit_scope()
133
- if not self.has_scope():
134
- raise DIDError('Object construction from non-splitable string is ambigious')
135
- else:
136
- self.scope = did_parts[0]
137
- self.name = did_parts[1]
131
+ try:
132
+ self.scope, self.name = extract_scope(did)
133
+ except (ImportError, InvalidAlgorithmName, ConfigNotFound, NoSectionError) as e: # Only use when the policy can not be found
134
+ logging.debug("Failure using extract_scope policy for '%s': %s - Using fallback." % (did, type(e).__name__))
135
+ did_parts = did.split(DID.SCOPE_SEPARATOR, 1)
136
+ if len(did_parts) == 1:
137
+ self.name = did
138
+ self._update_implicit_scope()
139
+ if not self.has_scope():
140
+ error = f"Could not parse scope from did string {did} - fallback policy expects only one '{DID.SCOPE_SEPARATOR}'"
141
+ raise DIDError(error)
142
+ else:
143
+ self.scope = did_parts[0]
144
+ self.name = did_parts[1]
138
145
 
139
146
  def _did_from_dict(self, did: dict[str, str]) -> None:
140
147
  """
@@ -4,8 +4,8 @@ This file is automatically generated; Do not edit it. :)
4
4
  '''
5
5
  VERSION_INFO = {
6
6
  'final': True,
7
- 'version': '38.4.0',
7
+ 'version': '38.5.0',
8
8
  'branch_nick': 'release-38-LTS',
9
- 'revision_id': '945ab71be90243fe96148bb3bd13c1c3ae410765',
10
- 'revno': 14030
9
+ 'revision_id': '430fd3dd8f4dc5103e1e932c9515421e1c515c3e',
10
+ 'revno': 14073
11
11
  }
@@ -12,9 +12,11 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import logging
15
16
  import os
16
17
  import random
17
18
  import re
19
+ import shlex
18
20
  import tempfile
19
21
  from datetime import datetime, timedelta, timezone
20
22
 
@@ -1292,3 +1294,80 @@ def test_download_file_check_by_size(rse_factory, mock_scope, did_factory):
1292
1294
  exitcode, out, err = execute(cmd)
1293
1295
  assert exitcode == 0
1294
1296
  assert "File with same name exists locally, but filesize mismatches" in err
1297
+
1298
+
1299
+ @pytest.mark.parametrize(
1300
+ ("cli", "lfn"),
1301
+ [
1302
+ ("new", True),
1303
+ ("old", True),
1304
+ ("new", False),
1305
+ ("old", False),
1306
+ ]
1307
+ )
1308
+ def test_cli_declare_bad_replicas(cli, lfn, rse_factory, mock_scope, did_factory, tmp_path, rucio_client):
1309
+ """CLIENT(USER): Rucio declare bad replica"""
1310
+ log = logging.getLogger("bad-replicas")
1311
+
1312
+ rse, _ = rse_factory.make_posix_rse()
1313
+ scope = mock_scope.external
1314
+
1315
+ did = did_factory.upload_test_file(rse_name=rse, scope=scope)
1316
+ # replace scope object with scope name str
1317
+ did["scope"] = did["scope"].external
1318
+
1319
+ cmd = []
1320
+ if cli == "new":
1321
+ cmd = ["rucio", "replica", "state", "update", "bad"]
1322
+ else:
1323
+ cmd = ["rucio-admin", "replicas", "declare-bad"]
1324
+
1325
+ cmd.extend(["--reason", "test"])
1326
+
1327
+ bad_replicas = []
1328
+
1329
+ if lfn:
1330
+ lfn_path = tmp_path / "lfns.txt"
1331
+ lfn_path.write_text(did["name"] + "\n")
1332
+
1333
+ if cli == "new":
1334
+ cmd.append("--lfn")
1335
+ bad_replicas.append(str(lfn_path))
1336
+ else:
1337
+ cmd.extend(["--lfns", str(lfn_path)])
1338
+
1339
+ cmd.extend(["--rse", rse, "--scope", scope])
1340
+ else:
1341
+ bad_replicas.append(f"{did['scope']}:{did['name']}")
1342
+
1343
+ cmd.extend(bad_replicas)
1344
+ cmd = shlex.join(cmd)
1345
+
1346
+ code, stdout, stderr = execute(cmd)
1347
+ log.info("Command stdout:\n%s", stdout)
1348
+ log.warning("Command stderr:\n%s", stderr)
1349
+ assert code == 0, f"Running {cmd} failed. out:\n{stdout}\nerr\n{stderr}"
1350
+
1351
+ replicas = next(rucio_client.list_replicas([did], rse_expression=rse, all_states=True))
1352
+ assert replicas["states"][rse] == "BAD"
1353
+
1354
+
1355
+ def test_cli_declare_bad_replicas_invalid_usage():
1356
+ """CLIENT(USER): Rucio declare bad replica invalid argument handling"""
1357
+ base_cmd = ["rucio", "replica", "state", "update", "bad"]
1358
+
1359
+ def run(expected_error, args=None, expected_code=1):
1360
+ args = args or []
1361
+ cmd = shlex.join(base_cmd + args)
1362
+ code, stdout, stderr = execute(cmd)
1363
+
1364
+ assert code == expected_code, f"Running {cmd} did not fail as expected. out:\n{stdout}\nerr\n{stderr}"
1365
+ assert expected_error in stderr, f"Expected error message not found in stderr:\n{stderr}"
1366
+
1367
+ run("Missing option '--reason'", expected_code=2)
1368
+
1369
+ args = ["--reason", "test", "--lfn", "foo"]
1370
+ run("Scope and RSE are required", args=args, expected_code=1)
1371
+
1372
+ args = ["--reason", "test", "--scope", "test", "--rse", "test", "--lfn", "foo", "bar"]
1373
+ run("Exactly one", args=args, expected_code=1)
@@ -857,20 +857,29 @@ def test_rule(rucio_client, mock_scope):
857
857
  assert len(out.split("\n")) == 3 # Creates two rules with independent IDs and one extra line at the end
858
858
 
859
859
 
860
- def test_scope():
861
- new_scope = scope_name_generator()
862
- cmd = f"rucio scope add {new_scope} --account root"
860
+ def test_scope(rucio_client, scope_factory, random_account_factory, vo):
861
+ scope = scope_name_generator()
862
+ account = random_account_factory().external
863
+ cmd = f"rucio scope add {scope} --account {account}"
863
864
  exitcode, _, err = execute(cmd)
864
865
  assert exitcode == 0
865
866
  assert "ERROR" not in err
866
867
 
867
- cmd = "rucio scope list --account root"
868
+ cmd = f"rucio scope list --account {account}"
868
869
  exitcode, out, err = execute(cmd)
869
870
  assert exitcode == 0
870
871
  assert "ERROR" not in err
871
872
  # assert new_scope in out
872
873
  # See issue https://github.com/rucio/rucio/issues/7316
873
874
 
875
+ new_scope, _ = scope_factory(vos=[vo], account_name=account)
876
+ new_account = random_account_factory().external
877
+ cmd = f"rucio scope update {new_scope} --account {new_account}"
878
+ exitcode, out, err = execute(cmd)
879
+ assert exitcode == 0
880
+ assert "ERROR" not in err
881
+ assert new_scope in rucio_client.list_scopes_for_account(new_account)
882
+
874
883
 
875
884
  def test_subscription(rucio_client, mock_scope):
876
885
  subscription_name = generate_uuid()
@@ -452,7 +452,6 @@ def test_multisource(vo, did_factory, root_account, replica_client, caches_mock,
452
452
  )
453
453
 
454
454
 
455
- @pytest.mark.skip(reason="Pending https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC4506150")
456
455
  @skip_rse_tests_with_accounts
457
456
  @pytest.mark.dirty(reason="leaves files in XRD containers")
458
457
  @pytest.mark.noparallel(groups=[NoParallelGroups.XRD, NoParallelGroups.SUBMITTER, NoParallelGroups.RECEIVER])
@@ -526,7 +525,6 @@ def test_multisource_receiver(vo, did_factory, replica_client, root_account, met
526
525
  RECEIVER_GRACEFUL_STOP.clear()
527
526
 
528
527
 
529
- @pytest.mark.skip(reason="Pending https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC4506150")
530
528
  @skip_rse_tests_with_accounts
531
529
  @pytest.mark.noparallel(groups=[NoParallelGroups.XRD, NoParallelGroups.SUBMITTER, NoParallelGroups.RECEIVER])
532
530
  @pytest.mark.parametrize("caches_mock", [{"caches_to_mock": [
@@ -581,7 +579,6 @@ def test_multihop_receiver_on_failure(vo, did_factory, replica_client, root_acco
581
579
  RECEIVER_GRACEFUL_STOP.clear()
582
580
 
583
581
 
584
- @pytest.mark.skip(reason="Pending https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC4506150")
585
582
  @skip_rse_tests_with_accounts
586
583
  @pytest.mark.noparallel(groups=[NoParallelGroups.XRD, NoParallelGroups.SUBMITTER, NoParallelGroups.RECEIVER])
587
584
  @pytest.mark.parametrize("caches_mock", [{"caches_to_mock": [
@@ -626,7 +623,6 @@ def test_multihop_receiver_on_success(vo, did_factory, root_account, caches_mock
626
623
  RECEIVER_GRACEFUL_STOP.clear()
627
624
 
628
625
 
629
- @pytest.mark.skip(reason="Pending https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC4506150")
630
626
  @skip_rse_tests_with_accounts
631
627
  @pytest.mark.dirty(reason="leaves files in XRD containers")
632
628
  @pytest.mark.noparallel(groups=[NoParallelGroups.XRD, NoParallelGroups.SUBMITTER, NoParallelGroups.RECEIVER, NoParallelGroups.POLLER])
@@ -696,7 +692,6 @@ def test_receiver_archiving(vo, did_factory, root_account, caches_mock, scitags_
696
692
  RECEIVER_GRACEFUL_STOP.clear()
697
693
 
698
694
 
699
- @pytest.mark.skip(reason="Pending https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC4506150")
700
695
  @skip_rse_tests_with_accounts
701
696
  @pytest.mark.noparallel(groups=[NoParallelGroups.PREPARER, NoParallelGroups.THROTTLER, NoParallelGroups.SUBMITTER, NoParallelGroups.POLLER])
702
697
  @pytest.mark.parametrize("file_config_mock", [{
@@ -713,6 +708,10 @@ def test_preparer_throttler_submitter(rse_factory, did_factory, root_account, fi
713
708
 
714
709
  for rse_id in all_rses:
715
710
  rse_core.add_rse_attribute(rse_id, RseAttr.FTS, TEST_FTS_HOST)
711
+ # Disable checksum verification
712
+ # to avoid user-defining source and destination checksum for each transfer
713
+ # (required when using the mock protocol on FTS >= 3.14.1)
714
+ rse_core.add_rse_attribute(rse_id, RseAttr.VERIFY_CHECKSUM, False)
716
715
  distance_core.add_distance(src_rse_id, dst_rse_id1, distance=10)
717
716
  distance_core.add_distance(src_rse_id, dst_rse_id2, distance=10)
718
717
  # Set limits only for one of the RSEs
@@ -1029,7 +1028,6 @@ def test_failed_transfers_to_mas_existing_replica(rse_factory, did_factory, root
1029
1028
  assert rule_core.get_rule(rule2_id)['state'] == RuleState.STUCK
1030
1029
 
1031
1030
 
1032
- @pytest.mark.skip(reason="Pending https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC4506150")
1033
1031
  @skip_rse_tests_with_accounts
1034
1032
  @pytest.mark.noparallel(groups=[NoParallelGroups.SUBMITTER, NoParallelGroups.POLLER, NoParallelGroups.FINISHER])
1035
1033
  def test_lost_transfers(rse_factory, did_factory, root_account):
@@ -1045,11 +1043,21 @@ def test_lost_transfers(rse_factory, did_factory, root_account):
1045
1043
  rse_core.add_rse_attribute(rse_id, RseAttr.FTS, TEST_FTS_HOST)
1046
1044
 
1047
1045
  did = did_factory.upload_test_file(src_rse)
1046
+ replica = replica_core.get_replica(rse_id=src_rse_id, **did)
1048
1047
 
1049
1048
  rule_core.add_rule(dids=[did], account=root_account, copies=1, rse_expression=dst_rse, grouping='ALL', weight=None, lifetime=None, locked=False, subscription_id=None)
1050
1049
 
1051
- # Fake that the transfer is submitted and lost
1052
- submitter(once=True, rses=[{'id': rse_id} for rse_id in all_rses], group_bulk=2, partition_wait_time=0, transfertype='single', filter_transfertool=None)
1050
+ class _FTSWrapper(FTSWrapper):
1051
+ @staticmethod
1052
+ def on_submit(file):
1053
+ # Set the correct checksum on both source and destination
1054
+ file['sources'] = [set_query_parameters(s_url, {'checksum': replica['adler32']}) for s_url in file['sources']]
1055
+ file['destinations'] = [set_query_parameters(d_url, {'checksum': replica['adler32']}) for d_url in file['destinations']]
1056
+
1057
+ with patch('rucio.core.transfer.TRANSFERTOOL_CLASSES_BY_NAME', new={'fts3': _FTSWrapper}):
1058
+ # Fake that the transfer is submitted and lost
1059
+ submitter(once=True, rses=[{'id': rse_id} for rse_id in all_rses], group_bulk=2, partition_wait_time=0, transfertype='single', filter_transfertool=None)
1060
+
1053
1061
  request = request_core.get_request_by_did(rse_id=dst_rse_id, **did)
1054
1062
  __update_request(request['id'], external_id='some-fake-random-id')
1055
1063
 
@@ -1064,7 +1072,8 @@ def test_lost_transfers(rse_factory, did_factory, root_account):
1064
1072
  # The source ranking must not be updated for submission failures and lost transfers
1065
1073
  request = request_core.get_request_by_did(rse_id=dst_rse_id, **did)
1066
1074
  assert __get_source(request_id=request['id'], src_rse_id=src_rse_id, **did).ranking == 0
1067
- submitter(once=True, rses=[{'id': rse_id} for rse_id in all_rses], group_bulk=2, partition_wait_time=0, transfertype='single', filter_transfertool=None)
1075
+ with patch('rucio.core.transfer.TRANSFERTOOL_CLASSES_BY_NAME', new={'fts3': _FTSWrapper}):
1076
+ submitter(once=True, rses=[{'id': rse_id} for rse_id in all_rses], group_bulk=2, partition_wait_time=0, transfertype='single', filter_transfertool=None)
1068
1077
  replica = __wait_for_replica_transfer(dst_rse_id=dst_rse_id, **did)
1069
1078
  assert replica['state'] == ReplicaState.AVAILABLE
1070
1079
 
@@ -1430,7 +1439,6 @@ def test_multi_vo_certificates(file_config_mock, rse_factory, did_factory, scope
1430
1439
  assert sorted(certs_used_by_poller) == ['DEFAULT_DUMMY_CERT', 'NEW_VO_DUMMY_CERT']
1431
1440
 
1432
1441
 
1433
- @pytest.mark.skip(reason="Pending https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC4506150")
1434
1442
  @skip_rse_tests_with_accounts
1435
1443
  @pytest.mark.noparallel(groups=[NoParallelGroups.SUBMITTER, NoParallelGroups.POLLER, NoParallelGroups.FINISHER])
1436
1444
  @pytest.mark.parametrize("core_config_mock", [
@@ -1474,6 +1482,7 @@ def test_two_multihops_same_intermediate_rse(rse_factory, did_factory, root_acco
1474
1482
  all_rses = [rse1_id, rse2_id, rse3_id, rse4_id, rse5_id, rse6_id, rse7_id]
1475
1483
  for rse_id in all_rses:
1476
1484
  rse_core.add_rse_attribute(rse_id, RseAttr.FTS, TEST_FTS_HOST)
1485
+ rse_core.add_rse_attribute(rse_id, RseAttr.VERIFY_CHECKSUM, False)
1477
1486
  rse_core.set_rse_limits(rse_id=rse_id, name='MinFreeSpace', value=1)
1478
1487
  rse_core.set_rse_usage(rse_id=rse_id, source='storage', used=1, free=0)
1479
1488
  distance_core.add_distance(rse1_id, rse2_id, distance=10)
@@ -1562,7 +1571,6 @@ def test_two_multihops_same_intermediate_rse(rse_factory, did_factory, root_acco
1562
1571
  assert dict_stats[rse2_id][rse1_id]['bytes_done'] == 2
1563
1572
 
1564
1573
 
1565
- @pytest.mark.skip(reason="Pending https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC4506150")
1566
1574
  @skip_rse_tests_with_accounts
1567
1575
  @pytest.mark.noparallel(groups=[NoParallelGroups.SUBMITTER, NoParallelGroups.POLLER])
1568
1576
  def test_checksum_validation(rse_factory, did_factory, root_account):
@@ -1607,15 +1615,14 @@ def test_checksum_validation(rse_factory, did_factory, root_account):
1607
1615
  # No common supported checksum between the source and destination rse. It will verify the destination rse checksum and fail
1608
1616
  request = __wait_for_state_transition(dst_rse_id=dst_rse2_id, **did)
1609
1617
  assert request['state'] == RequestState.FAILED
1610
- assert 'User and destination checksums do not match' in request['err_msg']
1618
+ assert 'User-defined and destination MD5 checksum do not match' in request['err_msg']
1611
1619
 
1612
- # Common checksum exists between the two. It must use "both" validation strategy and fail
1620
+ # Common checksum exists between the two. It It will fail early when checking the user-defined and destination checksums.
1613
1621
  request = __wait_for_state_transition(dst_rse_id=dst_rse3_id, **did)
1614
- assert 'Source and destination checksums do not match' in request['err_msg']
1622
+ assert 'User-defined and destination ADLER32 checksum do not match' in request['err_msg']
1615
1623
  assert request['state'] == RequestState.FAILED
1616
1624
 
1617
1625
 
1618
- @pytest.mark.skip(reason="Pending https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC4506150")
1619
1626
  @skip_rse_tests_with_accounts
1620
1627
  @pytest.mark.needs_iam
1621
1628
  @pytest.mark.noparallel(groups=[NoParallelGroups.XRD, NoParallelGroups.SUBMITTER, NoParallelGroups.RECEIVER])
@@ -431,6 +431,27 @@ class TestDidMetaExternalPostgresJSON:
431
431
  postgres_json_meta.set_metadata(scope=mock_scope, name=did_name, key=meta_key, value=meta_value)
432
432
  assert postgres_json_meta.get_metadata(scope=mock_scope, name=did_name)[meta_key] == meta_value
433
433
 
434
+ @pytest.mark.dirty
435
+ def test_delete_metadata(self, mock_scope, root_account, postgres_json_meta):
436
+ """ DID Meta (POSTGRES_JSON): delete DID meta """
437
+
438
+ did_name = did_name_generator('dataset')
439
+ meta_key1 = 'my_key_%s' % generate_uuid()
440
+ meta_value1 = 'my_value_%s' % generate_uuid()
441
+ meta_key2 = 'my_key_%s' % generate_uuid()
442
+ meta_value2 = 'my_value_%s' % generate_uuid()
443
+ add_did(scope=mock_scope, name=did_name, did_type='DATASET', account=root_account)
444
+ postgres_json_meta.set_metadata(scope=mock_scope, name=did_name, key=meta_key1, value=meta_value1)
445
+ postgres_json_meta.set_metadata(scope=mock_scope, name=did_name, key=meta_key2, value=meta_value2)
446
+
447
+ assert postgres_json_meta.get_metadata(scope=mock_scope, name=did_name)[meta_key1] == meta_value1
448
+ assert postgres_json_meta.get_metadata(scope=mock_scope, name=did_name)[meta_key2] == meta_value2
449
+
450
+ postgres_json_meta.delete_metadata(scope=mock_scope, name=did_name, key=meta_key2)
451
+ metadata = postgres_json_meta.get_metadata(scope=mock_scope, name=did_name)
452
+ assert metadata[meta_key1] == meta_value1
453
+ assert meta_key2 not in metadata
454
+
434
455
  @pytest.mark.dirty
435
456
  def test_list_did_meta(self, mock_scope, root_account, postgres_json_meta):
436
457
  """ DID Meta (POSTGRES_JSON): List DID meta """
@@ -407,7 +407,7 @@ class TestGatewayExternalRepresentation:
407
407
  def test_gateway_scope(self, vo, vo2, account_name, scope_name, scope):
408
408
  """ SCOPE (Gateway): Test external representation of scopes """
409
409
 
410
- out = list_scopes()
410
+ out = [s['scope'] for s in list_scopes()]
411
411
  assert scope_name in out
412
412
  if vo2:
413
413
  assert scope.internal not in out
@@ -757,8 +757,8 @@ class TestMultiVoClients:
757
757
  scope_client.add_scope('root', shr)
758
758
  add_scope(new, 'root', 'root', vo=second_vo)
759
759
  add_scope(shr, 'root', 'root', vo=second_vo)
760
- scope_list_tst = list(scope_client.list_scopes())
761
- scope_list_new = list(list_scopes(filter_={}, vo=second_vo))
760
+ scope_list_tst = [s['scope'] for s in scope_client.list_scopes()]
761
+ scope_list_new = [s['scope'] for s in list_scopes(filter_={}, vo=second_vo)]
762
762
  assert tst in scope_list_tst
763
763
  assert new not in scope_list_tst
764
764
  assert shr in scope_list_tst