Skip to content

Commit 7f17904

Browse files
authored
Merge pull request #24 from ModbusScope/dev/integration_test
Add full integration test
2 parents ecf857b + 94a2c80 commit 7f17904

2 files changed

Lines changed: 120 additions & 0 deletions

File tree

tests/integration/tst_dummyadapter.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "ProtocolAdapter/adapterclient.h"
44
#include "ProtocolAdapter/adapterprocess.h"
5+
#include "util/result.h"
56

67
#include <QJsonArray>
78
#include <QJsonObject>
@@ -13,6 +14,11 @@ namespace {
1314
constexpr int cSessionTimeoutMs = 10000;
1415
constexpr int cReadTimeoutMs = 5000;
1516

17+
// Dummy adapter built-in server settings
18+
constexpr const char* DUMMY_IP = "127.0.0.1";
19+
constexpr quint16 DUMMY_PORT = 5020;
20+
constexpr quint8 DUMMY_SLAVE_ID = 1;
21+
1622
//! Minimal adapter configuration with no real connections or devices.
1723
//! The dummymodbusadapter accepts this without attempting any real I/O.
1824
QJsonObject minimalConfig()
@@ -25,6 +31,30 @@ QJsonObject minimalConfig()
2531
return config;
2632
}
2733

34+
//! Full configuration pointing at the dummymodbusadapter's built-in TCP server.
35+
QJsonObject realConfig()
36+
{
37+
QJsonObject connection;
38+
connection["id"] = 0;
39+
connection["type"] = QStringLiteral("tcp");
40+
connection["ip"] = DUMMY_IP;
41+
connection["port"] = static_cast<int>(DUMMY_PORT);
42+
connection["persistent"] = true;
43+
connection["timeout"] = 1000;
44+
45+
QJsonObject device;
46+
device["id"] = 1;
47+
device["connectionId"] = 0;
48+
device["slaveId"] = static_cast<int>(DUMMY_SLAVE_ID);
49+
50+
QJsonObject config;
51+
config["version"] = 1;
52+
config["general"] = QJsonObject();
53+
config["connections"] = QJsonArray({ connection });
54+
config["devices"] = QJsonArray({ device });
55+
return config;
56+
}
57+
2858
} // namespace
2959

3060
void TestDummyAdapter::describeReturnsRequiredFields()
@@ -97,4 +127,91 @@ void TestDummyAdapter::fullLifecycleSessionStarts()
97127
client.stopSession();
98128
}
99129

130+
void TestDummyAdapter::readRegistersReturnsValidData()
131+
{
132+
auto* process = new AdapterProcess();
133+
AdapterClient client(process);
134+
135+
const QStringList registers = { "${40001}", "${40002}", "${40010}" };
136+
137+
connect(&client, &AdapterClient::describeResult, &client,
138+
[&client, &registers]() { client.provideConfig(realConfig(), registers); });
139+
140+
QSignalSpy spyStarted(&client, &AdapterClient::sessionStarted);
141+
QSignalSpy spyError(&client, &AdapterClient::sessionError);
142+
143+
client.prepareAdapter(QString::fromUtf8(DUMMY_ADAPTER_EXECUTABLE));
144+
145+
QVERIFY2(spyStarted.wait(cSessionTimeoutMs), "sessionStarted not emitted");
146+
QCOMPARE(spyError.count(), 0);
147+
148+
QSignalSpy spyData(&client, &AdapterClient::readDataResult);
149+
client.requestReadData();
150+
QVERIFY2(spyData.wait(cReadTimeoutMs), "readDataResult not emitted");
151+
152+
const auto results = spyData.at(0).at(0).value<ResultDoubleList>();
153+
QCOMPARE(results.size(), registers.size());
154+
// The dummymodbusadapter stores the 0-based register offset as the register value:
155+
// register 40001 → offset 0, register 40002 → offset 1, register 40010 → offset 9.
156+
QVERIFY2(results[0].isValid(), "Expected SUCCESS for register 40001");
157+
QCOMPARE(results[0].value(), 0.0);
158+
QVERIFY2(results[1].isValid(), "Expected SUCCESS for register 40002");
159+
QCOMPARE(results[1].value(), 1.0);
160+
QVERIFY2(results[2].isValid(), "Expected SUCCESS for register 40010");
161+
QCOMPARE(results[2].value(), 9.0);
162+
163+
client.stopSession();
164+
}
165+
166+
void TestDummyAdapter::multipleReadCyclesAllSucceed()
167+
{
168+
auto* process = new AdapterProcess();
169+
AdapterClient client(process);
170+
171+
const QStringList registers = { "${40001}", "${40005}" };
172+
173+
connect(&client, &AdapterClient::describeResult, &client,
174+
[&client, &registers]() { client.provideConfig(realConfig(), registers); });
175+
176+
QSignalSpy spyStarted(&client, &AdapterClient::sessionStarted);
177+
client.prepareAdapter(QString::fromUtf8(DUMMY_ADAPTER_EXECUTABLE));
178+
QVERIFY2(spyStarted.wait(cSessionTimeoutMs), "sessionStarted not emitted");
179+
180+
QSignalSpy spyData(&client, &AdapterClient::readDataResult);
181+
182+
constexpr int cReadCycles = 3;
183+
for (int cycle = 0; cycle < cReadCycles; ++cycle)
184+
{
185+
client.requestReadData();
186+
QVERIFY2(spyData.wait(cReadTimeoutMs), "readDataResult not emitted");
187+
188+
const auto results = spyData.takeLast().at(0).value<ResultDoubleList>();
189+
QCOMPARE(results.size(), registers.size());
190+
// The dummymodbusadapter stores the 0-based register offset as the value.
191+
QVERIFY2(results[0].isValid(), "Expected SUCCESS for register 40001 on each cycle");
192+
QCOMPARE(results[0].value(), 0.0);
193+
QVERIFY2(results[1].isValid(), "Expected SUCCESS for register 40005 on each cycle");
194+
QCOMPARE(results[1].value(), 4.0);
195+
}
196+
197+
client.stopSession();
198+
}
199+
200+
void TestDummyAdapter::stopSessionEmitsSessionStopped()
201+
{
202+
auto* process = new AdapterProcess();
203+
AdapterClient client(process);
204+
205+
connect(&client, &AdapterClient::describeResult, &client,
206+
[&client]() { client.provideConfig(realConfig(), QStringList()); });
207+
208+
QSignalSpy spyStarted(&client, &AdapterClient::sessionStarted);
209+
client.prepareAdapter(QString::fromUtf8(DUMMY_ADAPTER_EXECUTABLE));
210+
QVERIFY2(spyStarted.wait(cSessionTimeoutMs), "sessionStarted not emitted");
211+
212+
QSignalSpy spyStopped(&client, &AdapterClient::sessionStopped);
213+
client.stopSession();
214+
QVERIFY2(spyStopped.wait(cSessionTimeoutMs), "sessionStopped not emitted after stopSession");
215+
}
216+
100217
QTEST_GUILESS_MAIN(TestDummyAdapter)

tests/integration/tst_dummyadapter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ private slots:
1616
void describeReturnsRequiredFields();
1717
void describeNameIsModbusAdapter();
1818
void fullLifecycleSessionStarts();
19+
void readRegistersReturnsValidData();
20+
void multipleReadCyclesAllSucceed();
21+
void stopSessionEmitsSessionStopped();
1922
};
2023

2124
#endif // TST_DUMMYADAPTER_H

0 commit comments

Comments
 (0)