couchbase 3.4.4 → 3.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/couchbase/CMakeLists.txt +7 -0
  4. data/ext/couchbase/core/cluster.hxx +7 -0
  5. data/ext/couchbase/core/impl/create_bucket.cxx +3 -0
  6. data/ext/couchbase/core/impl/create_collection.cxx +83 -0
  7. data/ext/couchbase/core/impl/create_scope.cxx +69 -0
  8. data/ext/couchbase/core/impl/drop_collection.cxx +76 -0
  9. data/ext/couchbase/core/impl/drop_scope.cxx +68 -0
  10. data/ext/couchbase/core/impl/get_all_buckets.cxx +19 -4
  11. data/ext/couchbase/core/impl/get_all_scopes.cxx +94 -0
  12. data/ext/couchbase/core/impl/get_bucket.cxx +19 -4
  13. data/ext/couchbase/core/impl/lookup_in_all_replicas.cxx +2 -0
  14. data/ext/couchbase/core/impl/lookup_in_any_replica.cxx +2 -0
  15. data/ext/couchbase/core/impl/lookup_in_replica.cxx +8 -1
  16. data/ext/couchbase/core/impl/update_bucket.cxx +3 -0
  17. data/ext/couchbase/core/impl/update_collection.cxx +83 -0
  18. data/ext/couchbase/core/management/bucket_settings.hxx +8 -5
  19. data/ext/couchbase/core/management/bucket_settings_json.hxx +12 -2
  20. data/ext/couchbase/core/meta/features.hxx +17 -0
  21. data/ext/couchbase/core/operations/document_lookup_in.cxx +8 -1
  22. data/ext/couchbase/core/operations/management/CMakeLists.txt +1 -0
  23. data/ext/couchbase/core/operations/management/bucket_create.cxx +30 -9
  24. data/ext/couchbase/core/operations/management/bucket_update.cxx +27 -6
  25. data/ext/couchbase/core/operations/management/collection_create.cxx +5 -1
  26. data/ext/couchbase/core/operations/management/collection_create.hxx +1 -0
  27. data/ext/couchbase/core/operations/management/collection_update.cxx +87 -0
  28. data/ext/couchbase/core/operations/management/collection_update.hxx +54 -0
  29. data/ext/couchbase/core/operations/management/collections.hxx +1 -0
  30. data/ext/couchbase/core/timeout_defaults.hxx +1 -1
  31. data/ext/couchbase/core/topology/capabilities.hxx +1 -0
  32. data/ext/couchbase/core/topology/capabilities_fmt.hxx +3 -0
  33. data/ext/couchbase/core/topology/collections_manifest.hxx +2 -0
  34. data/ext/couchbase/core/topology/collections_manifest_json.hxx +3 -0
  35. data/ext/couchbase/core/topology/configuration.hxx +5 -0
  36. data/ext/couchbase/core/topology/configuration_json.hxx +2 -0
  37. data/ext/couchbase/couchbase/bucket.hxx +14 -0
  38. data/ext/couchbase/couchbase/collection_manager.hxx +160 -0
  39. data/ext/couchbase/couchbase/create_collection_options.hxx +44 -0
  40. data/ext/couchbase/couchbase/create_scope_options.hxx +41 -0
  41. data/ext/couchbase/couchbase/drop_collection_options.hxx +41 -0
  42. data/ext/couchbase/couchbase/drop_scope_options.hxx +41 -0
  43. data/ext/couchbase/couchbase/get_all_scopes_options.hxx +44 -0
  44. data/ext/couchbase/couchbase/management/bucket_settings.hxx +8 -5
  45. data/ext/couchbase/couchbase/management/collection_spec.hxx +29 -0
  46. data/ext/couchbase/couchbase/management/scope_spec.hxx +29 -0
  47. data/ext/couchbase/couchbase/update_collection_options.hxx +44 -0
  48. data/ext/couchbase/test/test_integration_management.cxx +305 -48
  49. data/ext/couchbase/test/test_integration_subdoc.cxx +81 -22
  50. data/ext/couchbase.cxx +155 -34
  51. data/ext/revisions.rb +3 -3
  52. data/lib/couchbase/collection_options.rb +1 -2
  53. data/lib/couchbase/management/bucket_manager.rb +22 -15
  54. data/lib/couchbase/management/collection_manager.rb +158 -9
  55. data/lib/couchbase/version.rb +1 -1
  56. metadata +23 -6
