Skip to content

Commit 8f45f94

Browse files
author
Andy Ford
authored
Merge pull request #16 from ECFMP/15-messages-not-arriving
fix: flow measure statuses not being delivered
2 parents 73593bc + 083a578 commit 8f45f94

File tree

3 files changed

+187
-2
lines changed

3 files changed

+187
-2
lines changed

src/flowmeasure/FlowMeasureStatusUpdates.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace ECFMP::FlowMeasure {
2626
if (!canonicalFlowMeasures.contains(canonicalInformation.Identifier())) {
2727
canonicalFlowMeasures[canonicalInformation.Identifier()] = measure;
2828
BroadcastStatusUpdate(measure);
29-
return;
29+
continue;
3030
}
3131

3232
// Switch the measure we have stored out for the new one

test/api/FlowMeasureDataParserTest.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,106 @@ namespace ECFMPTest::Api {
329329
}
330330
);
331331

332+
class FlowMeasureDataParserMultipleMeasuresTest : public testing::Test
333+
{
334+
public:
335+
void SetUp() override
336+
{
337+
// Create the mock parsers
338+
auto filterParser = std::make_unique<MockFlowMeasureFilterParser>();
339+
filterParserRaw = filterParser.get();
340+
auto measureParser = std::make_unique<MockFlowMeasureMeasureParser>();
341+
measureParserRaw = measureParser.get();
342+
343+
eventBus = ECFMP::EventBus::MakeEventBus();
344+
mockEventHandler = std::make_shared<MockFlowMeasuresUpdatedEventHandler>(2);
345+
mockEventHandlerInternal = std::make_shared<MockInternalFlowMeasuresUpdatedEventHandler>(2);
346+
eventBus->SubscribeSync<ECFMP::Plugin::FlowMeasuresUpdatedEvent>(mockEventHandler);
347+
eventBus->SubscribeSync<ECFMP::Plugin::InternalFlowMeasuresUpdatedEvent>(mockEventHandlerInternal);
348+
349+
customFilters =
350+
std::make_shared<std::vector<std::shared_ptr<ECFMP::FlowMeasure::CustomFlowMeasureFilter>>>();
351+
parser = std::make_unique<ECFMP::Api::FlowMeasureDataParser>(
352+
std::move(filterParser), std::move(measureParser), std::make_shared<Log::MockLogger>(), eventBus,
353+
customFilters
354+
);
355+
356+
firs.Add(std::make_shared<ECFMP::FlightInformationRegion::ConcreteFlightInformationRegion>(
357+
1, "EGTT", "London"
358+
));
359+
firs.Add(std::make_shared<ECFMP::FlightInformationRegion::ConcreteFlightInformationRegion>(
360+
2, "EGPX", "Scottish"
361+
));
362+
363+
events.Add(std::make_shared<ECFMP::Event::ConcreteEvent>(
364+
1, "Test event", now, plusOneHour, firs.Get(1), "abc",
365+
std::vector<std::shared_ptr<ECFMP::Event::EventParticipant>>{}
366+
));
367+
}
368+
369+
std::shared_ptr<std::vector<std::shared_ptr<ECFMP::FlowMeasure::CustomFlowMeasureFilter>>> customFilters;
370+
std::shared_ptr<MockFlowMeasuresUpdatedEventHandler> mockEventHandler;
371+
std::shared_ptr<MockInternalFlowMeasuresUpdatedEventHandler> mockEventHandlerInternal;
372+
std::shared_ptr<ECFMP::EventBus::InternalEventBus> eventBus;
373+
MockFlowMeasureFilterParser* filterParserRaw;
374+
MockFlowMeasureMeasureParser* measureParserRaw;
375+
ECFMP::Api::InternalEventCollection events;
376+
ECFMP::Api::InternalFlightInformationRegionCollection firs;
377+
std::unique_ptr<ECFMP::Api::FlowMeasureDataParser> parser;
378+
};
379+
380+
TEST_F(FlowMeasureDataParserMultipleMeasuresTest, ItParsesFlowMeasures)
381+
{
382+
// Mock the measure and filter parser returns
383+
ON_CALL(*filterParserRaw, Parse(testing::_, testing::_))
384+
.WillByDefault(testing::Invoke([&](const nlohmann::json& data,
385+
const ECFMP::Api::InternalEventCollection& events) {
386+
return std::make_unique<ECFMP::FlowMeasure::ConcreteFlowMeasureFilters>(
387+
std::list<std::shared_ptr<ECFMP::FlowMeasure::AirportFilter>>(),
388+
std::list<std::shared_ptr<ECFMP::FlowMeasure::EventFilter>>(),
389+
std::list<std::shared_ptr<ECFMP::FlowMeasure::RouteFilter>>(),
390+
std::list<std::shared_ptr<ECFMP::FlowMeasure::LevelRangeFilter>>(),
391+
std::list<std::shared_ptr<ECFMP::FlowMeasure::MultipleLevelFilter>>(),
392+
std::list<std::shared_ptr<ECFMP::FlowMeasure::RangeToDestinationFilter>>(),
393+
std::make_shared<Euroscope::MockEuroscopeAircraftFactory>()
394+
);
395+
}));
396+
397+
ON_CALL(*measureParserRaw, Parse(testing::_)).WillByDefault(testing::Invoke([&](const nlohmann::json& data) {
398+
return std::make_unique<ECFMP::FlowMeasure::ConcreteMeasure>(ECFMP::FlowMeasure::MeasureType::GroundStop);
399+
}));
400+
401+
const auto measure1 = nlohmann::json{
402+
{"id", 1},
403+
{"event_id", 1},
404+
{"ident", "EGTT-01A"},
405+
{"reason", "reason 1"},
406+
{"starttime", ECFMP::Date::DateStringFromTimePoint(plusOneHour)},
407+
{"endtime", ECFMP::Date::DateStringFromTimePoint(plusTwoHours)},
408+
{"withdrawn_at", nlohmann::json::value_t::null},
409+
{"measure", {{"foo", "bar"}}},// Measure is mocked and handled elsewhere, so placeholder
410+
{"filters", {{"foo", "baz"}}},// Filter is mocked and handled elsewhere, so placeholder
411+
{"notified_flight_information_regions", nlohmann::json::array({1, 2})}};
412+
413+
const auto measure2 = nlohmann::json{
414+
{"id", 2},
415+
{"event_id", 1},
416+
{"ident", "EGTT-01B"},
417+
{"reason", "reason 1"},
418+
{"starttime", ECFMP::Date::DateStringFromTimePoint(plusOneHour)},
419+
{"endtime", ECFMP::Date::DateStringFromTimePoint(plusTwoHours)},
420+
{"withdrawn_at", nlohmann::json::value_t::null},
421+
{"measure", {{"foo", "bar"}}},// Measure is mocked and handled elsewhere, so placeholder
422+
{"filters", {{"foo", "baz"}}},// Filter is mocked and handled elsewhere, so placeholder
423+
{"notified_flight_information_regions", nlohmann::json::array({1, 2})}};
424+
425+
auto data = nlohmann::json{{"flow_measures", nlohmann::json::array({measure1, measure2})}};
426+
auto flowMeasures = parser->ParseFlowMeasures(data, events, firs);
427+
EXPECT_EQ(2, flowMeasures->Count());
428+
EXPECT_EQ("EGTT-01A", flowMeasures->begin()->Identifier());
429+
EXPECT_EQ("EGTT-01B", (++flowMeasures->begin())->Identifier());
430+
}
431+
332432
struct FlowMeasureDataParserBadDataTestCase {
333433
std::string description;
334434
nlohmann::json data;

test/flowmeasure/FlowMeasureStatusUpdatesTest.cpp

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,44 @@ namespace ECFMPTest::FlowMeasure {
4343
std::shared_ptr<ECFMP::FlowMeasure::FlowMeasure> expectedMeasure;
4444
};
4545

46+
template<typename EventType>
47+
class FlowMeasureStatusUpdatesMultipleEventListener : public ECFMP::EventBus::EventListener<EventType>
48+
{
49+
public:
50+
FlowMeasureStatusUpdatesMultipleEventListener(
51+
std::unordered_map<int, std::shared_ptr<ECFMP::FlowMeasure::FlowMeasure>> expectedMeasures
52+
)
53+
: expectedMeasures(std::move(expectedMeasures))
54+
{}
55+
56+
void OnEvent(const EventType& event) override
57+
{
58+
callCount++;
59+
EXPECT_TRUE(expectedMeasures.contains(event.flowMeasure->Id()));
60+
expectedMeasures.erase(event.flowMeasure->Id());
61+
}
62+
63+
void AssertCalledOnce()
64+
{
65+
EXPECT_EQ(callCount, 1);
66+
}
67+
68+
void AssertCalledTwice()
69+
{
70+
EXPECT_EQ(callCount, 2);
71+
}
72+
73+
void AssertNotCalled()
74+
{
75+
EXPECT_EQ(callCount, 0);
76+
}
77+
78+
private:
79+
int callCount = 0;
80+
81+
std::unordered_map<int, std::shared_ptr<ECFMP::FlowMeasure::FlowMeasure>> expectedMeasures;
82+
};
83+
4684
class FlowMeasureReissuedEventListener
4785
: public ECFMP::EventBus::EventListener<ECFMP::Plugin::FlowMeasureReissuedEvent>
4886
{
@@ -87,12 +125,13 @@ namespace ECFMPTest::FlowMeasure {
87125
{}
88126

89127
[[nodiscard]] static auto
90-
GetMeasureMock(const std::string& identifier, const ECFMP::FlowMeasure::MeasureStatus status)
128+
GetMeasureMock(const std::string& identifier, const ECFMP::FlowMeasure::MeasureStatus status, int id = 1)
91129
-> std::shared_ptr<ECFMP::Mock::FlowMeasure::FlowMeasureMock>
92130
{
93131
auto measure = std::make_shared<ECFMP::Mock::FlowMeasure::FlowMeasureMock>();
94132
auto canonicalInformation = std::make_shared<ECFMP::FlowMeasure::CanonicalFlowMeasureInfo>(identifier);
95133

134+
ON_CALL(*measure, Id).WillByDefault(testing::Return(id));
96135
ON_CALL(*measure, CanonicalInformation)
97136
.WillByDefault(testing::Invoke(
98137
[canonicalInformation]() -> const ECFMP::FlowMeasure::CanonicalFlowMeasureInfo& {
@@ -265,6 +304,52 @@ namespace ECFMPTest::FlowMeasure {
265304
listenerExpired->AssertCalledOnce();
266305
}
267306

307+
TEST_F(FlowMeasureStatusUpdatesTest, ItBroadcastsMultipleMeasures)
308+
{
309+
// Set up the measure and collection
310+
auto measure1 = GetMeasureMock("EGTT01A", ECFMP::FlowMeasure::MeasureStatus::Expired);
311+
auto measure2 = GetMeasureMock("EGTT01B", ECFMP::FlowMeasure::MeasureStatus::Expired, 2);
312+
std::shared_ptr<ECFMP::Api::InternalFlowMeasureCollection> flowMeasures =
313+
std::make_shared<ECFMP::Api::InternalFlowMeasureCollection>();
314+
flowMeasures->Add(measure1);
315+
flowMeasures->Add(measure2);
316+
317+
// Set up event listeners
318+
auto listenerNotified =
319+
std::make_shared<FlowMeasureStatusUpdatesEventListener<ECFMP::Plugin ::FlowMeasureNotifiedEvent>>(
320+
measure1
321+
);
322+
auto listenerActivated =
323+
std::make_shared<FlowMeasureStatusUpdatesEventListener<ECFMP::Plugin::FlowMeasureActivatedEvent>>(
324+
measure1
325+
);
326+
auto listenerWithdrawn =
327+
std::make_shared<FlowMeasureStatusUpdatesEventListener<ECFMP::Plugin::FlowMeasureWithdrawnEvent>>(
328+
measure1
329+
);
330+
331+
const std::unordered_map<int, std::shared_ptr<ECFMP::FlowMeasure::FlowMeasure>> expectedMeasures = {
332+
{measure1->Id(), measure1},
333+
{measure2->Id(), measure2}};
334+
auto listenerExpired =
335+
std::make_shared<FlowMeasureStatusUpdatesMultipleEventListener<ECFMP::Plugin::FlowMeasureExpiredEvent>>(
336+
expectedMeasures
337+
);
338+
339+
eventBus->SubscribeSync<ECFMP::Plugin::FlowMeasureNotifiedEvent>(listenerNotified);
340+
eventBus->SubscribeSync<ECFMP::Plugin::FlowMeasureActivatedEvent>(listenerActivated);
341+
eventBus->SubscribeSync<ECFMP::Plugin::FlowMeasureWithdrawnEvent>(listenerWithdrawn);
342+
eventBus->SubscribeSync<ECFMP::Plugin::FlowMeasureExpiredEvent>(listenerExpired);
343+
344+
// Run event and check the events broadcast
345+
EXPECT_EQ(2, flowMeasures->GetUnderlyingCollection().size());
346+
flowMeasureStatusUpdates->OnEvent({flowMeasures});
347+
listenerNotified->AssertNotCalled();
348+
listenerActivated->AssertNotCalled();
349+
listenerWithdrawn->AssertNotCalled();
350+
listenerExpired->AssertCalledTwice();
351+
}
352+
268353
TEST_F(FlowMeasureStatusUpdatesTest, ItBroadcastsReissuedEventOnCanonicalUpodate)
269354
{
270355
// Set up the measure and collection

0 commit comments

Comments
 (0)