couchbase 3.4.4 → 3.4.5

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 (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