2017-12-13 20:04:58 +03:00
/*
* This software is in the public domain , furnished " as is " , without technical
* support , and with no warranty , express or implied , as to its usefulness for
* any purpose .
*
*/
# include <QtTest>
# include "syncenginetestutils.h"
2018-08-15 11:46:16 +03:00
# include "common/vfs.h"
2019-06-28 11:44:13 +03:00
# include "config.h"
2017-12-13 20:04:58 +03:00
# include <syncengine.h>
using namespace OCC ;
2022-11-30 12:34:49 +03:00
namespace {
QStringList findCaseClashConflicts ( const FileInfo & dir )
{
QStringList conflicts ;
for ( const auto & item : dir . children ) {
if ( item . name . contains ( " (case clash from " ) ) {
conflicts . append ( item . path ( ) ) ;
}
}
return conflicts ;
}
bool expectConflict ( FileInfo state , const QString path )
{
PathComponents pathComponents ( path ) ;
auto base = state . find ( pathComponents . parentDirComponents ( ) ) ;
if ( ! base )
return false ;
for ( const auto & item : qAsConst ( base - > children ) ) {
if ( item . name . startsWith ( pathComponents . fileName ( ) ) & & item . name . contains ( " (case clash from " ) ) {
return true ;
}
}
return false ;
}
}
2019-06-28 11:44:13 +03:00
# define DVSUFFIX APPLICATION_DOTVIRTUALFILE_SUFFIX
2020-04-22 16:23:18 +03:00
bool itemInstruction ( const ItemCompletedSpy & spy , const QString & path , const SyncInstructions instr )
2017-12-13 20:04:58 +03:00
{
2019-10-07 16:25:36 +03:00
auto item = spy . findItem ( path ) ;
2017-12-13 20:04:58 +03:00
return item - > _instruction = = instr ;
}
SyncJournalFileRecord dbRecord ( FakeFolder & folder , const QString & path )
{
SyncJournalFileRecord record ;
2022-08-04 17:51:26 +03:00
[[maybe_unused]] const auto result = folder . syncJournal ( ) . getFileRecord ( path , & record ) ;
2017-12-13 20:04:58 +03:00
return record ;
}
2018-09-26 14:41:02 +03:00
void triggerDownload ( FakeFolder & folder , const QByteArray & path )
{
auto & journal = folder . syncJournal ( ) ;
SyncJournalFileRecord record ;
2022-08-04 17:51:26 +03:00
if ( ! journal . getFileRecord ( path + DVSUFFIX , & record ) | | ! record . isValid ( ) ) {
2018-09-26 14:41:02 +03:00
return ;
2022-08-04 17:51:26 +03:00
}
2018-09-26 14:41:02 +03:00
record . _type = ItemTypeVirtualFileDownload ;
2022-08-04 17:51:26 +03:00
QVERIFY ( journal . setFileRecord ( record ) ) ;
2019-02-13 16:18:54 +03:00
journal . schedulePathForRemoteDiscovery ( record . _path ) ;
2018-09-26 14:41:02 +03:00
}
2018-08-15 11:46:16 +03:00
void markForDehydration ( FakeFolder & folder , const QByteArray & path )
{
auto & journal = folder . syncJournal ( ) ;
SyncJournalFileRecord record ;
2022-08-04 17:51:26 +03:00
if ( ! journal . getFileRecord ( path , & record ) | | ! record . isValid ( ) ) {
2018-08-15 11:46:16 +03:00
return ;
2022-08-04 17:51:26 +03:00
}
2018-08-15 11:46:16 +03:00
record . _type = ItemTypeVirtualFileDehydration ;
2022-08-04 17:51:26 +03:00
QVERIFY ( journal . setFileRecord ( record ) ) ;
2019-02-13 16:18:54 +03:00
journal . schedulePathForRemoteDiscovery ( record . _path ) ;
2018-08-15 11:46:16 +03:00
}
2019-01-23 17:12:02 +03:00
QSharedPointer < Vfs > setupVfs ( FakeFolder & folder )
2018-08-15 11:46:16 +03:00
{
2019-01-23 17:12:02 +03:00
auto suffixVfs = QSharedPointer < Vfs > ( createVfsFromPlugin ( Vfs : : WithSuffix ) . release ( ) ) ;
folder . switchToVfs ( suffixVfs ) ;
2019-04-03 14:32:05 +03:00
// Using this directly doesn't recursively unpin everything and instead leaves
// the files in the hydration that that they start with
folder . syncJournal ( ) . internalPinStates ( ) . setForPath ( " " , PinState : : Unspecified ) ;
2019-01-23 17:12:02 +03:00
return suffixVfs ;
2018-08-15 11:46:16 +03:00
}
2018-05-18 09:29:40 +03:00
class TestSyncVirtualFiles : public QObject
2017-12-13 20:04:58 +03:00
{
Q_OBJECT
private slots :
2024-04-30 11:04:32 +03:00
void initTestCase ( )
{
OCC : : Logger : : instance ( ) - > setLogFlush ( true ) ;
OCC : : Logger : : instance ( ) - > setLogDebug ( true ) ;
QStandardPaths : : setTestModeEnabled ( true ) ;
}
2018-05-18 09:29:40 +03:00
void testVirtualFileLifecycle_data ( )
2017-12-13 20:04:58 +03:00
{
QTest : : addColumn < bool > ( " doLocalDiscovery " ) ;
QTest : : newRow ( " full local discovery " ) < < true ;
QTest : : newRow ( " skip local discovery " ) < < false ;
}
2018-05-18 09:29:40 +03:00
void testVirtualFileLifecycle ( )
2017-12-13 20:04:58 +03:00
{
QFETCH ( bool , doLocalDiscovery ) ;
2018-05-18 09:29:40 +03:00
FakeFolder fakeFolder { FileInfo ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2017-12-13 20:04:58 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2019-10-07 16:25:36 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2017-12-13 20:04:58 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
if ( ! doLocalDiscovery )
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
} ;
cleanup ( ) ;
2018-05-18 09:29:40 +03:00
// Create a virtual file for a new remote file
2017-12-13 20:04:58 +03:00
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a1 " , 64 ) ;
2018-08-18 10:14:01 +03:00
auto someDate = QDateTime ( QDate ( 1984 , 07 , 30 ) , QTime ( 1 , 3 , 2 ) ) ;
fakeFolder . remoteModifier ( ) . setModTime ( " A/a1 " , someDate ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QCOMPARE ( QFileInfo ( fakeFolder . localPath ( ) + " A/a1 " DVSUFFIX ) . lastModified ( ) , someDate ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_NEW ) ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . _type , ItemTypeVirtualFile ) ;
2017-12-13 20:04:58 +03:00
cleanup ( ) ;
// Another sync doesn't actually lead to changes
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QCOMPARE ( QFileInfo ( fakeFolder . localPath ( ) + " A/a1 " DVSUFFIX ) . lastModified ( ) , someDate ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . _type , ItemTypeVirtualFile ) ;
2018-01-25 12:07:55 +03:00
QVERIFY ( completeSpy . isEmpty ( ) ) ;
cleanup ( ) ;
// Not even when the remote is rediscovered
fakeFolder . syncJournal ( ) . forceRemoteDiscoveryNextSync ( ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QCOMPARE ( QFileInfo ( fakeFolder . localPath ( ) + " A/a1 " DVSUFFIX ) . lastModified ( ) , someDate ) ;
2018-01-25 12:07:55 +03:00
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . _type , ItemTypeVirtualFile ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( completeSpy . isEmpty ( ) ) ;
cleanup ( ) ;
// Neither does a remote change
fakeFolder . remoteModifier ( ) . appendByte ( " A/a1 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_UPDATE_METADATA ) ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . _type , ItemTypeVirtualFile ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . _fileSize , 65 ) ;
2017-12-13 20:04:58 +03:00
cleanup ( ) ;
2024-06-25 18:26:15 +03:00
// If the local virtual file is removed, it should be gone remotely too
2017-12-13 20:04:58 +03:00
if ( ! doLocalDiscovery )
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( LocalDiscoveryStyle : : DatabaseAndFilesystem , { " A " } ) ;
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . remove ( " A/a1 " DVSUFFIX ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
2024-06-25 18:26:15 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
2024-06-26 10:07:50 +03:00
QVERIFY ( ! fakeFolder . remoteModifier ( ) . find ( " A/a1 " ) ) ;
cleanup ( ) ;
// Restore the state prior to next test
// Essentially repeating creation of virtual file
fakeFolder . remoteModifier ( ) . insert ( " A/a1 " , 64 ) ;
fakeFolder . remoteModifier ( ) . setModTime ( " A/a1 " , someDate ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QCOMPARE ( QFileInfo ( fakeFolder . localPath ( ) + " A/a1 " DVSUFFIX ) . lastModified ( ) , someDate ) ;
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/a1 " ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_NEW ) ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . _type , ItemTypeVirtualFile ) ;
2017-12-13 20:04:58 +03:00
cleanup ( ) ;
// Remote rename is propagated
fakeFolder . remoteModifier ( ) . rename ( " A/a1 " , " A/a1m " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1m " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1m " DVSUFFIX ) ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( ! fakeFolder . currentRemoteState ( ) . find ( " A/a1 " ) ) ;
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/a1m " ) ) ;
2018-10-19 11:24:47 +03:00
QVERIFY (
2019-06-28 11:44:13 +03:00
itemInstruction ( completeSpy , " A/a1m " DVSUFFIX , CSYNC_INSTRUCTION_RENAME )
| | ( itemInstruction ( completeSpy , " A/a1m " DVSUFFIX , CSYNC_INSTRUCTION_NEW )
& & itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_REMOVE ) ) ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/a1m " DVSUFFIX ) . _type , ItemTypeVirtualFile ) ;
2017-12-13 20:04:58 +03:00
cleanup ( ) ;
// Remote remove is propagated
fakeFolder . remoteModifier ( ) . remove ( " A/a1m " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1m " DVSUFFIX ) ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( ! fakeFolder . currentRemoteState ( ) . find ( " A/a1m " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1m " DVSUFFIX , CSYNC_INSTRUCTION_REMOVE ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a1m " DVSUFFIX ) . isValid ( ) ) ;
2017-12-13 20:04:58 +03:00
cleanup ( ) ;
2018-01-29 15:02:31 +03:00
2018-05-18 09:29:40 +03:00
// Edge case: Local virtual file but no db entry for some reason
2018-01-29 15:02:31 +03:00
fakeFolder . remoteModifier ( ) . insert ( " A/a2 " , 64 ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a3 " , 64 ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a2 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a3 " DVSUFFIX ) ) ;
2018-01-29 15:02:31 +03:00
cleanup ( ) ;
2022-08-04 17:51:26 +03:00
QVERIFY ( fakeFolder . syncEngine ( ) . journal ( ) - > deleteFileRecord ( " A/a2 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . syncEngine ( ) . journal ( ) - > deleteFileRecord ( " A/a3 " DVSUFFIX ) ) ;
2018-01-29 15:02:31 +03:00
fakeFolder . remoteModifier ( ) . remove ( " A/a3 " ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( LocalDiscoveryStyle : : FilesystemOnly ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a2 " DVSUFFIX ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/a2 " DVSUFFIX , CSYNC_INSTRUCTION_UPDATE_METADATA ) ) ;
QVERIFY ( dbRecord ( fakeFolder , " A/a2 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a3 " DVSUFFIX ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/a3 " DVSUFFIX , CSYNC_INSTRUCTION_REMOVE ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a3 " DVSUFFIX ) . isValid ( ) ) ;
2018-01-29 15:02:31 +03:00
cleanup ( ) ;
2017-12-13 20:04:58 +03:00
}
2018-05-18 09:29:40 +03:00
void testVirtualFileConflict ( )
2018-01-17 12:48:25 +03:00
{
FakeFolder fakeFolder { FileInfo ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2018-01-17 12:48:25 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2019-10-07 16:25:36 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2018-01-17 12:48:25 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
} ;
cleanup ( ) ;
2018-05-18 09:29:40 +03:00
// Create a virtual file for a new remote file
2018-01-17 12:48:25 +03:00
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a1 " , 64 ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a2 " , 64 ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " B " ) ;
fakeFolder . remoteModifier ( ) . insert ( " B/b1 " , 64 ) ;
fakeFolder . remoteModifier ( ) . insert ( " B/b2 " , 64 ) ;
2018-01-25 12:07:55 +03:00
fakeFolder . remoteModifier ( ) . mkdir ( " C " ) ;
fakeFolder . remoteModifier ( ) . insert ( " C/c1 " , 64 ) ;
2018-01-17 12:48:25 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " B/b2 " DVSUFFIX ) ) ;
2018-01-17 12:48:25 +03:00
cleanup ( ) ;
2018-05-18 09:29:40 +03:00
// A: the correct file and a conflicting file are added, virtual files stay
// B: same setup, but the virtual files are deleted by the user
2018-01-25 12:07:55 +03:00
// C: user adds a *directory* locally
2018-01-17 12:48:25 +03:00
fakeFolder . localModifier ( ) . insert ( " A/a1 " , 64 ) ;
fakeFolder . localModifier ( ) . insert ( " A/a2 " , 30 ) ;
fakeFolder . localModifier ( ) . insert ( " B/b1 " , 64 ) ;
fakeFolder . localModifier ( ) . insert ( " B/b2 " , 30 ) ;
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . remove ( " B/b1 " DVSUFFIX ) ;
fakeFolder . localModifier ( ) . remove ( " B/b2 " DVSUFFIX ) ;
2018-01-25 12:07:55 +03:00
fakeFolder . localModifier ( ) . mkdir ( " C/c1 " ) ;
fakeFolder . localModifier ( ) . insert ( " C/c1/foo " ) ;
2018-01-17 12:48:25 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
// Everything is CONFLICT since mtimes are different even for a1/b1
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " , CSYNC_INSTRUCTION_CONFLICT ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/a2 " , CSYNC_INSTRUCTION_CONFLICT ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " B/b1 " , CSYNC_INSTRUCTION_CONFLICT ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " B/b2 " , CSYNC_INSTRUCTION_CONFLICT ) ) ;
2018-01-25 12:07:55 +03:00
QVERIFY ( itemInstruction ( completeSpy , " C/c1 " , CSYNC_INSTRUCTION_CONFLICT ) ) ;
2018-01-17 12:48:25 +03:00
2018-05-18 09:29:40 +03:00
// no virtual file files should remain
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a2 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " B/b1 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " B/b2 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " C/c1 " DVSUFFIX ) ) ;
2018-01-17 12:48:25 +03:00
// conflict files should exist
2018-01-25 12:07:55 +03:00
QCOMPARE ( fakeFolder . syncJournal ( ) . conflictRecordPaths ( ) . size ( ) , 3 ) ;
2018-01-17 12:48:25 +03:00
2018-05-18 09:29:40 +03:00
// nothing should have the virtual file tag
2018-01-17 12:48:25 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " ) . _type , ItemTypeFile ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/a2 " ) . _type , ItemTypeFile ) ;
QCOMPARE ( dbRecord ( fakeFolder , " B/b1 " ) . _type , ItemTypeFile ) ;
QCOMPARE ( dbRecord ( fakeFolder , " B/b2 " ) . _type , ItemTypeFile ) ;
2018-01-25 12:07:55 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " C/c1 " ) . _type , ItemTypeFile ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a2 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " B/b1 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " B/b2 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " C/c1 " DVSUFFIX ) . isValid ( ) ) ;
2018-01-17 12:48:25 +03:00
cleanup ( ) ;
}
2017-12-13 20:04:58 +03:00
void testWithNormalSync ( )
{
2018-05-18 09:29:40 +03:00
FakeFolder fakeFolder { FileInfo : : A12_B12_C12_S12 ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2017-12-13 20:04:58 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2019-10-07 16:25:36 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2017-12-13 20:04:58 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
} ;
cleanup ( ) ;
// No effect sync
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
cleanup ( ) ;
// Existing files are propagated just fine in both directions
fakeFolder . localModifier ( ) . appendByte ( " A/a1 " ) ;
fakeFolder . localModifier ( ) . insert ( " A/a3 " ) ;
fakeFolder . remoteModifier ( ) . appendByte ( " A/a2 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
cleanup ( ) ;
2018-05-18 09:29:40 +03:00
// New files on the remote create virtual files
2017-12-13 20:04:58 +03:00
fakeFolder . remoteModifier ( ) . insert ( " A/new " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/new " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/new " DVSUFFIX ) ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/new " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/new " DVSUFFIX , CSYNC_INSTRUCTION_NEW ) ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/new " DVSUFFIX ) . _type , ItemTypeVirtualFile ) ;
2017-12-13 20:04:58 +03:00
cleanup ( ) ;
}
2018-05-18 09:29:40 +03:00
void testVirtualFileDownload ( )
2017-12-13 20:04:58 +03:00
{
2018-05-18 09:29:40 +03:00
FakeFolder fakeFolder { FileInfo ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2017-12-13 20:04:58 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2019-10-07 16:25:36 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2017-12-13 20:04:58 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
} ;
cleanup ( ) ;
2018-05-18 09:29:40 +03:00
// Create a virtual file for remote files
2017-12-13 20:04:58 +03:00
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a2 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a3 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a4 " ) ;
2018-01-17 12:48:25 +03:00
fakeFolder . remoteModifier ( ) . insert ( " A/a5 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a6 " ) ;
2019-04-02 12:51:47 +03:00
fakeFolder . remoteModifier ( ) . insert ( " A/a7 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/b1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/b2 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/b3 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/b4 " ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a2 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a3 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a4 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a5 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a6 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a7 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/b1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/b2 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/b3 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/b4 " DVSUFFIX ) ) ;
2017-12-13 20:04:58 +03:00
cleanup ( ) ;
// Download by changing the db entry
2018-09-26 14:41:02 +03:00
triggerDownload ( fakeFolder , " A/a1 " ) ;
triggerDownload ( fakeFolder , " A/a2 " ) ;
triggerDownload ( fakeFolder , " A/a3 " ) ;
triggerDownload ( fakeFolder , " A/a4 " ) ;
triggerDownload ( fakeFolder , " A/a5 " ) ;
triggerDownload ( fakeFolder , " A/a6 " ) ;
2019-04-02 12:51:47 +03:00
triggerDownload ( fakeFolder , " A/a7 " ) ;
// Download by renaming locally
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . rename ( " A/b1 " DVSUFFIX , " A/b1 " ) ;
fakeFolder . localModifier ( ) . rename ( " A/b2 " DVSUFFIX , " A/b2 " ) ;
fakeFolder . localModifier ( ) . rename ( " A/b3 " DVSUFFIX , " A/b3 " ) ;
fakeFolder . localModifier ( ) . rename ( " A/b4 " DVSUFFIX , " A/b4 " ) ;
2019-04-02 12:51:47 +03:00
// Remote complications
2017-12-13 20:04:58 +03:00
fakeFolder . remoteModifier ( ) . appendByte ( " A/a2 " ) ;
fakeFolder . remoteModifier ( ) . remove ( " A/a3 " ) ;
fakeFolder . remoteModifier ( ) . rename ( " A/a4 " , " A/a4m " ) ;
2019-04-02 12:51:47 +03:00
fakeFolder . remoteModifier ( ) . appendByte ( " A/b2 " ) ;
fakeFolder . remoteModifier ( ) . remove ( " A/b3 " ) ;
fakeFolder . remoteModifier ( ) . rename ( " A/b4 " , " A/b4m " ) ;
// Local complications
2018-01-17 12:48:25 +03:00
fakeFolder . localModifier ( ) . insert ( " A/a5 " ) ;
fakeFolder . localModifier ( ) . insert ( " A/a6 " ) ;
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . remove ( " A/a6 " DVSUFFIX ) ;
fakeFolder . localModifier ( ) . rename ( " A/a7 " DVSUFFIX , " A/a7 " ) ;
2019-04-02 12:51:47 +03:00
2017-12-13 20:04:58 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-03-25 12:53:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " , CSYNC_INSTRUCTION_SYNC ) ) ;
2019-10-07 16:25:36 +03:00
QCOMPARE ( completeSpy . findItem ( " A/a1 " ) - > _type , ItemTypeVirtualFileDownload ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_NONE ) ) ;
2019-03-25 12:53:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a2 " , CSYNC_INSTRUCTION_SYNC ) ) ;
2019-10-07 16:25:36 +03:00
QCOMPARE ( completeSpy . findItem ( " A/a2 " ) - > _type , ItemTypeVirtualFileDownload ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a2 " DVSUFFIX , CSYNC_INSTRUCTION_NONE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/a3 " DVSUFFIX , CSYNC_INSTRUCTION_REMOVE ) ) ;
2017-12-13 20:04:58 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a4m " , CSYNC_INSTRUCTION_NEW ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a4 " DVSUFFIX , CSYNC_INSTRUCTION_REMOVE ) ) ;
2018-01-17 12:48:25 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a5 " , CSYNC_INSTRUCTION_CONFLICT ) ) ;
2019-08-02 15:25:40 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a5 " DVSUFFIX , CSYNC_INSTRUCTION_REMOVE ) ) ;
2018-01-17 12:48:25 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a6 " , CSYNC_INSTRUCTION_CONFLICT ) ) ;
2019-04-02 12:51:47 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a7 " , CSYNC_INSTRUCTION_SYNC ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/b1 " , CSYNC_INSTRUCTION_SYNC ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/b2 " , CSYNC_INSTRUCTION_SYNC ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/b3 " , CSYNC_INSTRUCTION_REMOVE ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/b4m " DVSUFFIX , CSYNC_INSTRUCTION_NEW ) ) ;
2019-04-02 12:51:47 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/b4 " , CSYNC_INSTRUCTION_REMOVE ) ) ;
2018-01-17 12:48:25 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " ) . _type , ItemTypeFile ) ;
2019-07-24 17:07:28 +03:00
QVERIFY ( ! dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . isValid ( ) ) ;
2018-01-17 12:48:25 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " A/a2 " ) . _type , ItemTypeFile ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a3 " ) . isValid ( ) ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/a4m " ) . _type , ItemTypeFile ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/a5 " ) . _type , ItemTypeFile ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/a6 " ) . _type , ItemTypeFile ) ;
2019-04-02 12:51:47 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " A/a7 " ) . _type , ItemTypeFile ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/b1 " ) . _type , ItemTypeFile ) ;
2019-07-24 17:07:28 +03:00
QVERIFY ( ! dbRecord ( fakeFolder , " A/b1 " DVSUFFIX ) . isValid ( ) ) ;
2019-04-02 12:51:47 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " A/b2 " ) . _type , ItemTypeFile ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/b3 " ) . isValid ( ) ) ;
2019-06-28 11:44:13 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " A/b4m " DVSUFFIX ) . _type , ItemTypeVirtualFile ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a2 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a3 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a4 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a5 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a6 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/a7 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/b1 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/b2 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/b3 " DVSUFFIX ) . isValid ( ) ) ;
QVERIFY ( ! dbRecord ( fakeFolder , " A/b4 " DVSUFFIX ) . isValid ( ) ) ;
2019-04-02 12:51:47 +03:00
triggerDownload ( fakeFolder , " A/b4m " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2018-01-25 12:07:55 +03:00
}
2018-05-30 11:33:32 +03:00
void testVirtualFileDownloadResume ( )
{
FakeFolder fakeFolder { FileInfo ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2018-05-30 11:33:32 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2019-10-07 16:25:36 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2018-05-30 11:33:32 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
2022-08-04 17:51:26 +03:00
QVERIFY ( fakeFolder . syncJournal ( ) . wipeErrorBlacklist ( ) ! = - 1 ) ;
2018-05-30 11:33:32 +03:00
} ;
cleanup ( ) ;
// Create a virtual file for remote files
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a1 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
2018-05-30 11:33:32 +03:00
cleanup ( ) ;
// Download by changing the db entry
2018-09-26 14:41:02 +03:00
triggerDownload ( fakeFolder , " A/a1 " ) ;
2018-05-30 11:33:32 +03:00
fakeFolder . serverErrorPaths ( ) . append ( " A/a1 " , 500 ) ;
QVERIFY ( ! fakeFolder . syncOnce ( ) ) ;
2019-03-25 12:53:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " , CSYNC_INSTRUCTION_SYNC ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_NONE ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
2018-05-30 11:33:32 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . _type , ItemTypeVirtualFileDownload ) ;
2018-05-30 11:33:32 +03:00
QVERIFY ( ! dbRecord ( fakeFolder , " A/a1 " ) . isValid ( ) ) ;
cleanup ( ) ;
fakeFolder . serverErrorPaths ( ) . clear ( ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-03-25 12:53:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " , CSYNC_INSTRUCTION_SYNC ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_NONE ) ) ;
2018-05-30 11:33:32 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " ) . _type , ItemTypeFile ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . isValid ( ) ) ;
2018-05-30 11:33:32 +03:00
}
2018-11-26 13:33:29 +03:00
void testNewFilesNotVirtual ( )
2018-01-25 12:07:55 +03:00
{
FakeFolder fakeFolder { FileInfo ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2018-01-25 12:07:55 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a1 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
2018-01-25 12:07:55 +03:00
2019-01-29 12:53:47 +03:00
fakeFolder . syncJournal ( ) . internalPinStates ( ) . setForPath ( " " , PinState : : AlwaysLocal ) ;
2018-01-25 12:07:55 +03:00
2018-11-26 13:33:29 +03:00
// Create a new remote file, it'll not be virtual
fakeFolder . remoteModifier ( ) . insert ( " A/a2 " ) ;
2018-01-29 15:02:31 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2018-11-26 13:33:29 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a2 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a2 " DVSUFFIX ) ) ;
2018-01-29 15:02:31 +03:00
}
2018-05-28 15:49:02 +03:00
void testDownloadRecursive ( )
{
FakeFolder fakeFolder { FileInfo ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2018-05-28 15:49:02 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
// Create a virtual file for remote files
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " A/Sub " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " A/Sub/SubSub " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " A/Sub2 " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " B " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " B/Sub " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a2 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/Sub/a3 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/Sub/a4 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/Sub/SubSub/a5 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/Sub2/a6 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " B/b1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " B/Sub/b2 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a2 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/a3 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/a4 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/SubSub/a5 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub2/a6 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " B/b1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " B/Sub/b2 " DVSUFFIX ) ) ;
2018-05-28 15:49:02 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a2 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/a3 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/a4 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/SubSub/a5 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub2/a6 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " B/b1 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " B/Sub/b2 " ) ) ;
// Download All file in the directory A/Sub
// (as in Folder::downloadVirtualFile)
fakeFolder . syncJournal ( ) . markVirtualFileForDownloadRecursively ( " A/Sub " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a2 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/a3 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/a4 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/SubSub/a5 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub2/a6 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " B/b1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " B/Sub/b2 " DVSUFFIX ) ) ;
2018-05-28 15:49:02 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a2 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/a3 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/a4 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/SubSub/a5 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub2/a6 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " B/b1 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " B/Sub/b2 " ) ) ;
// Add a file in a subfolder that was downloaded
// Currently, this continue to add it as a virtual file.
fakeFolder . remoteModifier ( ) . insert ( " A/Sub/SubSub/a7 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/SubSub/a7 " DVSUFFIX ) ) ;
2018-05-28 15:49:02 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/SubSub/a7 " ) ) ;
// Now download all files in "A"
fakeFolder . syncJournal ( ) . markVirtualFileForDownloadRecursively ( " A " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a2 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/a3 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/a4 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/SubSub/a5 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub2/a6 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/Sub/SubSub/a7 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " B/b1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " B/Sub/b2 " DVSUFFIX ) ) ;
2018-05-28 15:49:02 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a2 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/a3 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/a4 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/SubSub/a5 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub2/a6 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/Sub/SubSub/a7 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " B/b1 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " B/Sub/b2 " ) ) ;
// Now download remaining files in "B"
fakeFolder . syncJournal ( ) . markVirtualFileForDownloadRecursively ( " B " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
}
2018-08-16 13:38:39 +03:00
void testRenameToVirtual ( )
{
FakeFolder fakeFolder { FileInfo : : A12_B12_C12_S12 ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2018-08-16 13:38:39 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2019-10-07 16:25:36 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2018-08-16 13:38:39 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
} ;
cleanup ( ) ;
2019-06-28 11:44:13 +03:00
// If a file is renamed to <name>.owncloud, it becomes virtual
fakeFolder . localModifier ( ) . rename ( " A/a1 " , " A/a1 " DVSUFFIX ) ;
// If a file is renamed to <random>.owncloud, the rename propagates but the
2019-03-07 16:35:39 +03:00
// file isn't made virtual the first sync run.
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . rename ( " A/a2 " , " A/rand " DVSUFFIX ) ;
2018-09-26 14:41:02 +03:00
// dangling virtual files are removed
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . insert ( " A/dangling " DVSUFFIX , 1 , ' ' ) ;
2018-08-16 13:38:39 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
2019-10-30 15:16:32 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) - > size < = 1 ) ;
2018-08-16 13:38:39 +03:00
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/a1 " ) ) ;
2019-07-24 17:07:28 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_SYNC ) ) ;
2019-06-28 11:44:13 +03:00
QCOMPARE ( dbRecord ( fakeFolder , " A/a1 " DVSUFFIX ) . _type , ItemTypeVirtualFile ) ;
2019-07-24 17:07:28 +03:00
QVERIFY ( ! dbRecord ( fakeFolder , " A/a1 " ) . isValid ( ) ) ;
2018-08-16 13:38:39 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a2 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a2 " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/rand " ) ) ;
2018-08-16 13:38:39 +03:00
QVERIFY ( ! fakeFolder . currentRemoteState ( ) . find ( " A/a2 " ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/rand " ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/rand " , CSYNC_INSTRUCTION_RENAME ) ) ;
QVERIFY ( dbRecord ( fakeFolder , " A/rand " ) . _type = = ItemTypeFile ) ;
2018-08-16 13:38:39 +03:00
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/dangling " DVSUFFIX ) ) ;
2018-09-26 14:41:02 +03:00
cleanup ( ) ;
}
void testRenameVirtual ( )
{
FakeFolder fakeFolder { FileInfo ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2018-09-26 14:41:02 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2019-10-07 16:25:36 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2018-09-26 14:41:02 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
} ;
2018-08-16 13:38:39 +03:00
cleanup ( ) ;
2018-09-26 14:41:02 +03:00
fakeFolder . remoteModifier ( ) . insert ( " file1 " , 128 , ' C ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " file2 " , 256 , ' C ' ) ;
2019-03-07 16:35:39 +03:00
fakeFolder . remoteModifier ( ) . insert ( " file3 " , 256 , ' C ' ) ;
2018-09-26 14:41:02 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " file1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " file2 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " file3 " DVSUFFIX ) ) ;
2018-09-26 14:41:02 +03:00
cleanup ( ) ;
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . rename ( " file1 " DVSUFFIX , " renamed1 " DVSUFFIX ) ;
fakeFolder . localModifier ( ) . rename ( " file2 " DVSUFFIX , " renamed2 " DVSUFFIX ) ;
2018-09-26 14:41:02 +03:00
triggerDownload ( fakeFolder , " file2 " ) ;
2019-03-07 16:35:39 +03:00
triggerDownload ( fakeFolder , " file3 " ) ;
2018-09-26 14:41:02 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " file1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " renamed1 " DVSUFFIX ) ) ;
2018-09-26 14:41:02 +03:00
QVERIFY ( ! fakeFolder . currentRemoteState ( ) . find ( " file1 " ) ) ;
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " renamed1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " renamed1 " DVSUFFIX , CSYNC_INSTRUCTION_RENAME ) ) ;
QVERIFY ( dbRecord ( fakeFolder , " renamed1 " DVSUFFIX ) . isValid ( ) ) ;
2018-09-26 14:41:02 +03:00
// file2 has a conflict between the download request and the rename:
2019-03-07 16:35:39 +03:00
// the rename wins, the download is ignored
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " file2 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " file2 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " renamed2 " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " renamed2 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " renamed2 " DVSUFFIX , CSYNC_INSTRUCTION_RENAME ) ) ;
QVERIFY ( dbRecord ( fakeFolder , " renamed2 " DVSUFFIX ) . _type = = ItemTypeVirtualFile ) ;
2019-03-07 16:35:39 +03:00
2019-03-25 12:53:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " file3 " , CSYNC_INSTRUCTION_SYNC ) ) ;
QVERIFY ( dbRecord ( fakeFolder , " file3 " ) . _type = = ItemTypeFile ) ;
2019-03-07 16:35:39 +03:00
cleanup ( ) ;
// Test rename while adding/removing vfs suffix
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . rename ( " renamed1 " DVSUFFIX , " R1 " ) ;
2019-03-07 16:35:39 +03:00
// Contents of file2 could also change at the same time...
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . rename ( " file3 " , " R3 " DVSUFFIX ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
cleanup ( ) ;
}
void testRenameVirtual2 ( )
{
FakeFolder fakeFolder { FileInfo ( ) } ;
setupVfs ( fakeFolder ) ;
2019-10-07 16:25:36 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2019-03-07 16:35:39 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
} ;
cleanup ( ) ;
fakeFolder . remoteModifier ( ) . insert ( " case3 " , 128 , ' C ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " case4 " , 256 , ' C ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " case5 " , 256 , ' C ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " case6 " , 256 , ' C ' ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
triggerDownload ( fakeFolder , " case4 " ) ;
triggerDownload ( fakeFolder , " case6 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " case3 " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " case4 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " case5 " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " case6 " ) ) ;
cleanup ( ) ;
// Case 1: foo -> bar (tested elsewhere)
// Case 2: foo.oc -> bar.oc (tested elsewhere)
// Case 3: foo.oc -> bar (db unchanged)
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . rename ( " case3 " DVSUFFIX , " case3-rename " ) ;
2019-03-07 16:35:39 +03:00
// Case 4: foo -> bar.oc (db unchanged)
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . rename ( " case4 " , " case4-rename " DVSUFFIX ) ;
2019-03-07 16:35:39 +03:00
2019-07-24 16:25:02 +03:00
// Case 5: foo.oc -> bar.oc (db hydrate)
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . rename ( " case5 " DVSUFFIX , " case5-rename " DVSUFFIX ) ;
2019-03-07 16:35:39 +03:00
triggerDownload ( fakeFolder , " case5 " ) ;
2019-07-24 16:25:02 +03:00
// Case 6: foo -> bar (db dehydrate)
2019-03-07 16:35:39 +03:00
fakeFolder . localModifier ( ) . rename ( " case6 " , " case6-rename " ) ;
markForDehydration ( fakeFolder , " case6 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
// Case 3: the rename went though, hydration is forgotten
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case3 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case3 " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case3-rename " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " case3-rename " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( ! fakeFolder . currentRemoteState ( ) . find ( " case3 " ) ) ;
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " case3-rename " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " case3-rename " DVSUFFIX , CSYNC_INSTRUCTION_RENAME ) ) ;
QVERIFY ( dbRecord ( fakeFolder , " case3-rename " DVSUFFIX ) . _type = = ItemTypeVirtualFile ) ;
2019-03-07 16:35:39 +03:00
// Case 4: the rename went though, dehydration is forgotten
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case4 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case4 " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " case4-rename " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case4-rename " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( ! fakeFolder . currentRemoteState ( ) . find ( " case4 " ) ) ;
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " case4-rename " ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " case4-rename " , CSYNC_INSTRUCTION_RENAME ) ) ;
QVERIFY ( dbRecord ( fakeFolder , " case4-rename " ) . _type = = ItemTypeFile ) ;
// Case 5: the rename went though, hydration is forgotten
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case5 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case5 " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case5-rename " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " case5-rename " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( ! fakeFolder . currentRemoteState ( ) . find ( " case5 " ) ) ;
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " case5-rename " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " case5-rename " DVSUFFIX , CSYNC_INSTRUCTION_RENAME ) ) ;
QVERIFY ( dbRecord ( fakeFolder , " case5-rename " DVSUFFIX ) . _type = = ItemTypeVirtualFile ) ;
2019-03-07 16:35:39 +03:00
// Case 6: the rename went though, dehydration is forgotten
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case6 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case6 " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " case6-rename " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " case6-rename " DVSUFFIX ) ) ;
2019-03-07 16:35:39 +03:00
QVERIFY ( ! fakeFolder . currentRemoteState ( ) . find ( " case6 " ) ) ;
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " case6-rename " ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " case6-rename " , CSYNC_INSTRUCTION_RENAME ) ) ;
QVERIFY ( dbRecord ( fakeFolder , " case6-rename " ) . _type = = ItemTypeFile ) ;
2018-08-16 13:38:39 +03:00
}
2018-08-15 11:46:16 +03:00
2022-04-06 12:42:10 +03:00
void testCreateFileWithTrailingSpaces_acceptAndRejectInvalidFileName ( )
2022-02-01 21:15:37 +03:00
{
FakeFolder fakeFolder { FileInfo ( ) } ;
setupVfs ( fakeFolder ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
const QString fileWithSpaces1 ( " foo " ) ;
2022-04-06 12:42:10 +03:00
const QString fileWithSpaces2 ( " bar " ) ;
2022-02-01 21:15:37 +03:00
const QString fileWithSpaces3 ( " bla " ) ;
const QString fileWithSpaces4 ( " A/ foo " ) ;
2022-04-06 12:42:10 +03:00
const QString fileWithSpaces5 ( " A/ bar " ) ;
2022-02-01 21:15:37 +03:00
const QString fileWithSpaces6 ( " A/bla " ) ;
fakeFolder . localModifier ( ) . insert ( fileWithSpaces1 ) ;
fakeFolder . localModifier ( ) . insert ( fileWithSpaces2 ) ;
fakeFolder . localModifier ( ) . insert ( fileWithSpaces3 ) ;
fakeFolder . localModifier ( ) . mkdir ( " A " ) ;
fakeFolder . localModifier ( ) . insert ( fileWithSpaces4 ) ;
fakeFolder . localModifier ( ) . insert ( fileWithSpaces5 ) ;
fakeFolder . localModifier ( ) . insert ( fileWithSpaces6 ) ;
2022-04-06 12:42:10 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
completeSpy . clear ( ) ;
2022-02-01 21:15:37 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2024-09-26 15:21:34 +03:00
if ( Utility : : isWindows ( ) ) {
QCOMPARE ( completeSpy . findItem ( fileWithSpaces1 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces2 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces3 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces4 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces5 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces6 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
} else {
QCOMPARE ( completeSpy . findItem ( fileWithSpaces1 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces2 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces3 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces4 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces5 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces6 ) - > _status , SyncFileItem : : Status : : Success ) ;
}
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
fakeFolder . syncEngine ( ) . addAcceptedInvalidFileName ( fakeFolder . localPath ( ) + fileWithSpaces1 ) ;
fakeFolder . syncEngine ( ) . addAcceptedInvalidFileName ( fakeFolder . localPath ( ) + fileWithSpaces2 ) ;
fakeFolder . syncEngine ( ) . addAcceptedInvalidFileName ( fakeFolder . localPath ( ) + fileWithSpaces3 ) ;
fakeFolder . syncEngine ( ) . addAcceptedInvalidFileName ( fakeFolder . localPath ( ) + fileWithSpaces4 ) ;
fakeFolder . syncEngine ( ) . addAcceptedInvalidFileName ( fakeFolder . localPath ( ) + fileWithSpaces5 ) ;
fakeFolder . syncEngine ( ) . addAcceptedInvalidFileName ( fakeFolder . localPath ( ) + fileWithSpaces6 ) ;
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
completeSpy . clear ( ) ;
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2022-02-01 21:15:37 +03:00
2024-09-26 15:21:34 +03:00
if ( Utility : : isWindows ( ) ) {
QCOMPARE ( completeSpy . findItem ( fileWithSpaces1 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces2 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces3 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces4 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces5 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces6 ) - > _status , SyncFileItem : : Status : : Success ) ;
} else {
QCOMPARE ( completeSpy . findItem ( fileWithSpaces1 ) - > _status , SyncFileItem : : Status : : NoStatus ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces2 ) - > _status , SyncFileItem : : Status : : NoStatus ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces3 ) - > _status , SyncFileItem : : Status : : NoStatus ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces4 ) - > _status , SyncFileItem : : Status : : NoStatus ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces5 ) - > _status , SyncFileItem : : Status : : NoStatus ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces6 ) - > _status , SyncFileItem : : Status : : NoStatus ) ;
}
2022-04-06 12:42:10 +03:00
}
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
void testCreateFileWithTrailingSpaces_remoteDontGetRenamedAutomatically ( )
{
// On Windows we can't create files/folders with leading/trailing spaces locally. So, we have to fail those items. On other OSs - we just sync them down normally.
FakeFolder fakeFolder { FileInfo ( ) } ;
setupVfs ( fakeFolder ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
const QString fileWithSpaces4 ( " A/ foo " ) ;
const QString fileWithSpaces5 ( " A/ bar " ) ;
const QString fileWithSpaces6 ( " A/bla " ) ;
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
const QString fileWithSpacesVirtual4 ( fileWithSpaces4 + DVSUFFIX ) ;
const QString fileWithSpacesVirtual5 ( fileWithSpaces5 + DVSUFFIX ) ;
const QString fileWithSpacesVirtual6 ( fileWithSpaces6 + DVSUFFIX ) ;
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . insert ( fileWithSpaces4 ) ;
fakeFolder . remoteModifier ( ) . insert ( fileWithSpaces5 ) ;
fakeFolder . remoteModifier ( ) . insert ( fileWithSpaces6 ) ;
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
completeSpy . clear ( ) ;
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
if ( Utility : : isWindows ( ) ) {
QCOMPARE ( completeSpy . findItem ( fileWithSpaces4 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces5 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces6 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
} else {
QCOMPARE ( completeSpy . findItem ( fileWithSpacesVirtual4 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpacesVirtual5 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpacesVirtual6 ) - > _status , SyncFileItem : : Status : : Success ) ;
}
2022-02-01 21:15:37 +03:00
}
2022-04-06 12:42:10 +03:00
void testCreateFileWithTrailingSpaces_remoteGetRenamedManually ( )
2022-02-01 21:15:37 +03:00
{
2022-04-06 12:42:10 +03:00
// On Windows we can't create files/folders with leading/trailing spaces locally. So, we have to fail those items. On other OSs - we just sync them down normally.
FakeFolder fakeFolder { FileInfo ( ) } ;
2022-02-01 21:15:37 +03:00
setupVfs ( fakeFolder ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
const QString fileWithSpaces4 ( " A/ foo " ) ;
2022-04-06 12:42:10 +03:00
const QString fileWithSpaces5 ( " A/ bar " ) ;
2022-02-01 21:15:37 +03:00
const QString fileWithSpaces6 ( " A/bla " ) ;
2022-04-06 12:42:10 +03:00
const QString fileWithSpacesVirtual4 ( fileWithSpaces4 + DVSUFFIX ) ;
const QString fileWithSpacesVirtual5 ( fileWithSpaces5 + DVSUFFIX ) ;
const QString fileWithSpacesVirtual6 ( fileWithSpaces6 + DVSUFFIX ) ;
const QString fileWithoutSpaces4 ( " A/foo " ) ;
const QString fileWithoutSpaces5 ( " A/bar " ) ;
const QString fileWithoutSpaces6 ( " A/bla " ) ;
const QString fileWithoutSpacesVirtual4 ( fileWithoutSpaces4 + DVSUFFIX ) ;
const QString fileWithoutSpacesVirtual5 ( fileWithoutSpaces5 + DVSUFFIX ) ;
const QString fileWithoutSpacesVirtual6 ( fileWithoutSpaces6 + DVSUFFIX ) ;
2022-02-01 21:15:37 +03:00
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . insert ( fileWithSpaces4 ) ;
fakeFolder . remoteModifier ( ) . insert ( fileWithSpaces5 ) ;
fakeFolder . remoteModifier ( ) . insert ( fileWithSpaces6 ) ;
2022-04-06 12:42:10 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
completeSpy . clear ( ) ;
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
if ( Utility : : isWindows ( ) ) {
QCOMPARE ( completeSpy . findItem ( fileWithSpaces4 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces5 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpaces6 ) - > _status , SyncFileItem : : Status : : FileNameInvalid ) ;
} else {
QCOMPARE ( completeSpy . findItem ( fileWithSpacesVirtual4 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpacesVirtual5 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithSpacesVirtual6 ) - > _status , SyncFileItem : : Status : : Success ) ;
}
fakeFolder . remoteModifier ( ) . rename ( fileWithSpaces4 , fileWithoutSpaces4 ) ;
fakeFolder . remoteModifier ( ) . rename ( fileWithSpaces5 , fileWithoutSpaces5 ) ;
fakeFolder . remoteModifier ( ) . rename ( fileWithSpaces6 , fileWithoutSpaces6 ) ;
2022-02-01 21:15:37 +03:00
2022-04-06 12:42:10 +03:00
completeSpy . clear ( ) ;
2022-02-01 21:15:37 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2022-04-06 12:42:10 +03:00
if ( Utility : : isWindows ( ) ) {
QCOMPARE ( completeSpy . findItem ( fileWithoutSpaces4 + DVSUFFIX ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithoutSpaces5 + DVSUFFIX ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithoutSpaces6 + DVSUFFIX ) - > _status , SyncFileItem : : Status : : Success ) ;
} else {
QCOMPARE ( completeSpy . findItem ( fileWithoutSpacesVirtual4 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithoutSpacesVirtual5 ) - > _status , SyncFileItem : : Status : : Success ) ;
QCOMPARE ( completeSpy . findItem ( fileWithoutSpacesVirtual6 ) - > _status , SyncFileItem : : Status : : Success ) ;
}
2022-02-01 21:15:37 +03:00
}
2018-08-15 11:46:16 +03:00
// Dehydration via sync works
void testSyncDehydration ( )
{
FakeFolder fakeFolder { FileInfo : : A12_B12_C12_S12 ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2018-08-15 11:46:16 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2019-10-07 16:25:36 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2018-08-15 11:46:16 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
} ;
cleanup ( ) ;
//
// Mark for dehydration and check
//
markForDehydration ( fakeFolder , " A/a1 " ) ;
markForDehydration ( fakeFolder , " A/a2 " ) ;
fakeFolder . remoteModifier ( ) . appendByte ( " A/a2 " ) ;
// expect: normal dehydration
markForDehydration ( fakeFolder , " B/b1 " ) ;
fakeFolder . remoteModifier ( ) . remove ( " B/b1 " ) ;
// expect: local removal
markForDehydration ( fakeFolder , " B/b2 " ) ;
fakeFolder . remoteModifier ( ) . rename ( " B/b2 " , " B/b3 " ) ;
// expect: B/b2 is gone, B/b3 is NEW placeholder
markForDehydration ( fakeFolder , " C/c1 " ) ;
fakeFolder . localModifier ( ) . appendByte ( " C/c1 " ) ;
// expect: no dehydration, upload of c1
markForDehydration ( fakeFolder , " C/c2 " ) ;
fakeFolder . localModifier ( ) . appendByte ( " C/c2 " ) ;
fakeFolder . remoteModifier ( ) . appendByte ( " C/c2 " ) ;
fakeFolder . remoteModifier ( ) . appendByte ( " C/c2 " ) ;
// expect: no dehydration, conflict
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
auto isDehydrated = [ & ] ( const QString & path ) {
2019-06-28 11:44:13 +03:00
QString placeholder = path + DVSUFFIX ;
2018-08-15 11:46:16 +03:00
return ! fakeFolder . currentLocalState ( ) . find ( path )
& & fakeFolder . currentLocalState ( ) . find ( placeholder ) ;
} ;
2019-02-06 17:07:54 +03:00
auto hasDehydratedDbEntries = [ & ] ( const QString & path ) {
SyncJournalFileRecord normal , suffix ;
2022-08-04 17:51:26 +03:00
return ( ! fakeFolder . syncJournal ( ) . getFileRecord ( path , & normal ) | | ! normal . isValid ( ) )
& & fakeFolder . syncJournal ( ) . getFileRecord ( path + DVSUFFIX , & suffix ) & & suffix . isValid ( )
& & suffix . _type = = ItemTypeVirtualFile ;
2019-02-06 17:07:54 +03:00
} ;
2018-08-15 11:46:16 +03:00
QVERIFY ( isDehydrated ( " A/a1 " ) ) ;
2019-02-06 17:07:54 +03:00
QVERIFY ( hasDehydratedDbEntries ( " A/a1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_SYNC ) ) ;
2019-10-07 16:25:36 +03:00
QCOMPARE ( completeSpy . findItem ( " A/a1 " DVSUFFIX ) - > _type , ItemTypeVirtualFileDehydration ) ;
QCOMPARE ( completeSpy . findItem ( " A/a1 " DVSUFFIX ) - > _file , QStringLiteral ( " A/a1 " ) ) ;
QCOMPARE ( completeSpy . findItem ( " A/a1 " DVSUFFIX ) - > _renameTarget , QStringLiteral ( " A/a1 " DVSUFFIX ) ) ;
2018-08-15 11:46:16 +03:00
QVERIFY ( isDehydrated ( " A/a2 " ) ) ;
2019-02-06 17:07:54 +03:00
QVERIFY ( hasDehydratedDbEntries ( " A/a2 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/a2 " DVSUFFIX , CSYNC_INSTRUCTION_SYNC ) ) ;
2019-10-07 16:25:36 +03:00
QCOMPARE ( completeSpy . findItem ( " A/a2 " DVSUFFIX ) - > _type , ItemTypeVirtualFileDehydration ) ;
2018-08-15 11:46:16 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " B/b1 " ) ) ;
QVERIFY ( ! fakeFolder . currentRemoteState ( ) . find ( " B/b1 " ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " B/b1 " , CSYNC_INSTRUCTION_REMOVE ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " B/b2 " ) ) ;
QVERIFY ( ! fakeFolder . currentRemoteState ( ) . find ( " B/b2 " ) ) ;
QVERIFY ( isDehydrated ( " B/b3 " ) ) ;
2019-02-06 17:07:54 +03:00
QVERIFY ( hasDehydratedDbEntries ( " B/b3 " ) ) ;
2018-08-15 11:46:16 +03:00
QVERIFY ( itemInstruction ( completeSpy , " B/b2 " , CSYNC_INSTRUCTION_REMOVE ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " B/b3 " DVSUFFIX , CSYNC_INSTRUCTION_NEW ) ) ;
2018-08-15 11:46:16 +03:00
QCOMPARE ( fakeFolder . currentRemoteState ( ) . find ( " C/c1 " ) - > size , 25 ) ;
QVERIFY ( itemInstruction ( completeSpy , " C/c1 " , CSYNC_INSTRUCTION_SYNC ) ) ;
QCOMPARE ( fakeFolder . currentRemoteState ( ) . find ( " C/c2 " ) - > size , 26 ) ;
QVERIFY ( itemInstruction ( completeSpy , " C/c2 " , CSYNC_INSTRUCTION_CONFLICT ) ) ;
cleanup ( ) ;
auto expectedLocalState = fakeFolder . currentLocalState ( ) ;
auto expectedRemoteState = fakeFolder . currentRemoteState ( ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , expectedLocalState ) ;
QCOMPARE ( fakeFolder . currentRemoteState ( ) , expectedRemoteState ) ;
}
void testWipeVirtualSuffixFiles ( )
{
FakeFolder fakeFolder { FileInfo { } } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2018-08-15 11:46:16 +03:00
// Create a suffix-vfs baseline
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " A/B " ) ;
fakeFolder . remoteModifier ( ) . insert ( " f1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a3 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/B/b1 " ) ;
fakeFolder . localModifier ( ) . mkdir ( " A " ) ;
fakeFolder . localModifier ( ) . mkdir ( " A/B " ) ;
fakeFolder . localModifier ( ) . insert ( " f2 " ) ;
fakeFolder . localModifier ( ) . insert ( " A/a2 " ) ;
fakeFolder . localModifier ( ) . insert ( " A/B/b2 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " f1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a3 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/B/b1 " DVSUFFIX ) ) ;
2018-08-15 11:46:16 +03:00
// Make local changes to a3
2019-06-28 11:44:13 +03:00
fakeFolder . localModifier ( ) . remove ( " A/a3 " DVSUFFIX ) ;
fakeFolder . localModifier ( ) . insert ( " A/a3 " DVSUFFIX , 100 ) ;
2018-08-15 11:46:16 +03:00
// Now wipe the virtuals
2018-11-21 14:23:08 +03:00
SyncEngine : : wipeVirtualFiles ( fakeFolder . localPath ( ) , fakeFolder . syncJournal ( ) , * fakeFolder . syncEngine ( ) . syncOptions ( ) . _vfs ) ;
2018-08-15 11:46:16 +03:00
2019-06-28 11:44:13 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " f1 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/a3 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/B/b1 " DVSUFFIX ) ) ;
2018-08-15 11:46:16 +03:00
2019-01-23 17:12:02 +03:00
fakeFolder . switchToVfs ( QSharedPointer < Vfs > ( new VfsOff ) ) ;
2018-08-15 11:46:16 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/a3 " DVSUFFIX ) ) ; // regular upload
2018-08-15 11:46:16 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
}
2018-11-27 12:22:23 +03:00
void testNewVirtuals ( )
{
FakeFolder fakeFolder { FileInfo ( ) } ;
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2018-11-27 12:22:23 +03:00
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
auto setPin = [ & ] ( const QByteArray & path , PinState state ) {
2019-01-29 12:53:47 +03:00
fakeFolder . syncJournal ( ) . internalPinStates ( ) . setForPath ( path , state ) ;
2018-11-27 12:22:23 +03:00
} ;
fakeFolder . remoteModifier ( ) . mkdir ( " local " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " online " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " unspec " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
setPin ( " local " , PinState : : AlwaysLocal ) ;
setPin ( " online " , PinState : : OnlineOnly ) ;
2019-01-23 17:12:02 +03:00
setPin ( " unspec " , PinState : : Unspecified ) ;
2018-11-27 12:22:23 +03:00
2019-04-03 14:32:05 +03:00
// Test 1: root is Unspecified
2018-11-27 12:22:23 +03:00
fakeFolder . remoteModifier ( ) . insert ( " file1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " online/file1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " local/file1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " unspec/file1 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " file1 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " online/file1 " DVSUFFIX ) ) ;
2018-11-27 12:22:23 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " local/file1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " unspec/file1 " DVSUFFIX ) ) ;
2018-11-27 12:22:23 +03:00
2019-04-03 14:32:05 +03:00
// Test 2: change root to AlwaysLocal
2019-01-29 12:53:47 +03:00
setPin ( " " , PinState : : AlwaysLocal ) ;
2018-11-27 12:22:23 +03:00
fakeFolder . remoteModifier ( ) . insert ( " file2 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " online/file2 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " local/file2 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " unspec/file2 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " file2 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " online/file2 " DVSUFFIX ) ) ;
2018-11-27 12:22:23 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " local/file2 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " unspec/file2 " DVSUFFIX ) ) ;
2018-11-27 12:22:23 +03:00
2019-04-03 14:32:05 +03:00
// root file1 was hydrated due to its new pin state
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " file1 " ) ) ;
// file1 is unchanged in the explicitly pinned subfolders
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " online/file1 " DVSUFFIX ) ) ;
2019-04-03 14:32:05 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " local/file1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " unspec/file1 " DVSUFFIX ) ) ;
2019-04-03 14:32:05 +03:00
// Test 3: change root to OnlineOnly
setPin ( " " , PinState : : OnlineOnly ) ;
fakeFolder . remoteModifier ( ) . insert ( " file3 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " online/file3 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " local/file3 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " unspec/file3 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " file3 " DVSUFFIX ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " online/file3 " DVSUFFIX ) ) ;
2019-04-03 14:32:05 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " local/file3 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " unspec/file3 " DVSUFFIX ) ) ;
2019-04-03 14:32:05 +03:00
// root file1 was dehydrated due to its new pin state
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " file1 " DVSUFFIX ) ) ;
2019-04-03 14:32:05 +03:00
// file1 is unchanged in the explicitly pinned subfolders
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " online/file1 " DVSUFFIX ) ) ;
2018-11-27 12:22:23 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " local/file1 " ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " unspec/file1 " DVSUFFIX ) ) ;
2018-11-27 12:22:23 +03:00
}
2019-01-10 15:26:26 +03:00
2019-08-02 15:25:40 +03:00
// Check what happens if vfs-suffixed files exist on the server or locally
// while the file is hydrated
void testSuffixFilesWhileLocalHydrated ( )
2019-01-10 15:26:26 +03:00
{
FakeFolder fakeFolder { FileInfo ( ) } ;
2019-10-07 16:25:36 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2019-01-10 15:26:26 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
} ;
cleanup ( ) ;
2019-08-02 15:25:40 +03:00
// suffixed files are happily synced with Vfs::Off
2019-01-10 15:26:26 +03:00
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
2019-08-02 15:25:40 +03:00
fakeFolder . remoteModifier ( ) . insert ( " A/test1 " DVSUFFIX , 10 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/test2 " DVSUFFIX , 20 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file1 " DVSUFFIX , 30 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file2 " , 40 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file2 " DVSUFFIX , 50 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file3 " , 60 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file3 " DVSUFFIX , 70 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file3 " DVSUFFIX DVSUFFIX , 80 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/remote1 " DVSUFFIX , 30 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/remote2 " , 40 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/remote2 " DVSUFFIX , 50 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/remote3 " , 60 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/remote3 " DVSUFFIX , 70 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/remote3 " DVSUFFIX DVSUFFIX , 80 , ' A ' ) ;
2019-01-10 15:26:26 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
cleanup ( ) ;
// Enable suffix vfs
2019-01-23 17:12:02 +03:00
setupVfs ( fakeFolder ) ;
2019-01-10 15:26:26 +03:00
2019-08-02 15:25:40 +03:00
// A simple sync removes the files that are now ignored (?)
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file1 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file2 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file3 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file3 " DVSUFFIX DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
cleanup ( ) ;
// Add a real file where the suffixed file exists
fakeFolder . localModifier ( ) . insert ( " A/test1 " , 11 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/test2 " , 21 , ' A ' ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/test1 " , CSYNC_INSTRUCTION_NEW ) ) ;
// this isn't fully good since some code requires size == 1 for placeholders
// (when renaming placeholder to real file). But the alternative would mean
// special casing this to allow CONFLICT at virtual file creation level. Ew.
QVERIFY ( itemInstruction ( completeSpy , " A/test2 " DVSUFFIX , CSYNC_INSTRUCTION_UPDATE_METADATA ) ) ;
cleanup ( ) ;
2019-01-10 15:26:26 +03:00
// Local changes of suffixed file do nothing
2019-08-02 15:25:40 +03:00
fakeFolder . localModifier ( ) . setContents ( " A/file1 " DVSUFFIX , ' B ' ) ;
fakeFolder . localModifier ( ) . setContents ( " A/file2 " DVSUFFIX , ' B ' ) ;
fakeFolder . localModifier ( ) . setContents ( " A/file3 " DVSUFFIX , ' B ' ) ;
fakeFolder . localModifier ( ) . setContents ( " A/file3 " DVSUFFIX DVSUFFIX , ' B ' ) ;
2019-01-10 15:26:26 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/file1 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
2019-08-02 15:25:40 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/file2 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file3 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file3 " DVSUFFIX DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
2019-01-10 15:26:26 +03:00
cleanup ( ) ;
2019-08-02 15:25:40 +03:00
// Remote changes don't do anything either
fakeFolder . remoteModifier ( ) . setContents ( " A/file1 " DVSUFFIX , ' C ' ) ;
fakeFolder . remoteModifier ( ) . setContents ( " A/file2 " DVSUFFIX , ' C ' ) ;
fakeFolder . remoteModifier ( ) . setContents ( " A/file3 " DVSUFFIX , ' C ' ) ;
fakeFolder . remoteModifier ( ) . setContents ( " A/file3 " DVSUFFIX DVSUFFIX , ' C ' ) ;
2019-01-10 15:26:26 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/file1 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
2019-08-02 15:25:40 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/file2 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file3 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file3 " DVSUFFIX DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
2019-01-10 15:26:26 +03:00
cleanup ( ) ;
2019-08-02 15:25:40 +03:00
// Local removal: when not querying server
fakeFolder . localModifier ( ) . remove ( " A/file1 " DVSUFFIX ) ;
fakeFolder . localModifier ( ) . remove ( " A/file2 " DVSUFFIX ) ;
fakeFolder . localModifier ( ) . remove ( " A/file3 " DVSUFFIX ) ;
fakeFolder . localModifier ( ) . remove ( " A/file3 " DVSUFFIX DVSUFFIX ) ;
2019-01-10 15:26:26 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2019-10-30 19:49:25 +03:00
QVERIFY ( completeSpy . findItem ( " A/file1 " DVSUFFIX ) - > isEmpty ( ) ) ;
QVERIFY ( completeSpy . findItem ( " A/file2 " DVSUFFIX ) - > isEmpty ( ) ) ;
QVERIFY ( completeSpy . findItem ( " A/file3 " DVSUFFIX ) - > isEmpty ( ) ) ;
QVERIFY ( completeSpy . findItem ( " A/file3 " DVSUFFIX DVSUFFIX ) - > isEmpty ( ) ) ;
2019-08-02 15:25:40 +03:00
cleanup ( ) ;
// Local removal: when querying server
fakeFolder . remoteModifier ( ) . setContents ( " A/file1 " DVSUFFIX , ' D ' ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file1 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
2019-06-28 11:44:13 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/file2 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
2019-08-02 15:25:40 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/file3 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file3 " DVSUFFIX DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
cleanup ( ) ;
// Remote removal
fakeFolder . remoteModifier ( ) . remove ( " A/remote1 " DVSUFFIX ) ;
fakeFolder . remoteModifier ( ) . remove ( " A/remote2 " DVSUFFIX ) ;
fakeFolder . remoteModifier ( ) . remove ( " A/remote3 " DVSUFFIX ) ;
fakeFolder . remoteModifier ( ) . remove ( " A/remote3 " DVSUFFIX DVSUFFIX ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/remote1 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/remote2 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/remote3 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/remote3 " DVSUFFIX DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
cleanup ( ) ;
// New files with a suffix aren't propagated downwards in the first place
fakeFolder . remoteModifier ( ) . insert ( " A/new1 " DVSUFFIX ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/new1 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( fakeFolder . currentRemoteState ( ) . find ( " A/new1 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/new1 " ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/new1 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/new1 " DVSUFFIX DVSUFFIX ) ) ;
cleanup ( ) ;
}
// Check what happens if vfs-suffixed files exist on the server or in the db
void testExtraFilesLocalDehydrated ( )
{
FakeFolder fakeFolder { FileInfo ( ) } ;
setupVfs ( fakeFolder ) ;
2019-10-30 19:49:25 +03:00
ItemCompletedSpy completeSpy ( fakeFolder ) ;
2019-08-02 15:25:40 +03:00
auto cleanup = [ & ] ( ) {
completeSpy . clear ( ) ;
} ;
cleanup ( ) ;
// create a bunch of local virtual files, in some instances
// ignore remote files
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file1 " , 30 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file2 " , 40 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file3 " , 60 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file3 " DVSUFFIX , 70 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file4 " , 80 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file4 " DVSUFFIX , 90 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file4 " DVSUFFIX DVSUFFIX , 100 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file5 " , 110 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file6 " , 120 , ' A ' ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/file1 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/file1 " DVSUFFIX ) ) ;
2019-01-10 15:26:26 +03:00
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/file2 " ) ) ;
2019-08-02 15:25:40 +03:00
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/file2 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/file3 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/file3 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/file4 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " A/file4 " DVSUFFIX ) ) ;
QVERIFY ( ! fakeFolder . currentLocalState ( ) . find ( " A/file4 " DVSUFFIX DVSUFFIX ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file1 " DVSUFFIX , CSYNC_INSTRUCTION_NEW ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file2 " DVSUFFIX , CSYNC_INSTRUCTION_NEW ) ) ;
2019-10-30 20:25:52 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/file3 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file4 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
2019-08-02 15:25:40 +03:00
QVERIFY ( itemInstruction ( completeSpy , " A/file4 " DVSUFFIX DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
cleanup ( ) ;
// Create odd extra files locally and remotely
fakeFolder . localModifier ( ) . insert ( " A/file1 " , 10 , ' A ' ) ;
fakeFolder . localModifier ( ) . insert ( " A/file2 " DVSUFFIX DVSUFFIX , 10 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file5 " DVSUFFIX , 10 , ' A ' ) ;
fakeFolder . localModifier ( ) . insert ( " A/file6 " , 10 , ' A ' ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/file6 " DVSUFFIX , 10 , ' A ' ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file1 " , CSYNC_INSTRUCTION_CONFLICT ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file1 " DVSUFFIX , CSYNC_INSTRUCTION_REMOVE ) ) ; // it's now a pointless real virtual file
QVERIFY ( itemInstruction ( completeSpy , " A/file2 " DVSUFFIX DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file5 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file6 " , CSYNC_INSTRUCTION_CONFLICT ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/file6 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
2019-01-10 15:26:26 +03:00
cleanup ( ) ;
}
2019-04-03 11:53:04 +03:00
void testAvailability ( )
{
FakeFolder fakeFolder { FileInfo ( ) } ;
auto vfs = setupVfs ( fakeFolder ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
auto setPin = [ & ] ( const QByteArray & path , PinState state ) {
fakeFolder . syncJournal ( ) . internalPinStates ( ) . setForPath ( path , state ) ;
} ;
fakeFolder . remoteModifier ( ) . mkdir ( " local " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " local/sub " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " online " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " online/sub " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " unspec " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
setPin ( " local " , PinState : : AlwaysLocal ) ;
setPin ( " online " , PinState : : OnlineOnly ) ;
setPin ( " unspec " , PinState : : Unspecified ) ;
fakeFolder . remoteModifier ( ) . insert ( " file1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " online/file1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " online/file2 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " local/file1 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " local/file2 " ) ;
fakeFolder . remoteModifier ( ) . insert ( " unspec/file1 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
// root is unspecified
2024-03-22 19:24:40 +03:00
QCOMPARE ( * vfs - > availability ( " file1 " DVSUFFIX , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : AllDehydrated ) ;
QCOMPARE ( * vfs - > availability ( " local " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : AlwaysLocal ) ;
QCOMPARE ( * vfs - > availability ( " local/file1 " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : AlwaysLocal ) ;
QCOMPARE ( * vfs - > availability ( " online " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : OnlineOnly ) ;
QCOMPARE ( * vfs - > availability ( " online/file1 " DVSUFFIX , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : OnlineOnly ) ;
QCOMPARE ( * vfs - > availability ( " unspec " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : AllDehydrated ) ;
QCOMPARE ( * vfs - > availability ( " unspec/file1 " DVSUFFIX , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : AllDehydrated ) ;
2019-04-03 11:53:04 +03:00
// Subitem pin states can ruin "pure" availabilities
setPin ( " local/sub " , PinState : : OnlineOnly ) ;
2024-03-22 19:24:40 +03:00
QCOMPARE ( * vfs - > availability ( " local " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : AllHydrated ) ;
2019-04-03 11:53:04 +03:00
setPin ( " online/sub " , PinState : : Unspecified ) ;
2024-03-22 19:24:40 +03:00
QCOMPARE ( * vfs - > availability ( " online " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : AllDehydrated ) ;
2019-04-03 11:53:04 +03:00
triggerDownload ( fakeFolder , " unspec/file1 " ) ;
setPin ( " local/file2 " , PinState : : OnlineOnly ) ;
2019-06-28 11:44:13 +03:00
setPin ( " online/file2 " DVSUFFIX , PinState : : AlwaysLocal ) ;
2019-04-03 11:53:04 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2024-03-22 19:24:40 +03:00
QCOMPARE ( * vfs - > availability ( " unspec " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : AllHydrated ) ;
QCOMPARE ( * vfs - > availability ( " local " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : Mixed ) ;
QCOMPARE ( * vfs - > availability ( " online " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : Mixed ) ;
2019-04-03 11:53:04 +03:00
2021-07-23 18:30:48 +03:00
QVERIFY ( vfs - > setPinState ( " local " , PinState : : AlwaysLocal ) ) ;
QVERIFY ( vfs - > setPinState ( " online " , PinState : : OnlineOnly ) ) ;
2019-04-03 11:53:04 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
2024-03-22 19:24:40 +03:00
QCOMPARE ( * vfs - > availability ( " online " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : OnlineOnly ) ;
QCOMPARE ( * vfs - > availability ( " local " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) , VfsItemAvailability : : AlwaysLocal ) ;
2019-05-07 09:21:46 +03:00
2024-03-22 19:24:40 +03:00
auto r = vfs - > availability ( " nonexistent " , Vfs : : AvailabilityRecursivity : : RecursiveAvailability ) ;
2019-05-07 09:21:46 +03:00
QVERIFY ( ! r ) ;
QCOMPARE ( r . error ( ) , Vfs : : AvailabilityError : : NoSuchItem ) ;
2019-04-03 11:53:04 +03:00
}
2019-06-21 10:06:07 +03:00
void testPinStateLocals ( )
{
FakeFolder fakeFolder { FileInfo ( ) } ;
auto vfs = setupVfs ( fakeFolder ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
auto setPin = [ & ] ( const QByteArray & path , PinState state ) {
fakeFolder . syncJournal ( ) . internalPinStates ( ) . setForPath ( path , state ) ;
} ;
fakeFolder . remoteModifier ( ) . mkdir ( " local " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " online " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " unspec " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
setPin ( " local " , PinState : : AlwaysLocal ) ;
setPin ( " online " , PinState : : OnlineOnly ) ;
setPin ( " unspec " , PinState : : Unspecified ) ;
fakeFolder . localModifier ( ) . insert ( " file1 " ) ;
fakeFolder . localModifier ( ) . insert ( " online/file1 " ) ;
fakeFolder . localModifier ( ) . insert ( " online/file2 " ) ;
fakeFolder . localModifier ( ) . insert ( " local/file1 " ) ;
fakeFolder . localModifier ( ) . insert ( " unspec/file1 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
// root is unspecified
2019-06-28 11:44:13 +03:00
QCOMPARE ( * vfs - > pinState ( " file1 " DVSUFFIX ) , PinState : : Unspecified ) ;
2019-06-21 10:06:07 +03:00
QCOMPARE ( * vfs - > pinState ( " local/file1 " ) , PinState : : AlwaysLocal ) ;
QCOMPARE ( * vfs - > pinState ( " online/file1 " ) , PinState : : Unspecified ) ;
QCOMPARE ( * vfs - > pinState ( " unspec/file1 " ) , PinState : : Unspecified ) ;
// Sync again: bad pin states of new local files usually take effect on second sync
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2019-06-21 10:39:33 +03:00
// When a file in an online-only folder is renamed, it retains its pin
fakeFolder . localModifier ( ) . rename ( " online/file1 " , " online/file1rename " ) ;
fakeFolder . remoteModifier ( ) . rename ( " online/file2 " , " online/file2rename " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( * vfs - > pinState ( " online/file1rename " ) , PinState : : Unspecified ) ;
QCOMPARE ( * vfs - > pinState ( " online/file2rename " ) , PinState : : Unspecified ) ;
// When a folder is renamed, the pin states inside should be retained
fakeFolder . localModifier ( ) . rename ( " online " , " onlinerenamed1 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( * vfs - > pinState ( " onlinerenamed1 " ) , PinState : : OnlineOnly ) ;
QCOMPARE ( * vfs - > pinState ( " onlinerenamed1/file1rename " ) , PinState : : Unspecified ) ;
fakeFolder . remoteModifier ( ) . rename ( " onlinerenamed1 " , " onlinerenamed2 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( * vfs - > pinState ( " onlinerenamed2 " ) , PinState : : OnlineOnly ) ;
QCOMPARE ( * vfs - > pinState ( " onlinerenamed2/file1rename " ) , PinState : : Unspecified ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
2019-06-27 16:47:04 +03:00
// When a file is deleted and later a new file has the same name, the old pin
// state isn't preserved.
QCOMPARE ( * vfs - > pinState ( " onlinerenamed2/file1rename " ) , PinState : : Unspecified ) ;
fakeFolder . remoteModifier ( ) . remove ( " onlinerenamed2/file1rename " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( * vfs - > pinState ( " onlinerenamed2/file1rename " ) , PinState : : OnlineOnly ) ;
fakeFolder . remoteModifier ( ) . insert ( " onlinerenamed2/file1rename " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( * vfs - > pinState ( " onlinerenamed2/file1rename " ) , PinState : : OnlineOnly ) ;
2019-06-28 11:44:13 +03:00
QCOMPARE ( * vfs - > pinState ( " onlinerenamed2/file1rename " DVSUFFIX ) , PinState : : OnlineOnly ) ;
2019-07-18 16:30:40 +03:00
// When a file is hydrated or dehydrated due to pin state it retains its pin state
2021-07-23 18:30:48 +03:00
QVERIFY ( vfs - > setPinState ( " onlinerenamed2/file1rename " DVSUFFIX , PinState : : AlwaysLocal ) ) ;
2019-07-18 16:30:40 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " onlinerenamed2/file1rename " ) ) ;
QCOMPARE ( * vfs - > pinState ( " onlinerenamed2/file1rename " ) , PinState : : AlwaysLocal ) ;
2021-07-23 18:30:48 +03:00
QVERIFY ( vfs - > setPinState ( " onlinerenamed2 " , PinState : : Unspecified ) ) ;
QVERIFY ( vfs - > setPinState ( " onlinerenamed2/file1rename " , PinState : : OnlineOnly ) ) ;
2019-07-18 16:30:40 +03:00
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " onlinerenamed2/file1rename " DVSUFFIX ) ) ;
QCOMPARE ( * vfs - > pinState ( " onlinerenamed2/file1rename " DVSUFFIX ) , PinState : : OnlineOnly ) ;
2019-06-21 10:06:07 +03:00
}
2019-07-24 16:25:02 +03:00
void testIncompatiblePins ( )
{
FakeFolder fakeFolder { FileInfo ( ) } ;
auto vfs = setupVfs ( fakeFolder ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
auto setPin = [ & ] ( const QByteArray & path , PinState state ) {
fakeFolder . syncJournal ( ) . internalPinStates ( ) . setForPath ( path , state ) ;
} ;
fakeFolder . remoteModifier ( ) . mkdir ( " local " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " online " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
setPin ( " local " , PinState : : AlwaysLocal ) ;
setPin ( " online " , PinState : : OnlineOnly ) ;
fakeFolder . localModifier ( ) . insert ( " local/file1 " ) ;
fakeFolder . localModifier ( ) . insert ( " online/file1 " ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
markForDehydration ( fakeFolder , " local/file1 " ) ;
triggerDownload ( fakeFolder , " online/file1 " ) ;
// the sync sets the changed files pin states to unspecified
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " online/file1 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " local/file1 " DVSUFFIX ) ) ;
QCOMPARE ( * vfs - > pinState ( " online/file1 " ) , PinState : : Unspecified ) ;
QCOMPARE ( * vfs - > pinState ( " local/file1 " DVSUFFIX ) , PinState : : Unspecified ) ;
// no change on another sync
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " online/file1 " ) ) ;
QVERIFY ( fakeFolder . currentLocalState ( ) . find ( " local/file1 " DVSUFFIX ) ) ;
}
2019-10-30 15:16:32 +03:00
void testPlaceHolderExist ( ) {
FakeFolder fakeFolder { FileInfo : : A12_B12_C12_S12 ( ) } ;
fakeFolder . remoteModifier ( ) . insert ( " A/a1 " DVSUFFIX , 111 ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/hello " DVSUFFIX , 222 ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
auto vfs = setupVfs ( fakeFolder ) ;
ItemCompletedSpy completeSpy ( fakeFolder ) ;
auto cleanup = [ & ] ( ) { completeSpy . clear ( ) ; } ;
cleanup ( ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/hello " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a2 " DVSUFFIX ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/hello " , 12 ) ;
fakeFolder . localModifier ( ) . insert ( " A/igno " DVSUFFIX , 123 ) ;
cleanup ( ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/a1 " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/igno " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
// verify that the files are still present
QCOMPARE ( fakeFolder . currentLocalState ( ) . find ( " A/hello " DVSUFFIX ) - > size , 222 ) ;
QCOMPARE ( * fakeFolder . currentLocalState ( ) . find ( " A/hello " DVSUFFIX ) ,
* fakeFolder . currentRemoteState ( ) . find ( " A/hello " DVSUFFIX ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) . find ( " A/igno " DVSUFFIX ) - > size , 123 ) ;
cleanup ( ) ;
// Dehydrate
2021-07-23 18:30:48 +03:00
QVERIFY ( vfs - > setPinState ( QString ( ) , PinState : : OnlineOnly ) ) ;
2019-10-30 15:16:32 +03:00
QVERIFY ( ! fakeFolder . syncOnce ( ) ) ;
QVERIFY ( itemInstruction ( completeSpy , " A/igno " DVSUFFIX , CSYNC_INSTRUCTION_IGNORE ) ) ;
// verify that the files are still present
QCOMPARE ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) - > size , 111 ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) . find ( " A/hello " DVSUFFIX ) - > size , 222 ) ;
QCOMPARE ( * fakeFolder . currentLocalState ( ) . find ( " A/hello " DVSUFFIX ) ,
* fakeFolder . currentRemoteState ( ) . find ( " A/hello " DVSUFFIX ) ) ;
QCOMPARE ( * fakeFolder . currentLocalState ( ) . find ( " A/a1 " ) ,
* fakeFolder . currentRemoteState ( ) . find ( " A/a1 " ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) . find ( " A/igno " DVSUFFIX ) - > size , 123 ) ;
// Now disable vfs and check that all files are still there
cleanup ( ) ;
SyncEngine : : wipeVirtualFiles ( fakeFolder . localPath ( ) , fakeFolder . syncJournal ( ) , * vfs ) ;
fakeFolder . switchToVfs ( QSharedPointer < Vfs > ( new VfsOff ) ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) . find ( " A/a1 " DVSUFFIX ) - > size , 111 ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) . find ( " A/hello " ) - > size , 12 ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) . find ( " A/hello " DVSUFFIX ) - > size , 222 ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) . find ( " A/igno " DVSUFFIX ) - > size , 123 ) ;
}
2022-03-03 12:53:50 +03:00
void testUpdateMetadataErrorManagement ( )
{
FakeFolder fakeFolder { FileInfo { } } ;
setupVfs ( fakeFolder ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
// Existing files are propagated just fine in both directions
fakeFolder . remoteModifier ( ) . mkdir ( QStringLiteral ( " aaa " ) ) ;
fakeFolder . remoteModifier ( ) . mkdir ( QStringLiteral ( " aaa/subfolder " ) ) ;
fakeFolder . remoteModifier ( ) . insert ( QStringLiteral ( " aaa/subfolder/bar " ) ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
// New files on the remote create virtual files
fakeFolder . remoteModifier ( ) . setModTime ( QStringLiteral ( " aaa/subfolder/bar " ) , QDateTime : : fromSecsSinceEpoch ( 0 ) ) ;
QVERIFY ( ! fakeFolder . syncOnce ( ) ) ;
QVERIFY ( ! fakeFolder . syncOnce ( ) ) ;
}
void testInvalidFutureMtimeRecovery ( )
{
constexpr auto FUTURE_MTIME = 0xFFFFFFFF ;
constexpr auto CURRENT_MTIME = 1646057277 ;
FakeFolder fakeFolder { FileInfo { } } ;
setupVfs ( fakeFolder ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
const QString fooFileRootFolder ( " foo " ) ;
const QString barFileRootFolder ( " bar " ) ;
const QString fooFileSubFolder ( " subfolder/foo " ) ;
const QString barFileSubFolder ( " subfolder/bar " ) ;
const QString fooFileAaaSubFolder ( " aaa/subfolder/foo " ) ;
const QString barFileAaaSubFolder ( " aaa/subfolder/bar " ) ;
fakeFolder . remoteModifier ( ) . insert ( fooFileRootFolder ) ;
fakeFolder . remoteModifier ( ) . insert ( barFileRootFolder ) ;
fakeFolder . remoteModifier ( ) . mkdir ( QStringLiteral ( " subfolder " ) ) ;
fakeFolder . remoteModifier ( ) . insert ( fooFileSubFolder ) ;
fakeFolder . remoteModifier ( ) . insert ( barFileSubFolder ) ;
fakeFolder . remoteModifier ( ) . mkdir ( QStringLiteral ( " aaa " ) ) ;
fakeFolder . remoteModifier ( ) . mkdir ( QStringLiteral ( " aaa/subfolder " ) ) ;
fakeFolder . remoteModifier ( ) . insert ( fooFileAaaSubFolder ) ;
fakeFolder . remoteModifier ( ) . insert ( barFileAaaSubFolder ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
fakeFolder . remoteModifier ( ) . setModTimeKeepEtag ( fooFileRootFolder , QDateTime : : fromSecsSinceEpoch ( CURRENT_MTIME ) ) ;
fakeFolder . remoteModifier ( ) . setModTimeKeepEtag ( barFileRootFolder , QDateTime : : fromSecsSinceEpoch ( CURRENT_MTIME ) ) ;
fakeFolder . remoteModifier ( ) . setModTimeKeepEtag ( fooFileSubFolder , QDateTime : : fromSecsSinceEpoch ( CURRENT_MTIME ) ) ;
fakeFolder . remoteModifier ( ) . setModTimeKeepEtag ( barFileSubFolder , QDateTime : : fromSecsSinceEpoch ( CURRENT_MTIME ) ) ;
fakeFolder . remoteModifier ( ) . setModTimeKeepEtag ( fooFileAaaSubFolder , QDateTime : : fromSecsSinceEpoch ( CURRENT_MTIME ) ) ;
fakeFolder . remoteModifier ( ) . setModTimeKeepEtag ( barFileAaaSubFolder , QDateTime : : fromSecsSinceEpoch ( CURRENT_MTIME ) ) ;
fakeFolder . localModifier ( ) . setModTime ( fooFileRootFolder + DVSUFFIX , QDateTime : : fromSecsSinceEpoch ( FUTURE_MTIME ) ) ;
fakeFolder . localModifier ( ) . setModTime ( barFileRootFolder + DVSUFFIX , QDateTime : : fromSecsSinceEpoch ( FUTURE_MTIME ) ) ;
fakeFolder . localModifier ( ) . setModTime ( fooFileSubFolder + DVSUFFIX , QDateTime : : fromSecsSinceEpoch ( FUTURE_MTIME ) ) ;
fakeFolder . localModifier ( ) . setModTime ( barFileSubFolder + DVSUFFIX , QDateTime : : fromSecsSinceEpoch ( FUTURE_MTIME ) ) ;
fakeFolder . localModifier ( ) . setModTime ( fooFileAaaSubFolder + DVSUFFIX , QDateTime : : fromSecsSinceEpoch ( FUTURE_MTIME ) ) ;
fakeFolder . localModifier ( ) . setModTime ( barFileAaaSubFolder + DVSUFFIX , QDateTime : : fromSecsSinceEpoch ( FUTURE_MTIME ) ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
}
2022-03-04 20:48:12 +03:00
void testInvalidMtimeLocalDiscovery ( )
{
constexpr auto INVALID_MTIME1 = 0 ;
constexpr auto INVALID_MTIME2 = 0xFFFFFFFF ;
constexpr auto CURRENT_MTIME = 1646057277 ;
FakeFolder fakeFolder { FileInfo { } } ;
setupVfs ( fakeFolder ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
QSignalSpy statusSpy ( & fakeFolder . syncEngine ( ) . syncFileStatusTracker ( ) , & SyncFileStatusTracker : : fileStatusChanged ) ;
const QString fooFileRootFolder ( " foo " ) ;
const QString barFileRootFolder ( " bar " ) ;
const QString fooFileSubFolder ( " subfolder/foo " ) ;
const QString barFileSubFolder ( " subfolder/bar " ) ;
const QString fooFileAaaSubFolder ( " aaa/subfolder/foo " ) ;
const QString barFileAaaSubFolder ( " aaa/subfolder/bar " ) ;
auto checkStatus = [ & ] ( ) - > SyncFileStatus : : SyncFileStatusTag {
auto file = QFileInfo { fakeFolder . syncEngine ( ) . localPath ( ) , barFileAaaSubFolder } ;
auto locPath = fakeFolder . syncEngine ( ) . localPath ( ) ;
auto itemFound = false ;
// Start from the end to get the latest status
for ( int i = statusSpy . size ( ) - 1 ; i > = 0 & & ! itemFound ; - - i ) {
if ( QFileInfo ( statusSpy . at ( i ) [ 0 ] . toString ( ) ) = = file ) {
itemFound = true ;
return statusSpy . at ( i ) [ 1 ] . value < SyncFileStatus > ( ) . tag ( ) ;
}
}
return { } ;
} ;
fakeFolder . localModifier ( ) . insert ( fooFileRootFolder ) ;
fakeFolder . localModifier ( ) . insert ( barFileRootFolder ) ;
fakeFolder . localModifier ( ) . mkdir ( QStringLiteral ( " subfolder " ) ) ;
fakeFolder . localModifier ( ) . insert ( fooFileSubFolder ) ;
fakeFolder . localModifier ( ) . insert ( barFileSubFolder ) ;
fakeFolder . localModifier ( ) . mkdir ( QStringLiteral ( " aaa " ) ) ;
fakeFolder . localModifier ( ) . mkdir ( QStringLiteral ( " aaa/subfolder " ) ) ;
fakeFolder . localModifier ( ) . insert ( fooFileAaaSubFolder ) ;
fakeFolder . localModifier ( ) . insert ( barFileAaaSubFolder ) ;
fakeFolder . localModifier ( ) . setModTime ( barFileAaaSubFolder , QDateTime : : fromSecsSinceEpoch ( INVALID_MTIME1 ) ) ;
fakeFolder . scheduleSync ( ) ;
fakeFolder . execUntilBeforePropagation ( ) ;
QCOMPARE ( checkStatus ( ) , SyncFileStatus : : StatusError ) ;
fakeFolder . execUntilFinished ( ) ;
fakeFolder . localModifier ( ) . setModTime ( barFileAaaSubFolder , QDateTime : : fromSecsSinceEpoch ( CURRENT_MTIME ) ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
fakeFolder . localModifier ( ) . appendByte ( barFileAaaSubFolder ) ;
fakeFolder . localModifier ( ) . setModTime ( barFileAaaSubFolder , QDateTime : : fromSecsSinceEpoch ( INVALID_MTIME1 ) ) ;
fakeFolder . scheduleSync ( ) ;
fakeFolder . execUntilBeforePropagation ( ) ;
QCOMPARE ( checkStatus ( ) , SyncFileStatus : : StatusError ) ;
fakeFolder . execUntilFinished ( ) ;
fakeFolder . localModifier ( ) . setModTime ( barFileAaaSubFolder , QDateTime : : fromSecsSinceEpoch ( CURRENT_MTIME ) ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
fakeFolder . localModifier ( ) . appendByte ( barFileAaaSubFolder ) ;
fakeFolder . localModifier ( ) . setModTime ( barFileAaaSubFolder , QDateTime : : fromSecsSinceEpoch ( INVALID_MTIME2 ) ) ;
fakeFolder . scheduleSync ( ) ;
fakeFolder . execUntilBeforePropagation ( ) ;
QCOMPARE ( checkStatus ( ) , SyncFileStatus : : StatusError ) ;
2022-11-30 12:34:49 +03:00
fakeFolder . execUntilFinished ( ) ;
}
void testServer_caseClash_createConflict ( )
{
constexpr auto testLowerCaseFile = " test " ;
constexpr auto testUpperCaseFile = " TEST " ;
# if defined Q_OS_LINUX
constexpr auto shouldHaveCaseClashConflict = false ;
# else
constexpr auto shouldHaveCaseClashConflict = true ;
# endif
FakeFolder fakeFolder { FileInfo { } } ;
setupVfs ( fakeFolder ) ;
fakeFolder . remoteModifier ( ) . insert ( " otherFile.txt " ) ;
fakeFolder . remoteModifier ( ) . insert ( testLowerCaseFile ) ;
fakeFolder . remoteModifier ( ) . insert ( testUpperCaseFile ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
auto conflicts = findCaseClashConflicts ( fakeFolder . currentLocalState ( ) ) ;
QCOMPARE ( conflicts . size ( ) , shouldHaveCaseClashConflict ? 1 : 0 ) ;
const auto hasConflict = expectConflict ( fakeFolder . currentLocalState ( ) , testLowerCaseFile ) ;
QCOMPARE ( hasConflict , shouldHaveCaseClashConflict ? true : false ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
conflicts = findCaseClashConflicts ( fakeFolder . currentLocalState ( ) ) ;
QCOMPARE ( conflicts . size ( ) , shouldHaveCaseClashConflict ? 1 : 0 ) ;
}
void testServer_subFolderCaseClash_createConflict ( )
{
constexpr auto testLowerCaseFile = " a/b/test " ;
constexpr auto testUpperCaseFile = " a/b/TEST " ;
# if defined Q_OS_LINUX
constexpr auto shouldHaveCaseClashConflict = false ;
# else
constexpr auto shouldHaveCaseClashConflict = true ;
# endif
FakeFolder fakeFolder { FileInfo { } } ;
setupVfs ( fakeFolder ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " a " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " a/b " ) ;
fakeFolder . remoteModifier ( ) . insert ( " a/b/otherFile.txt " ) ;
fakeFolder . remoteModifier ( ) . insert ( testLowerCaseFile ) ;
fakeFolder . remoteModifier ( ) . insert ( testUpperCaseFile ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
auto conflicts = findCaseClashConflicts ( * fakeFolder . currentLocalState ( ) . find ( " a/b " ) ) ;
QCOMPARE ( conflicts . size ( ) , shouldHaveCaseClashConflict ? 1 : 0 ) ;
const auto hasConflict = expectConflict ( fakeFolder . currentLocalState ( ) , testLowerCaseFile ) ;
QCOMPARE ( hasConflict , shouldHaveCaseClashConflict ? true : false ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
conflicts = findCaseClashConflicts ( * fakeFolder . currentLocalState ( ) . find ( " a/b " ) ) ;
QCOMPARE ( conflicts . size ( ) , shouldHaveCaseClashConflict ? 1 : 0 ) ;
}
void testServer_caseClash_createConflictOnMove ( )
{
constexpr auto testLowerCaseFile = " test " ;
constexpr auto testUpperCaseFile = " TEST2 " ;
constexpr auto testUpperCaseFileAfterMove = " TEST " ;
# if defined Q_OS_LINUX
constexpr auto shouldHaveCaseClashConflict = false ;
# else
constexpr auto shouldHaveCaseClashConflict = true ;
# endif
FakeFolder fakeFolder { FileInfo { } } ;
setupVfs ( fakeFolder ) ;
fakeFolder . remoteModifier ( ) . insert ( " otherFile.txt " ) ;
fakeFolder . remoteModifier ( ) . insert ( testLowerCaseFile ) ;
fakeFolder . remoteModifier ( ) . insert ( testUpperCaseFile ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
auto conflicts = findCaseClashConflicts ( fakeFolder . currentLocalState ( ) ) ;
QCOMPARE ( conflicts . size ( ) , 0 ) ;
const auto hasConflict = expectConflict ( fakeFolder . currentLocalState ( ) , testLowerCaseFile ) ;
QCOMPARE ( hasConflict , false ) ;
fakeFolder . remoteModifier ( ) . rename ( testUpperCaseFile , testUpperCaseFileAfterMove ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
conflicts = findCaseClashConflicts ( fakeFolder . currentLocalState ( ) ) ;
QCOMPARE ( conflicts . size ( ) , shouldHaveCaseClashConflict ? 1 : 0 ) ;
const auto hasConflictAfterMove = expectConflict ( fakeFolder . currentLocalState ( ) , testUpperCaseFileAfterMove ) ;
QCOMPARE ( hasConflictAfterMove , shouldHaveCaseClashConflict ? true : false ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
conflicts = findCaseClashConflicts ( fakeFolder . currentLocalState ( ) ) ;
QCOMPARE ( conflicts . size ( ) , shouldHaveCaseClashConflict ? 1 : 0 ) ;
}
void testServer_subFolderCaseClash_createConflictOnMove ( )
{
constexpr auto testLowerCaseFile = " a/b/test " ;
constexpr auto testUpperCaseFile = " a/b/TEST2 " ;
constexpr auto testUpperCaseFileAfterMove = " a/b/TEST " ;
# if defined Q_OS_LINUX
constexpr auto shouldHaveCaseClashConflict = false ;
# else
constexpr auto shouldHaveCaseClashConflict = true ;
# endif
FakeFolder fakeFolder { FileInfo { } } ;
setupVfs ( fakeFolder ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " a " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " a/b " ) ;
fakeFolder . remoteModifier ( ) . insert ( " a/b/otherFile.txt " ) ;
fakeFolder . remoteModifier ( ) . insert ( testLowerCaseFile ) ;
fakeFolder . remoteModifier ( ) . insert ( testUpperCaseFile ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
auto conflicts = findCaseClashConflicts ( * fakeFolder . currentLocalState ( ) . find ( " a/b " ) ) ;
QCOMPARE ( conflicts . size ( ) , 0 ) ;
const auto hasConflict = expectConflict ( fakeFolder . currentLocalState ( ) , testLowerCaseFile ) ;
QCOMPARE ( hasConflict , false ) ;
fakeFolder . remoteModifier ( ) . rename ( testUpperCaseFile , testUpperCaseFileAfterMove ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
conflicts = findCaseClashConflicts ( * fakeFolder . currentLocalState ( ) . find ( " a/b " ) ) ;
QCOMPARE ( conflicts . size ( ) , shouldHaveCaseClashConflict ? 1 : 0 ) ;
const auto hasConflictAfterMove = expectConflict ( fakeFolder . currentLocalState ( ) , testUpperCaseFileAfterMove ) ;
QCOMPARE ( hasConflictAfterMove , shouldHaveCaseClashConflict ? true : false ) ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
conflicts = findCaseClashConflicts ( * fakeFolder . currentLocalState ( ) . find ( " a/b " ) ) ;
QCOMPARE ( conflicts . size ( ) , shouldHaveCaseClashConflict ? 1 : 0 ) ;
2022-03-04 20:48:12 +03:00
}
2023-03-06 18:27:57 +03:00
void testDataFingerPrint ( )
{
FakeFolder fakeFolder { FileInfo { } } ;
setupVfs ( fakeFolder ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " a " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " a/b " ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " a/b/d " ) ;
fakeFolder . remoteModifier ( ) . insert ( " a/b/otherFile.txt " ) ;
//Server support finger print, but none is set.
fakeFolder . remoteModifier ( ) . extraDavProperties = " <oc:data-fingerprint></oc:data-fingerprint> " ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
fakeFolder . remoteModifier ( ) . remove ( " a/b/otherFile.txt " ) ;
fakeFolder . remoteModifier ( ) . remove ( " a/b/d " ) ;
fakeFolder . remoteModifier ( ) . extraDavProperties = " <oc:data-fingerprint>initial_finger_print</oc:data-fingerprint> " ;
fakeFolder . syncEngine ( ) . setLocalDiscoveryOptions ( OCC : : LocalDiscoveryStyle : : DatabaseAndFilesystem ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( fakeFolder . currentLocalState ( ) , fakeFolder . currentRemoteState ( ) ) ;
}
2023-08-21 12:31:56 +03:00
void testLockFile_lockedFileReadOnly_afterSync ( )
{
FakeFolder fakeFolder { FileInfo { } } ;
setupVfs ( fakeFolder ) ;
ItemCompletedSpy completeSpy ( fakeFolder ) ;
fakeFolder . remoteModifier ( ) . mkdir ( " A " ) ;
fakeFolder . remoteModifier ( ) . insert ( " A/a1 " ) ;
completeSpy . clear ( ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( completeSpy . findItem ( QStringLiteral ( " A/a1 " ) + DVSUFFIX ) - > _locked , OCC : : SyncFileItem : : LockStatus : : UnlockedItem ) ;
OCC : : SyncJournalFileRecord fileRecordBefore ;
QVERIFY ( fakeFolder . syncJournal ( ) . getFileRecord ( QStringLiteral ( " A/a1 " ) + DVSUFFIX , & fileRecordBefore ) ) ;
QVERIFY ( fileRecordBefore . isValid ( ) ) ;
QVERIFY ( ! fileRecordBefore . _lockstate . _locked ) ;
const auto localFileNotLocked = QFileInfo { fakeFolder . localPath ( ) + u " A/a1 " + DVSUFFIX } ;
QVERIFY ( localFileNotLocked . isWritable ( ) ) ;
fakeFolder . remoteModifier ( ) . modifyLockState ( QStringLiteral ( " A/a1 " ) , FileModifier : : LockState : : FileLocked , 1 , QStringLiteral ( " Nextcloud Office " ) , { } , QStringLiteral ( " richdocuments " ) , QDateTime : : currentDateTime ( ) . toSecsSinceEpoch ( ) , 1226 ) ;
fakeFolder . remoteModifier ( ) . setModTimeKeepEtag ( QStringLiteral ( " A/a1 " ) , QDateTime : : currentDateTime ( ) ) ;
fakeFolder . remoteModifier ( ) . appendByte ( QStringLiteral ( " A/a1 " ) ) ;
completeSpy . clear ( ) ;
QVERIFY ( fakeFolder . syncOnce ( ) ) ;
QCOMPARE ( completeSpy . findItem ( QStringLiteral ( " A/a1 " ) + DVSUFFIX ) - > _locked , OCC : : SyncFileItem : : LockStatus : : LockedItem ) ;
OCC : : SyncJournalFileRecord fileRecordLocked ;
QVERIFY ( fakeFolder . syncJournal ( ) . getFileRecord ( QStringLiteral ( " A/a1 " ) + DVSUFFIX , & fileRecordLocked ) ) ;
QVERIFY ( fileRecordLocked . isValid ( ) ) ;
QVERIFY ( fileRecordLocked . _lockstate . _locked ) ;
const auto localFileLocked = QFileInfo { fakeFolder . localPath ( ) + u " A/a1 " + DVSUFFIX } ;
QVERIFY ( ! localFileLocked . isWritable ( ) ) ;
}
2017-12-13 20:04:58 +03:00
} ;
2018-05-18 09:29:40 +03:00
QTEST_GUILESS_MAIN ( TestSyncVirtualFiles )
# include "testsyncvirtualfiles.moc"