mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-08-09 02:56:01 +08:00
refs #297 Added the kernel of the distributed value cache system.
This commit is contained in:
225
tests/blackmisc/testvaluecache.cpp
Normal file
225
tests/blackmisc/testvaluecache.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
/* Copyright (C) 2015
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "testvaluecache.h"
|
||||
#include "blackmisc/worker.h"
|
||||
#include "blackmisc/identifier.h"
|
||||
#include <future>
|
||||
|
||||
namespace BlackMiscTest
|
||||
{
|
||||
|
||||
using namespace BlackMisc;
|
||||
|
||||
CTestValueCache::CTestValueCache(QObject *parent) : QObject(parent)
|
||||
{
|
||||
CVariant::registerMetadata();
|
||||
}
|
||||
|
||||
void CTestValueCache::insertAndGet()
|
||||
{
|
||||
CVariantMap testData
|
||||
{
|
||||
{ "value1", CVariant::from(1) },
|
||||
{ "value2", CVariant::from(2) },
|
||||
{ "value3", CVariant::from(3) }
|
||||
};
|
||||
CVariantMap testData2
|
||||
{
|
||||
{ "value2", CVariant::from(42) },
|
||||
{ "value4", CVariant::from(4) }
|
||||
};
|
||||
CVariantMap testDataCombined
|
||||
{
|
||||
{ "value1", CVariant::from(1) },
|
||||
{ "value2", CVariant::from(42) },
|
||||
{ "value3", CVariant::from(3) },
|
||||
{ "value4", CVariant::from(4) }
|
||||
};
|
||||
|
||||
CValueCache cache(CValueCache::LocalOnly);
|
||||
QVERIFY(cache.getAllValues() == CVariantMap());
|
||||
cache.insertValues(testData);
|
||||
QVERIFY(cache.getAllValues() == testData);
|
||||
cache.insertValues(testData2);
|
||||
QVERIFY(cache.getAllValues() == testDataCombined);
|
||||
}
|
||||
|
||||
void waitForQueueOf(QObject *object)
|
||||
{
|
||||
if (object->thread() != QThread::currentThread())
|
||||
{
|
||||
std::promise<void> promise;
|
||||
QTimer::singleShot(0, object, [ & ] { promise.set_value(); });
|
||||
promise.get_future().wait();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void singleShotAndWait(QObject *object, F task)
|
||||
{
|
||||
if (object->thread() == QThread::currentThread())
|
||||
{
|
||||
task();
|
||||
}
|
||||
else
|
||||
{
|
||||
QTimer::singleShot(0, object, task);
|
||||
waitForQueueOf(object);
|
||||
}
|
||||
}
|
||||
|
||||
void testCommon(CValueCacheUser &user1, CValueCacheUser &user2)
|
||||
{
|
||||
user1.m_value1.set(42);
|
||||
QVERIFY(user2.slotFired());
|
||||
QVERIFY(! user1.slotFired());
|
||||
singleShotAndWait(&user2, [ & ] { QVERIFY(user2.m_value1.get() == 42); });
|
||||
QVERIFY(user1.m_value1.get() == 42);
|
||||
|
||||
user1.m_value2.set(42);
|
||||
user2.slotFired();
|
||||
QTest::ignoreMessage(QtCriticalMsg, QRegularExpression("-1337 is not valid"));
|
||||
user1.m_value2.set(-1337);
|
||||
QVERIFY(! user1.slotFired());
|
||||
QVERIFY(! user2.slotFired());
|
||||
singleShotAndWait(&user2, [ & ] { QVERIFY(user2.m_value2.get() == 42); });
|
||||
QVERIFY(user1.m_value2.get() == 42);
|
||||
}
|
||||
|
||||
void CTestValueCache::localOnly()
|
||||
{
|
||||
CValueCache cache(CValueCache::LocalOnly);
|
||||
for (int i = 0; i < 4; ++i) { QTest::ignoreMessage(QtWarningMsg, QRegularExpression("Uninitialized value")); }
|
||||
CValueCacheUser user1(&cache);
|
||||
CValueCacheUser user2(&cache);
|
||||
testCommon(user1, user2);
|
||||
}
|
||||
|
||||
void CTestValueCache::localOnlyWithThreads()
|
||||
{
|
||||
CValueCache cache(CValueCache::LocalOnly);
|
||||
for (int i = 0; i < 4; ++i) { QTest::ignoreMessage(QtWarningMsg, QRegularExpression("Uninitialized value")); }
|
||||
CValueCacheUser user1(&cache);
|
||||
CValueCacheUser user2(&cache);
|
||||
CRegularThread thread;
|
||||
user2.moveToThread(&thread);
|
||||
thread.start();
|
||||
testCommon(user1, user2);
|
||||
}
|
||||
|
||||
void CTestValueCache::distributed()
|
||||
{
|
||||
CIdentifier thisProcess;
|
||||
CIdentifier otherProcess;
|
||||
auto json = otherProcess.toJson();
|
||||
json.insert("processId", otherProcess.getProcessId() + 1);
|
||||
otherProcess.convertFromJson(json);
|
||||
|
||||
CValueCache thisCache(CValueCache::Distributed);
|
||||
CValueCache otherCache(CValueCache::Distributed);
|
||||
connect(&thisCache, &CValueCache::valuesChangedByLocal, &thisCache, [ & ](const CVariantMap &values)
|
||||
{
|
||||
QMetaObject::invokeMethod(&thisCache, "changeValuesFromRemote", Q_ARG(BlackMisc::CVariantMap, values), Q_ARG(BlackMisc::CIdentifier, thisProcess));
|
||||
QMetaObject::invokeMethod(&otherCache, "changeValuesFromRemote", Q_ARG(BlackMisc::CVariantMap, values), Q_ARG(BlackMisc::CIdentifier, otherProcess));
|
||||
});
|
||||
connect(&otherCache, &CValueCache::valuesChangedByLocal, &thisCache, [ & ](const CVariantMap &values)
|
||||
{
|
||||
QMetaObject::invokeMethod(&thisCache, "changeValuesFromRemote", Q_ARG(BlackMisc::CVariantMap, values), Q_ARG(BlackMisc::CIdentifier, otherProcess));
|
||||
QMetaObject::invokeMethod(&otherCache, "changeValuesFromRemote", Q_ARG(BlackMisc::CVariantMap, values), Q_ARG(BlackMisc::CIdentifier, thisProcess));
|
||||
});
|
||||
|
||||
for (int i = 0; i < 4; ++i) { QTest::ignoreMessage(QtWarningMsg, QRegularExpression("Uninitialized value")); }
|
||||
CValueCacheUser thisUser(&thisCache);
|
||||
CValueCacheUser otherUser(&otherCache);
|
||||
|
||||
CRegularThread thread;
|
||||
otherCache.moveToThread(&thread);
|
||||
otherUser.moveToThread(&thread);
|
||||
thread.start();
|
||||
|
||||
singleShotAndWait(&otherUser, [ & ] { otherUser.m_value1.set(99); });
|
||||
thisUser.m_value1.set(100);
|
||||
QCoreApplication::processEvents();
|
||||
waitForQueueOf(&otherUser);
|
||||
QVERIFY(thisUser.slotFired() != otherUser.slotFired());
|
||||
auto thisValue = thisUser.m_value1.get();
|
||||
singleShotAndWait(&otherUser, [ & ] { QVERIFY(thisValue == otherUser.m_value1.get()); });
|
||||
}
|
||||
|
||||
void CTestValueCache::batched()
|
||||
{
|
||||
CValueCache cache(CValueCache::LocalOnly);
|
||||
for (int i = 0; i < 4; ++i) { QTest::ignoreMessage(QtWarningMsg, QRegularExpression("Uninitialized value")); }
|
||||
CValueCacheUser user1(&cache);
|
||||
CValueCacheUser user2(&cache);
|
||||
|
||||
{
|
||||
auto batch = cache.batchChanges(&user1);
|
||||
user1.m_value1.set(42);
|
||||
user1.m_value2.set(42);
|
||||
}
|
||||
QVERIFY(! user1.slotFired());
|
||||
QVERIFY(user2.slotFired());
|
||||
singleShotAndWait(&user2, [ & ]
|
||||
{
|
||||
QVERIFY(user2.m_value1.get() == 42);
|
||||
QVERIFY(user2.m_value2.get() == 42);
|
||||
});
|
||||
}
|
||||
|
||||
void CTestValueCache::json()
|
||||
{
|
||||
QJsonObject testJson
|
||||
{
|
||||
{ "value1", CVariant::from(1).toJson() },
|
||||
{ "value2", CVariant::from(2).toJson() },
|
||||
{ "value3", CVariant::from(3).toJson() }
|
||||
};
|
||||
CVariantMap testData
|
||||
{
|
||||
{ "value1", CVariant::from(1) },
|
||||
{ "value2", CVariant::from(2) },
|
||||
{ "value3", CVariant::from(3) }
|
||||
};
|
||||
|
||||
CValueCache cache(CValueCache::LocalOnly);
|
||||
cache.loadFromJson(testJson);
|
||||
QVERIFY(cache.getAllValues() == testData);
|
||||
QVERIFY(cache.saveToJson() == testJson);
|
||||
}
|
||||
|
||||
bool validator(int value)
|
||||
{
|
||||
return value >= 0 && value <= 100;
|
||||
}
|
||||
|
||||
CValueCacheUser::CValueCacheUser(CValueCache *cache) :
|
||||
m_value1(cache, "value1", validator, 0, this, &CValueCacheUser::ps_valueChanged),
|
||||
m_value2(cache, "value2", validator, 0, this, &CValueCacheUser::ps_valueChanged)
|
||||
{}
|
||||
|
||||
void CValueCacheUser::ps_valueChanged()
|
||||
{
|
||||
m_slotFired.set_value();
|
||||
}
|
||||
|
||||
bool CValueCacheUser::slotFired()
|
||||
{
|
||||
auto status = m_slotFired.get_future().wait_for(std::chrono::milliseconds(250));
|
||||
m_slotFired = std::promise<void>();
|
||||
switch (status)
|
||||
{
|
||||
case std::future_status::deferred: default: QTEST_ASSERT(false);
|
||||
case std::future_status::ready: return true;
|
||||
case std::future_status::timeout: return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user