Skip to content

Commit 90cc7f4

Browse files
committed
fix: Fix bug with deleting an actual file instead of doc only
1 parent a74f2c1 commit 90cc7f4

3 files changed

Lines changed: 55 additions & 22 deletions

File tree

web/sharings/drives_test.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/cozy/cozy-stack/model/instance/lifecycle"
2222
"github.com/cozy/cozy-stack/model/job"
2323
"github.com/cozy/cozy-stack/model/sharing"
24+
"github.com/cozy/cozy-stack/model/vfs"
2425
"github.com/cozy/cozy-stack/pkg/assets/dynamic"
2526
build "github.com/cozy/cozy-stack/pkg/config"
2627
"github.com/cozy/cozy-stack/pkg/config/config"
@@ -117,12 +118,17 @@ func verifyFileMove(t *testing.T, inst *instance.Instance, fileID, expectedName,
117118
require.Equal(t, expectedContent, string(content))
118119
}
119120

120-
// verifyFileDeleted verifies that a file was deleted from the source instance.
121-
func verifyFileDeleted(t *testing.T, inst *instance.Instance, fileID string) {
121+
// verifyFileDeleted verifies that a file was fully deleted from the source instance: both the
122+
// CouchDB metadata record and the physical file content in storage. doc must be fetched before
123+
// the deletion so its path is available after the CouchDB record is gone.
124+
func verifyFileDeleted(t *testing.T, inst *instance.Instance, doc *vfs.FileDoc) {
122125
t.Helper()
123-
_, err := inst.VFS().FileByID(fileID)
126+
_, err := inst.VFS().FileByID(doc.DocID)
124127
require.Error(t, err)
125128
require.True(t, os.IsNotExist(err))
129+
130+
_, err = inst.VFS().OpenFile(doc)
131+
require.Error(t, err, "expected physical file to be deleted from storage, but it is still readable")
126132
}
127133

128134
// verifyNodeDeleted verifies that a node (file or directory) was deleted from the source instance.

web/sharings/move.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,7 @@ func copyFileContent(destVFS vfs.VFS, newFileDoc *vfs.FileDoc, srcVFS vfs.VFS, s
10001000
}
10011001

10021002
func deleteSourceFile(srcVFS vfs.VFS, srcFile *vfs.FileDoc) error {
1003-
if err := srcVFS.GetIndexer().DeleteFileDoc(srcFile); err != nil {
1003+
if err := srcVFS.DestroyFile(srcFile); err != nil {
10041004
return files.WrapVfsError(err)
10051005
}
10061006
return nil

web/sharings/move_test.go

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"testing"
88

99
"github.com/cozy/cozy-stack/model/instance"
10-
1110
"github.com/cozy/cozy-stack/model/instance/lifecycle"
1211
"github.com/cozy/cozy-stack/pkg/assets/dynamic"
1312
build "github.com/cozy/cozy-stack/pkg/config"
@@ -206,6 +205,11 @@ func TestSharedDrivesMove(t *testing.T) {
206205
_, eB, _ := env.createClients(t)
207206
// Perform the move operation
208207
fileToMoveSameStack := createFile(t, eB, "", "file-to-upload.txt", env.bettyToken)
208+
209+
// Pre-fetch the source FileDoc before the move so we can verify physical deletion later
210+
srcFileDoc, err := env.betty.VFS().FileByID(fileToMoveSameStack)
211+
require.NoError(t, err)
212+
209213
responseObj := postMove(t, eB, env.bettyToken, `{
210214
"source": {
211215
"file_id": "`+fileToMoveSameStack+`"
@@ -223,8 +227,8 @@ func TestSharedDrivesMove(t *testing.T) {
223227
// Verify the file was moved and content preserved
224228
verifyFileMove(t, env.acme, movedFileID, "file-to-upload.txt", env.productDirID, "foo")
225229

226-
// Verify the original file was deleted
227-
verifyFileDeleted(t, env.betty, fileToMoveSameStack)
230+
// Verify the original file was deleted (both metadata and physical content)
231+
verifyFileDeleted(t, env.betty, srcFileDoc)
228232
})
229233

230234
// Force the cross-stack path even if instances are on the same server
@@ -233,6 +237,10 @@ func TestSharedDrivesMove(t *testing.T) {
233237
fileToMoveDifferentStack := createFile(t, eB, "", "file-to-upload-diff.txt", env.bettyToken)
234238
destDirInSharedDrive := createDirectory(t, eA, env.productDirID, "Dest DIR To Move", env.acmeToken)
235239

240+
// Pre-fetch the source FileDoc before the move so we can verify physical deletion later
241+
srcFileDoc, err := env.betty.VFS().FileByID(fileToMoveDifferentStack)
242+
require.NoError(t, err)
243+
236244
cleanup := forceCrossStack(t, env.tsA.URL)
237245
defer cleanup()
238246

@@ -253,8 +261,8 @@ func TestSharedDrivesMove(t *testing.T) {
253261
// Verify the file was moved and content preserved
254262
verifyFileMove(t, env.acme, movedFileID, "file-to-upload-diff.txt", destDirInSharedDrive, "foo")
255263

256-
// Verify the original file was deleted
257-
verifyFileDeleted(t, env.acme, fileToMoveDifferentStack)
264+
// Verify the original file was deleted from betty (both metadata and physical content)
265+
verifyFileDeleted(t, env.betty, srcFileDoc)
258266
})
259267

260268
t.Run("SuccessfulMove_FromSharedDrive_SameStack", func(t *testing.T) {
@@ -264,6 +272,10 @@ func TestSharedDrivesMove(t *testing.T) {
264272
// Create destination directory on the target instance
265273
destDirID := createRootDirectory(t, eB, "Destination Dir", env.bettyToken)
266274

275+
// Pre-fetch the source FileDoc before the move so we can verify physical deletion later
276+
srcFileDoc, err := env.acme.VFS().FileByID(fileToMove)
277+
require.NoError(t, err)
278+
267279
responseObj := postMove(t, eB, env.bettyToken, `{
268280
"source": {
269281
"instance": "https://`+env.acme.Domain+`",
@@ -281,8 +293,8 @@ func TestSharedDrivesMove(t *testing.T) {
281293
// Verify the file was moved to the destination
282294
verifyFileMove(t, env.betty, movedFileID, "file-to-move-upstream.txt", destDirID, "foo")
283295

284-
// Verify the original file was deleted from source
285-
verifyFileDeleted(t, env.acme, fileToMove)
296+
// Verify the original file was deleted (both metadata and physical content)
297+
verifyFileDeleted(t, env.acme, srcFileDoc)
286298
})
287299

288300
// Force the cross-stack path even if instances are on the same server
@@ -293,6 +305,10 @@ func TestSharedDrivesMove(t *testing.T) {
293305
// Create destination directory on the target (owner) instance
294306
destDirID := createRootDirectory(t, eB, "Destination Dir Diff", env.bettyToken)
295307

308+
// Pre-fetch the source FileDoc before the move so we can verify physical deletion later
309+
srcFileDoc, err := env.acme.VFS().FileByID(fileToDiffStack)
310+
require.NoError(t, err)
311+
296312
cleanup := forceCrossStack(t, env.tsA.URL)
297313
defer cleanup()
298314

@@ -313,8 +329,8 @@ func TestSharedDrivesMove(t *testing.T) {
313329
// Verify the file was moved to the destination
314330
verifyFileMove(t, env.betty, movedFileID, fileName, destDirID, "foo")
315331

316-
// Verify the original file was deleted from source
317-
verifyFileDeleted(t, env.acme, fileToDiffStack)
332+
// Verify the original file was deleted from source (both metadata and physical content)
333+
verifyFileDeleted(t, env.acme, srcFileDoc)
318334
})
319335

320336
t.Run("SuccessfulMove_BetweenSharedDrives_DifferentStack", func(t *testing.T) {
@@ -328,6 +344,10 @@ func TestSharedDrivesMove(t *testing.T) {
328344
fileName := "file-to-move-between-shared-drives.txt"
329345
toMove := createFile(t, eA, secondRootDirID, fileName, env.acmeToken)
330346

347+
// Pre-fetch the source FileDoc before the move so we can verify physical deletion later
348+
srcFileDoc, err := env.acme.VFS().FileByID(toMove)
349+
require.NoError(t, err)
350+
331351
cleanup := forceCrossStack(t, env.tsA.URL)
332352
defer cleanup()
333353

@@ -349,7 +369,8 @@ func TestSharedDrivesMove(t *testing.T) {
349369

350370
// Verify the file was moved to the destination
351371
verifyFileMove(t, env.acme, movedFileID, fileName, env.meetingsDirID, "foo")
352-
verifyFileDeleted(t, env.acme, toMove)
372+
// Verify the original file was deleted (both metadata and physical content)
373+
verifyFileDeleted(t, env.acme, srcFileDoc)
353374
})
354375

355376
t.Run("SuccessfulMoveBetween_SharedDrives_SameStack", func(t *testing.T) {
@@ -392,11 +413,10 @@ func TestSharedDrivesMove(t *testing.T) {
392413
// Verify the response contains the new file
393414
movedFileID := assertMoveResponseWithSharing(t, responseObj, fileName, meetingsID, firstSharingID)
394415

395-
// Verify the file was moved to the destination
416+
// Verify the file was moved to the destination.
417+
// Same-instance move preserves the file ID (metadata-only update via ModifyFileMetadata).
418+
require.Equal(t, toMove, movedFileID, "same-instance move must preserve the file ID")
396419
verifyFileMove(t, env.acme, movedFileID, fileName, meetingsID, "foo")
397-
398-
// Verify the original file was deleted from source
399-
verifyFileDeleted(t, env.acme, toMove)
400420
})
401421

402422
// File move with conflict resolution: moving a file between shared drives (same stack)
@@ -432,12 +452,15 @@ func TestSharedDrivesMove(t *testing.T) {
432452

433453
// Verify the file was moved with a renamed name (conflict resolution)
434454
movedFileName := assertAutoRename(t, responseObj, conflictName)
455+
movedFileID := responseObj.Path("$.data.id").String().Raw()
435456

436457
// Verify both files exist in destination (original + renamed)
437458
verifyBothFilesExist(t, env.acme, env.meetingsDirID, conflictName, movedFileName)
438459

439-
// Verify source file was deleted
440-
verifyFileDeleted(t, env.acme, sourceFileID)
460+
// Same-instance move preserves the file ID (metadata-only update via ModifyFileMetadata).
461+
// The source file was moved (not deleted): verify it now lives at the destination with the renamed name.
462+
require.Equal(t, sourceFileID, movedFileID, "same-instance move must preserve the file ID")
463+
verifyFileExists(t, env.acme, sourceFileID, movedFileName, env.meetingsDirID, "foo")
441464
})
442465

443466
// File move with conflict resolution: moving a file between shared drives (same stack)
@@ -459,6 +482,10 @@ func TestSharedDrivesMove(t *testing.T) {
459482
// Create source file with the same name in the second shared drive (source)
460483
sourceFileID := createFile(t, eA, secondRootDirID, conflictName, env.acmeToken)
461484

485+
// Pre-fetch the source FileDoc before the move so we can verify physical deletion later
486+
srcFileDoc, err := env.acme.VFS().FileByID(sourceFileID)
487+
require.NoError(t, err)
488+
462489
// Attempt to move → should succeed with auto-renaming
463490
responseObj := postMove(t, eB, env.bettyToken, `{
464491
"source": {
@@ -479,8 +506,8 @@ func TestSharedDrivesMove(t *testing.T) {
479506
// Verify both files exist in destination (original + renamed)
480507
verifyBothFilesExist(t, env.acme, env.meetingsDirID, conflictName, movedFileName)
481508

482-
// Verify source file was deleted
483-
verifyFileDeleted(t, env.acme, sourceFileID)
509+
// Verify source file was deleted (both metadata and physical content)
510+
verifyFileDeleted(t, env.acme, srcFileDoc)
484511
})
485512

486513
// Folder move with conflict resolution: moving a directory between shared drives (same stack)

0 commit comments

Comments
 (0)