@@ -109,6 +109,14 @@ TEST_CASE("integration: bucket management", "[integration]")
109
109
  REQUIRE(bucket_settings.compression_mode == resp.bucket.compression_mode);
110
110
  REQUIRE(bucket_settings.replica_indexes == resp.bucket.replica_indexes);
111
111
  }
112
+
113
+ {
114
+ couchbase::core::operations::management::bucket_create_request req;
115
+ req.bucket = bucket_settings;
116
+ auto resp = test::utils::execute(integration.cluster, req);
117
+ REQUIRE(resp.ctx.ec == couchbase::errc::management::bucket_exists);
118
+ }
119
+
112
120
  std::uint64_t old_quota_mb{ 0 };
113
121
  {
114
122
  couchbase::core::operations::management::bucket_get_all_request req{};
@@ -894,6 +902,86 @@ TEST_CASE("integration: bucket management", "[integration]")
894
902
  }
895
903
  }
896
904
 
905
+ TEST_CASE("integration: bucket management history", "[integration]")
906
+ {
907
+ test::utils::integration_test_guard integration;
908
+
909
+ if (!integration.cluster_version().supports_bucket_management()) {
910
+ SKIP("cluster does not support bucket management");
911
+ }
912
+
913
+ if (!integration.cluster_version().supports_gcccp()) {
914
+ test::utils::open_bucket(integration.cluster, integration.ctx.bucket);
915
+ }
916
+
917
+ if (!integration.cluster_version().supports_bucket_history()) {
918
+ SKIP("cluster does not support bucket history");
919
+ }
920
+
921
+ auto bucket_name = test::utils::uniq_id("bucket");
922
+ auto update_bucket_name = test::utils::uniq_id("bucket");
923
+
924
+ SECTION("create history")
925
+ {
926
+ {
927
+ couchbase::core::management::cluster::bucket_settings bucket_settings;
928
+ bucket_settings.name = bucket_name;
929
+ bucket_settings.ram_quota_mb = integration.cluster_version().is_neo() ? 1'024 : 256;
930
+ bucket_settings.storage_backend = couchbase::core::management::cluster::bucket_storage_backend::magma;
931
+ bucket_settings.history_retention_collection_default = true;
932
+ bucket_settings.history_retention_bytes = 2147483648;
933
+ bucket_settings.history_retention_duration = 13000;
934
+ couchbase::core::operations::management::bucket_create_request req{ bucket_settings };
935
+ auto resp = test::utils::execute(integration.cluster, req);
936
+ REQUIRE_SUCCESS(resp.ctx.ec);
937
+ }
938
+
939
+ {
940
+ auto resp = wait_for_bucket_created(integration, bucket_name);
941
+ REQUIRE_SUCCESS(resp.ctx.ec);
942
+ REQUIRE(resp.bucket.storage_backend == couchbase::core::management::cluster::bucket_storage_backend::magma);
943
+ REQUIRE(resp.bucket.history_retention_collection_default == true);
944
+ REQUIRE(resp.bucket.history_retention_duration == 13000);
945
+ REQUIRE(resp.bucket.history_retention_bytes == 2147483648);
946
+ }
947
+ }
948
+
949
+ SECTION("update history")
950
+ {
951
+ couchbase::core::management::cluster::bucket_settings bucket_settings;
952
+ bucket_settings.ram_quota_mb = integration.cluster_version().is_neo() ? 1'024 : 256;
953
+ bucket_settings.name = update_bucket_name;
954
+ bucket_settings.storage_backend = couchbase::core::management::cluster::bucket_storage_backend::magma;
955
+ {
956
+ couchbase::core::operations::management::bucket_create_request req{ bucket_settings };
957
+ auto resp = test::utils::execute(integration.cluster, req);
958
+ REQUIRE_SUCCESS(resp.ctx.ec);
959
+ auto get_resp = wait_for_bucket_created(integration, update_bucket_name);
960
+ REQUIRE_SUCCESS(get_resp.ctx.ec);
961
+ }
962
+ {
963
+ bucket_settings.history_retention_collection_default = true;
964
+ bucket_settings.history_retention_bytes = 2147483648;
965
+ bucket_settings.history_retention_duration = 13000;
966
+ couchbase::core::operations::management::bucket_update_request req{ bucket_settings };
967
+ auto resp = test::utils::execute(integration.cluster, req);
968
+ REQUIRE_SUCCESS(resp.ctx.ec);
969
+ auto get_resp = wait_for_bucket_created(integration, update_bucket_name);
970
+ REQUIRE_SUCCESS(get_resp.ctx.ec);
971
+ REQUIRE(get_resp.bucket.storage_backend == couchbase::core::management::cluster::bucket_storage_backend::magma);
972
+ REQUIRE(get_resp.bucket.history_retention_collection_default == true);
973
+ REQUIRE(get_resp.bucket.history_retention_duration == 13000);
974
+ REQUIRE(get_resp.bucket.history_retention_bytes == 2147483648);
975
+ }
976
+ }
977
+ {
978
+ couchbase::core::operations::management::bucket_drop_request req{ bucket_name };
979
+ couchbase::core::operations::management::bucket_drop_request update_req{ update_bucket_name };
980
+ test::utils::execute(integration.cluster, req);
981
+ test::utils::execute(integration.cluster, update_req);
982
+ }
983
+ }
984
+
897
985
  std::optional<couchbase::core::topology::collections_manifest::collection>
