From 34e7caeea1c25bcf9116af7d465bb9b67f0ade5a Mon Sep 17 00:00:00 2001 From: Charles Dixon Date: Mon, 13 Oct 2025 16:18:13 +0100 Subject: [PATCH] RSCBC-211: Community version testing --- .github/workflows/tests.yml | 40 +++-- sdk/couchbase-core/src/agent_ops.rs | 20 --- sdk/couchbase-core/src/memdx/datatype.rs | 9 +- sdk/couchbase-core/tests/common/features.rs | 31 +++- sdk/couchbase-core/tests/common/helpers.rs | 15 +- sdk/couchbase-core/tests/common/test_agent.rs | 34 ++--- .../tests/common/test_config.rs | 2 +- sdk/couchbase-core/tests/diagnostics.rs | 4 +- sdk/couchbase-core/tests/mgmt.rs | 139 ++++++++++++++---- sdk/couchbase-core/tests/users.rs | 49 ++++-- sdk/couchbase/tests/bucket_management.rs | 8 +- sdk/couchbase/tests/collections_management.rs | 16 +- sdk/couchbase/tests/common/features.rs | 46 +++++- sdk/couchbase/tests/common/helpers.rs | 37 +++++ sdk/couchbase/tests/common/mod.rs | 26 ++++ .../tests/common/test_binary_collection.rs | 39 ++--- sdk/couchbase/tests/common/test_bucket.rs | 15 +- sdk/couchbase/tests/common/test_cluster.rs | 24 ++- sdk/couchbase/tests/common/test_collection.rs | 99 ++++--------- sdk/couchbase/tests/common/test_scope.rs | 11 +- sdk/couchbase/tests/connections.rs | 32 ++-- sdk/couchbase/tests/diagnostics.rs | 8 +- sdk/couchbase/tests/user_management.rs | 49 ++++-- 23 files changed, 486 insertions(+), 267 deletions(-) create mode 100644 sdk/couchbase/tests/common/helpers.rs diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ab516ca1..8a9aa6ba 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,19 +14,17 @@ jobs: strategy: matrix: - server: - - 8.0.0-3716 - - 7.6.7 - - 7.2.7 - - 7.1.6 - - 7.0.4 - + server: [ 8.0.0, 7.6.7, 7.2.7, 7.1.6, 7.0.4, community-8.0.0 ] + include: + - server: community-8.0.0 + rcbserverVersion: 8.0.0-community + runs-on: ubuntu-latest steps: - name: Install cbdinocluster run: | mkdir -p "$HOME/bin" - wget -nv -O $HOME/bin/cbdinocluster https://github.com/couchbaselabs/cbdinocluster/releases/download/v0.0.41/cbdinocluster-linux-amd64 + wget -nv -O $HOME/bin/cbdinocluster https://github.com/couchbaselabs/cbdinocluster/releases/download/v0.0.89/cbdinocluster-linux-amd64 chmod +x $HOME/bin/cbdinocluster echo "$HOME/bin" >> $GITHUB_PATH @@ -50,12 +48,20 @@ jobs: CBDC_ID=$(cbdinocluster -v alloc --def="${CLUSTERCONFIG}") cbdinocluster -v buckets add ${CBDC_ID} default --ram-quota-mb=100 --flush-enabled=true --num-replicas=2 cbdinocluster -v collections add ${CBDC_ID} default _default test - CBDC_CONNSTR=$(cbdinocluster -v connstr --tls $CBDC_ID) CBDC_IP=$(cbdinocluster -v ip $CBDC_ID) echo "CBDC_ID=$CBDC_ID" >> "$GITHUB_ENV" - echo "CBDC_CONNSTR=$CBDC_CONNSTR" >> "$GITHUB_ENV" echo "CBDC_IP=$CBDC_IP" >> "$GITHUB_ENV" + - name: Set connection string + run: | + if [[ "${{ matrix.server }}" == community* ]]; then + CBDC_CONNSTR=$(cbdinocluster -v connstr $CBDC_ID) + else + CBDC_CONNSTR=$(cbdinocluster -v connstr --tls $CBDC_ID) + fi + + echo "CBDC_CONNSTR=$CBDC_CONNSTR" >> "$GITHUB_ENV" + - name: Create fts index run: | curl -XPUT -H "Content-Type: application/json" -u Administrator:password http://${{ env.CBDC_IP }}:8094/api/index/basic_search_index -d '{"type": "fulltext-index","name": "basic_search_index","sourceType": "gocbcore","sourceName": "default","planParams": {"maxPartitionsPerPIndex": 1024,"indexPartitions": 1},"params": {"doc_config": {"docid_prefix_delim": "","docid_regexp": "","mode": "type_field","type_field": "type"},"mapping": {"analysis": {},"default_analyzer": "standard","default_datetime_parser": "dateTimeOptional","default_field": "_all","default_mapping": {"dynamic": true,"enabled": true},"default_type": "_default","docvalues_dynamic": true,"index_dynamic": true,"store_dynamic": true,"type_field": "_type"},"store": {"indexType": "scorch","segmentVersion": 15}},"sourceParams": {}}' @@ -72,8 +78,13 @@ jobs: CBDC_CONNSTR: # from above RCBDINOID: ${{ env.CBDC_ID }} RCBCONNSTR: ${{ env.CBDC_CONNSTR }} - RCBSERVER_VERSION: ${{ matrix.server }} run: | + if [[ -z "${{ matrix.rcbserverVersion }}" ]]; then + export RCBSERVER_VERSION=${{ matrix.server }} + else + export RCBSERVER_VERSION=${{ matrix.rcbserverVersion }} + fi + cargo test --color=always --no-fail-fast -- --nocapture - name: Run allocation tests @@ -83,8 +94,13 @@ jobs: CBDC_CONNSTR: # from above RCBDINOID: ${{ env.CBDC_ID }} RCBCONNSTR: ${{ env.CBDC_CONNSTR }} - RCBSERVER_VERSION: ${{ matrix.server }} run: | + if [[ -z "${{ matrix.rcbserverVersion }}" ]]; then + export RCBSERVER_VERSION=${{ matrix.server }} + else + export RCBSERVER_VERSION=${{ matrix.rcbserverVersion }} + fi + cargo test --features dhat-heap --test allocations --color=always --no-fail-fast -- --nocapture # - name: Collect couchbase logs diff --git a/sdk/couchbase-core/src/agent_ops.rs b/sdk/couchbase-core/src/agent_ops.rs index f741bb63..6224fbd3 100644 --- a/sdk/couchbase-core/src/agent_ops.rs +++ b/sdk/couchbase-core/src/agent_ops.rs @@ -274,16 +274,6 @@ impl Agent { &self, opts: &CreateCollectionOptions<'_>, ) -> Result { - if opts.history_enabled.is_some() { - return self.run_with_bucket_feature_check( - BucketFeature::NonDedupedHistory, - || async { - self.inner.mgmt.create_collection(opts).await - }, - "History retention is not supported - note that the Magma storage engine must be used", - ).await; - } - self.inner.mgmt.create_collection(opts).await } @@ -298,16 +288,6 @@ impl Agent { &self, opts: &UpdateCollectionOptions<'_>, ) -> Result { - if opts.history_enabled.is_some() { - return self.run_with_bucket_feature_check( - BucketFeature::NonDedupedHistory, - || async { - self.inner.mgmt.update_collection(opts).await - }, - "History retention is not supported - note that the Magma storage engine must be used", - ) - .await; - } self.inner.mgmt.update_collection(opts).await } diff --git a/sdk/couchbase-core/src/memdx/datatype.rs b/sdk/couchbase-core/src/memdx/datatype.rs index 981df27c..75040d2b 100644 --- a/sdk/couchbase-core/src/memdx/datatype.rs +++ b/sdk/couchbase-core/src/memdx/datatype.rs @@ -15,22 +15,19 @@ * * limitations under the License. * */ +use std::convert::From; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] +#[derive(Default)] pub enum DataTypeFlag { + #[default] None, Json, Compressed, Xattrs, } -impl Default for DataTypeFlag { - fn default() -> Self { - Self::None - } -} - impl From for u8 { fn from(value: DataTypeFlag) -> Self { match value { diff --git a/sdk/couchbase-core/tests/common/features.rs b/sdk/couchbase-core/tests/common/features.rs index 2ee37e5c..c1f20a19 100644 --- a/sdk/couchbase-core/tests/common/features.rs +++ b/sdk/couchbase-core/tests/common/features.rs @@ -16,7 +16,7 @@ * */ -use crate::common::node_version::NodeVersion; +use crate::common::node_version::{NodeEdition, NodeVersion}; use crate::common::test_agent::TestAgent; const SERVER_VERSION_720: NodeVersion = NodeVersion { @@ -46,6 +46,15 @@ const SERVER_VERSION_762: NodeVersion = NodeVersion { modifier: None, }; +const SERVER_VERSION_800_COMMUNITY: NodeVersion = NodeVersion { + major: 8, + minor: 0, + patch: 0, + build: 0, + edition: Some(NodeEdition::Community), + modifier: None, +}; + #[derive(Debug, PartialEq, Eq, Hash)] pub enum TestFeatureCode { KV, @@ -55,9 +64,11 @@ pub enum TestFeatureCode { SearchManagement, SearchManagementCollections, BucketManagement, - CollectionNoExpiry, + CollectionMaxExpiry, CollectionUpdates, HistoryRetention, + UserGroups, + UsersMB69096, } impl TestAgent { @@ -72,12 +83,24 @@ impl TestAgent { TestFeatureCode::SearchManagementCollections => { !self.cluster_version.lower(&SERVER_VERSION_762) } - TestFeatureCode::CollectionNoExpiry => !self.cluster_version.lower(&SERVER_VERSION_762), + TestFeatureCode::CollectionMaxExpiry => { + self.cluster_version.edition != Some(NodeEdition::Community) + && !self.cluster_version.lower(&SERVER_VERSION_762) + } TestFeatureCode::CollectionUpdates => { !self.cluster_version.lower(&SERVER_VERSION_722) && !self.cluster_version.equal(&SERVER_VERSION_722) } - TestFeatureCode::HistoryRetention => !self.cluster_version.lower(&SERVER_VERSION_720), + TestFeatureCode::HistoryRetention => { + self.cluster_version.edition != Some(NodeEdition::Community) + && !self.cluster_version.lower(&SERVER_VERSION_720) + } + TestFeatureCode::UserGroups => { + self.cluster_version.edition != Some(NodeEdition::Community) + } + TestFeatureCode::UsersMB69096 => { + !self.cluster_version.equal(&SERVER_VERSION_800_COMMUNITY) + } } } } diff --git a/sdk/couchbase-core/tests/common/helpers.rs b/sdk/couchbase-core/tests/common/helpers.rs index 94946b44..d08c45c2 100644 --- a/sdk/couchbase-core/tests/common/helpers.rs +++ b/sdk/couchbase-core/tests/common/helpers.rs @@ -16,6 +16,7 @@ * */ +use crate::common::node_version::{NodeEdition, NodeVersion}; use crate::common::test_agent::TestAgent; use couchbase_core::agent::Agent; use couchbase_core::error::{Error, ErrorKind}; @@ -262,13 +263,19 @@ where timeout_at(deadline, f).await.unwrap() } -pub async fn run_with_std_kv_deadline(f: Fut) -> Result +pub async fn run_with_std_kv_deadline( + node_version: &NodeVersion, + f: Fut, +) -> Result where Fut: std::future::Future>, { - timeout_at(Instant::now().add(Duration::from_millis(2500)), f) - .await - .unwrap() + let timeout = match node_version.edition { + Some(NodeEdition::Community) => Duration::from_millis(10000), + _ => Duration::from_millis(2500), + }; + + timeout_at(Instant::now().add(timeout), f).await.unwrap() } pub async fn run_with_std_mgmt_deadline(f: Fut) -> Result diff --git a/sdk/couchbase-core/tests/common/test_agent.rs b/sdk/couchbase-core/tests/common/test_agent.rs index ff91fef4..38080a6c 100644 --- a/sdk/couchbase-core/tests/common/test_agent.rs +++ b/sdk/couchbase-core/tests/common/test_agent.rs @@ -82,74 +82,74 @@ impl TestAgent { } pub async fn upsert(&self, opts: UpsertOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.upsert(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.upsert(opts)).await } pub async fn get(&self, opts: GetOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.get(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.get(opts)).await } pub async fn get_meta(&self, opts: GetMetaOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.get_meta(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.get_meta(opts)).await } pub async fn delete(&self, opts: DeleteOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.delete(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.delete(opts)).await } pub async fn get_and_lock(&self, opts: GetAndLockOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.get_and_lock(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.get_and_lock(opts)).await } pub async fn get_and_touch(&self, opts: GetAndTouchOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.get_and_touch(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.get_and_touch(opts)).await } pub async fn unlock(&self, opts: UnlockOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.unlock(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.unlock(opts)).await } pub async fn touch(&self, opts: TouchOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.touch(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.touch(opts)).await } pub async fn add(&self, opts: AddOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.add(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.add(opts)).await } pub async fn replace(&self, opts: ReplaceOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.replace(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.replace(opts)).await } pub async fn append(&self, opts: AppendOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.append(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.append(opts)).await } pub async fn prepend(&self, opts: PrependOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.prepend(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.prepend(opts)).await } pub async fn increment(&self, opts: IncrementOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.increment(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.increment(opts)).await } pub async fn decrement(&self, opts: DecrementOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.decrement(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.decrement(opts)).await } pub async fn get_collection_id( &self, opts: GetCollectionIdOptions<'_>, ) -> Result { - run_with_std_kv_deadline(self.agent.get_collection_id(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.get_collection_id(opts)).await } pub async fn lookup_in(&self, opts: LookupInOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.lookup_in(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.lookup_in(opts)).await } pub async fn mutate_in(&self, opts: MutateInOptions<'_>) -> Result { - run_with_std_kv_deadline(self.agent.mutate_in(opts)).await + run_with_std_kv_deadline(&self.cluster_version, self.agent.mutate_in(opts)).await } pub async fn query(&self, opts: QueryOptions) -> Result { diff --git a/sdk/couchbase-core/tests/common/test_config.rs b/sdk/couchbase-core/tests/common/test_config.rs index 5b3e8174..bcc3954e 100644 --- a/sdk/couchbase-core/tests/common/test_config.rs +++ b/sdk/couchbase-core/tests/common/test_config.rs @@ -48,7 +48,7 @@ pub struct EnvTestConfig { pub username: String, #[envconfig(from = "RCBPASSWORD", default = "password")] pub password: String, - #[envconfig(from = "RCBCONNSTR", default = "couchbases://192.168.107.128")] + #[envconfig(from = "RCBCONNSTR", default = "couchbase://192.168.107.132")] pub conn_string: String, #[envconfig(from = "RCBBUCKET", default = "default")] pub default_bucket: String, diff --git a/sdk/couchbase-core/tests/diagnostics.rs b/sdk/couchbase-core/tests/diagnostics.rs index 452bbe2c..3867cad0 100644 --- a/sdk/couchbase-core/tests/diagnostics.rs +++ b/sdk/couchbase-core/tests/diagnostics.rs @@ -37,8 +37,8 @@ fn test_ping() { run_test(async |mut agent| { let opts = PingOptions::new() .kv_timeout(Duration::from_millis(1000)) - .query_timeout(Duration::from_millis(1000)) - .search_timeout(Duration::from_millis(1000)); + .query_timeout(Duration::from_millis(75000)) + .search_timeout(Duration::from_millis(75000)); let report = agent.ping(&opts).await.unwrap(); diff --git a/sdk/couchbase-core/tests/mgmt.rs b/sdk/couchbase-core/tests/mgmt.rs index eb751a2a..98dc5875 100644 --- a/sdk/couchbase-core/tests/mgmt.rs +++ b/sdk/couchbase-core/tests/mgmt.rs @@ -16,16 +16,16 @@ * */ +use crate::common::features::TestFeatureCode; use crate::common::helpers::{ - create_scope, delete_collection, delete_scope, feature_supported, generate_string_value, + create_scope, delete_collection, delete_scope, ensure_manifest, generate_string_value, try_until, }; use crate::common::test_config::run_test; use common::helpers; use couchbase_core::agent::Agent; use couchbase_core::cbconfig::CollectionManifest; -use couchbase_core::features::BucketFeature; -use couchbase_core::mgmtx::bucket_settings::{BucketSettings, BucketType}; +use couchbase_core::mgmtx::bucket_settings::{BucketSettings, BucketType, StorageBackend}; use couchbase_core::options::management::{ CreateBucketOptions, CreateCollectionOptions, DeleteBucketOptions, EnsureBucketOptions, GetBucketOptions, GetCollectionManifestOptions, UpdateBucketOptions, @@ -70,14 +70,32 @@ fn test_scopes() { }); } +#[serial] #[test] -fn test_collections() { +fn test_collections_history_retention() { run_test(async |mut agent| { - let history_supported = feature_supported(&agent, BucketFeature::NonDedupedHistory).await; + if !agent.supports_feature(&TestFeatureCode::HistoryRetention) { + return; + } let scope_name = generate_string_value(10); let collection_name = generate_string_value(10); - let bucket_name = agent.test_setup_config.bucket.clone(); + let bucket_name = generate_string_value(10); + + let settings = BucketSettings::default() + .bucket_type(BucketType::COUCHBASE) + .storage_backend(StorageBackend::MAGMA) + .history_retention_seconds(5) + .ram_quota_mb(1024); + + let opts = &CreateBucketOptions::new(&bucket_name, &settings); + + agent.create_bucket(opts).await.unwrap(); + + agent + .ensure_bucket(&EnsureBucketOptions::new(&bucket_name, false)) + .await + .unwrap(); let resp = create_scope(&agent, &bucket_name, &scope_name) .await @@ -86,12 +104,11 @@ fn test_collections() { helpers::ensure_manifest(&agent, &bucket_name, resp.manifest_uid).await; - let mut opts = - CreateCollectionOptions::new(&bucket_name, &scope_name, &collection_name).max_ttl(25); - - if history_supported { - opts = opts.history_enabled(true) - }; + let mut opts = CreateCollectionOptions::new(&bucket_name, &scope_name, &collection_name) + .history_enabled(true); + if agent.supports_feature(&TestFeatureCode::CollectionMaxExpiry) { + opts = opts.max_ttl(25); + } let resp = agent.create_collection(&opts).await.unwrap(); assert!(!resp.manifest_uid.is_empty()); @@ -106,13 +123,80 @@ fn test_collections() { assert!(collection_found.is_some()); let collection_found = collection_found.unwrap(); - assert_eq!(collection_found.max_ttl, Some(25)); - if history_supported { - assert_eq!(collection_found.history, Some(true)); - } else { - // Depending on server version the collection may have inherited the bucket default. - assert!(collection_found.history.is_none() || collection_found.history == Some(false)); + if agent.supports_feature(&TestFeatureCode::CollectionMaxExpiry) { + assert_eq!(collection_found.max_ttl, Some(25)); } + assert_eq!(collection_found.history, Some(true)); + + let resp = delete_collection(&agent, &bucket_name, &scope_name, &collection_name) + .await + .unwrap(); + assert!(!resp.manifest_uid.is_empty()); + + ensure_manifest(&agent, &bucket_name, resp.manifest_uid).await; + + let manifest = get_manifest(&agent, &bucket_name).await.unwrap(); + + let mut scope_found = find_scope(&manifest, &scope_name); + let scope_found = scope_found.unwrap(); + let mut collection_found = find_collection(&scope_found, &collection_name); + assert!(collection_found.is_none()); + + let resp = delete_scope(&agent, &bucket_name, &scope_name) + .await + .unwrap(); + assert!(!resp.manifest_uid.is_empty()); + + let _ = agent + .delete_bucket(&DeleteBucketOptions::new(&bucket_name)) + .await; + + // We can't fire and forget the delete, the server will error if we try to update a bucket + // whilst one is being deleted which could fail other tests. + agent + .ensure_bucket(&EnsureBucketOptions::new(&bucket_name, true)) + .await + .unwrap(); + }); +} + +#[test] +fn test_collections() { + run_test(async |mut agent| { + let scope_name = generate_string_value(10); + let collection_name = generate_string_value(10); + let bucket_name = agent.test_setup_config.bucket.clone(); + + let resp = create_scope(&agent, &bucket_name, &scope_name) + .await + .unwrap(); + assert!(!resp.manifest_uid.is_empty()); + + ensure_manifest(&agent, &bucket_name, resp.manifest_uid).await; + + let mut opts = CreateCollectionOptions::new(&bucket_name, &scope_name, &collection_name); + if agent.supports_feature(&TestFeatureCode::CollectionMaxExpiry) { + opts = opts.max_ttl(25); + } + + let resp = agent.create_collection(&opts).await.unwrap(); + assert!(!resp.manifest_uid.is_empty()); + + ensure_manifest(&agent, &bucket_name, resp.manifest_uid).await; + + let manifest = get_manifest(&agent, &bucket_name).await.unwrap(); + assert!(!manifest.uid.is_empty()); + + let scope_found = find_scope(&manifest, &scope_name).unwrap(); + let mut collection_found = find_collection(&scope_found, &collection_name); + + assert!(collection_found.is_some()); + let collection_found = collection_found.unwrap(); + if agent.supports_feature(&TestFeatureCode::CollectionMaxExpiry) { + assert_eq!(collection_found.max_ttl, Some(25)); + } + // Depending on server version the collection may have inherited the bucket default. + assert!(collection_found.history.is_none() || collection_found.history == Some(false)); let resp = delete_collection(&agent, &bucket_name, &scope_name, &collection_name) .await @@ -241,9 +325,11 @@ fn test_update_bucket() { .await .unwrap(); - let update_settings = BucketSettings::default() - .ram_quota_mb(200) - .max_ttl(Duration::from_secs(3600)); + let mut update_settings = BucketSettings::default().ram_quota_mb(200); + + if agent.supports_feature(&TestFeatureCode::CollectionMaxExpiry) { + update_settings = update_settings.max_ttl(Duration::from_secs(3600)); + } agent .update_bucket(&UpdateBucketOptions::new(&bucket_name, &update_settings)) @@ -276,10 +362,13 @@ fn test_update_bucket() { .unwrap(); assert_eq!(bucket.bucket_settings.ram_quota_mb, Some(200)); - assert_eq!( - bucket.bucket_settings.max_ttl, - Some(Duration::from_secs(3600)) - ); + + if agent.supports_feature(&TestFeatureCode::CollectionMaxExpiry) { + assert_eq!( + bucket.bucket_settings.max_ttl, + Some(Duration::from_secs(3600)) + ); + } }); } diff --git a/sdk/couchbase-core/tests/users.rs b/sdk/couchbase-core/tests/users.rs index 0d74e060..a0348edc 100644 --- a/sdk/couchbase-core/tests/users.rs +++ b/sdk/couchbase-core/tests/users.rs @@ -16,6 +16,7 @@ * */ +use crate::common::features::TestFeatureCode; use crate::common::helpers::{generate_key_with_letter_prefix, try_until}; use crate::common::test_agent::TestAgent; use crate::common::test_config::run_test; @@ -50,11 +51,15 @@ fn test_get_all_roles() { #[test] fn test_delete_group() { run_test(async |mut agent| { + if !agent.supports_feature(&TestFeatureCode::UserGroups) { + return; + } + let group_name = generate_key_with_letter_prefix(); let desc = generate_key_with_letter_prefix(); let roles = vec![ - Role::new("replication_target").bucket(&agent.test_setup_config.bucket), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(&agent.test_setup_config.bucket), + Role::new("ro_admin"), ]; let group = Group::new(&group_name, desc, roles); @@ -84,11 +89,15 @@ fn test_delete_group() { #[test] fn test_get_group() { run_test(async |mut agent| { + if !agent.supports_feature(&TestFeatureCode::UserGroups) { + return; + } + let group_name = generate_key_with_letter_prefix(); let desc = generate_key_with_letter_prefix(); let roles = vec![ - Role::new("replication_target").bucket(&agent.test_setup_config.bucket), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(&agent.test_setup_config.bucket), + Role::new("ro_admin"), ]; let group = Group::new(&group_name, desc, roles); @@ -107,11 +116,15 @@ fn test_get_group() { #[test] fn test_get_all_groups() { run_test(async |mut agent| { + if !agent.supports_feature(&TestFeatureCode::UserGroups) { + return; + } + let group_name = generate_key_with_letter_prefix(); let desc = generate_key_with_letter_prefix(); let roles = vec![ - Role::new("replication_target").bucket(&agent.test_setup_config.bucket), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(&agent.test_setup_config.bucket), + Role::new("ro_admin"), ]; let group = Group::new(&group_name, desc, roles); @@ -139,11 +152,15 @@ fn test_get_all_groups() { #[test] fn test_delete_user() { run_test(async |mut agent| { + if !agent.supports_feature(&TestFeatureCode::UsersMB69096) { + return; + } + let username = generate_key_with_letter_prefix(); let display_name = generate_key_with_letter_prefix(); let roles = vec![ - Role::new("replication_target").bucket(&agent.test_setup_config.bucket), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(&agent.test_setup_config.bucket), + Role::new("ro_admin"), ]; let user = User::new(&username, display_name, roles).password("password"); @@ -173,11 +190,15 @@ fn test_delete_user() { #[test] fn test_get_user() { run_test(async |mut agent| { + if !agent.supports_feature(&TestFeatureCode::UsersMB69096) { + return; + } + let username = generate_key_with_letter_prefix(); let display_name = generate_key_with_letter_prefix(); let roles = vec![ - Role::new("replication_target").bucket(&agent.test_setup_config.bucket), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(&agent.test_setup_config.bucket), + Role::new("ro_admin"), ]; let user = User::new(&username, display_name, roles).password("password"); @@ -193,11 +214,15 @@ fn test_get_user() { #[test] fn test_get_all_users() { run_test(async |mut agent| { + if !agent.supports_feature(&TestFeatureCode::UsersMB69096) { + return; + } + let username = generate_key_with_letter_prefix(); let display_name = generate_key_with_letter_prefix(); let roles = vec![ - Role::new("replication_target").bucket(&agent.test_setup_config.bucket), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(&agent.test_setup_config.bucket), + Role::new("ro_admin"), ]; let user = User::new(username, display_name, roles).password("password"); diff --git a/sdk/couchbase/tests/bucket_management.rs b/sdk/couchbase/tests/bucket_management.rs index eb5f03c6..2b09c789 100644 --- a/sdk/couchbase/tests/bucket_management.rs +++ b/sdk/couchbase/tests/bucket_management.rs @@ -194,7 +194,9 @@ fn test_create_bucket_with_eviction_policy() { #[test] fn test_create_bucket_with_compression_mode() { run_test(async |cluster| { - if !cluster.supports_feature(&TestFeatureCode::BucketManagement) { + if !cluster.supports_feature(&TestFeatureCode::BucketManagement) + || !cluster.supports_feature(&TestFeatureCode::BucketManagementCompressionMode) + { return; } @@ -261,7 +263,9 @@ fn test_create_bucket_with_durability_min_level() { #[test] fn test_create_bucket_with_conflict_resolution_type() { run_test(async |cluster| { - if !cluster.supports_feature(&TestFeatureCode::BucketManagement) { + if !cluster.supports_feature(&TestFeatureCode::BucketManagement) + || !cluster.supports_feature(&TestFeatureCode::BucketManagementConflictResolutionType) + { return; } diff --git a/sdk/couchbase/tests/collections_management.rs b/sdk/couchbase/tests/collections_management.rs index 0cd1f2e4..4874eb3c 100644 --- a/sdk/couchbase/tests/collections_management.rs +++ b/sdk/couchbase/tests/collections_management.rs @@ -69,8 +69,10 @@ fn test_create_collection() { manager.create_scope(&scope_name, None).await.unwrap(); verify_scope_created(&manager, &scope_name).await; - let settings = CreateCollectionSettings::new() - .max_expiry(MaxExpiryValue::Seconds(Duration::from_secs(2000))); + let mut settings = CreateCollectionSettings::new(); + if cluster.supports_feature(&TestFeatureCode::CollectionMaxExpiry) { + settings = settings.max_expiry(MaxExpiryValue::Seconds(Duration::from_secs(2000))); + } manager .create_collection(&scope_name, &collection_name, settings, None) @@ -81,10 +83,12 @@ fn test_create_collection() { assert_eq!(collection_name, collection.name()); assert_eq!(scope_name, collection.scope_name()); - assert_eq!( - MaxExpiryValue::Seconds(Duration::from_secs(2000)), - collection.max_expiry() - ); + if cluster.supports_feature(&TestFeatureCode::CollectionMaxExpiry) { + assert_eq!( + MaxExpiryValue::Seconds(Duration::from_secs(2000)), + collection.max_expiry() + ); + } assert!(!collection.history()); }) } diff --git a/sdk/couchbase/tests/common/features.rs b/sdk/couchbase/tests/common/features.rs index d98dcd20..24d4a6ff 100644 --- a/sdk/couchbase/tests/common/features.rs +++ b/sdk/couchbase/tests/common/features.rs @@ -16,7 +16,7 @@ * */ -use crate::common::node_version::NodeVersion; +use crate::common::node_version::{NodeEdition, NodeVersion}; use crate::common::test_cluster::TestCluster; const SERVER_VERSION_720: NodeVersion = NodeVersion { @@ -46,6 +46,15 @@ const SERVER_VERSION_800: NodeVersion = NodeVersion { modifier: None, }; +const SERVER_VERSION_800_COMMUNITY: NodeVersion = NodeVersion { + major: 8, + minor: 0, + patch: 0, + build: 0, + edition: Some(NodeEdition::Community), + modifier: None, +}; + #[derive(Debug, PartialEq, Eq, Hash)] pub enum TestFeatureCode { KV, @@ -55,10 +64,14 @@ pub enum TestFeatureCode { SearchManagement, SearchManagementCollections, BucketManagement, - CollectionNoExpiry, + BucketManagementCompressionMode, + BucketManagementConflictResolutionType, + CollectionMaxExpiry, CollectionUpdateMaxExpiry, HistoryRetention, VectorSearch, + UserGroups, + UsersMB69096, } impl TestCluster { @@ -68,17 +81,38 @@ impl TestCluster { TestFeatureCode::Search => true, TestFeatureCode::Query => true, TestFeatureCode::BucketManagement => true, + TestFeatureCode::BucketManagementCompressionMode => { + self.cluster_version.edition != Some(NodeEdition::Community) + } + TestFeatureCode::BucketManagementConflictResolutionType => { + self.cluster_version.edition != Some(NodeEdition::Community) + } TestFeatureCode::QueryManagement => true, TestFeatureCode::SearchManagement => true, TestFeatureCode::SearchManagementCollections => { !self.cluster_version.lower(&SERVER_VERSION_760) } - TestFeatureCode::CollectionNoExpiry => !self.cluster_version.lower(&SERVER_VERSION_760), + TestFeatureCode::CollectionMaxExpiry => { + self.cluster_version.edition != Some(NodeEdition::Community) + } TestFeatureCode::CollectionUpdateMaxExpiry => { - !self.cluster_version.lower(&SERVER_VERSION_760) + self.cluster_version.edition != Some(NodeEdition::Community) + && !self.cluster_version.lower(&SERVER_VERSION_760) + } + TestFeatureCode::HistoryRetention => { + self.cluster_version.edition != Some(NodeEdition::Community) + && !self.cluster_version.lower(&SERVER_VERSION_720) + } + TestFeatureCode::VectorSearch => { + self.cluster_version.edition != Some(NodeEdition::Community) + && !self.cluster_version.lower(&SERVER_VERSION_760) + } + TestFeatureCode::UserGroups => { + self.cluster_version.edition != Some(NodeEdition::Community) + } + TestFeatureCode::UsersMB69096 => { + !self.cluster_version.equal(&SERVER_VERSION_800_COMMUNITY) } - TestFeatureCode::HistoryRetention => !self.cluster_version.lower(&SERVER_VERSION_720), - TestFeatureCode::VectorSearch => !self.cluster_version.lower(&SERVER_VERSION_760), } } } diff --git a/sdk/couchbase/tests/common/helpers.rs b/sdk/couchbase/tests/common/helpers.rs new file mode 100644 index 00000000..4eeaeab5 --- /dev/null +++ b/sdk/couchbase/tests/common/helpers.rs @@ -0,0 +1,37 @@ +/* + * + * * Copyright (c) 2025 Couchbase, Inc. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ +use crate::common::node_version::{NodeEdition, NodeVersion}; +use couchbase::error::Error; +use std::ops::Add; +use std::time::Duration; +use tokio::time::{timeout_at, Instant}; + +pub async fn run_with_std_kv_deadline( + node_version: &NodeVersion, + f: Fut, +) -> Result +where + Fut: std::future::Future>, +{ + let timeout = match node_version.edition { + Some(NodeEdition::Community) => Duration::from_millis(10000), + _ => Duration::from_millis(2500), + }; + + timeout_at(Instant::now().add(timeout), f).await.unwrap() +} diff --git a/sdk/couchbase/tests/common/mod.rs b/sdk/couchbase/tests/common/mod.rs index d572b6b7..14c2fe2a 100644 --- a/sdk/couchbase/tests/common/mod.rs +++ b/sdk/couchbase/tests/common/mod.rs @@ -23,6 +23,7 @@ pub mod consistency_utils; pub mod default_cluster_options; pub mod doc_generation; pub mod features; +mod helpers; pub mod node_version; mod test_binary_collection; mod test_bucket; @@ -50,6 +51,31 @@ pub fn generate_string_value(len: usize) -> String { .collect::() } +pub async fn try_times( + times: usize, + sleep: tokio::time::Duration, + fail_msg: impl AsRef, + mut f: impl FnMut() -> Fut, +) -> T +where + Fut: std::future::Future, couchbase::error::Error>>, +{ + let mut count = 0; + while count < times { + match f().await { + Ok(Some(r)) => return r, + Ok(None) => {} + Err(e) => { + error!("{e:?}"); + } + }; + + tokio::time::sleep(sleep).await; + count += 1; + } + panic!("{}", fail_msg.as_ref()); +} + pub async fn try_until( deadline: Instant, sleep: tokio::time::Duration, diff --git a/sdk/couchbase/tests/common/test_binary_collection.rs b/sdk/couchbase/tests/common/test_binary_collection.rs index 628c476c..314fb673 100644 --- a/sdk/couchbase/tests/common/test_binary_collection.rs +++ b/sdk/couchbase/tests/common/test_binary_collection.rs @@ -16,17 +16,19 @@ * */ +use crate::common::helpers::run_with_std_kv_deadline; +use crate::common::node_version::NodeVersion; use couchbase::collection::BinaryCollection; use couchbase::error; use couchbase::options::kv_binary_options::*; use couchbase::results::kv_binary_results::CounterResult; use couchbase::results::kv_results::*; use std::ops::Deref; -use tokio::time::{timeout, Duration}; #[derive(Clone)] pub struct TestBinaryCollection { inner: BinaryCollection, + node_version: NodeVersion, } impl Deref for TestBinaryCollection { @@ -38,8 +40,11 @@ impl Deref for TestBinaryCollection { } impl TestBinaryCollection { - pub fn new(inner: BinaryCollection) -> Self { - Self { inner } + pub fn new(inner: BinaryCollection, node_version: NodeVersion) -> Self { + Self { + inner, + node_version, + } } pub async fn append( @@ -48,12 +53,7 @@ impl TestBinaryCollection { value: &[u8], options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), - self.inner.append(id, value, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.append(id, value, options)).await } pub async fn prepend( @@ -62,12 +62,7 @@ impl TestBinaryCollection { value: &[u8], options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), - self.inner.prepend(id, value, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.prepend(id, value, options)).await } pub async fn increment( @@ -75,12 +70,7 @@ impl TestBinaryCollection { id: impl AsRef, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), - self.inner.increment(id, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.increment(id, options)).await } pub async fn decrement( @@ -88,11 +78,6 @@ impl TestBinaryCollection { id: impl AsRef, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), - self.inner.decrement(id, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.decrement(id, options)).await } } diff --git a/sdk/couchbase/tests/common/test_bucket.rs b/sdk/couchbase/tests/common/test_bucket.rs index 66afac32..4e6dbb99 100644 --- a/sdk/couchbase/tests/common/test_bucket.rs +++ b/sdk/couchbase/tests/common/test_bucket.rs @@ -16,6 +16,7 @@ * */ +use crate::common::node_version::NodeVersion; use crate::common::test_collection::TestCollection; use crate::common::test_manager::TestCollectionManager; use crate::common::test_scope::TestScope; @@ -27,6 +28,7 @@ use tokio::time::timeout; #[derive(Clone)] pub struct TestBucket { inner: Bucket, + node_version: NodeVersion, } impl std::ops::Deref for TestBucket { @@ -38,8 +40,11 @@ impl std::ops::Deref for TestBucket { } impl TestBucket { - pub fn new(inner: Bucket) -> Self { - Self { inner } + pub fn new(inner: Bucket, node_version: NodeVersion) -> Self { + Self { + inner, + node_version, + } } pub fn name(&self) -> &str { @@ -47,15 +52,15 @@ impl TestBucket { } pub fn scope(&self, name: impl Into) -> TestScope { - TestScope::new(self.inner.scope(name)) + TestScope::new(self.inner.scope(name), self.node_version.clone()) } pub fn collection(&self, name: impl Into) -> TestCollection { - TestCollection::new(self.inner.collection(name)) + TestCollection::new(self.inner.collection(name), self.node_version.clone()) } pub fn default_collection(&self) -> TestCollection { - TestCollection::new(self.inner.default_collection()) + TestCollection::new(self.inner.default_collection(), self.node_version.clone()) } pub fn collections(&self) -> TestCollectionManager { diff --git a/sdk/couchbase/tests/common/test_cluster.rs b/sdk/couchbase/tests/common/test_cluster.rs index 201bc917..ec9fbc5e 100644 --- a/sdk/couchbase/tests/common/test_cluster.rs +++ b/sdk/couchbase/tests/common/test_cluster.rs @@ -44,6 +44,16 @@ impl Deref for TestCluster { } impl TestCluster { + pub async fn new(cluster_version: NodeVersion, test_setup_config: TestSetupConfig) -> Self { + let inner = test_setup_config.setup_cluster().await; + + Self { + cluster_version, + test_setup_config, + inner, + } + } + pub fn default_bucket(&self) -> &str { &self.test_setup_config.default_bucket } @@ -55,21 +65,9 @@ impl TestCluster { pub fn default_collection(&self) -> &str { &self.test_setup_config.default_collection } -} - -impl TestCluster { - pub async fn new(cluster_version: NodeVersion, test_setup_config: TestSetupConfig) -> Self { - let inner = test_setup_config.setup_cluster().await; - - Self { - cluster_version, - test_setup_config, - inner, - } - } pub fn bucket(&self, name: impl Into) -> TestBucket { - TestBucket::new(self.inner.bucket(name)) + TestBucket::new(self.inner.bucket(name), self.cluster_version.clone()) } pub async fn query( diff --git a/sdk/couchbase/tests/common/test_collection.rs b/sdk/couchbase/tests/common/test_collection.rs index ea3a708c..92f055fc 100644 --- a/sdk/couchbase/tests/common/test_collection.rs +++ b/sdk/couchbase/tests/common/test_collection.rs @@ -16,6 +16,8 @@ * */ +use crate::common::helpers::run_with_std_kv_deadline; +use crate::common::node_version::NodeVersion; use crate::common::test_binary_collection::TestBinaryCollection; use crate::common::test_query_index_manager::TestQueryIndexManager; use couchbase::collection::Collection; @@ -27,11 +29,11 @@ use couchbase::subdoc::mutate_in_specs::MutateInSpec; use serde::Serialize; use std::ops::Deref; use std::time::Duration; -use tokio::time::timeout; #[derive(Clone)] pub struct TestCollection { inner: Collection, + node_version: NodeVersion, } impl Deref for TestCollection { @@ -43,8 +45,11 @@ impl Deref for TestCollection { } impl TestCollection { - pub fn new(inner: Collection) -> Self { - Self { inner } + pub fn new(inner: Collection, node_version: NodeVersion) -> Self { + Self { + inner, + node_version, + } } pub fn query_indexes(&self) -> TestQueryIndexManager { @@ -57,12 +62,7 @@ impl TestCollection { value: V, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), - self.inner.upsert(id, value, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.upsert(id, value, options)).await } pub async fn upsert_raw( @@ -72,12 +72,11 @@ impl TestCollection { flags: u32, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), + run_with_std_kv_deadline( + &self.node_version, self.inner.upsert_raw(id, value, flags, options), ) .await - .unwrap() } pub async fn insert( @@ -86,12 +85,7 @@ impl TestCollection { value: V, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), - self.inner.insert(id, value, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.insert(id, value, options)).await } pub async fn insert_raw( @@ -101,12 +95,11 @@ impl TestCollection { flags: u32, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), + run_with_std_kv_deadline( + &self.node_version, self.inner.insert_raw(id, value, flags, options), ) .await - .unwrap() } pub async fn replace( @@ -115,12 +108,7 @@ impl TestCollection { value: V, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), - self.inner.replace(id, value, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.replace(id, value, options)).await } pub async fn replace_raw( @@ -130,12 +118,11 @@ impl TestCollection { flags: u32, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), + run_with_std_kv_deadline( + &self.node_version, self.inner.replace_raw(id, value, flags, options), ) .await - .unwrap() } pub async fn remove( @@ -143,9 +130,7 @@ impl TestCollection { id: impl AsRef, options: impl Into>, ) -> error::Result { - timeout(Duration::from_millis(2500), self.inner.remove(id, options)) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.remove(id, options)).await } pub async fn get( @@ -153,9 +138,7 @@ impl TestCollection { id: impl AsRef, options: impl Into>, ) -> error::Result { - timeout(Duration::from_millis(2500), self.inner.get(id, options)) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.get(id, options)).await } pub async fn exists( @@ -163,9 +146,7 @@ impl TestCollection { id: impl AsRef, options: impl Into>, ) -> error::Result { - timeout(Duration::from_millis(2500), self.inner.exists(id, options)) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.exists(id, options)).await } pub async fn get_and_touch( @@ -174,12 +155,11 @@ impl TestCollection { expiry: Duration, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), + run_with_std_kv_deadline( + &self.node_version, self.inner.get_and_touch(id, expiry, options), ) .await - .unwrap() } pub async fn get_and_lock( @@ -188,12 +168,11 @@ impl TestCollection { lock_time: Duration, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), + run_with_std_kv_deadline( + &self.node_version, self.inner.get_and_lock(id, lock_time, options), ) .await - .unwrap() } pub async fn unlock( @@ -202,12 +181,7 @@ impl TestCollection { cas: u64, options: impl Into>, ) -> error::Result<()> { - timeout( - Duration::from_millis(2500), - self.inner.unlock(id, cas, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.unlock(id, cas, options)).await } pub async fn touch( @@ -216,12 +190,7 @@ impl TestCollection { expiry: Duration, options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), - self.inner.touch(id, expiry, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.touch(id, expiry, options)).await } pub async fn lookup_in( @@ -230,12 +199,7 @@ impl TestCollection { specs: &[LookupInSpec], options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), - self.inner.lookup_in(id, specs, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.lookup_in(id, specs, options)).await } pub async fn mutate_in( @@ -244,15 +208,10 @@ impl TestCollection { specs: &[MutateInSpec], options: impl Into>, ) -> error::Result { - timeout( - Duration::from_millis(2500), - self.inner.mutate_in(id, specs, options), - ) - .await - .unwrap() + run_with_std_kv_deadline(&self.node_version, self.inner.mutate_in(id, specs, options)).await } pub fn binary(&self) -> TestBinaryCollection { - TestBinaryCollection::new(self.inner.binary()) + TestBinaryCollection::new(self.inner.binary(), self.node_version.clone()) } } diff --git a/sdk/couchbase/tests/common/test_scope.rs b/sdk/couchbase/tests/common/test_scope.rs index 856fba8c..8ff95d5e 100644 --- a/sdk/couchbase/tests/common/test_scope.rs +++ b/sdk/couchbase/tests/common/test_scope.rs @@ -16,6 +16,7 @@ * */ +use crate::common::node_version::NodeVersion; use crate::common::test_collection::TestCollection; use crate::common::test_search_index_manager::TestSearchIndexManager; use couchbase::error; @@ -32,6 +33,7 @@ use tokio::time::timeout; #[derive(Clone)] pub struct TestScope { inner: Scope, + node_version: NodeVersion, } impl Deref for TestScope { @@ -43,12 +45,15 @@ impl Deref for TestScope { } impl TestScope { - pub fn new(inner: Scope) -> Self { - Self { inner } + pub fn new(inner: Scope, node_version: NodeVersion) -> Self { + Self { + inner, + node_version, + } } pub fn collection(&self, name: impl Into) -> TestCollection { - TestCollection::new(self.inner.collection(name)) + TestCollection::new(self.inner.collection(name), self.node_version.clone()) } pub fn search_indexes(&self) -> TestSearchIndexManager { diff --git a/sdk/couchbase/tests/connections.rs b/sdk/couchbase/tests/connections.rs index adf3c3d2..7a60edfc 100644 --- a/sdk/couchbase/tests/connections.rs +++ b/sdk/couchbase/tests/connections.rs @@ -17,15 +17,15 @@ */ use crate::common::test_config::{create_test_cluster, run_test}; -use crate::common::{new_key, try_until}; +use crate::common::{new_key, try_times}; use couchbase::error::ErrorKind; use std::ops::Add; use std::time::Duration; -use tokio::time::Instant; mod common; -// Tests in this file use try_until as it takes some time for the drop chain to be realized. +// Tests in this file use try_times as it takes some time for the drop chain to be realized, +// but by the time that the operation runs a second time it should be completed. #[test] fn test_collection_use_after_cluster_drop() { @@ -41,9 +41,9 @@ fn test_collection_use_after_cluster_drop() { let key = new_key(); - try_until( - Instant::now().add(Duration::from_millis(1000)), - Duration::from_millis(10), + try_times( + 2, + Duration::from_millis(1000), "operation didn't fail with disconnected", async || { let err = match collection.upsert(&key, "test", None).await { @@ -76,8 +76,8 @@ fn test_collection_level_mgr_use_after_cluster_drop() { collection.query_indexes() }; - try_until( - Instant::now().add(Duration::from_millis(1000)), + try_times( + 2, Duration::from_millis(10), "operation didn't fail with disconnected", async || { @@ -108,8 +108,8 @@ fn test_scope_use_after_cluster_drop() { .scope(cluster.default_scope()) }; - try_until( - Instant::now().add(Duration::from_millis(1000)), + try_times( + 2, Duration::from_millis(10), "operation didn't fail with disconnected", async || { @@ -142,8 +142,8 @@ fn test_scope_level_mgr_use_after_cluster_drop() { scope.search_indexes() }; - try_until( - Instant::now().add(Duration::from_millis(1000)), + try_times( + 2, Duration::from_millis(10), "operation didn't fail with disconnected", async || { @@ -174,8 +174,8 @@ fn test_bucket_level_mgr_use_after_cluster_drop() { bucket.collections() }; - try_until( - Instant::now().add(Duration::from_millis(1000)), + try_times( + 2, Duration::from_millis(10), "operation didn't fail with disconnected", async || { @@ -204,8 +204,8 @@ fn test_cluster_level_mgr_use_after_cluster_drop() { cluster.users() }; - try_until( - Instant::now().add(Duration::from_millis(1000)), + try_times( + 2, Duration::from_millis(10), "operation didn't fail with disconnected", async || { diff --git a/sdk/couchbase/tests/diagnostics.rs b/sdk/couchbase/tests/diagnostics.rs index 3542c95a..014fc906 100644 --- a/sdk/couchbase/tests/diagnostics.rs +++ b/sdk/couchbase/tests/diagnostics.rs @@ -30,8 +30,8 @@ fn test_cluster_ping() { run_test(async |mut cluster| { let opts = PingOptions::new() .kv_timeout(Duration::from_millis(1000)) - .query_timeout(Duration::from_millis(1000)) - .search_timeout(Duration::from_millis(1000)); + .query_timeout(Duration::from_millis(75000)) + .search_timeout(Duration::from_millis(75000)); let report = cluster.ping(opts).await.unwrap(); @@ -48,8 +48,8 @@ fn test_bucket_ping() { let opts = PingOptions::new() .kv_timeout(Duration::from_millis(1000)) - .query_timeout(Duration::from_millis(1000)) - .search_timeout(Duration::from_millis(1000)); + .query_timeout(Duration::from_millis(75000)) + .search_timeout(Duration::from_millis(75000)); let report = bucket.ping(opts).await.unwrap(); diff --git a/sdk/couchbase/tests/user_management.rs b/sdk/couchbase/tests/user_management.rs index 5ed33ef6..c8a6ee8b 100644 --- a/sdk/couchbase/tests/user_management.rs +++ b/sdk/couchbase/tests/user_management.rs @@ -16,6 +16,7 @@ * */ +use crate::common::features::TestFeatureCode; use crate::common::test_config::run_test; use crate::common::test_manager::TestUserManager; use crate::common::{new_key, try_until}; @@ -49,11 +50,15 @@ fn test_get_all_roles() { #[test] fn test_delete_group() { run_test(async |cluster| { + if !cluster.supports_feature(&TestFeatureCode::UserGroups) { + return; + } + let group_name = new_key(); let desc = new_key(); let roles = vec![ - Role::new("replication_target").bucket(cluster.default_bucket()), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(cluster.default_bucket()), + Role::new("ro_admin"), ]; let group = Group::new(&group_name, desc, roles); @@ -86,11 +91,15 @@ fn test_delete_group() { #[test] fn test_get_group() { run_test(async |cluster| { + if !cluster.supports_feature(&TestFeatureCode::UserGroups) { + return; + } + let group_name = new_key(); let desc = new_key(); let roles = vec![ - Role::new("replication_target").bucket(cluster.default_bucket()), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(cluster.default_bucket()), + Role::new("ro_admin"), ]; let group = Group::new(&group_name, desc, roles); @@ -119,11 +128,15 @@ fn test_get_group() { #[test] fn test_get_all_groups() { run_test(async |cluster| { + if !cluster.supports_feature(&TestFeatureCode::UserGroups) { + return; + } + let group_name = new_key(); let desc = new_key(); let roles = vec![ - Role::new("replication_target").bucket(cluster.default_bucket()), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(cluster.default_bucket()), + Role::new("ro_admin"), ]; let group = Group::new(&group_name, desc, roles); @@ -156,11 +169,15 @@ fn test_get_all_groups() { #[test] fn test_delete_user() { run_test(async |cluster| { + if !cluster.supports_feature(&TestFeatureCode::UsersMB69096) { + return; + } + let username = new_key(); let display_name = new_key(); let roles = vec![ - Role::new("replication_target").bucket(cluster.default_bucket()), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(cluster.default_bucket()), + Role::new("ro_admin"), ]; let user = User::new(&username, display_name, roles).password("password"); @@ -211,11 +228,15 @@ fn test_delete_user() { #[test] fn test_get_user() { run_test(async |cluster| { + if !cluster.supports_feature(&TestFeatureCode::UsersMB69096) { + return; + } + let username = new_key(); let display_name = new_key(); let roles = vec![ - Role::new("replication_target").bucket(cluster.default_bucket()), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(cluster.default_bucket()), + Role::new("ro_admin"), ]; let user = User::new(&username, display_name, roles).password("password"); @@ -241,11 +262,15 @@ fn test_get_user() { #[test] fn test_get_all_users() { run_test(async |cluster| { + if !cluster.supports_feature(&TestFeatureCode::UsersMB69096) { + return; + } + let username = new_key(); let display_name = new_key(); let roles = vec![ - Role::new("replication_target").bucket(cluster.default_bucket()), - Role::new("replication_admin"), + Role::new("bucket_full_access").bucket(cluster.default_bucket()), + Role::new("ro_admin"), ]; let user = User::new(&username, display_name, roles).password("password");