opendal 0.1.9 → 0.1.11

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.
Files changed (566) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +89 -56
  3. data/Cargo.toml +1 -1
  4. data/DEPENDENCIES.rust.tsv +55 -41
  5. data/LICENSE +201 -0
  6. data/LICENSE-MPL-2.0.txt +373 -0
  7. data/NOTICE +5 -0
  8. data/core/CHANGELOG.md +175 -0
  9. data/core/Cargo.lock +225 -298
  10. data/core/Cargo.toml +100 -94
  11. data/core/DEPENDENCIES.rust.tsv +44 -73
  12. data/core/benches/metadata/README.md +21 -0
  13. data/core/benches/metadata/main.rs +541 -0
  14. data/core/benches/vs_fs/Cargo.toml +1 -1
  15. data/core/benches/vs_s3/Cargo.toml +1 -1
  16. data/core/core/Cargo.toml +7 -2
  17. data/core/core/src/blocking/delete.rs +5 -1
  18. data/core/core/src/blocking/operator.rs +12 -0
  19. data/core/core/src/blocking/read/std_reader.rs +25 -0
  20. data/core/core/src/docs/concepts.rs +70 -94
  21. data/core/core/src/docs/internals/accessor.rs +62 -293
  22. data/core/core/src/docs/internals/layer.rs +43 -59
  23. data/core/core/src/docs/internals/mod.rs +21 -23
  24. data/core/core/src/docs/mod.rs +10 -6
  25. data/core/core/src/docs/performance/concurrent_write.md +92 -55
  26. data/core/core/src/docs/performance/http_optimization.md +120 -104
  27. data/core/core/src/docs/performance/mod.rs +8 -6
  28. data/core/core/src/docs/rfcs/5485_conditional_reader.md +4 -0
  29. data/core/core/src/docs/rfcs/7182_restore_api.md +139 -557
  30. data/core/core/src/docs/rfcs/7945_limited_read.md +210 -0
  31. data/core/core/src/docs/rfcs/7948_s3_provider_presets.md +254 -0
  32. data/core/core/src/docs/rfcs/8109_writer_copy_from.md +330 -0
  33. data/core/core/src/docs/rfcs/8145_conflict_error_kind.md +210 -0
  34. data/core/core/src/docs/rfcs/8147_write_if_not_changed.md +233 -0
  35. data/core/core/src/docs/rfcs/8188_compose_api.md +292 -0
  36. data/core/core/src/docs/rfcs/8194_compact_metadata_and_operation_args.md +444 -0
  37. data/core/core/src/docs/rfcs/README.md +14 -3
  38. data/core/core/src/docs/rfcs/mod.rs +46 -22
  39. data/core/core/src/docs/specs/README.md +34 -0
  40. data/core/core/src/docs/specs/conditional-operations.md +156 -0
  41. data/core/core/src/docs/specs/metadata.md +63 -0
  42. data/core/core/src/docs/specs/mod.rs +26 -0
  43. data/core/core/src/docs/upgrade.md +114 -1
  44. data/core/core/src/layers/capability_override.rs +15 -2
  45. data/core/core/src/layers/complete.rs +347 -43
  46. data/core/core/src/layers/correctness_check.rs +718 -51
  47. data/core/core/src/layers/error_context.rs +76 -2
  48. data/core/core/src/layers/simulate.rs +91 -28
  49. data/core/core/src/lib.rs +1 -0
  50. data/core/core/src/raw/accessor.rs +91 -15
  51. data/core/core/src/raw/enum_utils.rs +7 -0
  52. data/core/core/src/raw/http_util/header.rs +22 -17
  53. data/core/core/src/raw/oio/compose/api.rs +92 -0
  54. data/core/core/src/raw/oio/compose/mod.rs +19 -0
  55. data/core/core/src/raw/oio/copy/api.rs +3 -3
  56. data/core/core/src/raw/oio/copy/block_copy.rs +32 -4
  57. data/core/core/src/raw/oio/copy/multipart_copy.rs +36 -7
  58. data/core/core/src/raw/oio/entry.rs +48 -22
  59. data/core/core/src/raw/oio/list/flat_list.rs +1 -1
  60. data/core/core/src/raw/oio/list/hierarchy_list.rs +3 -2
  61. data/core/core/src/raw/oio/mod.rs +3 -0
  62. data/core/core/src/raw/oio/read/position_read.rs +1 -1
  63. data/core/core/src/raw/oio/write/api.rs +40 -0
  64. data/core/core/src/raw/oio/write/append_write.rs +4 -4
  65. data/core/core/src/raw/oio/write/block_write.rs +2 -2
  66. data/core/core/src/raw/oio/write/multipart_write.rs +181 -48
  67. data/core/core/src/raw/oio/write/position_write.rs +1 -1
  68. data/core/core/src/raw/operation.rs +6 -0
  69. data/core/core/src/raw/ops.rs +1191 -456
  70. data/core/core/src/raw/rps.rs +11 -0
  71. data/core/core/src/raw/time.rs +14 -3
  72. data/core/core/src/services/memory/backend.rs +5 -10
  73. data/core/core/src/services/memory/lister.rs +4 -4
  74. data/core/core/src/services/memory/writer.rs +7 -6
  75. data/core/core/src/types/buffer.rs +102 -12
  76. data/core/core/src/types/bytes_range.rs +20 -1
  77. data/core/core/src/types/capability.rs +65 -0
  78. data/core/core/src/types/compact.rs +329 -0
  79. data/core/core/src/types/compose/composer.rs +183 -0
  80. data/core/core/src/types/compose/input.rs +57 -0
  81. data/core/core/src/types/compose/mod.rs +23 -0
  82. data/core/core/src/types/context/read.rs +16 -11
  83. data/core/core/src/types/context/write.rs +150 -2
  84. data/core/core/src/types/copy.rs +5 -3
  85. data/core/core/src/types/delete/deleter.rs +20 -12
  86. data/core/core/src/types/delete/input.rs +22 -64
  87. data/core/core/src/types/delete/mod.rs +0 -1
  88. data/core/core/src/types/entry.rs +8 -14
  89. data/core/core/src/types/error.rs +28 -11
  90. data/core/core/src/types/metadata.rs +709 -322
  91. data/core/core/src/types/mod.rs +9 -1
  92. data/core/core/src/types/operator/operator.rs +278 -29
  93. data/core/core/src/types/operator/operator_futures.rs +466 -105
  94. data/core/core/src/types/options.rs +631 -158
  95. data/core/core/src/types/read/futures_async_reader.rs +663 -50
  96. data/core/core/src/types/read/reader.rs +23 -5
  97. data/core/core/src/types/write/futures_async_writer.rs +27 -0
  98. data/core/core/src/types/write/writer.rs +47 -5
  99. data/core/http-transports/reqwest/Cargo.toml +1 -1
  100. data/core/layers/async-backtrace/Cargo.toml +2 -2
  101. data/core/layers/async-backtrace/src/lib.rs +21 -2
  102. data/core/layers/await-tree/Cargo.toml +2 -2
  103. data/core/layers/await-tree/src/lib.rs +25 -2
  104. data/core/layers/capability-check/Cargo.toml +2 -2
  105. data/core/layers/capability-check/src/lib.rs +98 -10
  106. data/core/layers/chaos/Cargo.toml +2 -2
  107. data/core/layers/chaos/src/lib.rs +18 -3
  108. data/core/layers/concurrent-limit/Cargo.toml +3 -3
  109. data/core/layers/concurrent-limit/src/lib.rs +53 -13
  110. data/core/layers/dtrace/Cargo.toml +2 -2
  111. data/core/layers/dtrace/src/lib.rs +29 -2
  112. data/core/layers/fastmetrics/Cargo.toml +3 -3
  113. data/core/layers/fastrace/Cargo.toml +2 -2
  114. data/core/layers/fastrace/src/lib.rs +28 -2
  115. data/core/layers/foyer/Cargo.toml +2 -2
  116. data/core/layers/foyer/src/full.rs +16 -19
  117. data/core/layers/foyer/src/lib.rs +67 -14
  118. data/core/layers/hotpath/Cargo.toml +2 -2
  119. data/core/layers/hotpath/src/lib.rs +20 -2
  120. data/core/layers/immutable-index/Cargo.toml +2 -2
  121. data/core/layers/immutable-index/src/lib.rs +48 -24
  122. data/core/layers/logging/Cargo.toml +2 -2
  123. data/core/layers/logging/src/lib.rs +46 -2
  124. data/core/layers/metrics/Cargo.toml +3 -3
  125. data/core/layers/mime-guess/Cargo.toml +2 -2
  126. data/core/layers/mime-guess/src/lib.rs +31 -4
  127. data/core/layers/observe-metrics-common/Cargo.toml +2 -2
  128. data/core/layers/observe-metrics-common/src/lib.rs +55 -2
  129. data/core/layers/otelmetrics/Cargo.toml +3 -3
  130. data/core/layers/oteltrace/Cargo.toml +2 -2
  131. data/core/layers/oteltrace/src/lib.rs +27 -2
  132. data/core/layers/prometheus/Cargo.toml +3 -3
  133. data/core/layers/prometheus-client/Cargo.toml +3 -3
  134. data/core/layers/retry/Cargo.toml +4 -4
  135. data/core/layers/retry/src/lib.rs +76 -19
  136. data/core/layers/route/Cargo.toml +3 -3
  137. data/core/layers/route/src/lib.rs +34 -7
  138. data/core/layers/tail-cut/Cargo.toml +2 -2
  139. data/core/layers/tail-cut/src/lib.rs +28 -2
  140. data/core/layers/throttle/Cargo.toml +2 -2
  141. data/core/layers/throttle/src/lib.rs +19 -2
  142. data/core/layers/timeout/Cargo.toml +3 -3
  143. data/core/layers/timeout/src/lib.rs +38 -13
  144. data/core/layers/tracing/Cargo.toml +2 -2
  145. data/core/layers/tracing/src/lib.rs +24 -3
  146. data/core/services/aliyun-drive/Cargo.toml +2 -2
  147. data/core/services/aliyun-drive/src/backend.rs +34 -24
  148. data/core/services/aliyun-drive/src/core.rs +143 -54
  149. data/core/services/aliyun-drive/src/lister.rs +19 -18
  150. data/core/services/aliyun-drive/src/reader.rs +4 -1
  151. data/core/services/aliyun-drive/src/writer.rs +3 -3
  152. data/core/services/alluxio/Cargo.toml +1 -1
  153. data/core/services/alluxio/src/backend.rs +1 -1
  154. data/core/services/alluxio/src/core.rs +113 -94
  155. data/core/services/alluxio/src/reader.rs +7 -3
  156. data/core/services/alluxio/src/writer.rs +2 -2
  157. data/core/services/azblob/Cargo.toml +2 -2
  158. data/core/services/azblob/src/backend.rs +17 -9
  159. data/core/services/azblob/src/copier.rs +41 -15
  160. data/core/services/azblob/src/core.rs +372 -135
  161. data/core/services/azblob/src/deleter.rs +41 -18
  162. data/core/services/azblob/src/lister.rs +16 -10
  163. data/core/services/azblob/src/reader.rs +4 -1
  164. data/core/services/azblob/src/writer.rs +48 -15
  165. data/core/services/azdls/Cargo.toml +3 -3
  166. data/core/services/azdls/src/backend.rs +45 -15
  167. data/core/services/azdls/src/config.rs +4 -1
  168. data/core/services/azdls/src/core.rs +276 -87
  169. data/core/services/azdls/src/deleter.rs +13 -4
  170. data/core/services/azdls/src/lister.rs +18 -12
  171. data/core/services/azdls/src/reader.rs +6 -2
  172. data/core/services/azdls/src/writer.rs +44 -23
  173. data/core/services/azfile/Cargo.toml +2 -2
  174. data/core/services/azfile/src/backend.rs +24 -8
  175. data/core/services/azfile/src/core.rs +195 -77
  176. data/core/services/azfile/src/deleter.rs +8 -1
  177. data/core/services/azfile/src/lister.rs +20 -14
  178. data/core/services/azfile/src/reader.rs +5 -2
  179. data/core/services/azfile/src/writer.rs +27 -15
  180. data/core/services/azure-common/Cargo.toml +1 -1
  181. data/core/services/b2/Cargo.toml +2 -2
  182. data/core/services/b2/src/backend.rs +30 -11
  183. data/core/services/b2/src/core.rs +134 -120
  184. data/core/services/b2/src/deleter.rs +1 -1
  185. data/core/services/b2/src/lister.rs +5 -2
  186. data/core/services/b2/src/reader.rs +5 -2
  187. data/core/services/b2/src/writer.rs +29 -12
  188. data/core/services/cacache/Cargo.toml +1 -1
  189. data/core/services/cacache/src/backend.rs +4 -5
  190. data/core/services/cacache/src/reader.rs +4 -1
  191. data/core/services/cacache/src/writer.rs +6 -2
  192. data/core/services/cloudflare-kv/Cargo.toml +1 -1
  193. data/core/services/cloudflare-kv/src/backend.rs +26 -15
  194. data/core/services/cloudflare-kv/src/config.rs +13 -2
  195. data/core/services/cloudflare-kv/src/core.rs +62 -56
  196. data/core/services/cloudflare-kv/src/deleter.rs +12 -3
  197. data/core/services/cloudflare-kv/src/lister.rs +66 -17
  198. data/core/services/cloudflare-kv/src/reader.rs +14 -9
  199. data/core/services/cloudflare-kv/src/writer.rs +10 -7
  200. data/core/services/compfs/Cargo.toml +1 -1
  201. data/core/services/compfs/src/backend.rs +11 -7
  202. data/core/services/compfs/src/lister.rs +7 -7
  203. data/core/services/compfs/src/writer.rs +1 -1
  204. data/core/services/cos/Cargo.toml +1 -1
  205. data/core/services/cos/src/backend.rs +129 -16
  206. data/core/services/cos/src/core.rs +198 -80
  207. data/core/services/cos/src/deleter.rs +4 -1
  208. data/core/services/cos/src/lister.rs +42 -27
  209. data/core/services/cos/src/reader.rs +6 -2
  210. data/core/services/cos/src/writer.rs +45 -21
  211. data/core/services/d1/Cargo.toml +1 -1
  212. data/core/services/d1/src/backend.rs +6 -5
  213. data/core/services/d1/src/core.rs +79 -63
  214. data/core/services/d1/src/reader.rs +4 -1
  215. data/core/services/d1/src/writer.rs +6 -2
  216. data/core/services/dashmap/Cargo.toml +1 -1
  217. data/core/services/dashmap/src/backend.rs +2 -2
  218. data/core/services/dashmap/src/reader.rs +4 -1
  219. data/core/services/dashmap/src/writer.rs +11 -8
  220. data/core/services/dbfs/Cargo.toml +1 -1
  221. data/core/services/dbfs/src/backend.rs +21 -15
  222. data/core/services/dbfs/src/core.rs +65 -60
  223. data/core/services/dbfs/src/deleter.rs +4 -1
  224. data/core/services/dbfs/src/lister.rs +10 -10
  225. data/core/services/dbfs/src/writer.rs +6 -3
  226. data/core/services/dropbox/Cargo.toml +2 -2
  227. data/core/services/dropbox/src/backend.rs +30 -23
  228. data/core/services/dropbox/src/core.rs +65 -63
  229. data/core/services/dropbox/src/deleter.rs +1 -1
  230. data/core/services/dropbox/src/lister.rs +17 -8
  231. data/core/services/dropbox/src/reader.rs +4 -1
  232. data/core/services/dropbox/src/writer.rs +13 -10
  233. data/core/services/etcd/Cargo.toml +1 -1
  234. data/core/services/etcd/src/backend.rs +8 -5
  235. data/core/services/etcd/src/core.rs +5 -11
  236. data/core/services/etcd/src/lister.rs +6 -1
  237. data/core/services/etcd/src/reader.rs +4 -1
  238. data/core/services/etcd/src/writer.rs +6 -3
  239. data/core/services/foundationdb/Cargo.toml +1 -1
  240. data/core/services/foundationdb/src/backend.rs +6 -5
  241. data/core/services/foundationdb/src/reader.rs +4 -1
  242. data/core/services/foundationdb/src/writer.rs +6 -2
  243. data/core/services/foyer/Cargo.toml +3 -3
  244. data/core/services/foyer/src/backend.rs +6 -5
  245. data/core/services/foyer/src/reader.rs +4 -1
  246. data/core/services/foyer/src/writer.rs +6 -2
  247. data/core/services/fs/Cargo.toml +1 -1
  248. data/core/services/fs/src/backend.rs +4 -3
  249. data/core/services/fs/src/core.rs +44 -26
  250. data/core/services/fs/src/lister.rs +9 -6
  251. data/core/services/fs/src/writer.rs +20 -13
  252. data/core/services/ftp/Cargo.toml +4 -6
  253. data/core/services/ftp/src/backend.rs +9 -5
  254. data/core/services/ftp/src/core.rs +9 -7
  255. data/core/services/ftp/src/lister.rs +7 -8
  256. data/core/services/ftp/src/reader.rs +3 -3
  257. data/core/services/ftp/src/writer.rs +3 -3
  258. data/core/services/gcs/Cargo.toml +4 -2
  259. data/core/services/gcs/src/backend.rs +53 -7
  260. data/core/services/gcs/src/composer.rs +705 -0
  261. data/core/services/gcs/src/copier.rs +14 -4
  262. data/core/services/gcs/src/core.rs +828 -124
  263. data/core/services/gcs/src/deleter.rs +33 -18
  264. data/core/services/gcs/src/lib.rs +1 -0
  265. data/core/services/gcs/src/lister.rs +21 -12
  266. data/core/services/gcs/src/reader.rs +12 -5
  267. data/core/services/gcs/src/writer.rs +632 -10
  268. data/core/services/gcs-grpc/Cargo.toml +58 -0
  269. data/core/services/gcs-grpc/README.md +19 -0
  270. data/core/services/gcs-grpc/proto/README.md +23 -0
  271. data/core/services/gcs-grpc/proto/google/storage/v2/storage.proto +171 -0
  272. data/core/services/gcs-grpc/proto/upstream-descriptor.bin +0 -0
  273. data/core/services/gcs-grpc/src/backend.rs +449 -0
  274. data/core/services/gcs-grpc/src/config.rs +116 -0
  275. data/core/services/gcs-grpc/src/copier.rs +98 -0
  276. data/core/services/gcs-grpc/src/core.rs +298 -0
  277. data/core/services/gcs-grpc/src/deleter.rs +65 -0
  278. data/core/services/gcs-grpc/src/docs.md +19 -0
  279. data/core/services/gcs-grpc/src/generated/google.storage.v2.rs +541 -0
  280. data/core/services/gcs-grpc/src/generated/mod.rs +24 -0
  281. data/core/services/gcs-grpc/src/lib.rs +43 -0
  282. data/core/services/gcs-grpc/src/lister.rs +125 -0
  283. data/core/services/gcs-grpc/src/reader.rs +140 -0
  284. data/core/services/gcs-grpc/src/writer.rs +780 -0
  285. data/core/services/gdrive/Cargo.toml +2 -2
  286. data/core/services/gdrive/src/backend.rs +123 -69
  287. data/core/services/gdrive/src/core.rs +87 -69
  288. data/core/services/gdrive/src/deleter.rs +8 -2
  289. data/core/services/gdrive/src/lister.rs +38 -26
  290. data/core/services/gdrive/src/path_index.rs +2 -2
  291. data/core/services/gdrive/src/reader.rs +9 -3
  292. data/core/services/gdrive/src/writer.rs +13 -7
  293. data/core/services/ghac/Cargo.toml +2 -2
  294. data/core/services/ghac/src/backend.rs +5 -2
  295. data/core/services/ghac/src/core.rs +59 -37
  296. data/core/services/ghac/src/reader.rs +5 -2
  297. data/core/services/ghac/src/writer.rs +16 -6
  298. data/core/services/github/Cargo.toml +1 -1
  299. data/core/services/github/src/backend.rs +16 -8
  300. data/core/services/github/src/core.rs +88 -76
  301. data/core/services/github/src/lister.rs +17 -15
  302. data/core/services/github/src/reader.rs +5 -2
  303. data/core/services/github/src/writer.rs +12 -6
  304. data/core/services/goosefs/Cargo.toml +2 -2
  305. data/core/services/goosefs/src/backend.rs +2 -2
  306. data/core/services/goosefs/src/core.rs +291 -208
  307. data/core/services/goosefs/src/docs.md +3 -0
  308. data/core/services/goosefs/src/lister.rs +2 -3
  309. data/core/services/goosefs/src/reader.rs +7 -3
  310. data/core/services/goosefs/src/writer.rs +21 -10
  311. data/core/services/goosefs/tests/safe_conditional_put.rs +37 -0
  312. data/core/services/gridfs/Cargo.toml +2 -2
  313. data/core/services/gridfs/src/backend.rs +12 -8
  314. data/core/services/gridfs/src/core.rs +1 -1
  315. data/core/services/gridfs/src/reader.rs +4 -1
  316. data/core/services/gridfs/src/writer.rs +6 -2
  317. data/core/services/hdfs/Cargo.toml +1 -1
  318. data/core/services/hdfs/src/backend.rs +1 -1
  319. data/core/services/hdfs/src/core.rs +7 -4
  320. data/core/services/hdfs/src/lister.rs +7 -9
  321. data/core/services/hdfs/src/writer.rs +5 -1
  322. data/core/services/hdfs-native/Cargo.toml +1 -1
  323. data/core/services/hdfs-native/src/backend.rs +1 -1
  324. data/core/services/hdfs-native/src/core.rs +44 -50
  325. data/core/services/hdfs-native/src/lister.rs +8 -10
  326. data/core/services/hdfs-native/src/writer.rs +5 -1
  327. data/core/services/hf/Cargo.toml +4 -3
  328. data/core/services/hf/src/backend.rs +4 -3
  329. data/core/services/hf/src/core.rs +907 -153
  330. data/core/services/hf/src/lister.rs +16 -6
  331. data/core/services/hf/src/reader.rs +377 -57
  332. data/core/services/hf/src/writer.rs +6 -2
  333. data/core/services/http/Cargo.toml +3 -3
  334. data/core/services/http/src/backend.rs +8 -6
  335. data/core/services/http/src/core.rs +57 -35
  336. data/core/services/http/src/reader.rs +5 -2
  337. data/core/services/ipfs/Cargo.toml +1 -1
  338. data/core/services/ipfs/src/backend.rs +20 -9
  339. data/core/services/ipfs/src/core.rs +43 -34
  340. data/core/services/ipfs/src/reader.rs +5 -2
  341. data/core/services/ipmfs/Cargo.toml +1 -1
  342. data/core/services/ipmfs/src/backend.rs +17 -8
  343. data/core/services/ipmfs/src/core.rs +66 -60
  344. data/core/services/ipmfs/src/deleter.rs +5 -2
  345. data/core/services/ipmfs/src/lister.rs +15 -12
  346. data/core/services/ipmfs/src/reader.rs +5 -2
  347. data/core/services/ipmfs/src/writer.rs +6 -3
  348. data/core/services/koofr/Cargo.toml +2 -2
  349. data/core/services/koofr/src/backend.rs +46 -17
  350. data/core/services/koofr/src/core.rs +64 -48
  351. data/core/services/koofr/src/deleter.rs +4 -1
  352. data/core/services/koofr/src/lister.rs +11 -10
  353. data/core/services/koofr/src/reader.rs +5 -2
  354. data/core/services/koofr/src/writer.rs +13 -7
  355. data/core/services/lakefs/Cargo.toml +1 -1
  356. data/core/services/lakefs/src/backend.rs +25 -8
  357. data/core/services/lakefs/src/core.rs +79 -73
  358. data/core/services/lakefs/src/deleter.rs +4 -1
  359. data/core/services/lakefs/src/lister.rs +17 -14
  360. data/core/services/lakefs/src/reader.rs +5 -2
  361. data/core/services/lakefs/src/writer.rs +11 -10
  362. data/core/services/memcached/Cargo.toml +1 -1
  363. data/core/services/memcached/src/backend.rs +57 -7
  364. data/core/services/memcached/src/config.rs +13 -2
  365. data/core/services/memcached/src/core.rs +11 -1
  366. data/core/services/memcached/src/reader.rs +4 -1
  367. data/core/services/memcached/src/writer.rs +6 -2
  368. data/core/services/mini_moka/Cargo.toml +1 -1
  369. data/core/services/mini_moka/src/backend.rs +8 -8
  370. data/core/services/mini_moka/src/reader.rs +4 -1
  371. data/core/services/mini_moka/src/writer.rs +11 -7
  372. data/core/services/moka/Cargo.toml +1 -1
  373. data/core/services/moka/src/backend.rs +7 -7
  374. data/core/services/moka/src/reader.rs +4 -1
  375. data/core/services/moka/src/writer.rs +10 -6
  376. data/core/services/mongodb/Cargo.toml +2 -2
  377. data/core/services/mongodb/src/backend.rs +7 -6
  378. data/core/services/mongodb/src/core.rs +1 -1
  379. data/core/services/mongodb/src/reader.rs +4 -1
  380. data/core/services/mongodb/src/writer.rs +6 -2
  381. data/core/services/monoiofs/Cargo.toml +2 -2
  382. data/core/services/monoiofs/src/backend.rs +16 -10
  383. data/core/services/monoiofs/src/core.rs +8 -9
  384. data/core/services/monoiofs/src/reader.rs +8 -10
  385. data/core/services/monoiofs/src/writer.rs +19 -24
  386. data/core/services/mysql/Cargo.toml +2 -2
  387. data/core/services/mysql/src/backend.rs +7 -6
  388. data/core/services/mysql/src/core.rs +1 -1
  389. data/core/services/mysql/src/lister.rs +7 -3
  390. data/core/services/mysql/src/reader.rs +4 -1
  391. data/core/services/mysql/src/writer.rs +6 -2
  392. data/core/services/obs/Cargo.toml +1 -1
  393. data/core/services/obs/src/backend.rs +29 -11
  394. data/core/services/obs/src/core.rs +81 -82
  395. data/core/services/obs/src/deleter.rs +4 -1
  396. data/core/services/obs/src/lister.rs +12 -5
  397. data/core/services/obs/src/reader.rs +5 -2
  398. data/core/services/obs/src/writer.rs +40 -19
  399. data/core/services/onedrive/Cargo.toml +2 -2
  400. data/core/services/onedrive/src/backend.rs +30 -21
  401. data/core/services/onedrive/src/config.rs +2 -2
  402. data/core/services/onedrive/src/core.rs +191 -90
  403. data/core/services/onedrive/src/deleter.rs +5 -2
  404. data/core/services/onedrive/src/graph_model.rs +10 -51
  405. data/core/services/onedrive/src/lister.rs +60 -24
  406. data/core/services/onedrive/src/reader.rs +17 -2
  407. data/core/services/onedrive/src/writer.rs +26 -15
  408. data/core/services/opfs/Cargo.toml +1 -1
  409. data/core/services/opfs/src/backend.rs +6 -13
  410. data/core/services/opfs/src/core.rs +33 -37
  411. data/core/services/opfs/src/lister.rs +4 -4
  412. data/core/services/opfs/src/writer.rs +1 -3
  413. data/core/services/oss/Cargo.toml +1 -1
  414. data/core/services/oss/src/backend.rs +40 -8
  415. data/core/services/oss/src/core.rs +192 -92
  416. data/core/services/oss/src/deleter.rs +16 -6
  417. data/core/services/oss/src/lister.rs +43 -27
  418. data/core/services/oss/src/reader.rs +6 -2
  419. data/core/services/oss/src/writer.rs +40 -22
  420. data/core/services/pcloud/Cargo.toml +1 -1
  421. data/core/services/pcloud/src/backend.rs +40 -6
  422. data/core/services/pcloud/src/core.rs +80 -66
  423. data/core/services/pcloud/src/deleter.rs +8 -1
  424. data/core/services/pcloud/src/lister.rs +4 -1
  425. data/core/services/pcloud/src/reader.rs +5 -2
  426. data/core/services/pcloud/src/writer.rs +6 -3
  427. data/core/services/persy/Cargo.toml +1 -1
  428. data/core/services/persy/src/backend.rs +6 -5
  429. data/core/services/persy/src/core.rs +60 -15
  430. data/core/services/persy/src/reader.rs +4 -1
  431. data/core/services/persy/src/writer.rs +6 -2
  432. data/core/services/postgresql/Cargo.toml +2 -2
  433. data/core/services/postgresql/src/backend.rs +7 -6
  434. data/core/services/postgresql/src/core.rs +1 -1
  435. data/core/services/postgresql/src/reader.rs +4 -1
  436. data/core/services/postgresql/src/writer.rs +6 -2
  437. data/core/services/redb/Cargo.toml +1 -1
  438. data/core/services/redb/src/backend.rs +6 -5
  439. data/core/services/redb/src/reader.rs +4 -1
  440. data/core/services/redb/src/writer.rs +6 -2
  441. data/core/services/redis/Cargo.toml +1 -1
  442. data/core/services/redis/src/backend.rs +18 -8
  443. data/core/services/redis/src/config.rs +13 -2
  444. data/core/services/redis/src/reader.rs +8 -4
  445. data/core/services/redis/src/writer.rs +6 -2
  446. data/core/services/rocksdb/Cargo.toml +1 -1
  447. data/core/services/rocksdb/src/backend.rs +6 -5
  448. data/core/services/rocksdb/src/lister.rs +6 -5
  449. data/core/services/rocksdb/src/reader.rs +4 -1
  450. data/core/services/rocksdb/src/writer.rs +6 -2
  451. data/core/services/s3/Cargo.toml +5 -4
  452. data/core/services/s3/src/backend.rs +995 -39
  453. data/core/services/s3/src/compatible_services.md +57 -0
  454. data/core/services/s3/src/config.rs +16 -0
  455. data/core/services/s3/src/copier.rs +190 -55
  456. data/core/services/s3/src/core.rs +299 -190
  457. data/core/services/s3/src/deleter.rs +26 -7
  458. data/core/services/s3/src/docs.md +57 -0
  459. data/core/services/s3/src/lister.rs +55 -36
  460. data/core/services/s3/src/reader.rs +22 -2
  461. data/core/services/s3/src/writer.rs +154 -32
  462. data/core/services/seafile/Cargo.toml +2 -2
  463. data/core/services/seafile/src/backend.rs +3 -3
  464. data/core/services/seafile/src/core.rs +105 -79
  465. data/core/services/seafile/src/lister.rs +11 -8
  466. data/core/services/seafile/src/reader.rs +5 -2
  467. data/core/services/seafile/src/writer.rs +6 -3
  468. data/core/services/sftp/Cargo.toml +1 -1
  469. data/core/services/sftp/src/backend.rs +19 -4
  470. data/core/services/sftp/src/core.rs +51 -46
  471. data/core/services/sftp/src/lister.rs +4 -4
  472. data/core/services/sftp/src/writer.rs +1 -1
  473. data/core/services/sled/Cargo.toml +1 -1
  474. data/core/services/sled/src/backend.rs +6 -5
  475. data/core/services/sled/src/core.rs +28 -6
  476. data/core/services/sled/src/lister.rs +6 -5
  477. data/core/services/sled/src/reader.rs +4 -1
  478. data/core/services/sled/src/writer.rs +6 -2
  479. data/core/services/sqlite/Cargo.toml +2 -2
  480. data/core/services/sqlite/src/backend.rs +12 -7
  481. data/core/services/sqlite/src/core.rs +3 -3
  482. data/core/services/sqlite/src/reader.rs +4 -1
  483. data/core/services/sqlite/src/writer.rs +7 -3
  484. data/core/services/surrealdb/Cargo.toml +2 -2
  485. data/core/services/surrealdb/src/backend.rs +7 -6
  486. data/core/services/surrealdb/src/core.rs +1 -1
  487. data/core/services/surrealdb/src/reader.rs +4 -1
  488. data/core/services/surrealdb/src/writer.rs +6 -2
  489. data/core/services/swift/Cargo.toml +1 -1
  490. data/core/services/swift/src/backend.rs +38 -8
  491. data/core/services/swift/src/core.rs +63 -67
  492. data/core/services/swift/src/deleter.rs +8 -2
  493. data/core/services/swift/src/lister.rs +11 -8
  494. data/core/services/swift/src/reader.rs +5 -2
  495. data/core/services/swift/src/writer.rs +17 -8
  496. data/core/services/tikv/Cargo.toml +2 -2
  497. data/core/services/tikv/src/backend.rs +7 -6
  498. data/core/services/tikv/src/core.rs +31 -14
  499. data/core/services/tikv/src/reader.rs +4 -1
  500. data/core/services/tikv/src/writer.rs +6 -2
  501. data/core/services/tos/Cargo.toml +2 -2
  502. data/core/services/tos/src/backend.rs +45 -21
  503. data/core/services/tos/src/copier.rs +44 -17
  504. data/core/services/tos/src/core.rs +147 -117
  505. data/core/services/tos/src/deleter.rs +9 -3
  506. data/core/services/tos/src/docs.md +1 -1
  507. data/core/services/tos/src/lister.rs +43 -28
  508. data/core/services/tos/src/reader.rs +5 -2
  509. data/core/services/tos/src/writer.rs +37 -16
  510. data/core/services/upyun/Cargo.toml +1 -1
  511. data/core/services/upyun/src/backend.rs +30 -7
  512. data/core/services/upyun/src/core.rs +122 -87
  513. data/core/services/upyun/src/deleter.rs +4 -1
  514. data/core/services/upyun/src/lister.rs +10 -10
  515. data/core/services/upyun/src/reader.rs +5 -2
  516. data/core/services/upyun/src/writer.rs +19 -7
  517. data/core/services/vercel-artifacts/Cargo.toml +1 -1
  518. data/core/services/vercel-artifacts/src/backend.rs +6 -3
  519. data/core/services/vercel-artifacts/src/core.rs +32 -27
  520. data/core/services/vercel-artifacts/src/reader.rs +5 -2
  521. data/core/services/vercel-artifacts/src/writer.rs +6 -3
  522. data/core/services/vercel-blob/Cargo.toml +1 -1
  523. data/core/services/vercel-blob/src/backend.rs +23 -6
  524. data/core/services/vercel-blob/src/core.rs +92 -81
  525. data/core/services/vercel-blob/src/lister.rs +12 -3
  526. data/core/services/vercel-blob/src/reader.rs +5 -2
  527. data/core/services/vercel-blob/src/writer.rs +19 -7
  528. data/core/services/webdav/Cargo.toml +2 -2
  529. data/core/services/webdav/src/backend.rs +25 -5
  530. data/core/services/webdav/src/core.rs +116 -59
  531. data/core/services/webdav/src/deleter.rs +4 -1
  532. data/core/services/webdav/src/lister.rs +4 -1
  533. data/core/services/webdav/src/reader.rs +6 -2
  534. data/core/services/webdav/src/writer.rs +17 -7
  535. data/core/services/webhdfs/Cargo.toml +2 -2
  536. data/core/services/webhdfs/src/backend.rs +24 -11
  537. data/core/services/webhdfs/src/core.rs +99 -98
  538. data/core/services/webhdfs/src/deleter.rs +5 -2
  539. data/core/services/webhdfs/src/lister.rs +21 -9
  540. data/core/services/webhdfs/src/reader.rs +5 -2
  541. data/core/services/webhdfs/src/writer.rs +49 -14
  542. data/core/services/yandex-disk/Cargo.toml +1 -1
  543. data/core/services/yandex-disk/src/backend.rs +28 -6
  544. data/core/services/yandex-disk/src/core.rs +97 -79
  545. data/core/services/yandex-disk/src/deleter.rs +4 -1
  546. data/core/services/yandex-disk/src/lister.rs +25 -9
  547. data/core/services/yandex-disk/src/reader.rs +5 -2
  548. data/core/services/yandex-disk/src/writer.rs +6 -3
  549. data/core/src/lib.rs +5 -0
  550. data/core/testkit/Cargo.toml +4 -4
  551. data/core/testkit/src/utils.rs +53 -8
  552. data/core/tests/behavior/async_compose.rs +297 -0
  553. data/core/tests/behavior/async_copy.rs +162 -1
  554. data/core/tests/behavior/async_delete.rs +364 -3
  555. data/core/tests/behavior/async_read.rs +86 -0
  556. data/core/tests/behavior/async_restore.rs +162 -0
  557. data/core/tests/behavior/async_stat.rs +90 -0
  558. data/core/tests/behavior/async_write.rs +330 -2
  559. data/core/tests/behavior/main.rs +4 -0
  560. data/core/upgrade.md +114 -1
  561. data/src/capability.rs +0 -1
  562. data/src/io.rs +0 -1
  563. data/src/lister.rs +0 -1
  564. data/src/metadata.rs +0 -1
  565. data/src/operator_info.rs +0 -1
  566. metadata +44 -2