898
986
  get_collection(std::shared_ptr<couchbase::core::cluster> cluster,
899
987
  const std::string& bucket_name,
@@ -943,7 +1031,208 @@ TEST_CASE("integration: collection management", "[integration]")
943
1031
  auto scope_name = test::utils::uniq_id("scope");
944
1032
  auto collection_name = test::utils::uniq_id("collection");
945
1033
  std::uint32_t max_expiry = 5;
1034
+ SECTION("core api")
1035
+ {
1036
+ {
1037
+ couchbase::core::operations::management::scope_create_request req{ integration.ctx.bucket, scope_name };
1038
+ auto resp = test::utils::execute(integration.cluster, req);
1039
+ REQUIRE_SUCCESS(resp.ctx.ec);
1040
+ auto created = test::utils::wait_until_collection_manifest_propagated(integration.cluster, integration.ctx.bucket, resp.uid);
1041
+ REQUIRE(created);
1042
+ }
1043
+
1044
+ {
1045
+ auto created = test::utils::wait_until([&]() { return scope_exists(integration.cluster, integration.ctx.bucket, scope_name); });
1046
+ REQUIRE(created);
1047
+ }
1048
+
1049
+ {
1050
+ couchbase::core::operations::management::scope_create_request req{ integration.ctx.bucket, scope_name };
1051
+ auto resp = test::utils::execute(integration.cluster, req);
1052
+ REQUIRE(resp.ctx.ec == couchbase::errc::management::scope_exists);
1053
+ }
1054
+
1055
+ {
1056
+ couchbase::core::operations::management::collection_create_request req{ integration.ctx.bucket, scope_name, collection_name };
1057
+ if (integration.cluster_version().is_enterprise()) {
1058
+ req.max_expiry = max_expiry;
1059
+ }
1060
+ auto resp = test::utils::execute(integration.cluster, req);
1061
+ REQUIRE_SUCCESS(resp.ctx.ec);
1062
+ auto created = test::utils::wait_until_collection_manifest_propagated(integration.cluster, integration.ctx.bucket, resp.uid);
1063
+ REQUIRE(created);
1064
+ }
1065
+
1066
+ {
1067
+ couchbase::core::topology::collections_manifest::collection collection;
1068
+ auto created = test::utils::wait_until([&]() {
1069
+ auto coll = get_collection(integration.cluster, integration.ctx.bucket, scope_name, collection_name);
1070
+ if (coll) {
1071
+ collection = *coll;
1072
+ return true;
1073
+ }
1074
+ return false;
1075
+ });
1076
+ REQUIRE(created);
1077
+ if (integration.cluster_version().is_enterprise()) {
1078
+ REQUIRE(collection.max_expiry == max_expiry);
1079
+ }
1080
+ }
1081
+
1082
+ {
1083
+ couchbase::core::operations::management::collection_create_request req{ integration.ctx.bucket, scope_name, collection_name };
1084
+ auto resp = test::utils::execute(integration.cluster, req);
1085
+ REQUIRE(resp.ctx.ec == couchbase::errc::management::collection_exists);
1086
+ }
1087
+ {
1088
+ couchbase::core::operations::management::collection_drop_request req{ integration.ctx.bucket, scope_name, collection_name };
1089
+ auto resp = test::utils::execute(integration.cluster, req);
1090
+ REQUIRE_SUCCESS(resp.ctx.ec);
1091
+ }
1092
+
1093
+ {
1094
+ auto dropped = test::utils::wait_until(
1095
+ [&]() { return !get_collection(integration.cluster, integration.ctx.bucket, scope_name, collection_name).has_value(); });
1096
+ REQUIRE(dropped);
1097
+ }
1098
+
1099
+ {
1100
+ couchbase::core::operations::management::collection_drop_request req{ integration.ctx.bucket, scope_name, collection_name };
1101
+ auto resp = test::utils::execute(integration.cluster, req);
1102
+ REQUIRE(resp.ctx.ec == couchbase::errc::common::collection_not_found);
1103
+ }
1104
+
1105
+ {
1106
+ couchbase::core::operations::management::scope_drop_request req{ integration.ctx.bucket, scope_name };
1107
+ auto resp = test::utils::execute(integration.cluster, req);
1108
+ REQUIRE_SUCCESS(resp.ctx.ec);
1109
+ }
1110
+
1111
+ {
1112
+ auto dropped =
1113
+ test::utils::wait_until([&]() { return !scope_exists(integration.cluster, integration.ctx.bucket, scope_name); });
1114
+ REQUIRE(dropped);
1115
+ }
946
1116
 
1117
+ {
1118
+ couchbase::core::operations::management::scope_drop_request req{ integration.ctx.bucket, scope_name };
1119
+ auto resp = test::utils::execute(integration.cluster, req);
1120
+ REQUIRE(resp.ctx.ec == couchbase::errc::common::scope_not_found);
1121
+ }
1122
+ }
1123
+ SECTION("public API")
1124
+ {
1125
+ couchbase::cluster c(integration.cluster);
1126
+ auto manager = c.bucket(integration.ctx.bucket).collections();
1127
+ {
1128
+ auto ctx = manager.create_scope(scope_name).get();
1129
+ REQUIRE_SUCCESS(ctx.ec());
1130
+ }
1131
+ {
1132
+ auto scope_exists = test::utils::wait_until([&scope_name, &manager]() {
1133
+ auto [ctx, result] = manager.get_all_scopes().get();
1134
+ if (!ctx.ec()) {
1135
+ for (auto& scope : result) {
1136
+ if (scope.name == scope_name) {
1137
+ return true;
1138
+ }
1139
+ }
1140
+ }
1141
+ return false;
1142
+ });
1143
+ REQUIRE(scope_exists);
1144
+ }
1145
+ {
1146
+ auto ctx = manager.create_scope(scope_name).get();
1147
+ REQUIRE(ctx.ec() == couchbase::errc::management::scope_exists);
1148
+ }
1149
+ {
1150
+ couchbase::create_collection_settings settings{};
1151
+ if (integration.cluster_version().is_enterprise()) {
1152
+ settings.max_expiry = max_expiry;
1153
+ }
1154
+ auto ctx = manager.create_collection(scope_name, collection_name, settings).get();
1155
+ REQUIRE_SUCCESS(ctx.ec());
1156
+ auto created = test::utils::wait_until([&scope_name, &collection_name, &manager]() {
1157
+ auto [get_ctx, result] = manager.get_all_scopes().get();
1158
+ if (!get_ctx.ec()) {
1159
+ for (auto& scope : result) {
1160
+ if (scope.name == scope_name) {
1161
+ for (auto& collection : scope.collections) {
1162
+ if (collection.name == collection_name) {
1163
+ return true;
1164
+ }
1165
+ }
1166
+ }
1167
+ }
1168
+ }
1169
+ return false;
1170
+ });
1171
+ REQUIRE(created);
1172
+ }
1173
+ {
1174
+ auto [ctx, scopes] = manager.get_all_scopes().get();
1175
+ REQUIRE_SUCCESS(ctx.ec());
1176
+ couchbase::management::bucket::collection_spec spec;
1177
+ for (auto& scope : scopes) {
1178
+ if (scope.name == scope_name) {
1179
+ for (auto& collection : scope.collections) {
1180
+ if (collection.name == collection_name) {
1181
+ spec = collection;
1182
+ }
1183
+ }
1184
+ }
1185
+ }
1186
+ if (integration.cluster_version().is_enterprise()) {
1187
+ REQUIRE(spec.max_expiry == max_expiry);
1188
+ }
1189
+ }
1190
+ {
1191
+ couchbase::create_collection_settings settings{};
1192
+ auto ctx = manager.create_collection(scope_name, collection_name, settings).get();
1193
+ REQUIRE(ctx.ec() == couchbase::errc::management::collection_exists);
1194
+ }
1195
+ {
1196
+ auto ctx = manager.drop_collection(scope_name, collection_name).get();
1197
+ REQUIRE_SUCCESS(ctx.ec());
1198
+ }
1199
+ {
1200
+ auto bucket_name = integration.ctx.bucket;
1201
+ auto does_not_exist = test::utils::wait_until([&scope_name, &collection_name, &manager]() {
1202
+ auto ctx = manager.drop_collection(scope_name, collection_name).get();
1203
+ return (ctx.ec() == couchbase::errc::common::collection_not_found);
1204
+ });
1205
+ REQUIRE(does_not_exist);
1206
+ }
1207
+ {
1208
+ auto ctx = manager.drop_scope(scope_name).get();
1209
+ REQUIRE_SUCCESS(ctx.ec());
1210
+ }
1211
+ {
1212
+ auto does_not_exist = test::utils::wait_until([&scope_name, &manager]() {
1213
+ auto ctx = manager.drop_scope(scope_name).get();
1214
+ return (ctx.ec() == couchbase::errc::common::scope_not_found);
1215
+ });
1216
+ REQUIRE(does_not_exist);
1217
+ }
1218
+ }
1219
+ }
1220
+
1221
+ TEST_CASE("integration: collection management bucket dedup", "[integration]")
1222
+ {
1223
+ test::utils::integration_test_guard integration;
1224
+ test::utils::open_bucket(integration.cluster, integration.ctx.bucket);
1225
+
1226
+ if (!integration.cluster_version().supports_collections()) {
1227
+ SKIP("cluster does not support collections");
1228
+ }
1229
+ if (!integration.has_bucket_capability("nonDedupedHistory")) {
1230
+ SKIP("Bucket does not support non deduped history");
1231
+ }
1232
+
1233
+ auto bucket_name = test::utils::uniq_id("bucket");
1234
+ auto scope_name = test::utils::uniq_id("scope");
1235
+ auto collection_name = test::utils::uniq_id("collection");
947
1236
  {
948
1237
  couchbase::core::operations::management::scope_create_request req{ integration.ctx.bucket, scope_name };
949
1238
  auto resp = test::utils::execute(integration.cluster, req);
@@ -957,23 +1246,14 @@ TEST_CASE("integration: collection management", "[integration]")
957
1246
  REQUIRE(created);
958
1247
  }
959
1248
 
960
- {
961
- couchbase::core::operations::management::scope_create_request req{ integration.ctx.bucket, scope_name };
962
- auto resp = test::utils::execute(integration.cluster, req);
963
- REQUIRE(resp.ctx.ec == couchbase::errc::management::scope_exists);
964
- }
965
-
966
1249
  {
967
1250
  couchbase::core::operations::management::collection_create_request req{ integration.ctx.bucket, scope_name, collection_name };
968
- if (integration.cluster_version().is_enterprise()) {
969
- req.max_expiry = max_expiry;
970
- }
1251
+ req.history = true;
971
1252
  auto resp = test::utils::execute(integration.cluster, req);
972
1253
  REQUIRE_SUCCESS(resp.ctx.ec);
973
1254
  auto created = test::utils::wait_until_collection_manifest_propagated(integration.cluster, integration.ctx.bucket, resp.uid);
974
1255
  REQUIRE(created);
975
1256
  }
976
-
977
1257
  {
978
1258
  couchbase::core::topology::collections_manifest::collection collection;
979
1259
  auto created = test::utils::wait_until([&]() {
@@ -985,50 +1265,27 @@ TEST_CASE("integration: collection management", "[integration]")
985
1265
  return false;
986
1266
  });
987
1267
  REQUIRE(created);
988
- if (integration.cluster_version().is_enterprise()) {
989
- REQUIRE(collection.max_expiry == max_expiry);
990
- }
991
- }
992
-
993
- {
994
- couchbase::core::operations::management::collection_create_request req{ integration.ctx.bucket, scope_name, collection_name };
995
- auto resp = test::utils::execute(integration.cluster, req);
996
- REQUIRE(resp.ctx.ec == couchbase::errc::management::collection_exists);
1268
+ REQUIRE(collection.history.value());
997
1269
  }
998
-
999
- {
1000
- couchbase::core::operations::management::collection_drop_request req{ integration.ctx.bucket, scope_name, collection_name };
1001
- auto resp = test::utils::execute(integration.cluster, req);
1002
- REQUIRE_SUCCESS(resp.ctx.ec);
1003
- }
1004
-
1005
- {
1006
- auto dropped = test::utils::wait_until(
1007
- [&]() { return !get_collection(integration.cluster, integration.ctx.bucket, scope_name, collection_name).has_value(); });
1008
- REQUIRE(dropped);
1009
- }
1010
-
1011
- {
1012
- couchbase::core::operations::management::collection_drop_request req{ integration.ctx.bucket, scope_name, collection_name };
1013
- auto resp = test::utils::execute(integration.cluster, req);
1014
- REQUIRE(resp.ctx.ec == couchbase::errc::common::collection_not_found);
1015
- }
1016
-
1017
1270
  {
1018
- couchbase::core::operations::management::scope_drop_request req{ integration.ctx.bucket, scope_name };
1271
+ couchbase::core::operations::management::collection_update_request req{ integration.ctx.bucket, scope_name, collection_name };
1272
+ req.history = false;
1019
1273
  auto resp = test::utils::execute(integration.cluster, req);
1020
1274
  REQUIRE_SUCCESS(resp.ctx.ec);
1021
1275
  }
1022
-
1023
1276
  {
1024
- auto dropped = test::utils::wait_until([&]() { return !scope_exists(integration.cluster, integration.ctx.bucket, scope_name); });
1025
- REQUIRE(dropped);
1026
- }
1027
-
1028
- {
1029
- couchbase::core::operations::management::scope_drop_request req{ integration.ctx.bucket, scope_name };
1030
- auto resp = test::utils::execute(integration.cluster, req);
1031
- REQUIRE(resp.ctx.ec == couchbase::errc::common::scope_not_found);
1277
+ couchbase::core::topology::collections_manifest::collection collection;
1278
+ auto no_history = test::utils::wait_until([&]() {
1279
+ auto coll = get_collection(integration.cluster, integration.ctx.bucket, scope_name, collection_name);
1280
+ if (coll.has_value()) {
1281
+ if (!coll.value().history.value()) {
1282
+ return true;
1283
+ }
1284
+ return false;
1285
+ }
1286
+ return false;
1287
+ });
1288
+ REQUIRE(no_history);
1032
1289
  }
1033
1290
  }
1034
1291