Test recursive removal against real disk storage
This commit is contained in:
1 parent
afc54eae00
commit
b4a9339459
1 file changed
+82
@@ -29,6 +29,7 @@
|
||||
#include <functional>
|
||||
extern "C" {
|
||||
#include "member_files/member_files.h"
|
||||
#include "member_files/storage.h"
|
||||
#include "mem.h"
|
||||
#include "debug_config.h"
|
||||
}
|
||||
@@ -261,6 +262,87 @@ private slots:
|
||||
requestStarted = {}; transferStarted = {};
|
||||
}
|
||||
|
||||
void recursiveDeletion_data() {
|
||||
QTest::addColumn<QString>("scenario");
|
||||
for (const auto* scenario : {"complete", "cancel-scan", "cancel-remove", "changed-file", "new-child", "changed-page"})
|
||||
QTest::newRow(scenario) << QString::fromLatin1(scenario);
|
||||
}
|
||||
|
||||
void recursiveDeletion() {
|
||||
QFETCH(QString, scenario);
|
||||
QTemporaryDir root; QVERIFY(root.isValid());
|
||||
QString user = root.path() + "/42/22";
|
||||
QVERIFY(QDir().mkpath(user + "/folder/nested/empty")); QVERIFY(QDir().mkpath(user + "/other"));
|
||||
auto write = [&](const QString& path, const QByteArray& contents) {
|
||||
QFile file(user + '/' + path); QVERIFY(file.open(QIODevice::WriteOnly)); QCOMPARE(file.write(contents), qint64(contents.size()));
|
||||
};
|
||||
// Длинные имена вынуждают настоящий storage выдавать несколько страниц LIST.
|
||||
for (int i = 0; i < 40; i++) write("folder/" + QString::number(i) + QString(220, 'x'), "payload");
|
||||
write("folder/nested/file.txt", "nested"); write("loose.txt", "selected"); write("keep.txt", "unselected");
|
||||
auto* storage = mf_storage_create(root.path().toUtf8().constData(), 1000000, 200000);
|
||||
QVERIFY(storage); auto destroy = qScopeGuard([&] { mf_storage_destroy(storage); });
|
||||
QCOMPARE(mf_storage_initialize(storage), int(MF_OK));
|
||||
QList<MemberFileEntry> entries;
|
||||
for (const auto* path : {"folder", "loose.txt", "other"}) {
|
||||
mf_message q{}, r{}; q.kind = MF_REQUEST; q.command = MF_STAT; q.owner = 22; q.request_id = entries.size() + 1;
|
||||
strcpy(q.path, path); mf_storage_execute(storage, 42, 22, &q, &r); QCOMPARE(r.status, uint16_t(MF_OK));
|
||||
entries.append({QString::fromUtf8(path), {}, QByteArray((const char*)r.version, 16), r.type == MF_DIRECTORY});
|
||||
}
|
||||
MemberFileBatch batch(42, 33, 22, MemberFileBatch::Remove, nullptr);
|
||||
bool done = false, success = false, injected = false; QString summary, changed;
|
||||
int pages = 0, removed = 0, requests = 0, rootStats = 0;
|
||||
batch.progress = [](const QString&, int) {};
|
||||
batch.finished = [&](bool ok, const QString& status, const QStringList&) { done = true; success = ok; summary = status; };
|
||||
auto reset = qScopeGuard([] { requestStarted = {}; });
|
||||
requestStarted = [&](mf_gui_request request) {
|
||||
requests++;
|
||||
QTimer::singleShot(0, &batch, [&, request] {
|
||||
const auto& q = request.message; QString path = QString::fromUtf8(q.path);
|
||||
if (q.command == MF_STAT && path == "folder") {
|
||||
rootStats++;
|
||||
if (scenario == "new-child" && rootStats == 2) { write("folder/arrived.txt", "new arrival"); injected = true; }
|
||||
}
|
||||
if (q.command == MF_LIST) {
|
||||
QCOMPARE(removed, 0); pages++;
|
||||
QVERIFY(!mf_zero(q.version, 16));
|
||||
if (scenario == "changed-page" && q.cursor) { write("folder/arrived.txt", "new arrival"); injected = true; }
|
||||
}
|
||||
if (q.command == MF_REMOVE_PATH) {
|
||||
QVERIFY(pages >= 4); // folder: две страницы, nested и empty: по одной.
|
||||
if (scenario == "changed-file" && !injected) { changed = path; write(path, "changed contents"); injected = true; }
|
||||
}
|
||||
mf_message response{}; mf_storage_execute(storage, request.group, request.message.owner, &q, &response);
|
||||
if (q.command == MF_REMOVE_PATH && !response.status) {
|
||||
removed++; QVERIFY(!QFileInfo::exists(user + '/' + path));
|
||||
}
|
||||
if (scenario == "cancel-scan" && response.more) {
|
||||
batch.cancel(); QVERIFY(!batch.response(response)); return;
|
||||
}
|
||||
QVERIFY(batch.response(response));
|
||||
if (scenario == "cancel-remove" && removed == 1) { batch.cancel(); QVERIFY(!batch.response(response)); }
|
||||
});
|
||||
};
|
||||
batch.start(entries); QTRY_VERIFY(done);
|
||||
int stopped = requests; QCoreApplication::processEvents(); QCOMPARE(requests, stopped);
|
||||
QFile keep(user + "/keep.txt"); QVERIFY(keep.open(QIODevice::ReadOnly)); QCOMPARE(keep.readAll(), QByteArray("unselected"));
|
||||
if (scenario == "complete") {
|
||||
QVERIFY2(success, qPrintable(summary)); QCOMPARE(removed, 46);
|
||||
QVERIFY(!QFileInfo::exists(user + "/folder")); QVERIFY(!QFileInfo::exists(user + "/other"));
|
||||
QVERIFY(!QFileInfo::exists(user + "/loose.txt")); QVERIFY(summary.contains("Completed: 46"));
|
||||
} else {
|
||||
QVERIFY(!success); QVERIFY(QFileInfo::exists(user + "/folder"));
|
||||
if (scenario == "cancel-scan" || scenario == "changed-page" || scenario == "changed-file") QCOMPARE(removed, 0);
|
||||
if (scenario == "cancel-remove") { QCOMPARE(removed, 1); QVERIFY(summary.contains("Completed: 1")); }
|
||||
if (scenario.startsWith("cancel-")) QVERIFY(summary.contains("Deletion cancelled"));
|
||||
if (scenario == "changed-file") { QVERIFY(injected); QVERIFY(QFileInfo::exists(user + '/' + changed)); }
|
||||
if (scenario == "new-child") {
|
||||
QVERIFY(injected); QVERIFY(QFileInfo::exists(user + "/folder/arrived.txt"));
|
||||
QVERIFY(summary.contains(QString::fromUtf8(mf_status_text(MF_DIRECTORY_NOT_EMPTY))));
|
||||
}
|
||||
if (scenario == "changed-page") QVERIFY(summary.contains(QString::fromUtf8(mf_status_text(MF_STALE))));
|
||||
}
|
||||
}
|
||||
|
||||
void deleteAndParentShortcuts() {
|
||||
sqlite3* sql = nullptr; QCOMPARE(sqlite3_open(":memory:", &sql), SQLITE_OK);
|
||||
QCOMPARE(sqlite3_exec(sql, "CREATE TABLE accounts(node_id INTEGER,display_name TEXT);"
|
||||
|
||||
Reference in new issue
Block a user