The end result of the tested scenario is that the global version entry has an empty version vector and is not deleted, while everything is actually deleted. That then causes these files to be considered as needed, while they are not. https://github.com/syncthing/syncthing/issues/6961
(t *testing.T)
| 3717 | // That then causes these files to be considered as needed, while they are not. |
| 3718 | // https://github.com/syncthing/syncthing/issues/6961 |
| 3719 | func TestIssue6961(t *testing.T) { |
| 3720 | wcfg, fcfg := newDefaultCfgWrapper(t) |
| 3721 | tfs := fcfg.Filesystem() |
| 3722 | waiter, err := wcfg.Modify(func(cfg *config.Configuration) { |
| 3723 | cfg.SetDevice(newDeviceConfiguration(cfg.Defaults.Device, device2, "device2")) |
| 3724 | fcfg.Type = config.FolderTypeReceiveOnly |
| 3725 | fcfg.Devices = append(fcfg.Devices, config.FolderDeviceConfiguration{DeviceID: device2}) |
| 3726 | cfg.SetFolder(fcfg) |
| 3727 | }) |
| 3728 | must(t, err) |
| 3729 | waiter.Wait() |
| 3730 | // Always recalc/repair when opening a fileset. |
| 3731 | m := newModel(t, wcfg, myID, nil) |
| 3732 | m.ServeBackground() |
| 3733 | defer cleanupModelAndRemoveDir(m, tfs.URI()) |
| 3734 | conn1 := addFakeConn(m, device1, fcfg.ID) |
| 3735 | conn2 := addFakeConn(m, device2, fcfg.ID) |
| 3736 | m.ScanFolders() |
| 3737 | |
| 3738 | name := "foo" |
| 3739 | version := protocol.Vector{}.Update(device1.Short()) |
| 3740 | |
| 3741 | // Remote, valid and existing file |
| 3742 | must(t, m.Index(conn1, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: name, Version: version, Sequence: 1}}})) |
| 3743 | // Remote, invalid (receive-only) and existing file |
| 3744 | must(t, m.Index(conn2, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: name, LocalFlags: protocol.FlagLocalRemoteInvalid, Sequence: 1}}})) |
| 3745 | // Create a local file |
| 3746 | if fd, err := tfs.OpenFile(name, fs.OptCreate, 0o666); err != nil { |
| 3747 | t.Fatal(err) |
| 3748 | } else { |
| 3749 | fd.Close() |
| 3750 | } |
| 3751 | if info, err := tfs.Lstat(name); err != nil { |
| 3752 | t.Fatal(err) |
| 3753 | } else { |
| 3754 | t.Log(info.Mode()) |
| 3755 | } |
| 3756 | m.ScanFolders() |
| 3757 | |
| 3758 | // Get rid of valid global |
| 3759 | waiter, err = wcfg.RemoveDevice(device1) |
| 3760 | if err != nil { |
| 3761 | t.Fatal(err) |
| 3762 | } |
| 3763 | waiter.Wait() |
| 3764 | |
| 3765 | // Delete the local file |
| 3766 | must(t, tfs.Remove(name)) |
| 3767 | m.ScanFolders() |
| 3768 | |
| 3769 | // Drop the remote index, add some other file. |
| 3770 | must(t, m.Index(conn2, &protocol.Index{Folder: fcfg.ID, Files: []protocol.FileInfo{{Name: "bar", LocalFlags: protocol.FlagLocalRemoteInvalid, Sequence: 1}}})) |
| 3771 | |
| 3772 | // Pause and unpause folder to create new db.FileSet and thus recalculate everything |
| 3773 | pauseFolder(t, wcfg, fcfg.ID, true) |
| 3774 | pauseFolder(t, wcfg, fcfg.ID, false) |
| 3775 | |
| 3776 | if comp := m.testCompletion(device2, fcfg.ID); comp.NeedDeletes != 0 { |
nothing calls this directly
no test coverage detected