diff options
author | Erik Verbruggen <erik@verbruggen.consulting> | 2021-12-09 16:24:22 +0300 |
---|---|---|
committer | Erik Verbruggen <Erik.Verbruggen@Me.com> | 2021-12-15 15:23:55 +0300 |
commit | 8484e759060f221cbc6f519165572e3559cbc560 (patch) | |
tree | 9c097283ddf675031ba88f4f46748f17acedfe32 /test/testutils | |
parent | 6300c004300655c2de18da42766a547137217f8a (diff) |
Tests: always check the hydration state and the mtime
operator== will now always also check the hydration state and mtime.
For the few cases where this will fail (on purpose), the equals
method can be called with `IgnoreLastModified` passed to it.
Diffstat (limited to 'test/testutils')
-rw-r--r-- | test/testutils/syncenginetestutils.cpp | 86 | ||||
-rw-r--r-- | test/testutils/syncenginetestutils.h | 66 |
2 files changed, 98 insertions, 54 deletions
diff --git a/test/testutils/syncenginetestutils.cpp b/test/testutils/syncenginetestutils.cpp index 7edcb6e19..fe72c642f 100644 --- a/test/testutils/syncenginetestutils.cpp +++ b/test/testutils/syncenginetestutils.cpp @@ -166,7 +166,10 @@ void FileInfo::appendByte(const QString &relativePath, char contentChar) Q_UNUSED(contentChar); FileInfo *file = findInvalidatingEtags(relativePath); Q_ASSERT(file); - file->contentSize += 1; + if (!file->isDehydratedPlaceholder) { + file->contentSize += 1; + } + file->fileSize += 1; } void FileInfo::modifyByte(const QString &relativePath, quint64 offset, char contentChar) @@ -203,7 +206,7 @@ void FileInfo::setModTime(const QString &relativePath, const QDateTime &modTime) { FileInfo *file = findInvalidatingEtags(relativePath); Q_ASSERT(file); - file->lastModified = modTime; + file->setLastModified(modTime); } FileInfo *FileInfo::find(PathComponents pathComponents, const bool invalidateEtags) @@ -250,44 +253,45 @@ FileInfo *FileInfo::create(const QString &relativePath, qint64 size, char conten return &child; } -bool FileInfo::operator==(const FileInfo &other) const +bool FileInfo::equals(const FileInfo &other, CompareWhat compareWhat) const { - // Consider files to be equal between local<->remote as a user would. - return name == other.name - && isDir == other.isDir - && contentSize == other.contentSize - && contentChar == other.contentChar - && children == other.children; -} - -bool FileInfo::equals(const FileInfo &other, ComparissonOption opt) const -{ - switch (opt) { - case ContentIsKing: - return *this == other; - case IgnoreContentOfDehydratedFiles: - if (!isDehydratedPlaceholder && !other.isDehydratedPlaceholder) { - if (contentSize != other.contentSize || contentChar != other.contentChar) { - return false; - } + // Only check the content and contentSize if both files are hydrated: + if (!isDehydratedPlaceholder && !other.isDehydratedPlaceholder) { + if (contentSize != other.contentSize || contentChar != other.contentChar) { + return false; } + } - if (name == other.name && isDir == other.isDir && fileSize == other.fileSize && lastModified == other.lastModified) { - if (children.size() == other.children.size()) { - for (auto it = children.constBegin(), eit = children.constEnd(), - oit = other.children.constBegin(), oeit = other.children.constEnd(); - it != eit && oit != oeit; ++it, ++oit) { - if (!it->equals(*oit, opt)) { - return false; - } - } - } + // We need to check this before we use isDir in the next if-statement: + if (isDir != other.isDir) { + return false; + } + + if (compareWhat == CompareLastModified) { + // Don't check directory mtime: it might change when (unsynced) files get created. + if (!isDir && _lastModifiedInSecondsUTC != other._lastModifiedInSecondsUTC) { + return false; } + } + + if (name != other.name || fileSize != other.fileSize) { + return false; + } - return true; + if (children.size() != other.children.size()) { + return false; } - Q_UNREACHABLE(); + for (auto it = children.constBegin(), eit = children.constEnd(); it != eit; ++it) { + auto oit = other.children.constFind(it.key()); + if (oit == other.children.constEnd()) { + return false; + } else if (!it.value().equals(oit.value(), compareWhat)) { + return false; + } + } + + return true; } QString FileInfo::path() const @@ -360,7 +364,7 @@ FakePropfindReply::FakePropfindReply(FileInfo &remoteRootFileInfo, QNetworkAcces } else xml.writeEmptyElement(davUri, QStringLiteral("resourcetype")); - auto gmtDate = fileInfo.lastModified.toUTC(); + auto gmtDate = fileInfo.lastModifiedInUtc(); auto stringDate = QLocale::c().toString(gmtDate, QStringLiteral("ddd, dd MMM yyyy HH:mm:ss 'GMT'")); xml.writeTextElement(davUri, QStringLiteral("getlastmodified"), stringDate); xml.writeTextElement(davUri, QStringLiteral("getcontentlength"), QString::number(fileInfo.contentSize)); @@ -442,12 +446,12 @@ FileInfo *FakePutReply::perform(FileInfo &remoteRootFileInfo, const QNetworkRequ if (fileInfo) { fileInfo->contentSize = putPayload.size(); fileInfo->contentChar = putPayload.at(0); - fileInfo->fileSize = fileInfo->contentSize; // it's hydrated on the server, so these are the same } else { // Assume that the file is filled with the same character fileInfo = remoteRootFileInfo.create(fileName, putPayload.size(), putPayload.at(0)); } - fileInfo->lastModified = OCC::Utility::qDateTimeFromTime_t(request.rawHeader("X-OC-Mtime").toLongLong()); + fileInfo->fileSize = fileInfo->contentSize; // it's hydrated on the server, so these are the same + fileInfo->setLastModifiedFromSecondsUTC(request.rawHeader("X-OC-Mtime").toLongLong()); remoteRootFileInfo.find(fileName, /*invalidate_etags=*/true); return fileInfo; } @@ -574,6 +578,7 @@ void FakeGetReply::respond() setRawHeader("OC-ETag", fileInfo->etag); setRawHeader("ETag", fileInfo->etag); setRawHeader("OC-FileId", fileInfo->fileId); + setRawHeader("X-OC-Mtime", QByteArray::number(fileInfo->lastModifiedInSecondsUTC())); emit metaDataChanged(); if (bytesAvailable()) emit readyRead(); @@ -641,6 +646,7 @@ void FakeGetWithDataReply::respond() setRawHeader("OC-ETag", fileInfo->etag); setRawHeader("ETag", fileInfo->etag); setRawHeader("OC-FileId", fileInfo->fileId); + setRawHeader("X-OC-Mtime", QByteArray::number(fileInfo->lastModifiedInSecondsUTC())); emit metaDataChanged(); if (bytesAvailable()) emit readyRead(); @@ -739,7 +745,7 @@ FileInfo *FakeChunkMoveReply::perform(FileInfo &uploadsFileInfo, FileInfo &remot // Assume that the file is filled with the same character fileInfo = remoteRootFileInfo.create(fileName, size, payload); } - fileInfo->lastModified = OCC::Utility::qDateTimeFromTime_t(request.rawHeader("X-OC-Mtime").toLongLong()); + fileInfo->setLastModifiedFromSecondsUTC(request.rawHeader("X-OC-Mtime").toLongLong()); remoteRootFileInfo.find(fileName, /*invalidate_etags=*/true); return fileInfo; @@ -1052,7 +1058,7 @@ void FakeFolder::toDisk(QDir &dir, const FileInfo &templateFi) file.open(QFile::WriteOnly); file.write(QByteArray {}.fill(child.contentChar, child.contentSize)); file.close(); - OCC::FileSystem::setModTime(file.fileName(), OCC::Utility::qDateTimeToTime_t(child.lastModified)); + OCC::FileSystem::setModTime(file.fileName(), child.lastModifiedInSecondsUTC()); } } } @@ -1065,12 +1071,14 @@ void FakeFolder::fromDisk(QDir &dir, FileInfo &templateFi) QDir subDir = dir; subDir.cd(diskChild.fileName()); FileInfo &subFi = templateFi.children[diskChild.fileName()] = FileInfo { diskChild.fileName() }; + subFi.setLastModified(diskChild.lastModified()); fromDisk(subDir, subFi); } else { FileInfo fi(diskChild.fileName()); fi.isDir = false; fi.fileSize = diskChild.size(); fi.isDehydratedPlaceholder = isDehydratedPlaceholder(diskChild.absoluteFilePath()); + fi.setLastModified(diskChild.lastModified()); if (fi.isDehydratedPlaceholder) { fi.contentChar = '\0'; } else { @@ -1118,7 +1126,7 @@ FileInfo FakeFolder::dbState() const item.isDir = record._type == ItemTypeDirectory; item.permissions = record._remotePerm; item.etag = record._etag; - item.lastModified = OCC::Utility::qDateTimeFromTime_t(record._modtime); + item.setLastModifiedFromSecondsUTC(record._modtime); item.fileId = record._fileId; item.checksums = record._checksumHeader; // item.contentChar can't be set from the db diff --git a/test/testutils/syncenginetestutils.h b/test/testutils/syncenginetestutils.h index 22b0fa296..61b258b4a 100644 --- a/test/testutils/syncenginetestutils.h +++ b/test/testutils/syncenginetestutils.h @@ -109,6 +109,13 @@ public: void setModTime(const QString &relativePath, const QDateTime &modTime) override; }; +static inline qint64 defaultLastModified() +{ + auto precise = QDateTime::currentDateTimeUtc().addDays(-7); + time_t timeInSeconds = OCC::Utility::qDateTimeToTime_t(precise); + return timeInSeconds; +} + /// FIXME: we should make it explicit in the construtor if we're talking about a hydrated or a dehydrated file! class FileInfo : public FileModifier { @@ -167,19 +174,44 @@ public: return name < other.name; } - bool operator==(const FileInfo &other) const; + enum CompareWhat { + CompareLastModified, + IgnoreLastModified, + }; + + bool operator==(const FileInfo &other) const { return equals(other, CompareLastModified); } + + bool equals(const FileInfo &other, CompareWhat compareWhat) const; bool operator!=(const FileInfo &other) const { return !operator==(other); } - enum ComparissonOption { - IgnoreContentOfDehydratedFiles, - ContentIsKing, - }; + QDateTime lastModified() const + { + return QDateTime::fromSecsSinceEpoch(_lastModifiedInSecondsUTC, Qt::LocalTime); + } + + QDateTime lastModifiedInUtc() const + { + return QDateTime::fromSecsSinceEpoch(_lastModifiedInSecondsUTC, Qt::UTC); + } + + void setLastModified(const QDateTime &t) + { + _lastModifiedInSecondsUTC = t.toSecsSinceEpoch(); + } - bool equals(const FileInfo &other, ComparissonOption opt) const; + qint64 lastModifiedInSecondsUTC() const + { + return _lastModifiedInSecondsUTC; + } + + void setLastModifiedFromSecondsUTC(qint64 utcSecs) + { + _lastModifiedInSecondsUTC = utcSecs; + } QString path() const; QString absolutePath() const; @@ -190,7 +222,7 @@ public: bool isDir = true; bool isShared = false; OCC::RemotePermissions permissions; // When uset, defaults to everything - QDateTime lastModified = QDateTime::currentDateTimeUtc().addDays(-7); + qint64 _lastModifiedInSecondsUTC = defaultLastModified(); QByteArray etag = generateEtag(); QByteArray fileId = generateFileId(); QByteArray checksums; @@ -208,12 +240,16 @@ public: friend inline QDebug operator<<(QDebug dbg, const FileInfo &fi) { - return dbg << "{ " << fi.path() << ": " - << ", fileSize:" << fi.fileSize - << ", contentSize:" << fi.contentSize - << ", contentChar:" << fi.contentChar - << ", isDehydratedPlaceholder:" << fi.isDehydratedPlaceholder - << ", children:" << fi.children; + return dbg.nospace().noquote() + << "{ '" << fi.path() << "': " + << ", isDir:" << fi.isDir + << QStringLiteral(", lastModified: %1 (%2)").arg(QString::number(fi._lastModifiedInSecondsUTC), fi.lastModifiedInUtc().toString()) + << ", fileSize:" << fi.fileSize + << ", contentSize:" << fi.contentSize + << QStringLiteral(", contentChar: 0x%1").arg(QString::number(int(fi.contentChar), 16)) + << ", isDehydratedPlaceholder:" << fi.isDehydratedPlaceholder + << ", children:" << fi.children + << " }"; } }; @@ -614,11 +650,11 @@ inline void addFilesDbData(QStringList &dest, const FileInfo &fi) { // could include etag, permissions etc, but would need extra work if (fi.isDir) { - dest += QStringLiteral("%1 - %2 %3 %4").arg(fi.name, fi.isDir ? QStringLiteral("dir") : QStringLiteral("file"), QString::number(fi.lastModified.toSecsSinceEpoch()), QString::fromUtf8(fi.fileId)); + dest += QStringLiteral("%1 - %2 %3 %4").arg(fi.name, fi.isDir ? QStringLiteral("dir") : QStringLiteral("file"), QString::number(fi.lastModifiedInSecondsUTC()), QString::fromUtf8(fi.fileId)); for (const auto &fi : fi.children) addFilesDbData(dest, fi); } else { - dest += QStringLiteral("%1 - %2 %3 %4 %5").arg(fi.name, fi.isDir ? QStringLiteral("dir") : QStringLiteral("file"), QString::number(fi.contentSize), QString::number(fi.lastModified.toSecsSinceEpoch()), QString::fromUtf8(fi.fileId)); + dest += QStringLiteral("%1 - %2 %3 %4 %5").arg(fi.name, fi.isDir ? QStringLiteral("dir") : QStringLiteral("file"), QString::number(fi.contentSize), QString::number(fi.lastModifiedInSecondsUTC()), QString::fromUtf8(fi.fileId)); } } |