@@ -11,9 +11,12 @@ package base
11
11
import (
12
12
"errors"
13
13
"fmt"
14
+ "maps"
15
+ "slices"
14
16
"testing"
15
17
16
18
sgbucket "github.com/couchbase/sg-bucket"
19
+ "github.com/stretchr/testify/assert"
17
20
"github.com/stretchr/testify/require"
18
21
)
19
22
@@ -1649,3 +1652,114 @@ func requireDocFoundOrCasMismatchError(t testing.TB, err error) {
1649
1652
require .Fail (t , errMsg )
1650
1653
}
1651
1654
}
1655
+
1656
+ // TestDeleteWithXattrs tests various combinations of deleting documents (with zero to many xattrs, some of which may not exist) across bucket implementations to ensure consistency in behavior.
1657
+ func TestDeleteWithXattrs (t * testing.T ) {
1658
+ ctx := TestCtx (t )
1659
+ bucket := GetTestBucket (t )
1660
+ defer bucket .Close (ctx )
1661
+
1662
+ col := bucket .GetSingleDataStore ()
1663
+
1664
+ tests := []struct {
1665
+ name string
1666
+ xattrsValues map [string ][]byte
1667
+ xattrsToDelete []string
1668
+ expectedXattrs []string
1669
+ }{
1670
+ {
1671
+ name : "delete with no xattrs" ,
1672
+ xattrsValues : nil ,
1673
+ xattrsToDelete : nil ,
1674
+ expectedXattrs : nil ,
1675
+ },
1676
+ {
1677
+ name : "delete one only existing xattr" ,
1678
+ xattrsValues : map [string ][]byte {"xattr1" : []byte (`{"a":"b"}` )},
1679
+ xattrsToDelete : []string {"xattr1" },
1680
+ expectedXattrs : nil ,
1681
+ },
1682
+ {
1683
+ name : "delete two existing xattrs" ,
1684
+ xattrsValues : map [string ][]byte {"xattr1" : []byte (`{"a":"b"}` ), "xattr2" : []byte (`{"c":"d"}` )},
1685
+ xattrsToDelete : []string {"xattr1" , "xattr2" },
1686
+ expectedXattrs : nil ,
1687
+ },
1688
+ {
1689
+ name : "delete one xattr and one non-existing xattr" ,
1690
+ xattrsValues : map [string ][]byte {"xattr1" : []byte (`{"a":"b"}` )},
1691
+ xattrsToDelete : []string {"xattr1" , "notexists" },
1692
+ expectedXattrs : nil ,
1693
+ },
1694
+ {
1695
+ name : "delete one non-existing xattr" ,
1696
+ xattrsValues : map [string ][]byte {"xattr1" : []byte (`{"a":"b"}` )},
1697
+ xattrsToDelete : []string {"notexists" },
1698
+ expectedXattrs : []string {"xattr1" },
1699
+ },
1700
+ {
1701
+ name : "create and delete system xattr" ,
1702
+ xattrsValues : map [string ][]byte {"_sync" : []byte (`{"a":"b"}` )},
1703
+ xattrsToDelete : []string {"_sync" },
1704
+ expectedXattrs : nil ,
1705
+ },
1706
+ {
1707
+ name : "create and delete normal and system xattr" ,
1708
+ xattrsValues : map [string ][]byte {"xattr1" : []byte (`{"a":"b"}` ), "_sync" : []byte (`{"a":"b"}` )},
1709
+ xattrsToDelete : []string {"_sync" },
1710
+ expectedXattrs : nil , // user xattrs get removed along with regular delete...
1711
+ },
1712
+ {
1713
+ name : "create normal and system and do regular delete" ,
1714
+ xattrsValues : map [string ][]byte {"xattr1" : []byte (`{"a":"b"}` ), "_sync" : []byte (`{"a":"b"}` )},
1715
+ xattrsToDelete : nil ,
1716
+ expectedXattrs : []string {"_sync" },
1717
+ },
1718
+ {
1719
+ name : "create normal and system and delete system" ,
1720
+ xattrsValues : map [string ][]byte {"xattr1" : []byte (`{"a":"b"}` ), "_sync" : []byte (`{"a":"b"}` )},
1721
+ xattrsToDelete : []string {"_sync" },
1722
+ expectedXattrs : []string {"xattr1" },
1723
+ },
1724
+ {
1725
+ name : "create two system xattrs and delete one" ,
1726
+ xattrsValues : map [string ][]byte {"_sync" : []byte (`{"a":"b"}` ), "_globalSync" : []byte (`{"a":"b"}` )},
1727
+ xattrsToDelete : []string {"_sync" },
1728
+ expectedXattrs : []string {"_globalSync" },
1729
+ },
1730
+ {
1731
+ name : "create normal xattr and two system xattrs and delete one system xattr" ,
1732
+ xattrsValues : map [string ][]byte {"xattr1" : []byte (`{"a":"b"}` ), "_sync" : []byte (`{"a":"b"}` ), "_globalSync" : []byte (`{"a":"b"}` )},
1733
+ xattrsToDelete : []string {"_sync" },
1734
+ expectedXattrs : []string {"_globalSync" }, // user xattrs get removed along with regular delete...
1735
+ },
1736
+ {
1737
+ name : "create xattr and delete non-existing system xattr" ,
1738
+ xattrsValues : map [string ][]byte {"xattr1" : []byte (`{"a":"b"}` )},
1739
+ xattrsToDelete : []string {"_sync" },
1740
+ expectedXattrs : []string {"xattr1" },
1741
+ },
1742
+ }
1743
+
1744
+ for _ , test := range tests {
1745
+ t .Run (test .name , func (t * testing.T ) {
1746
+ docID := t .Name ()
1747
+
1748
+ _ , err := col .WriteWithXattrs (ctx , docID , 0 , 0 , []byte (`{"foo": "bar"}` ), test .xattrsValues , nil , nil )
1749
+ require .NoError (t , err )
1750
+
1751
+ err = col .DeleteWithXattrs (ctx , docID , test .xattrsToDelete )
1752
+ require .NoError (t , err )
1753
+
1754
+ v , xv , _ , err := col .GetWithXattrs (ctx , docID , slices .Collect (maps .Keys (test .xattrsValues )))
1755
+ if len (test .expectedXattrs ) == 0 {
1756
+ assert .Errorf (t , err , "Expected document and all xattrs to be deleted, but it still exists (no error on get)" )
1757
+ assert .Truef (t , IsDocNotFoundError (err ), "Expected document to be deleted, but got an error other than not found: %v" , err )
1758
+ } else {
1759
+ require .NoErrorf (t , err , "Expected document or at least one xattr to still exist with xattrs after deletion" )
1760
+ }
1761
+ assert .Nil (t , v , "Expected document to be deleted, but it still exists" )
1762
+ assert .Equal (t , test .expectedXattrs , slices .Collect (maps .Keys (xv )), "Expected xattrs to match expected values after deletion" )
1763
+ })
1764
+ }
1765
+ }
0 commit comments