@@ -0,0 +1,297 @@
1
+ // Licensed to the Apache Software Foundation (ASF) under one
2
+ // or more contributor license agreements. See the NOTICE file
3
+ // distributed with this work for additional information
4
+ // regarding copyright ownership. The ASF licenses this file
5
+ // to you under the Apache License, Version 2.0 (the
6
+ // "License"); you may not use this file except in compliance
7
+ // with the License. You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing,
12
+ // software distributed under the License is distributed on an
13
+ // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ // KIND, either express or implied. See the License for the
15
+ // specific language governing permissions and limitations
16
+ // under the License.
17
+
18
+ use anyhow::Result;
19
+
20
+ use crate::*;
21
+
22
+ pub fn tests(op: &Operator, tests: &mut Vec<Trial>) {
23
+ let cap = op.info().capability();
24
+
25
+ if cap.read && cap.write && cap.compose {
26
+ tests.extend(async_trials!(
27
+ op,
28
+ test_compose_ordered_sources,
29
+ test_compose_incrementally,
30
+ test_compose_empty,
31
+ test_compose_self,
32
+ test_compose_more_than_provider_request_limit
33
+ ));
34
+ }
35
+
36
+ if cap.read && cap.write && cap.stat && cap.compose && cap.compose_with_content_type {
37
+ tests.extend(async_trials!(op, test_compose_with_content_type));
38
+ }
39
+
40
+ if cap.read && cap.write && cap.stat && cap.compose && cap.compose_with_source_version {
41
+ tests.extend(async_trials!(op, test_compose_with_source_version));
42
+ }
43
+
44
+ if cap.read
45
+ && cap.write
46
+ && cap.stat
47
+ && cap.compose
48
+ && (cap.compose_with_source_version || cap.compose_with_source_if_match)
49
+ {
50
+ tests.extend(async_trials!(op, test_compose_with_source_if_not_changed));
51
+ }
52
+
53
+ if cap.read && cap.write && cap.stat && cap.compose && cap.compose_with_if_version_match {
54
+ tests.extend(async_trials!(op, test_compose_with_if_version_match));
55
+ }
56
+
57
+ if cap.read
58
+ && cap.write
59
+ && cap.stat
60
+ && cap.compose
61
+ && (cap.compose_with_if_version_match || cap.compose_with_if_match)
62
+ {
63
+ tests.extend(async_trials!(op, test_compose_with_if_not_changed));
64
+ }
65
+
66
+ if cap.read && cap.write && cap.compose && cap.compose_with_if_not_exists {
67
+ tests.extend(async_trials!(op, test_compose_with_if_not_exists));
68
+ }
69
+ }
70
+
71
+ pub async fn test_compose_ordered_sources(op: Operator) -> Result<()> {
72
+ let first = TEST_FIXTURE.new_file_path();
73
+ let second = TEST_FIXTURE.new_file_path();
74
+ let target = TEST_FIXTURE.new_file_path();
75
+
76
+ op.write(&first, "hello").await?;
77
+ op.write(&second, " world").await?;
78
+ op.write(&target, "stale").await?;
79
+
80
+ op.compose([first.as_str(), second.as_str(), first.as_str()], &target)
81
+ .await?;
82
+
83
+ assert_eq!(
84
+ op.read(&target).await?.to_bytes().as_ref(),
85
+ b"hello worldhello"
86
+ );
87
+ assert_eq!(op.read(&first).await?.to_bytes().as_ref(), b"hello");
88
+ assert_eq!(op.read(&second).await?.to_bytes().as_ref(), b" world");
89
+ Ok(())
90
+ }
91
+
92
+ pub async fn test_compose_incrementally(op: Operator) -> Result<()> {
93
+ let first = TEST_FIXTURE.new_file_path();
94
+ let second = TEST_FIXTURE.new_file_path();
95
+ let target = TEST_FIXTURE.new_file_path();
96
+
97
+ op.write(&first, "a").await?;
98
+ op.write(&second, "b").await?;
99
+
100
+ let mut composer = op.composer_with(&target).concurrent(2).await?;
101
+ composer.compose(first.as_str()).await?;
102
+ composer
103
+ .compose_options(second.as_str(), options::ComposeSourceOptions::default())
104
+ .await?;
105
+ let metadata = composer.close().await?;
106
+
107
+ assert_eq!(metadata.content_length(), 2);
108
+ assert_eq!(op.read(&target).await?.to_bytes().as_ref(), b"ab");
109
+ assert_eq!(composer.close().await?.content_length(), 2);
110
+ Ok(())
111
+ }
112
+
113
+ pub async fn test_compose_empty(op: Operator) -> Result<()> {
114
+ let target = TEST_FIXTURE.new_file_path();
115
+ let err = op
116
+ .compose(Vec::<String>::new(), &target)
117
+ .await
118
+ .expect_err("empty composition must fail");
119
+ assert_eq!(err.kind(), ErrorKind::ConfigInvalid);
120
+
121
+ if op.info().capability().stat {
122
+ assert!(!op.exists(&target).await?);
123
+ }
124
+ Ok(())
125
+ }
126
+
127
+ pub async fn test_compose_self(op: Operator) -> Result<()> {
128
+ let path = TEST_FIXTURE.new_file_path();
129
+ op.write(&path, "content").await?;
130
+
131
+ let err = op
132
+ .compose([path.as_str()], &path)
133
+ .await
134
+ .expect_err("composing a destination from itself must fail");
135
+ assert_eq!(err.kind(), ErrorKind::IsSameFile);
136
+ assert_eq!(op.read(&path).await?.to_bytes().as_ref(), b"content");
137
+ Ok(())
138
+ }
139
+
140
+ pub async fn test_compose_more_than_provider_request_limit(op: Operator) -> Result<()> {
141
+ let target = TEST_FIXTURE.new_file_path();
142
+ let mut sources = Vec::with_capacity(65);
143
+
144
+ for index in 0..65_u8 {
145
+ let path = TEST_FIXTURE.new_file_path();
146
+ op.write(&path, vec![index]).await?;
147
+ sources.push(path);
148
+ }
149
+
150
+ op.compose_with(sources.iter().map(String::as_str), &target)
151
+ .concurrent(4)
152
+ .await?;
153
+
154
+ assert_eq!(
155
+ op.read(&target).await?.to_bytes(),
156
+ (0..65_u8).collect::<Vec<_>>()
157
+ );
158
+ Ok(())
159
+ }
160
+
161
+ pub async fn test_compose_with_content_type(op: Operator) -> Result<()> {
162
+ let source = TEST_FIXTURE.new_file_path();
163
+ let target = TEST_FIXTURE.new_file_path();
164
+ op.write(&source, "content").await?;
165
+
166
+ op.compose_with([source.as_str()], &target)
167
+ .content_type("text/plain")
168
+ .await?;
169
+
170
+ assert_eq!(op.stat(&target).await?.content_type(), Some("text/plain"));
171
+ Ok(())
172
+ }
173
+
174
+ pub async fn test_compose_with_source_version(op: Operator) -> Result<()> {
175
+ let source = TEST_FIXTURE.new_file_path();
176
+ let target = TEST_FIXTURE.new_file_path();
177
+ op.write(&source, "content").await?;
178
+ let metadata = op.stat(&source).await?;
179
+ let version = metadata
180
+ .version()
181
+ .expect("source version capability requires stat to return a version");
182
+
183
+ let mut composer = op.composer(&target).await?;
184
+ composer
185
+ .compose_with(source.as_str())
186
+ .version(version)
187
+ .await?;
188
+ composer.close().await?;
189
+
190
+ assert_eq!(op.read(&target).await?.to_bytes().as_ref(), b"content");
191
+ Ok(())
192
+ }
193
+
194
+ pub async fn test_compose_with_source_if_not_changed(op: Operator) -> Result<()> {
195
+ let source = TEST_FIXTURE.new_file_path();
196
+ let other = TEST_FIXTURE.new_file_path();
197
+ let target = TEST_FIXTURE.new_file_path();
198
+ let rejected_target = TEST_FIXTURE.new_file_path();
199
+
200
+ op.write(&source, "source").await?;
201
+ let expected = op.stat(&source).await?;
202
+
203
+ op.write(&other, "other").await?;
204
+ op.write(&other, "unrelated").await?;
205
+ let unrelated = op.stat(&other).await?;
206
+
207
+ op.compose(
208
+ [(
209
+ source.as_str(),
210
+ options::ComposeSourceOptions {
211
+ if_not_changed: Some(expected),
212
+ ..Default::default()
213
+ },
214
+ )],
215
+ &target,
216
+ )
217
+ .await?;
218
+
219
+ assert_eq!(op.read(&target).await?.to_bytes().as_ref(), b"source");
220
+ assert_eq!(op.read(&source).await?.to_bytes().as_ref(), b"source");
221
+
222
+ op.compose(
223
+ [(
224
+ source.as_str(),
225
+ options::ComposeSourceOptions {
226
+ if_not_changed: Some(unrelated),
227
+ ..Default::default()
228
+ },
229
+ )],
230
+ &rejected_target,
231
+ )
232
+ .await
233
+ .expect_err("an unrelated source identity must not be ignored");
234
+
235
+ assert!(!op.exists(&rejected_target).await?);
236
+ assert_eq!(op.read(&source).await?.to_bytes().as_ref(), b"source");
237
+ Ok(())
238
+ }
239
+
240
+ pub async fn test_compose_with_if_version_match(op: Operator) -> Result<()> {
241
+ let source = TEST_FIXTURE.new_file_path();
242
+ let target = TEST_FIXTURE.new_file_path();
243
+ op.write(&source, "new").await?;
244
+ op.write(&target, "old").await?;
245
+ let metadata = op.stat(&target).await?;
246
+ let version = metadata
247
+ .version()
248
+ .expect("version match capability requires stat to return a version");
249
+
250
+ op.compose_with([source.as_str()], &target)
251
+ .if_version_match(version)
252
+ .await?;
253
+
254
+ assert_eq!(op.read(&target).await?.to_bytes().as_ref(), b"new");
255
+ Ok(())
256
+ }
257
+
258
+ pub async fn test_compose_with_if_not_changed(op: Operator) -> Result<()> {
259
+ let source = TEST_FIXTURE.new_file_path();
260
+ let target = TEST_FIXTURE.new_file_path();
261
+
262
+ op.write(&source, "composed").await?;
263
+ op.write(&target, "initial").await?;
264
+ let expected = op.stat(&target).await?;
265
+
266
+ op.compose_with([source.as_str()], &target)
267
+ .if_not_changed(&expected)
268
+ .await?;
269
+ assert_eq!(op.read(&target).await?.to_bytes().as_ref(), b"composed");
270
+
271
+ let stale = op.stat(&target).await?;
272
+ op.write(&target, "replacement").await?;
273
+ let err = op
274
+ .compose_with([source.as_str()], &target)
275
+ .if_not_changed(&stale)
276
+ .await
277
+ .expect_err("stale destination metadata must fail");
278
+ assert_eq!(err.kind(), ErrorKind::ConditionNotMatch);
279
+ assert_eq!(op.read(&target).await?.to_bytes().as_ref(), b"replacement");
280
+ Ok(())
281
+ }
282
+
283
+ pub async fn test_compose_with_if_not_exists(op: Operator) -> Result<()> {
284
+ let source = TEST_FIXTURE.new_file_path();
285
+ let target = TEST_FIXTURE.new_file_path();
286
+ op.write(&source, "new").await?;
287
+ op.write(&target, "existing").await?;
288
+
289
+ let err = op
290
+ .compose_with([source.as_str()], &target)
291
+ .if_not_exists(true)
292
+ .await
293
+ .expect_err("composition must not replace an existing destination");
294
+ assert_eq!(err.kind(), ErrorKind::ConditionNotMatch);
295
+ assert_eq!(op.read(&target).await?.to_bytes().as_ref(), b"existing");
296
+ Ok(())
297
+ }
@@ -65,6 +65,28 @@ pub fn tests(op: &Operator, tests: &mut Vec<Trial>) {
65
65
  ))
