Skip to content

Commit

Permalink
Merge pull request #391 from Infomaniak/kdesktop-1378-cannot-create-s…
Browse files Browse the repository at this point in the history
…ubdir-in-shared-unit-tests

[KDESKTOP-1378] Add further unit tests for the ExecutorWorker::isValidDestination method
  • Loading branch information
herve-er authored Nov 27, 2024
2 parents 4e5311b + c5f264b commit e11e1c3
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/libsyncengine/syncpal/operationprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class OperationProcessor : public ISyncWorker {
* @param node a shared pointer to the node in current tree.
* @return a shared pointer to the node in other tree. nullptr il not found.
*/
std::shared_ptr<Node> correspondingNodeInOtherTree(std::shared_ptr<Node> node);
virtual std::shared_ptr<Node> correspondingNodeInOtherTree(std::shared_ptr<Node> node);
/**
* Find the corresponding node in other tree.
* Looks in DB only.
Expand Down
166 changes: 140 additions & 26 deletions test/libsyncengine/propagation/executor/testexecutorworker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void TestExecutorWorker::setUp() {
}

_syncPal = std::make_shared<SyncPal>(_sync.dbId(), KDRIVE_VERSION_STRING);
_syncPal->createWorkers();
_executorWorker = std::shared_ptr<ExecutorWorker>(new ExecutorWorker(_syncPal, "Executor", "EXEC"));
_syncPal->syncDb()->setAutoDelete(true);
}

Expand Down Expand Up @@ -103,7 +103,7 @@ void TestExecutorWorker::testCheckLiteSyncInfoForCreate() {
});

bool isDehydratedPlaceholder = false;
_syncPal->_executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder);
_executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder);

CPPUNIT_ASSERT(!isDehydratedPlaceholder);
}
Expand All @@ -120,7 +120,7 @@ void TestExecutorWorker::testCheckLiteSyncInfoForCreate() {
});

bool isDehydratedPlaceholder = false;
_syncPal->_executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder);
_executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder);

CPPUNIT_ASSERT(isDehydratedPlaceholder);
}
Expand All @@ -137,7 +137,7 @@ void TestExecutorWorker::testCheckLiteSyncInfoForCreate() {
});

bool isDehydratedPlaceholder = false;
_syncPal->_executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder);
_executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder);

CPPUNIT_ASSERT(!isDehydratedPlaceholder);
}
Expand All @@ -154,7 +154,7 @@ void TestExecutorWorker::testCheckLiteSyncInfoForCreate() {
});

bool isDehydratedPlaceholder = false;
_syncPal->_executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder);
_executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder);

CPPUNIT_ASSERT(!isDehydratedPlaceholder);
}
Expand All @@ -178,23 +178,137 @@ SyncOpPtr TestExecutorWorker::generateSyncOperation(const DbNodeId dbNodeId, con
return op;
}


SyncOpPtr TestExecutorWorker::generateSyncOperationWithNestedNodes(const DbNodeId dbNodeId, const SyncName &parentFilename,
const OperationType opType, const NodeType nodeType) {
auto parentNode =
std::make_shared<Node>(dbNodeId, ReplicaSide::Local, parentFilename, NodeType::Directory, OperationType::None,
"local_parent_id", testhelpers::defaultTime, testhelpers::defaultTime,
testhelpers::defaultFileSize, _syncPal->updateTree(ReplicaSide::Local)->rootNode());

auto node = std::make_shared<Node>(dbNodeId, ReplicaSide::Local, Str("test_file.txt"), nodeType, OperationType::None,
"local_child_id", testhelpers::defaultTime, testhelpers::defaultTime,
testhelpers::defaultFileSize, parentNode);


auto correspondingNode =
std::make_shared<Node>(dbNodeId, ReplicaSide::Remote, Str("test_file.txt"), nodeType, OperationType::None,
"remote_child_id", testhelpers::defaultTime, testhelpers::defaultTime,
testhelpers::defaultFileSize, _syncPal->updateTree(ReplicaSide::Remote)->rootNode());

SyncOpPtr op = std::make_shared<SyncOperation>();
op->setAffectedNode(node);
op->setCorrespondingNode(correspondingNode);
op->setType(opType);

return op;
}

class ExecutorWorkerMock : public ExecutorWorker {
public:
ExecutorWorkerMock(std::shared_ptr<SyncPal> syncPal, const std::string &name, const std::string &shortName) :
ExecutorWorker(syncPal, name, shortName){};

using ArgsMap = std::map<std::shared_ptr<Node>, std::shared_ptr<Node>>;
void setCorrespondingNodeInOtherTree(ArgsMap nodeMap) { _correspondingNodeInOtherTree = nodeMap; };

protected:
ArgsMap _correspondingNodeInOtherTree;
virtual std::shared_ptr<Node> correspondingNodeInOtherTree(const std::shared_ptr<Node> node) {
if (auto it = _correspondingNodeInOtherTree.find(node); it != _correspondingNodeInOtherTree.cend()) {
return it->second;
}

return nullptr;
};
};

void TestExecutorWorker::testIsValidDestination() {
// Always true if the target side is local or unknown
{
SyncOpPtr op = generateSyncOperation(1, Str("test_file.txt"));
CPPUNIT_ASSERT(_syncPal->_executorWorker->isValidDestination(op));
CPPUNIT_ASSERT(_executorWorker->isValidDestination(op));
}
// Always true if the operation is not of type Create
{
SyncOpPtr op = generateSyncOperation(1, Str("test_file.txt"));
op->setTargetSide(ReplicaSide::Remote);
CPPUNIT_ASSERT(_syncPal->_executorWorker->isValidDestination(op));
CPPUNIT_ASSERT(_executorWorker->isValidDestination(op));
}
// Always true if the item is created on the local replica at the root of the synchronisation folder
{
SyncOpPtr op = generateSyncOperation(1, Str("parent_dir"));
op->setTargetSide(ReplicaSide::Remote);
CPPUNIT_ASSERT(_executorWorker->isValidDestination(op));
}
// Always true if the item is created on the local replica, at the root of the synchronisation folder


const auto executorWorkerMock = std::shared_ptr<ExecutorWorkerMock>(new ExecutorWorkerMock(_syncPal, "Executor", "EXEC"));
// False if the item created on the local replica is not at the root of the synchronisation folder and has no
// corresponding parent node.
{
SyncOpPtr op = generateSyncOperationWithNestedNodes(1, Str("test_file.txt"), OperationType::Create, NodeType::File);
executorWorkerMock->setCorrespondingNodeInOtherTree({{op->affectedNode()->parentNode(), nullptr}});
op->setTargetSide(ReplicaSide::Remote);
CPPUNIT_ASSERT(!executorWorkerMock->isValidDestination(op));
}

const auto root = _syncPal->updateTree(ReplicaSide::Remote)->rootNode();

// False if the item created on the local replica is not at the root of the synchronisation folder and has a
// corresponding parent node with no id.
{
const auto correspondingParentNode = std::make_shared<Node>(
666, ReplicaSide::Remote, Str("parent_dir"), NodeType::Directory, OperationType::None, std::nullopt,
testhelpers::defaultTime, testhelpers::defaultTime, testhelpers::defaultFileSize, root);


SyncOpPtr op = generateSyncOperationWithNestedNodes(1, Str("test_file.txt"), OperationType::Create, NodeType::File);
executorWorkerMock->setCorrespondingNodeInOtherTree({{op->affectedNode()->parentNode(), correspondingParentNode}});
op->setTargetSide(ReplicaSide::Remote);
CPPUNIT_ASSERT(!executorWorkerMock->isValidDestination(op));
}

const auto correspondingParentCommonDocsNode = std::make_shared<Node>(
666, ReplicaSide::Remote, Utility::commonDocumentsFolderName(), NodeType::Directory, OperationType::None,
"common_docs_id", testhelpers::defaultTime, testhelpers::defaultTime, testhelpers::defaultFileSize, root);

// False if the item created on the local replica is a file and has Common Documents as corresponding parent node.
{
SyncOpPtr op = generateSyncOperationWithNestedNodes(1, Str("test_file.txt"), OperationType::Create, NodeType::File);
op->setTargetSide(ReplicaSide::Remote);
executorWorkerMock->setCorrespondingNodeInOtherTree(
{{op->affectedNode()->parentNode(), correspondingParentCommonDocsNode}});
CPPUNIT_ASSERT(!executorWorkerMock->isValidDestination(op));
}

// True if the item created on the local replica is a directory and has Common Documents as corresponding parent node.
{
SyncOpPtr op = generateSyncOperationWithNestedNodes(1, Str("test_dir"), OperationType::Create, NodeType::Directory);
op->setTargetSide(ReplicaSide::Remote);
executorWorkerMock->setCorrespondingNodeInOtherTree(
{{op->affectedNode()->parentNode(), correspondingParentCommonDocsNode}});
CPPUNIT_ASSERT(executorWorkerMock->isValidDestination(op));
}

const auto correspondingParentSharedNode = std::make_shared<Node>(
777, ReplicaSide::Remote, Utility::sharedFolderName(), NodeType::Directory, OperationType::None, "shared_id",
testhelpers::defaultTime, testhelpers::defaultTime, testhelpers::defaultFileSize, root);

// False if the item is created on the local replica is a file and has Shared as corresponding parent node.
{
SyncOpPtr op = generateSyncOperationWithNestedNodes(1, Str("test_file.txt"), OperationType::Create, NodeType::File);
op->setTargetSide(ReplicaSide::Remote);
executorWorkerMock->setCorrespondingNodeInOtherTree({{op->affectedNode()->parentNode(), correspondingParentSharedNode}});
CPPUNIT_ASSERT(!executorWorkerMock->isValidDestination(op));
}

// False if the item created on the local replica is a directory and has Shared as corresponding parent node.
{
SyncOpPtr op = generateSyncOperation(1, Str("test_file.txt"), OperationType::Create);
SyncOpPtr op = generateSyncOperationWithNestedNodes(1, Str("test_dir"), OperationType::Create, NodeType::Directory);
op->setTargetSide(ReplicaSide::Remote);
CPPUNIT_ASSERT(_syncPal->_executorWorker->isValidDestination(op));
executorWorkerMock->setCorrespondingNodeInOtherTree({{op->affectedNode()->parentNode(), correspondingParentSharedNode}});
CPPUNIT_ASSERT(!executorWorkerMock->isValidDestination(op));
}
}

Expand Down Expand Up @@ -252,10 +366,10 @@ void TestExecutorWorker::testTerminatedJobsQueue() {

void TestExecutorWorker::testLogCorrespondingNodeErrorMsg() {
SyncOpPtr op = generateSyncOperation(1, Str("test_file.txt"));
_syncPal->_executorWorker->logCorrespondingNodeErrorMsg(op);
_executorWorker->logCorrespondingNodeErrorMsg(op);

op->setCorrespondingNode(nullptr);
_syncPal->_executorWorker->logCorrespondingNodeErrorMsg(op);
_executorWorker->logCorrespondingNodeErrorMsg(op);
}

void TestExecutorWorker::testFixModificationDate() {
Expand All @@ -278,7 +392,7 @@ void TestExecutorWorker::testFixModificationDate() {
_syncPal->syncDb()->insertNode(dbNode, dbNodeId, constraintError);

SyncOpPtr op = generateSyncOperation(dbNodeId, filename);
CPPUNIT_ASSERT(_syncPal->_executorWorker->fixModificationDate(op, path));
CPPUNIT_ASSERT(_executorWorker->fixModificationDate(op, path));

FileStat filestat;
IoError ioError = IoError::Unknown;
Expand All @@ -293,28 +407,28 @@ void TestExecutorWorker::testAffectedUpdateTree() {
auto syncOp = std::make_shared<SyncOperation>();
syncOp->setTargetSide(ReplicaSide::Local);

CPPUNIT_ASSERT_EQUAL(ReplicaSide::Remote, _syncPal->_executorWorker->affectedUpdateTree(syncOp)->side());
CPPUNIT_ASSERT_EQUAL(ReplicaSide::Remote, _executorWorker->affectedUpdateTree(syncOp)->side());

syncOp->setTargetSide(ReplicaSide::Remote);
CPPUNIT_ASSERT_EQUAL(ReplicaSide::Local, _syncPal->_executorWorker->affectedUpdateTree(syncOp)->side());
CPPUNIT_ASSERT_EQUAL(ReplicaSide::Local, _executorWorker->affectedUpdateTree(syncOp)->side());

// ReplicaSide::Unknown case
syncOp->setTargetSide(ReplicaSide::Unknown);
CPPUNIT_ASSERT_EQUAL(std::shared_ptr<UpdateTree>(nullptr), _syncPal->_executorWorker->affectedUpdateTree(syncOp));
CPPUNIT_ASSERT_EQUAL(std::shared_ptr<UpdateTree>(nullptr), _executorWorker->affectedUpdateTree(syncOp));
}

void TestExecutorWorker::testTargetUpdateTree() {
// Normal cases
auto syncOp = std::make_shared<SyncOperation>();
syncOp->setTargetSide(ReplicaSide::Local);
CPPUNIT_ASSERT_EQUAL(ReplicaSide::Local, _syncPal->_executorWorker->targetUpdateTree(syncOp)->side());
CPPUNIT_ASSERT_EQUAL(ReplicaSide::Local, _executorWorker->targetUpdateTree(syncOp)->side());

syncOp->setTargetSide(ReplicaSide::Remote);
CPPUNIT_ASSERT_EQUAL(ReplicaSide::Remote, _syncPal->_executorWorker->targetUpdateTree(syncOp)->side());
CPPUNIT_ASSERT_EQUAL(ReplicaSide::Remote, _executorWorker->targetUpdateTree(syncOp)->side());

// ReplicaSide::Unknown case
syncOp->setTargetSide(ReplicaSide::Unknown);
CPPUNIT_ASSERT_EQUAL(std::shared_ptr<UpdateTree>(nullptr), _syncPal->_executorWorker->targetUpdateTree(syncOp));
CPPUNIT_ASSERT_EQUAL(std::shared_ptr<UpdateTree>(nullptr), _executorWorker->targetUpdateTree(syncOp));
}

void TestExecutorWorker::testRemoveDependentOps() {
Expand Down Expand Up @@ -346,8 +460,8 @@ void TestExecutorWorker::testRemoveDependentOps() {
_syncPal->_syncOps->pushOp(op2Create);
_syncPal->_syncOps->pushOp(op3Create);

_syncPal->_executorWorker->_opList = _syncPal->_syncOps->opSortedList();
_syncPal->_executorWorker->removeDependentOps(op1Create); // op1Create failed, we should remove op2Create and op3Create.
_executorWorker->_opList = _syncPal->_syncOps->opSortedList();
_executorWorker->removeDependentOps(op1Create); // op1Create failed, we should remove op2Create and op3Create.

CPPUNIT_ASSERT(opsExist(op1Create));
CPPUNIT_ASSERT(!opsExist(op2Create));
Expand Down Expand Up @@ -378,8 +492,8 @@ void TestExecutorWorker::testRemoveDependentOps() {
_syncPal->_syncOps->pushOp(op1Create);
_syncPal->_syncOps->pushOp(op2Move);

_syncPal->_executorWorker->_opList = _syncPal->_syncOps->opSortedList();
_syncPal->_executorWorker->removeDependentOps(op1Create); // op2Move failed, we should remove op2Edit.
_executorWorker->_opList = _syncPal->_syncOps->opSortedList();
_executorWorker->removeDependentOps(op1Create); // op2Move failed, we should remove op2Edit.
CPPUNIT_ASSERT(opsExist(op1Create));
CPPUNIT_ASSERT(!opsExist(op2Move));
}
Expand Down Expand Up @@ -412,15 +526,15 @@ void TestExecutorWorker::testRemoveDependentOps() {
_syncPal->_syncOps->pushOp(op1Move);
_syncPal->_syncOps->pushOp(op2Move);

_syncPal->_executorWorker->_opList = _syncPal->_syncOps->opSortedList();
_syncPal->_executorWorker->removeDependentOps(op1Move); // op2Move failed, we should remove op2Edit.
_executorWorker->_opList = _syncPal->_syncOps->opSortedList();
_executorWorker->removeDependentOps(op1Move); // op2Move failed, we should remove op2Edit.
CPPUNIT_ASSERT(opsExist(op1Move));
CPPUNIT_ASSERT(!opsExist(op2Move));
}
}

bool TestExecutorWorker::opsExist(SyncOpPtr op) {
for (const auto &opId: _syncPal->_executorWorker->_opList) {
for (const auto &opId: _executorWorker->_opList) {
if (_syncPal->_syncOps->getOp(opId) == op) {
return true;
}
Expand Down
3 changes: 3 additions & 0 deletions test/libsyncengine/propagation/executor/testexecutorworker.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ class TestExecutorWorker : public CppUnit::TestFixture {
bool opsExist(SyncOpPtr op);
SyncOpPtr generateSyncOperation(const DbNodeId dbNodeId, const SyncName &filename,
const OperationType opType = OperationType::None);
SyncOpPtr generateSyncOperationWithNestedNodes(const DbNodeId dbNodeId, const SyncName &filename,
const OperationType opType, const NodeType nodeType);

std::shared_ptr<SyncPal> _syncPal;
Sync _sync;
std::shared_ptr<ExecutorWorker> _executorWorker;
LocalTemporaryDirectory _localTempDir{"TestExecutorWorker"};
};

Expand Down

0 comments on commit e11e1c3

Please sign in to comment.