diff --git a/base/bucket_gocb_test.go b/base/bucket_gocb_test.go index ea0ff5a606..ad070296df 100644 --- a/base/bucket_gocb_test.go +++ b/base/bucket_gocb_test.go @@ -557,6 +557,46 @@ func TestXattrWriteCasWithXattrCasCheck(t *testing.T) { } +func TestMultiXattrRoundtrip(t *testing.T) { + SkipXattrTestsIfNotEnabled(t) + + ctx := TestCtx(t) + bucket := GetTestBucket(t) + defer bucket.Close(ctx) + dataStore := bucket.GetSingleDataStore() + + const docID = "doc1" + xattrKeys := []string{"xattr1", "xattr2", "xattr3"} + inputXattrs := map[string][]byte{ + xattrKeys[0]: []byte(`{"key1": "value1"}`), + xattrKeys[1]: []byte(`{"key2": "value2"}`), + xattrKeys[2]: []byte(`{"key3": "value3"}`), + } + _, err := dataStore.WriteWithXattrs(ctx, docID, 0, 0, []byte(`{"key": "value"}`), inputXattrs, nil) + if dataStore.IsSupported(sgbucket.BucketStoreFeatureMultiXattrSubdocOperations) { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, "invalid xattr key combination") + inputXattrs = map[string][]byte{ + xattrKeys[0]: inputXattrs[xattrKeys[0]], + } + // write a document an xattrs, because subsequent GetXattrs needs a document to produce an error without multi-xattr support + _, err := dataStore.WriteWithXattrs(ctx, docID, 0, 0, []byte(`{"key": "value"}`), inputXattrs, nil) + require.NoError(t, err) + } + + xattrs, _, err := dataStore.GetXattrs(ctx, docID, xattrKeys) + if dataStore.IsSupported(sgbucket.BucketStoreFeatureMultiXattrSubdocOperations) { + require.NoError(t, err) + for _, key := range xattrKeys { + require.Contains(t, xattrs, key) + require.JSONEq(t, string(inputXattrs[key]), string(xattrs[key])) + } + } else { + require.ErrorContains(t, err, "not supported") + } +} + // TestWriteCasXATTRRaw. Validates basic write of document and xattr as raw bytes. func TestXattrWriteCasRaw(t *testing.T) { diff --git a/base/collection.go b/base/collection.go index 475b0e2ab3..62bd22bbe4 100644 --- a/base/collection.go +++ b/base/collection.go @@ -252,7 +252,7 @@ func (b *GocbV2Bucket) IsSupported(feature sgbucket.BucketStoreFeature) bool { case sgbucket.BucketStoreFeaturePreserveExpiry, sgbucket.BucketStoreFeatureCollections: // TODO: Change to capability check when GOCBC-1218 merged return isMinimumVersion(b.clusterCompatMajorVersion, b.clusterCompatMinorVersion, 7, 0) - case sgbucket.BucketStoreFeatureSystemCollections: + case sgbucket.BucketStoreFeatureSystemCollections, sgbucket.BucketStoreFeatureMultiXattrSubdocOperations: return isMinimumVersion(b.clusterCompatMajorVersion, b.clusterCompatMinorVersion, 7, 6) case sgbucket.BucketStoreFeatureMobileXDCR: return b.supportsHLV