From 02250fd5018f31542ba4090ba7bea13773ac7bd7 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Mon, 20 Jan 2020 16:32:54 +0300 Subject: [PATCH] [routing] Bugfixing in infrastructure of routing session state tests adding a test on changing states. --- .../routing_tests/routing_session_test.cpp | 294 ++++++++++++++---- 1 file changed, 230 insertions(+), 64 deletions(-) diff --git a/routing/routing_tests/routing_session_test.cpp b/routing/routing_tests/routing_session_test.cpp index 37b51fc2f0..6d573a9406 100644 --- a/routing/routing_tests/routing_session_test.cpp +++ b/routing/routing_tests/routing_session_test.cpp @@ -20,13 +20,23 @@ #include #include -namespace routing +namespace { +using namespace routing; using namespace std; using chrono::seconds; using chrono::steady_clock; +vector kTestRoute = {{0., 1.}, {0., 2.}, {0., 3.}, {0., 4.}}; +vector const kTestSegments({{0, 0, 0, true}, {0, 0, 1, true}, {0, 0, 2, true}}); +Route::TTurns const kTestTurns = {turns::TurnItem(3, turns::CarDirection::ReachedYourDestination)}; +Route::TTimes const kTestTimes({Route::TTimeItem(1, 5), Route::TTimeItem(2, 10), + Route::TTimeItem(3, 15)}); +auto const kRouteBuildingMaxDuration = seconds(30); + +void FillSubroutesInfo(Route & route); + // Simple router. It returns route given to him on creation. class DummyRouter : public IRouter { @@ -53,14 +63,34 @@ public: } }; -static vector kTestRoute = {{0., 1.}, {0., 2.}, {0., 3.}, {0., 4.}}; -static vector const kTestSegments({{0, 0, 0, true}, {0, 0, 1, true}, {0, 0, 2, true}}); -static Route::TTurns const kTestTurns = { - turns::TurnItem(3, turns::CarDirection::ReachedYourDestination)}; -static Route::TTimes const kTestTimes({Route::TTimeItem(1, 5), Route::TTimeItem(2, 10), - Route::TTimeItem(3, 15)}); +// Router which every next call of CalculateRoute() method return different return codes. +class ReturnCodesRouter : public IRouter +{ +public: + ReturnCodesRouter(initializer_list const & returnCodes, + vector const & route) + : m_returnCodes(returnCodes), m_route(route) + { + } -static auto kRouteBuildingMaxDuration = seconds(30); + // IRouter overrides: + string GetName() const override { return "return codes router"; } + void ClearState() override {} + RouterResultCode CalculateRoute(Checkpoints const & /* checkpoints */, + m2::PointD const & /* startDirection */, bool /* adjust */, + RouterDelegate const & /* delegate */, Route & route) override + { + TEST_LESS(m_returnCodesIdx, m_returnCodes.size(), ()); + route = Route(GetName(), m_route.begin(), m_route.end(), 0 /* route id */); + FillSubroutesInfo(route); + return m_returnCodes[m_returnCodesIdx++]; + } + +private: + vector m_returnCodes; + vector m_route; + size_t m_returnCodesIdx = 0; +}; class TimedSignal { @@ -97,12 +127,34 @@ public: SessionStateTest(initializer_list expectedStates, RoutingSession & routingSession) : m_expectedStates(expectedStates), m_session(routingSession) { - m_session.SetChangeSessionStateCallback([this](SessionState previous, SessionState current) { - TestChangeSessionStateCallbackCall(previous, current); + for (size_t i = 1; i < expectedStates.size(); ++i) + { + // Note. Change session state callback is called only if the state is change. + if (m_expectedStates[i - 1] != m_expectedStates[i]) + ++m_expectedNumberOfStateChanging; + } + + TimedSignal timedSignal; + GetPlatform().RunTask(Platform::Thread::Gui, [this, &timedSignal]() { + m_session.SetChangeSessionStateCallback([this](SessionState previous, SessionState current) { + TestChangeSessionStateCallbackCall(previous, current); + }); + timedSignal.Signal(); }); + TEST(timedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Callback is not set.")); } - ~SessionStateTest() { m_session.SetChangeSessionStateCallback(nullptr); } + ~SessionStateTest() + { + TEST_EQUAL(m_numberOfTestCalls, m_expectedNumberOfStateChanging, + ("Wrong number of calls of SetState() callback.", m_expectedStates)); + TimedSignal timedSignal; + GetPlatform().RunTask(Platform::Thread::Gui, [this, &timedSignal]() { + m_session.SetChangeSessionStateCallback(nullptr); + timedSignal.Signal(); + }); + TEST(timedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Callback is not set.")); + } private: void TestChangeSessionStateCallbackCall(SessionState previous, SessionState current) @@ -117,6 +169,7 @@ private: size_t m_numberOfTestCalls = 0; vector const m_expectedStates; + size_t m_expectedNumberOfStateChanging = 0; RoutingSession & m_session; }; @@ -134,6 +187,36 @@ void FillSubroutesInfo(Route & route) {Route::SubrouteAttrs(junctions.front(), junctions.back(), 0, kTestSegments.size())})); } +void TestMovingByUpdatingLat(SessionStateTest const & sessionState, vector const & lats, + location::GpsInfo const & info, RoutingSession & session) +{ + location::GpsInfo uptInfo(info); + TimedSignal signal; + GetPlatform().RunTask(Platform::Thread::Gui, [&session, &signal, &lats, &uptInfo]() { + for (auto const lat : lats) + { + uptInfo.m_latitude = lat; + session.OnLocationPositionChanged(uptInfo); + } + + signal.Signal(); + }); + TEST(signal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), + ("Along route moving timeout.")); +} + +void TestLeavingRoute(RoutingSession & session, location::GpsInfo const & info) +{ + vector const latitudes = {0.0, -0.001, -0.002, -0.003, -0.004, -0.005, + -0.006, -0.007, -0.008, -0.009, -0.01, -0.011}; + SessionStateTest sessionStateTest({SessionState::OnRoute, SessionState::RouteNeedRebuild}, + session); + TestMovingByUpdatingLat(sessionStateTest, latitudes, info, session); +} +} // namespace + +namespace routing +{ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteBuilding) { // Multithreading synchronization note. |counter| and |session| are constructed on the main thread, @@ -170,7 +253,6 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteBuilding) UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingMovingAway) { location::GpsInfo info; - FrozenDataSource dataSource; size_t counter = 0; TimedSignal alongTimedSignal; @@ -194,40 +276,40 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingMovingA TEST(alongTimedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Route was not built.")); TEST_EQUAL(counter, 1, ()); - TimedSignal oppositeTimedSignal; - GetPlatform().RunTask(Platform::Thread::Gui, [&oppositeTimedSignal, &info, this]() { - info.m_horizontalAccuracy = 0.01; - info.m_verticalAccuracy = 0.01; - info.m_longitude = 0.; - info.m_latitude = 1.; - SessionState code = SessionState::NoValidRoute; + { + SessionStateTest sessionStateTest( + {SessionState::RouteNotStarted, SessionState::OnRoute, SessionState::RouteBuilding, + SessionState::RouteNotStarted}, + *m_session); + TimedSignal oppositeTimedSignal; + GetPlatform().RunTask(Platform::Thread::Gui, [&oppositeTimedSignal, &info, this]() { + info.m_horizontalAccuracy = 0.01; + info.m_verticalAccuracy = 0.01; + info.m_longitude = 0.; + info.m_latitude = 1.; + SessionState code = SessionState::NoValidRoute; - { - SessionStateTest sessionStateTest({SessionState::RouteNotStarted, SessionState::OnRoute}, - *m_session); - while (info.m_latitude < kTestRoute.back().y) { - code = m_session->OnLocationPositionChanged(info); - TEST_EQUAL(code, SessionState::OnRoute, ()); - info.m_latitude += 0.01; + while (info.m_latitude < kTestRoute.back().y) + { + code = m_session->OnLocationPositionChanged(info); + TEST_EQUAL(code, SessionState::OnRoute, ()); + info.m_latitude += 0.01; + } } - } - // Rebuild route and go in opposite direction. So initiate a route rebuilding flag. - m_session->SetRoutingCallbacks( - [&oppositeTimedSignal](Route const &, RouterResultCode) { oppositeTimedSignal.Signal(); }, - nullptr /* rebuildReadyCallback */, nullptr /* needMoreMapsCallback */, - nullptr /* removeRouteCallback */); - { - SessionStateTest sessionStateTest( - {SessionState::OnRoute, SessionState::RouteBuilding}, - *m_session); - - m_session->BuildRoute(Checkpoints(kTestRoute.front(), kTestRoute.back()), - RouterDelegate::kNoTimeout); - } - }); - TEST(oppositeTimedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Route was not built.")); + // Rebuild route and go in opposite direction. So initiate a route rebuilding flag. + m_session->SetRoutingCallbacks( + [&oppositeTimedSignal](Route const &, RouterResultCode) { oppositeTimedSignal.Signal(); }, + nullptr /* rebuildReadyCallback */, nullptr /* needMoreMapsCallback */, + nullptr /* removeRouteCallback */); + { + m_session->BuildRoute(Checkpoints(kTestRoute.front(), kTestRoute.back()), + RouterDelegate::kNoTimeout); + } + }); + TEST(oppositeTimedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Route was not built.")); + } // Going away from route to set rebuilding flag. TimedSignal checkTimedSignal; @@ -253,7 +335,6 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingMovingA UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingMovingToRoute) { location::GpsInfo info; - FrozenDataSource dataSource; size_t counter = 0; TimedSignal alongTimedSignal; @@ -277,33 +358,34 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingMovingT TEST_EQUAL(counter, 1, ()); // Going starting far from the route and moving to the route but rebuild flag still is set. - TimedSignal checkTimedSignalAway; - GetPlatform().RunTask(Platform::Thread::Gui, [&checkTimedSignalAway, &info, this]() { - info.m_longitude = 0.0; - info.m_latitude = 0.0; - info.m_speedMpS = routing::KMPH2MPS(60); - SessionState code = SessionState::NoValidRoute; - { - SessionStateTest sessionStateTest( - {SessionState::RouteNotStarted, SessionState::RouteNeedRebuild}, - *m_session); - for (size_t i = 0; i < 8; ++i) + { + SessionStateTest sessionStateTest( + {SessionState::RouteNotStarted, SessionState::RouteNeedRebuild}, + *m_session); + TimedSignal checkTimedSignalAway; + GetPlatform().RunTask(Platform::Thread::Gui, [&checkTimedSignalAway, &info, this]() { + info.m_longitude = 0.0; + info.m_latitude = 0.0; + info.m_speedMpS = routing::KMPH2MPS(60); + SessionState code = SessionState::NoValidRoute; { - code = m_session->OnLocationPositionChanged(info); - info.m_latitude += 0.1; + for (size_t i = 0; i < 8; ++i) + { + code = m_session->OnLocationPositionChanged(info); + info.m_latitude += 0.1; + } } - } - TEST_EQUAL(code, SessionState::RouteNeedRebuild, ()); - checkTimedSignalAway.Signal(); - }); - TEST(checkTimedSignalAway.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), - ("Route was not rebuilt.")); + TEST_EQUAL(code, SessionState::RouteNeedRebuild, ()); + checkTimedSignalAway.Signal(); + }); + TEST(checkTimedSignalAway.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), + ("Route was not rebuilt.")); + } } UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestFollowRouteFlagPersistence) { location::GpsInfo info; - FrozenDataSource dataSource; size_t counter = 0; TimedSignal alongTimedSignal; @@ -390,7 +472,6 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestFollowRouteFlagPersist UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestFollowRoutePercentTest) { - FrozenDataSource dataSource; TimedSignal alongTimedSignal; GetPlatform().RunTask(Platform::Thread::Gui, [&alongTimedSignal, this]() { InitRoutingSession(); @@ -452,4 +533,89 @@ UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestFollowRoutePercentTest TEST(checkTimedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Route checking timeout.")); } + +UNIT_CLASS_TEST(AsyncGuiThreadTestWithRoutingSession, TestRouteRebuildingError) +{ + vector const kRoute = {{0.0, 0.001}, {0.0, 0.002}, {0.0, 0.003}, {0.0, 0.004}}; + // Creation RoutingSession. + TimedSignal createTimedSignal; + GetPlatform().RunTask(Platform::Thread::Gui, [this, &kRoute, &createTimedSignal]() { + InitRoutingSession(); + unique_ptr router = make_unique(initializer_list< + RouterResultCode>{RouterResultCode::NoError, RouterResultCode::InternalError}, kRoute); + m_session->SetRouter(move(router), nullptr); + createTimedSignal.Signal(); + }); + TEST(createTimedSignal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), + ("RouteSession was not created.")); + + // Building a route. + { + SessionStateTest sessionStateTest( + {SessionState::NoValidRoute, SessionState::RouteBuilding, SessionState::RouteNotStarted}, + *m_session); + TimedSignal buildTimedSignal; + GetPlatform().RunTask(Platform::Thread::Gui, [this, &kRoute, &buildTimedSignal]() { + m_session->SetRoutingCallbacks( + [&buildTimedSignal](Route const &, RouterResultCode) { buildTimedSignal.Signal(); }, + nullptr /* rebuildReadyCallback */, nullptr /* needMoreMapsCallback */, + nullptr /* removeRouteCallback */); + + m_session->BuildRoute(Checkpoints(kRoute.front(), kRoute.back()), + RouterDelegate::kNoTimeout); + }); + TEST(buildTimedSignal + .WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), ("Route was not built.")); + } + + location::GpsInfo info; + info.m_horizontalAccuracy = 5.0; // meters + info.m_verticalAccuracy = 5.0; // meters + info.m_longitude = 0.0; + + // Moving along route. + { + SessionStateTest sessionStateTest({SessionState::RouteNotStarted, SessionState::OnRoute}, + *m_session); + vector const latitudes = {0.001, 0.0015, 0.002}; + TestMovingByUpdatingLat(sessionStateTest, latitudes, info, *m_session); + } + + // Leaving the route until switching to |SessionState::RouteNeedRebuild| state. + TestLeavingRoute(*m_session, info); + + // Continue moving along the route. + { + SessionStateTest sessionStateTest({SessionState::RouteNeedRebuild, SessionState::OnRoute}, + *m_session); + vector const latitudes = {0.002, 0.0025, 0.003}; + TestMovingByUpdatingLat(sessionStateTest, latitudes, info, *m_session); + } + + // Leaving the route until switching to |SessionState::RouteRebuilding| state. + TestLeavingRoute(*m_session, info); + { + SessionStateTest sessionStateTest( + {SessionState::RouteNeedRebuild, SessionState::RouteRebuilding, + SessionState::RouteNotStarted + }, + *m_session); + TimedSignal signal; + GetPlatform().RunTask(Platform::Thread::Gui, [this, &signal]() { + m_session->SetState(SessionState::RouteRebuilding); + m_session->SetState(SessionState::RouteNotStarted); + signal.Signal(); + }); + TEST(signal.WaitUntil(steady_clock::now() + kRouteBuildingMaxDuration), + ("State was not set.")); + } + + // Continue moving along the route again. + { + SessionStateTest sessionStateTest({SessionState::RouteNotStarted, SessionState::OnRoute}, + *m_session); + vector const latitudes = {0.003, 0.0035, 0.004}; + TestMovingByUpdatingLat(sessionStateTest, latitudes, info, *m_session); + } +} } // namespace routing