66
66
  }
67
67
 
68
+ if cap.read && cap.write && cap.copy && cap.copy_with_if_none_match {
69
+ tests.extend(async_trials!(op, test_copy_with_if_none_match))
70
+ }
71
+
72
+ if cap.read
73
+ && cap.write
74
+ && cap.copy
75
+ && cap.copy_with_if_version_match
76
+ && cap.copy_with_if_version_not_match
77
+ {
78
+ tests.extend(async_trials!(op, test_copy_with_version_conditions))
79
+ }
80
+
81
+ if cap.read
82
+ && cap.write
83
+ && cap.stat
84
+ && cap.copy
85
+ && (cap.copy_with_if_match || cap.copy_with_if_version_match)
86
+ {
87
+ tests.extend(async_trials!(op, test_copy_if_not_changed))
88
+ }
89
+
68
90
  if cap.read && cap.write && cap.stat && cap.copy && cap.copy_with_source_version {
69
91
  tests.extend(async_trials!(
70
92
  op,
@@ -107,7 +129,10 @@ pub async fn test_copy_file_with_ascii_name(op: Operator) -> Result<()> {
107
129
 
108
130
  let target_path = uuid::Uuid::new_v4().to_string();
109
131
 
110
- op.copy(&source_path, &target_path).await?;
132
+ let metadata = op.copy(&source_path, &target_path).await?;
133
+ if metadata.is_file() {
134
+ assert_eq!(metadata.content_length(), source_content.len() as u64);
135
+ }
111
136
 
112
137
  let target_content = op
113
138
  .read(&target_path)
@@ -437,11 +462,147 @@ pub async fn test_copy_with_if_match_mismatch(op: Operator) -> Result<()> {
437
462
  sha256_digest(&target_content),
438
463
  );
439
464
 
465
+ let missing_path = uuid::Uuid::new_v4().to_string();
466
+ let err = op
467
+ .copy_with(&source_path, &missing_path)
468
+ .if_match("\"00000000000000000000000000000000\"")
469
+ .await
470
+ .expect_err("missing destination must fail");
471
+ assert_eq!(err.kind(), ErrorKind::ConditionNotMatch);
472
+
440
473
  op.delete(&source_path).await.expect("delete must succeed");
441
474
  op.delete(&target_path).await.expect("delete must succeed");
442
475
  Ok(())
443
476
  }
444
477
 
478
+ /// Copy with `If-None-Match` should reject equality and accept inequality or absence.
479
+ pub async fn test_copy_with_if_none_match(op: Operator) -> Result<()> {
480
+ let source_path = TEST_FIXTURE.new_file_path();
481
+ let target_path = TEST_FIXTURE.new_file_path();
482
+ let missing_path = TEST_FIXTURE.new_file_path();
483
+ let (source_content, _) = gen_bytes(op.info().capability());
484
+ let (target_content, _) = gen_bytes(op.info().capability());
485
+ assert_ne!(source_content, target_content);
486
+
487
+ op.write(&source_path, source_content.clone()).await?;
488
+ op.write(&target_path, target_content).await?;
489
+ let etag = op
490
+ .stat(&target_path)
491
+ .await?
492
+ .etag()
493
+ .expect("etag must exist")
494
+ .to_string();
495
+
496
+ let err = op
497
+ .copy_with(&source_path, &target_path)
498
+ .if_none_match(&etag)
499
+ .await
500
+ .expect_err("equal ETag non-match must fail");
501
+ assert_eq!(err.kind(), ErrorKind::ConditionNotMatch);
502
+
503
+ op.copy_with(&source_path, &target_path)
504
+ .if_none_match("\"different-etag\"")
505
+ .await?;
506
+ op.copy_with(&source_path, &missing_path)
507
+ .if_none_match(&etag)
508
+ .await?;
509
+
510
+ assert_eq!(op.read(&target_path).await?.to_bytes(), source_content);
511
+ Ok(())
512
+ }
513
+
514
+ /// Version preconditions should compare against the current destination version.
515
+ pub async fn test_copy_with_version_conditions(op: Operator) -> Result<()> {
516
+ let cap = op.info().capability();
517
+ let source_path = TEST_FIXTURE.new_file_path();
518
+ let target_path = TEST_FIXTURE.new_file_path();
519
+ let missing_path = TEST_FIXTURE.new_file_path();
520
+ let (source_content, _) = gen_bytes(cap);
521
+ let (first_target, _) = gen_bytes(cap);
522
+ let (second_target, _) = gen_bytes(cap);
523
+ assert_ne!(source_content, first_target);
524
+ assert_ne!(source_content, second_target);
525
+ assert_ne!(first_target, second_target);
526
+
527
+ op.write(&source_path, source_content).await?;
528
+ op.write(&target_path, first_target).await?;
529
+ let stale = op
530
+ .stat(&target_path)
531
+ .await?
532
+ .version()
533
+ .expect("version must exist")
534
+ .to_string();
535
+ op.write(&target_path, second_target).await?;
536
+ let current = op
537
+ .stat(&target_path)
538
+ .await?
539
+ .version()
540
+ .expect("version must exist")
541
+ .to_string();
542
+
543
+ let err = op
544
+ .copy_with(&source_path, &target_path)
545
+ .if_version_match(&stale)
546
+ .await
547
+ .expect_err("stale destination version must fail");
548
+ assert_eq!(err.kind(), ErrorKind::ConditionNotMatch);
549
+ let err = op
550
+ .copy_with(&source_path, &target_path)
551
+ .if_version_not_match(&current)
552
+ .await
553
+ .expect_err("equal destination version must fail");
554
+ assert_eq!(err.kind(), ErrorKind::ConditionNotMatch);
555
+
556
+ op.copy_with(&source_path, &target_path)
557
+ .if_version_match(&current)
558
+ .await?;
559
+ op.copy_with(&source_path, &target_path)
560
+ .if_version_not_match(&current)
561
+ .await?;
562
+
563
+ for result in [
564
+ op.copy_with(&source_path, &missing_path)
565
+ .if_version_match(&current)
566
+ .await,
567
+ op.copy_with(&source_path, &missing_path)
568
+ .if_version_not_match(&current)
569
+ .await,
570
+ ] {
571
+ assert_eq!(
572
+ result.expect_err("missing destination must fail").kind(),
573
+ ErrorKind::ConditionNotMatch
574
+ );
575
+ }
576
+
577
+ Ok(())
578
+ }
579
+
580
+ /// `if_not_changed` should guard the destination against a stale observation.
581
+ pub async fn test_copy_if_not_changed(op: Operator) -> Result<()> {
582
+ let cap = op.info().capability();
583
+ let source_path = TEST_FIXTURE.new_file_path();
584
+ let target_path = TEST_FIXTURE.new_file_path();
585
+ let (source_content, _) = gen_bytes(cap);
586
+ let (target_content, _) = gen_bytes(cap);
587
+ assert_ne!(source_content, target_content);
588
+
589
+ op.write(&source_path, source_content).await?;
590
+ op.write(&target_path, target_content).await?;
591
+ let expected = op.stat(&target_path).await?;
592
+
593
+ op.copy_with(&source_path, &target_path)
594
+ .if_not_changed(&expected)
595
+ .await?;
596
+ let err = op
597
+ .copy_with(&source_path, &target_path)
598
+ .if_not_changed(&expected)
599
+ .await
600
+ .expect_err("stale destination metadata must fail");
601
+ assert_eq!(err.kind(), ErrorKind::ConditionNotMatch);
602
+
603
+ Ok(())
604
+ }
605
+
445
606
  /// Copy with source_version should copy a specific source version to a new file.
446
607
  pub async fn test_copy_with_source_version_to_new_file(op: Operator) -> Result<()> {
447
608
  if !op.info().capability().copy_with_source_version {