handle NEW/NEW conflicts by being real conflicts
authorMatthieu Gallien <matthieu.gallien@nextcloud.com>
Wed, 16 Oct 2024 13:06:13 +0000 (15:06 +0200)
committerMatthieu Gallien <matthieu.gallien@nextcloud.com>
Thu, 17 Oct 2024 07:45:57 +0000 (09:45 +0200)
NEW/NEW conflicts could sometime be ignored and replaced by update
metadata instructions

we stop doing this and handle them like any other conflicts

that would cause more download from the server

those conflicts would be solved automatically in case this is not a real
conflict but the client was missing the server reply with the updated
metadata

will enable more changes to improve MOVE detection from server side

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
src/libsync/discovery.cpp
test/testchunkingng.cpp
test/testsyncengine.cpp

index cc61bfab548072dcc465db28ca1a25d1338391c7..bb8daf4a5a6a3204b1917260a171b22581276552 100644 (file)
@@ -1595,7 +1595,7 @@ void ProcessDirectoryJob::processFileConflict(const SyncFileItemPtr &item, Proce
     // If there's no content hash, use heuristics
     if (serverEntry.checksumHeader.isEmpty()) {
         // If the size or mtime is different, it's definitely a conflict.
-        bool isConflict = (serverEntry.size != localEntry.size) || (serverEntry.modtime != localEntry.modtime);
+        bool isConflict = (serverEntry.size != localEntry.size) || (serverEntry.modtime != localEntry.modtime) || (dbEntry.isValid() && dbEntry._modtime != localEntry.modtime && serverEntry.modtime == localEntry.modtime);
 
         // It could be a conflict even if size and mtime match!
         //
index 8ec79d34ad593e28c4f3b912288f81cd4d567f55..87612fab538a18b6b5278d2cc100c93c868de771 100644 (file)
@@ -328,35 +328,22 @@ private slots:
         fakeFolder.localModifier().insert("A/a0", size);
         QVERIFY(!fakeFolder.syncOnce()); // error: abort!
 
-        // Now the next sync gets a NEW/NEW conflict and since there's no checksum
-        // it just becomes a UPDATE_METADATA
-        auto checkEtagUpdated = [&](SyncFileItemVector &items) {
-            QCOMPARE(items.size(), 1);
-            QCOMPARE(items[0]->_file, QLatin1String("A"));
-            SyncJournalFileRecord record;
-            QVERIFY(fakeFolder.syncJournal().getFileRecord(QByteArray("A/a0"), &record));
-            QCOMPARE(record._etag, fakeFolder.remoteModifier().find("A/a0")->etag);
-        };
-        auto connection = connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToPropagate, checkEtagUpdated);
         QVERIFY(fakeFolder.syncOnce());
-        disconnect(connection);
         QCOMPARE(nGET, 0);
         QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
 
-
         // Test 2: modified file upload aborted
+        nGET = 0;
         fakeFolder.localModifier().appendByte("A/a0");
         QVERIFY(!fakeFolder.syncOnce()); // error: abort!
 
         // An EVAL/EVAL conflict is also UPDATE_METADATA when there's no checksums
-        connection = connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToPropagate, checkEtagUpdated);
         QVERIFY(fakeFolder.syncOnce());
-        disconnect(connection);
-        QCOMPARE(nGET, 0);
+        QCOMPARE(nGET, 1);
         QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
 
-
         // Test 3: modified file upload aborted, with good checksums
+        nGET = 0;
         fakeFolder.localModifier().appendByte("A/a0");
         QVERIFY(!fakeFolder.syncOnce()); // error: abort!
 
@@ -365,12 +352,11 @@ private slots:
         fakeFolder.remoteModifier().find("A/a0")->checksums = moveChecksumHeader;
 
         QVERIFY(fakeFolder.syncOnce());
-        disconnect(connection);
         QCOMPARE(nGET, 0); // no new download, just a metadata update!
         QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
 
-
         // Test 4: New file, that gets deleted locally before the next sync
+        nGET = 0;
         fakeFolder.localModifier().insert("A/a3", size);
         QVERIFY(!fakeFolder.syncOnce()); // error: abort!
         fakeFolder.localModifier().remove("A/a3");
index 120bc52d809e3856f9a5583927803788c6bd2c27..c46a9f7ab0143d4a179bc634d947dfef19367c85 100644 (file)
@@ -432,7 +432,7 @@ private slots:
 
         QTest::newRow("Same mtime, but no server checksum -> ignored in reconcile")
             << true << QByteArray()
-            << 0;
+            << 1;
 
         QTest::newRow("Same mtime, weak server checksum differ -> downloaded")
             << true << QByteArray("Adler32:bad")