Test: Add mqttitem unit tests
This commit is contained in:
parent
cb05c2237e
commit
869067c2f9
2 changed files with 309 additions and 1 deletions
|
|
@ -12,10 +12,11 @@ add_executable(test_sensor unit/sensors/test_sensor.cpp)
|
|||
add_executable(test_actor unit/actors/test_actor.cpp)
|
||||
add_executable(test_itemstore unit/items/test_itemstore.cpp)
|
||||
add_executable(test_itemloadersource unit/items/test_itemloadersource.cpp)
|
||||
add_executable(test_mqttitem unit/items/test_mqttitem.cpp)
|
||||
add_executable(test_tcp unit/service/test_tcp.cpp)
|
||||
|
||||
# Link all tests to static library
|
||||
foreach(test test_item test_sensor test_actor test_itemstore test_itemloadersource test_tcp)
|
||||
foreach(test test_item test_sensor test_actor test_itemstore test_itemloadersource test_mqttitem test_tcp)
|
||||
target_link_libraries(${test}
|
||||
smartvos_core
|
||||
Qt6::Core
|
||||
|
|
@ -41,4 +42,5 @@ add_test(NAME test_sensor COMMAND test_sensor)
|
|||
add_test(NAME test_actor COMMAND test_actor)
|
||||
add_test(NAME test_itemstore COMMAND test_itemstore)
|
||||
add_test(NAME test_itemloadersource COMMAND test_itemloadersource)
|
||||
add_test(NAME test_mqttitem COMMAND test_mqttitem)
|
||||
add_test(NAME test_tcp COMMAND test_tcp)
|
||||
306
tests/unit/items/test_mqttitem.cpp
Normal file
306
tests/unit/items/test_mqttitem.cpp
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
#include <QtTest/QtTest>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QSignalSpy>
|
||||
#include <QStandardPaths>
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "items/mqttitem.h"
|
||||
#include "mqttclient.h"
|
||||
#include "programmode.h"
|
||||
|
||||
class TestMqttItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase()
|
||||
{
|
||||
// Setup for all tests
|
||||
// Try to load config and connect to MQTT broker if configured
|
||||
QString settingsPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/shinterface.json";
|
||||
|
||||
QJsonObject json;
|
||||
if (QFile::exists(settingsPath)) {
|
||||
QFile file(settingsPath);
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
QJsonParseError error;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &error);
|
||||
if (error.error == QJsonParseError::NoError) {
|
||||
json = doc.object();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject mqttJson = json["Mqtt"].toObject();
|
||||
QString host = mqttJson["Host"].toString();
|
||||
int port = mqttJson["Port"].toInt(1883);
|
||||
|
||||
// If MQTT is configured with a host, try to connect
|
||||
static std::shared_ptr<MqttClient> mqttClient;
|
||||
if (!host.isEmpty()) {
|
||||
qDebug() << "MQTT configured:" << host << port;
|
||||
mqttClient = std::make_shared<MqttClient>();
|
||||
mqttClient->start(mqttJson);
|
||||
// Give it a moment to connect
|
||||
QTest::qWait(1000);
|
||||
|
||||
// Check if connected or connecting
|
||||
auto qClient = mqttClient->getClient();
|
||||
if (qClient && (qClient->state() == QMqttClient::Connected ||
|
||||
qClient->state() == QMqttClient::Connecting)) {
|
||||
qDebug() << "MQTT connected/connecting, using client";
|
||||
MqttItem::client = mqttClient;
|
||||
} else {
|
||||
qDebug() << "MQTT connection failed, using UI_ONLY mode";
|
||||
programMode = PROGRAM_MODE_UI_ONLY;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "No MQTT host configured, using UI_ONLY mode";
|
||||
programMode = PROGRAM_MODE_UI_ONLY;
|
||||
}
|
||||
}
|
||||
|
||||
void testMqttItemCreation()
|
||||
{
|
||||
MqttItem item("test_mqtt", 0);
|
||||
QCOMPARE(item.getName(), QString("test_mqtt"));
|
||||
QVERIFY(item.getTopic().isEmpty());
|
||||
QVERIFY(item.getValueKey() == "state");
|
||||
}
|
||||
|
||||
void testMqttItemSetTopic()
|
||||
{
|
||||
MqttItem item("test_mqtt", 0);
|
||||
item.setTopic("my_device");
|
||||
item.setValueKey("state");
|
||||
|
||||
QVERIFY(item.getTopic() == "my_device");
|
||||
QVERIFY(item.getValueKey() == "state");
|
||||
}
|
||||
|
||||
void testMqttItemSetValueType()
|
||||
{
|
||||
MqttItem item("test_mqtt", 0);
|
||||
|
||||
// Default should be BOOL
|
||||
QVERIFY(item.getValueType() == ITEM_VALUE_BOOL);
|
||||
|
||||
// Set to UINT
|
||||
item.setValueType(ITEM_VALUE_UINT);
|
||||
QVERIFY(item.getValueType() == ITEM_VALUE_UINT);
|
||||
|
||||
// Set to ENUM
|
||||
item.setValueType(ITEM_VALUE_ENUM);
|
||||
QVERIFY(item.getValueType() == ITEM_VALUE_ENUM);
|
||||
}
|
||||
|
||||
void testMqttItemValueNames()
|
||||
{
|
||||
MqttItem item("test_mqtt", 0);
|
||||
|
||||
// Initially empty
|
||||
QVERIFY(item.getValueNames().empty());
|
||||
|
||||
// Set value names
|
||||
std::vector<QString> names = {"off", "heat", "cool"};
|
||||
item.setValueNames(names);
|
||||
|
||||
auto storedNames = item.getValueNames();
|
||||
QVERIFY(storedNames.size() == 3);
|
||||
QVERIFY(storedNames[0] == "off");
|
||||
QVERIFY(storedNames[1] == "heat");
|
||||
QVERIFY(storedNames[2] == "cool");
|
||||
}
|
||||
|
||||
void testValueNameConversion()
|
||||
{
|
||||
MqttItem item("test_mqtt", 0);
|
||||
|
||||
// Set value names for enum
|
||||
std::vector<QString> names = {"off", "heat", "cool", "auto"};
|
||||
item.setValueNames(names);
|
||||
item.setValueType(ITEM_VALUE_ENUM);
|
||||
|
||||
// Test name to index
|
||||
QVERIFY(item.valueNameToIndex("heat") == 1);
|
||||
QVERIFY(item.valueNameToIndex("cool") == 2);
|
||||
QVERIFY(item.valueNameToIndex("unknown") == -1);
|
||||
|
||||
// Test index to name
|
||||
QVERIFY(item.indexToValueName(0) == "off");
|
||||
QVERIFY(item.indexToValueName(3) == "auto");
|
||||
QVERIFY(item.indexToValueName(99).isEmpty()); // Out of bounds
|
||||
}
|
||||
|
||||
void testSetFromExposeBinary()
|
||||
{
|
||||
MqttItem item("test_mqtt", 0);
|
||||
|
||||
QJsonObject expose;
|
||||
expose["type"] = "binary";
|
||||
expose["property"] = "state";
|
||||
expose["value_on"] = "ON";
|
||||
expose["value_off"] = "OFF";
|
||||
|
||||
item.setFromExpose(expose);
|
||||
|
||||
QVERIFY(item.getValueType() == ITEM_VALUE_BOOL);
|
||||
QVERIFY(item.getValueKey() == "state");
|
||||
QVERIFY(item.getValueOn() == "ON");
|
||||
QVERIFY(item.getValueOff() == "OFF");
|
||||
}
|
||||
|
||||
void testSetFromExposeNumeric()
|
||||
{
|
||||
MqttItem item("test_mqtt", 0);
|
||||
|
||||
QJsonObject expose;
|
||||
expose["type"] = "numeric";
|
||||
expose["property"] = "brightness";
|
||||
expose["value_min"] = 0;
|
||||
expose["value_max"] = 254;
|
||||
expose["value_step"] = 1;
|
||||
|
||||
item.setFromExpose(expose);
|
||||
|
||||
QVERIFY(item.getValueType() == ITEM_VALUE_UINT);
|
||||
QVERIFY(item.getValueKey() == "brightness");
|
||||
QVERIFY(item.getValueMin() == 0);
|
||||
QVERIFY(item.getValueMax() == 254);
|
||||
QVERIFY(item.getValueStep() == 1);
|
||||
}
|
||||
|
||||
void testSetFromExposeEnum()
|
||||
{
|
||||
MqttItem item("test_mqtt", 0);
|
||||
|
||||
QJsonObject expose;
|
||||
expose["type"] = "enum";
|
||||
expose["property"] = "system_mode";
|
||||
expose["values"] = QJsonArray{"off", "heat", "cool", "auto"};
|
||||
|
||||
item.setFromExpose(expose);
|
||||
|
||||
QVERIFY(item.getValueType() == ITEM_VALUE_ENUM);
|
||||
QVERIFY(item.getValueKey() == "system_mode");
|
||||
|
||||
auto names = item.getValueNames();
|
||||
QVERIFY(names.size() == 4);
|
||||
QVERIFY(names[0] == "off");
|
||||
QVERIFY(names[1] == "heat");
|
||||
QVERIFY(names[2] == "cool");
|
||||
QVERIFY(names[3] == "auto");
|
||||
}
|
||||
|
||||
void testJsonSerialization()
|
||||
{
|
||||
MqttItem item("test_mqtt", 1);
|
||||
item.setTopic("my_device");
|
||||
item.setValueKey("state");
|
||||
item.setValueOn("ON");
|
||||
item.setValueOff("OFF");
|
||||
|
||||
QJsonObject json;
|
||||
item.store(json);
|
||||
|
||||
QVERIFY(json["Type"] == "Mqtt");
|
||||
QVERIFY(json["Topic"] == "my_device");
|
||||
QVERIFY(json["ValueKey"] == "state");
|
||||
QVERIFY(json["ValueOn"] == "ON");
|
||||
QVERIFY(json["ValueOff"] == "OFF");
|
||||
}
|
||||
|
||||
void testJsonDeserialization()
|
||||
{
|
||||
QJsonObject json;
|
||||
json["Type"] = "Mqtt";
|
||||
json["ItemId"] = 100;
|
||||
json["Name"] = "loaded_mqtt";
|
||||
json["Topic"] = "test_device";
|
||||
json["ValueKey"] = "state";
|
||||
json["ValueOn"] = "ON";
|
||||
json["ValueOff"] = "OFF";
|
||||
json["Value"] = 1;
|
||||
|
||||
MqttItem item;
|
||||
item.load(json);
|
||||
|
||||
QVERIFY(item.getTopic() == "test_device");
|
||||
QVERIFY(item.getValueKey() == "state");
|
||||
QVERIFY(item.getValueOn() == "ON");
|
||||
QVERIFY(item.getValueOff() == "OFF");
|
||||
}
|
||||
|
||||
void testLoadExposeFromDevice()
|
||||
{
|
||||
// Create item with specific topic and valueKey
|
||||
MqttItem item("test", 0);
|
||||
item.setTopic("0xa4c138ef510950e3");
|
||||
item.setValueKey("system_mode");
|
||||
|
||||
// Simulate device data from zigbee2mqtt/bridge/devices
|
||||
QJsonObject device;
|
||||
device["friendly_name"] = "0xa4c138ef510950e3";
|
||||
device["ieee_address"] = "0xa4c138ef510950e3";
|
||||
|
||||
QJsonObject definition;
|
||||
definition["model"] = "TS0601_thermostat";
|
||||
definition["vendor"] = "Tuya";
|
||||
definition["description"] = "Thermostat";
|
||||
|
||||
QJsonArray exposes;
|
||||
|
||||
// Binary expose
|
||||
QJsonObject stateExpose;
|
||||
stateExpose["type"] = "binary";
|
||||
stateExpose["property"] = "state";
|
||||
stateExpose["value_on"] = "ON";
|
||||
stateExpose["value_off"] = "OFF";
|
||||
exposes.append(stateExpose);
|
||||
|
||||
// Enum expose - the one we're looking for
|
||||
QJsonObject systemModeExpose;
|
||||
systemModeExpose["type"] = "enum";
|
||||
systemModeExpose["property"] = "system_mode";
|
||||
systemModeExpose["values"] = QJsonArray{"off", "heat", "cool", "auto"};
|
||||
exposes.append(systemModeExpose);
|
||||
|
||||
// Numeric expose
|
||||
QJsonObject tempExpose;
|
||||
tempExpose["type"] = "numeric";
|
||||
tempExpose["property"] = "current_temperature";
|
||||
tempExpose["value_min"] = 0;
|
||||
tempExpose["value_max"] = 100;
|
||||
exposes.append(tempExpose);
|
||||
|
||||
definition["exposes"] = exposes;
|
||||
device["definition"] = definition;
|
||||
|
||||
// Call the private method via public API - we need to test the logic
|
||||
// Since loadExposeFromDevice is private, we test via setFromExpose
|
||||
QJsonObject enumExpose;
|
||||
enumExpose["type"] = "enum";
|
||||
enumExpose["property"] = "system_mode";
|
||||
enumExpose["values"] = QJsonArray{"off", "heat", "cool", "auto"};
|
||||
|
||||
item.setFromExpose(enumExpose);
|
||||
|
||||
QVERIFY(item.getValueType() == ITEM_VALUE_ENUM);
|
||||
QVERIFY(item.getValueNames().size() == 4);
|
||||
}
|
||||
|
||||
void cleanupTestCase()
|
||||
{
|
||||
// Cleanup after all tests
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_APPLESS_MAIN(TestMqttItem)
|
||||
|
||||
#include "test_mqttitem.moc"
|
||||
Loading…
Add table
Add a link
Reference in a new issue