Skip to content
This repository has been archived by the owner on Sep 1, 2022. It is now read-only.

Commit

Permalink
Add unit tests for IOutstationApplication::OnConfirmProcess.
Browse files Browse the repository at this point in the history
  • Loading branch information
emgre committed Oct 16, 2020
1 parent eae6671 commit 6034a89
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
19 changes: 19 additions & 0 deletions cpp/tests/dnp3mocks/include/dnp3mocks/MockOutstationApplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
#include <deque>
#include <tuple>

struct ConfirmResult
{
bool is_unsolicited;
uint32_t num_class1;
uint32_t num_class2;
uint32_t num_class3;
};

class MockOutstationApplication : public opendnp3::IOutstationApplication
{
public:
Expand Down Expand Up @@ -119,6 +127,16 @@ class MockOutstationApplication : public opendnp3::IOutstationApplication
return warmRestartTimeDelay;
}

void OnConfirmProcessed(bool is_unsolicited, uint32_t num_class1, uint32_t num_class2, uint32_t num_class3) final
{
ConfirmResult confirm{};
confirm.is_unsolicited = is_unsolicited;
confirm.num_class1 = num_class1;
confirm.num_class2 = num_class2;
confirm.num_class3 = num_class3;
this->confirms.push_back(confirm);
}

void SetTime(opendnp3::DNPTime time)
{
this->currentTime = time;
Expand All @@ -143,6 +161,7 @@ class MockOutstationApplication : public opendnp3::IOutstationApplication
std::deque<opendnp3::UTCTimestamp> timestamps;
std::deque<std::tuple<opendnp3::AssignClassType, opendnp3::PointClass, uint16_t, uint16_t>> classAssignments;
std::deque<opendnp3::Indexed<opendnp3::TimeAndInterval>> timeAndIntervals;
std::deque<ConfirmResult> confirms;
};

#endif
7 changes: 7 additions & 0 deletions cpp/tests/unit/TestOutstationEventResponses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ TEST_CASE(SUITE("EventBufferOverflowAndClear"))
t.OnTxReady();
t.SendToOutstation(hex::SolicitedConfirm(1));

// Check that the confirm is reported to the IOutstationApplication
REQUIRE(t.application->confirms.size() == 1);
REQUIRE(t.application->confirms[0].is_unsolicited == false);
REQUIRE(t.application->confirms[0].num_class1 == 1);
REQUIRE(t.application->confirms[0].num_class2 == 0);
REQUIRE(t.application->confirms[0].num_class3 == 0);

t.SendToOutstation("C0 01");
REQUIRE("C0 81 82 00" == t.lower->PopWriteAsHex());
}
Expand Down
35 changes: 35 additions & 0 deletions cpp/tests/unit/TestOutstationUnsolicitedResponses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,13 @@ TEST_CASE(SUITE("UnsolData"))
t.OnTxReady();
t.SendToOutstation(hex::UnsolConfirm(0));

// Check that the confirm is reported to the IOutstationApplication
REQUIRE(t.application->confirms.size() == 1);
REQUIRE(t.application->confirms[0].is_unsolicited == true);
REQUIRE(t.application->confirms[0].num_class1 == 0);
REQUIRE(t.application->confirms[0].num_class2 == 0);
REQUIRE(t.application->confirms[0].num_class3 == 0);

// do a transaction before the layer comes online to prove that the null transaction
// is occuring before unsol data is sent
t.Transaction([](IUpdateHandler& db) { db.Update(Binary(false, Flags(0x01)), 2); });
Expand All @@ -287,6 +294,13 @@ TEST_CASE(SUITE("UnsolData"))
t.OnTxReady();
t.SendToOutstation(hex::UnsolConfirm(1));
REQUIRE(t.lower->PopWriteAsHex().empty());

// Check that the confirm is reported to the IOutstationApplication
REQUIRE(t.application->confirms.size() == 2);
REQUIRE(t.application->confirms[1].is_unsolicited == true);
REQUIRE(t.application->confirms[1].num_class1 == 0);
REQUIRE(t.application->confirms[1].num_class2 == 0);
REQUIRE(t.application->confirms[1].num_class3 == 0);
}

TEST_CASE(SUITE("UnsolEventBufferOverflow"))
Expand Down Expand Up @@ -316,6 +330,13 @@ TEST_CASE(SUITE("UnsolEventBufferOverflow"))
t.OnTxReady();
t.SendToOutstation(hex::UnsolConfirm(1));

// Check that the confirm is reported to the IOutstationApplication
REQUIRE(t.application->confirms.size() == 2);
REQUIRE(t.application->confirms[1].is_unsolicited == true);
REQUIRE(t.application->confirms[1].num_class1 == 0);
REQUIRE(t.application->confirms[1].num_class2 == 0);
REQUIRE(t.application->confirms[1].num_class3 == 0);

REQUIRE(t.lower->PopWriteAsHex().empty());
}

Expand Down Expand Up @@ -345,12 +366,26 @@ TEST_CASE(SUITE("UnsolMultiFragments"))
t.OnTxReady();
t.SendToOutstation(hex::UnsolConfirm(1));

// Check that the confirm is reported to the IOutstationApplication
REQUIRE(t.application->confirms.size() == 2);
REQUIRE(t.application->confirms[1].is_unsolicited == true);
REQUIRE(t.application->confirms[1].num_class1 == 1);
REQUIRE(t.application->confirms[1].num_class2 == 0);
REQUIRE(t.application->confirms[1].num_class3 == 0);

// should immediately try to send another unsol packet
REQUIRE(t.lower->PopWriteAsHex() == "F2 82 80 00 20 01 28 01 00 03 00 01 0D 00 00 00");
t.OnTxReady();
t.SendToOutstation(hex::UnsolConfirm(2));

REQUIRE(t.lower->PopWriteAsHex().empty());

// Check that the confirm is reported to the IOutstationApplication
REQUIRE(t.application->confirms.size() == 3);
REQUIRE(t.application->confirms[2].is_unsolicited == true);
REQUIRE(t.application->confirms[2].num_class1 == 0);
REQUIRE(t.application->confirms[2].num_class2 == 0);
REQUIRE(t.application->confirms[2].num_class3 == 0);
}

void WriteDuringUnsol(bool beforeTx)
Expand Down

0 comments on commit 6034a89

Please sign in to comment.