@@ -2055,60 +2055,76 @@ func TestAttachmentRemovalWithConflicts(t *testing.T) {
20552055 rt := NewRestTester (t , nil )
20562056
20572057 defer rt .Close ()
2058-
20592058 rt .GetDatabase ().EnableAllowConflicts (rt .TB ())
2060- const docID = "doc"
2061- // Create doc rev 1
2062- version := rt .PutDoc (docID , `{"test": "x"}` )
20632059
2064- // Create doc rev 2 with attachment
2065- version = rt .UpdateDoc (docID , version , `{"_attachments": {"hello.txt": {"data": "aGVsbG8gd29ybGQ="}}}` )
2060+ testCases := []struct {
2061+ name string
2062+ eccv bool
2063+ }{
2064+ {name : "no eccv" , eccv : false },
2065+ {name : "eccv" , eccv : true },
2066+ }
2067+ for _ , tc := range testCases {
2068+ t .Run (tc .name , func (t * testing.T ) {
2069+ rt .GetDatabase ().CachedCCVEnabled .Store (tc .eccv )
20662070
2067- // Create doc rev 3 referencing previous attachment
2068- losingVersion3 := rt .UpdateDoc (docID , version , `{"_attachments": {"hello.txt": {"revpos":2,"stub":true,"digest":"sha1-Kq5sNclPz7QV2+lfQIuc6R7oRu0="}}}` )
2071+ docID := db .SafeDocumentName (t , t .Name ())
2072+ // Create doc rev 1
2073+ version := rt .PutDoc (docID , `{"test": "x"}` )
20692074
2070- // Create doc conflicting with previous revid referencing previous attachment too
2071- winningVersion3 : = rt .PutNewEditsFalse (docID , NewDocVersionFromFakeRev ( "3-b" ), & version , `{"_attachments": {"hello.txt": {"revpos":2,"stub":true,"digest":"sha1-Kq5sNclPz7QV2+lfQIuc6R7oRu0 ="}}, "Winning Rev": true }` )
2075+ // Create doc rev 2 with attachment
2076+ version = rt .UpdateDoc (docID , version , `{"_attachments": {"hello.txt": {"data": "aGVsbG8gd29ybGQ ="}}}` )
20722077
2073- // Update the winning rev 3 and ensure attachment remains around as the other leaf still references this attachment
2074- finalVersion4 := rt .UpdateDoc (docID , * winningVersion3 , `{"update ": 2 }` )
2078+ // Create doc rev 3 referencing previous attachment
2079+ losingVersion3 := rt .UpdateDoc (docID , version , `{"_attachments ": {"hello.txt": {"revpos":2,"stub":true,"digest":"sha1-Kq5sNclPz7QV2+lfQIuc6R7oRu0="}} }` )
20752080
2076- type docResp struct {
2077- Attachments db.AttachmentMap `json:"_attachments"`
2078- }
2081+ // Create doc conflicting with previous revid referencing previous attachment too
2082+ winningVersion3 := rt .PutNewEditsFalse (docID , NewDocVersionFromFakeRev ("3-b" ), & version , `{"_attachments": {"hello.txt": {"revpos":2,"stub":true,"digest":"sha1-Kq5sNclPz7QV2+lfQIuc6R7oRu0="}}, "Winning Rev": true}` )
20792083
2080- var doc1 docResp
2081- // Get losing rev and ensure attachment is still there and has not been deleted
2082- resp := rt .SendAdminRequestWithHeaders ("GET" , "/{{.keyspace}}/doc?attachments=true&rev=" + losingVersion3 .RevTreeID , "" , map [string ]string {"Accept" : "application/json" })
2083- RequireStatus (t , resp , http .StatusOK )
2084+ // Update the winning rev 3 and ensure attachment remains around as the other leaf still references this attachment
2085+ finalVersion4 := rt .UpdateDoc (docID , * winningVersion3 , `{"update": 2}` )
20842086
2085- err := base .JSONUnmarshal (resp .BodyBytes (), & doc1 )
2086- assert .NoError (t , err )
2087- require .Contains (t , doc1 .Attachments , "hello.txt" )
2088- require .Equal (t , db.DocAttachment {
2089- Digest : "sha1-Kq5sNclPz7QV2+lfQIuc6R7oRu0=" ,
2090- Length : 11 ,
2091- Revpos : 2 ,
2092- Data : []byte ("hello world" ),
2093- }, doc1 .Attachments ["hello.txt" ])
2094-
2095- attachmentKey := db .MakeAttachmentKey (2 , "doc" , doc1 .Attachments ["hello.txt" ].Digest )
2096-
2097- var doc2 docResp
2098- // Get winning rev and ensure attachment is indeed removed from this rev
2099- resp = rt .SendAdminRequestWithHeaders ("GET" , "/{{.keyspace}}/doc?attachments=true&rev=" + finalVersion4 .RevTreeID , "" , map [string ]string {"Accept" : "application/json" })
2100- RequireStatus (t , resp , http .StatusOK )
2087+ type docResp struct {
2088+ Attachments db.AttachmentMap `json:"_attachments"`
2089+ }
21012090
2102- err = base .JSONUnmarshal (resp .BodyBytes (), & doc2 )
2103- assert .NoError (t , err )
2104- require .NotContains (t , doc2 .Attachments , "hello.txt" )
2091+ var doc1 docResp
2092+ // Get losing rev and ensure attachment is still there and has not been deleted
2093+ resp := rt .SendAdminRequestWithHeaders ("GET" , "/{{.keyspace}}/" + docID + "?attachments=true&rev=" + losingVersion3 .RevTreeID , "" , map [string ]string {"Accept" : "application/json" })
2094+ RequireStatus (t , resp , http .StatusOK )
2095+
2096+ err := base .JSONUnmarshal (resp .BodyBytes (), & doc1 )
2097+ assert .NoError (t , err )
2098+ require .Contains (t , doc1 .Attachments , "hello.txt" )
2099+ require .Equal (t , db.DocAttachment {
2100+ Digest : "sha1-Kq5sNclPz7QV2+lfQIuc6R7oRu0=" ,
2101+ Length : 11 ,
2102+ Revpos : 2 ,
2103+ Data : []byte ("hello world" ),
2104+ }, doc1 .Attachments ["hello.txt" ])
2105+
2106+ attachmentKey := db .MakeAttachmentKey (2 , docID , doc1 .Attachments ["hello.txt" ].Digest )
2107+
2108+ var doc2 docResp
2109+ // Get winning rev and ensure attachment is indeed removed from this rev
2110+ resp = rt .SendAdminRequestWithHeaders ("GET" , "/{{.keyspace}}/" + docID + "?attachments=true&rev=" + finalVersion4 .RevTreeID , "" , map [string ]string {"Accept" : "application/json" })
2111+ RequireStatus (t , resp , http .StatusOK )
2112+
2113+ err = base .JSONUnmarshal (resp .BodyBytes (), & doc2 )
2114+ assert .NoError (t , err )
2115+ require .NotContains (t , doc2 .Attachments , "hello.txt" )
21052116
2106- // Now remove the attachment in the losing rev by deleting the revision and ensure the attachment gets deleted
2107- rt .DeleteDoc (docID , losingVersion3 )
2117+ // Now remove the attachment in the losing rev by deleting the revision and ensure the attachment gets deleted
2118+ rt .DeleteDoc (docID , losingVersion3 )
21082119
2109- _ , _ , err = rt .GetSingleDataStore ().GetRaw (attachmentKey )
2110- assert .Error (t , err )
2111- assert .True (t , base .IsDocNotFoundError (err ))
2120+ _ , _ , err = rt .GetSingleDataStore ().GetRaw (attachmentKey )
2121+ if rt .GetDatabase ().CachedCCVEnabled .Load () {
2122+ require .NoError (t , err , "Attachment should not be deleted as eccv is enabled" )
2123+ } else {
2124+ base .RequireDocNotFoundError (t , err )
2125+ }
2126+ })
2127+ }
21122128}
21132129
21142130func TestAttachmentsMissing (t * testing.T ) {
@@ -2208,36 +2224,45 @@ func TestAttachmentDeleteOnExpiry(t *testing.T) {
22082224
22092225 dataStore := rt .GetSingleDataStore ()
22102226
2211- // Create doc with attachment and expiry
2212- resp := rt .SendAdminRequest ("PUT" , "/{{.keyspace}}/" + t .Name (), `{"_attachments": {"hello.txt": {"data": "aGVsbG8gd29ybGQ="}}, "_exp": 1}` )
2213- RequireStatus (t , resp , http .StatusCreated )
2214-
2215- // Wait for document to be expired - this bucket get should also trigger the expiry purge interval
2216- require .EventuallyWithT (t , func (c * assert.CollectT ) {
2217- _ , _ , err := dataStore .GetRaw (t .Name ())
2218- assert .True (c , base .IsDocNotFoundError (err ), "expected err %v to be doc not found" , err )
2219- }, time .Second * 10 , time .Millisecond * 10 )
2220-
2221- if base .TestUseXattrs () {
2222- require .EventuallyWithT (t , func (c * assert.CollectT ) {
2223- assert .Equal (c , int64 (1 ), rt .GetDatabase ().DbStats .SharedBucketImport ().ImportCount .Value ())
2224- }, time .Second * 10 , time .Millisecond * 5 )
2225- } else {
2226- // Trigger OnDemand Import for that doc to trigger tombstone
2227- resp := rt .SendAdminRequest ("GET" , "/{{.keyspace}}/" + t .Name (), "" )
2228- RequireStatus (t , resp , http .StatusNotFound )
2227+ testCases := []struct {
2228+ name string
2229+ eccv bool
2230+ }{
2231+ {name : "no-eccv" , eccv : false },
2232+ {name : "eccv" , eccv : true },
22292233 }
2230- att2Key := db .MakeAttachmentKey (db .AttVersion2 , t .Name (), "sha1-Kq5sNclPz7QV2+lfQIuc6R7oRu0=" )
2231-
2232- // With xattrs doc will be imported and will be captured as tombstone and therefore purge attachments
2233- // Otherwise attachment will not be purged
2234- _ , _ , err := dataStore .GetRaw (att2Key )
2235- if base .TestUseXattrs () {
2236- base .RequireDocNotFoundError (t , err )
2237- } else {
2238- assert .NoError (t , err )
2234+ for _ , tc := range testCases {
2235+ t .Run (tc .name , func (t * testing.T ) {
2236+ lastImportCount := rt .GetDatabase ().DbStats .SharedBucketImport ().ImportCount .Value ()
2237+
2238+ rt .GetDatabase ().CachedCCVEnabled .Store (tc .eccv )
2239+ docID := db .SafeDocumentName (t , t .Name ())
2240+ // Create doc with attachment and expiry
2241+ resp := rt .SendAdminRequest ("PUT" , "/{{.keyspace}}/" + docID , `{"_attachments": {"hello.txt": {"data": "aGVsbG8gd29ybGQ="}}, "_exp": 1}` )
2242+ RequireStatus (t , resp , http .StatusCreated )
2243+
2244+ // Wait for document to be expired - this bucket get should also trigger the expiry purge interval
2245+ require .EventuallyWithT (t , func (c * assert.CollectT ) {
2246+ _ , _ , err := dataStore .GetRaw (docID )
2247+ assert .True (c , base .IsDocNotFoundError (err ), "expected err %v to be doc not found" , err )
2248+ }, time .Second * 10 , time .Millisecond * 10 )
2249+
2250+ require .EventuallyWithT (t , func (c * assert.CollectT ) {
2251+ newImportCount := rt .GetDatabase ().DbStats .SharedBucketImport ().ImportCount .Value () - lastImportCount
2252+ assert .Equal (c , int64 (1 ), newImportCount )
2253+ }, time .Second * 10 , time .Millisecond * 5 )
2254+ att2Key := db .MakeAttachmentKey (db .AttVersion2 , docID , "sha1-Kq5sNclPz7QV2+lfQIuc6R7oRu0=" )
2255+
2256+ // With xattrs doc will be imported and will be captured as tombstone and therefore purge attachments
2257+ // Otherwise attachment will not be purged
2258+ _ , _ , err := dataStore .GetRaw (att2Key )
2259+ if rt .GetDatabase ().CachedCCVEnabled .Load () {
2260+ assert .NoError (t , err )
2261+ } else {
2262+ base .RequireDocNotFoundError (t , err )
2263+ }
2264+ })
22392265 }
2240-
22412266}
22422267
22432268// TestUpdateViaBlipMigrateAttachment:
0 commit comments