[Merge] lp:~mandel/location-service/delayed-providers into lp:location-service

Jim Hodapp jim.hodapp at canonical.com
Mon Jun 15 18:33:44 UTC 2015


Review: Needs Fixing code

Some issues to address, see comments inline below.

Diff comments:

> === modified file 'include/location_service/com/ubuntu/location/provider.h'
> --- include/location_service/com/ubuntu/location/provider.h	2015-01-21 20:13:28 +0000
> +++ include/location_service/com/ubuntu/location/provider.h	2015-06-15 15:23:06 +0000
> @@ -150,6 +150,8 @@
>          friend class Provider;
>          explicit Controller(Provider& instance);
>  
> +        virtual void on_provider_booted(bool was_booted);
> +
>      private:
>          Provider& instance;
>          std::atomic<int> position_updates_counter;
> @@ -172,6 +174,20 @@
>          core::Signal<Update<std::set<SpaceVehicle>>> svs;
>      };
>  
> +    /**
> +     * @brief Wraps al those sigals that are related to the boot of the provider.

Typo, should read "all signals" and "boot process of the provider."

> +     */
> +    struct Signals
> +    {
> +        core::Signal<bool> booted;
> +    };
> +
> +    enum class BootState {
> +        NOT_BOOTED,
> +        BOOTING,
> +        BOOTED
> +    };
> +
>      virtual ~Provider() = default;
>  
>      Provider(const Provider&) = delete;
> @@ -189,6 +205,12 @@
>      virtual const Controller::Ptr& state_controller() const;
>  
>      /**
> +     * @brief Provides non-mutable access to this provider's signals.
> +     * @return A non-mutable reference to the signals.
> +     */
> +    virtual const Signals& signals() const;

Don't you just want a accessor method for the booted signal specifically instead of for the containing struct? This is how things are done for media-hub. Let me know if you need an example.

> +
> +    /**
>       * @brief Checks if the provider supports a specific feature.
>       * @param f Feature to test for
>       * @return true iff the provider supports the feature.
> @@ -210,6 +232,18 @@
>      virtual bool matches_criteria(const Criteria& criteria);
>  
>      /**
> +     * @brief States the booting state of the provider.
> +     * @return The boot state of the provider.
> +     */
> +    virtual BootState boot_state() const;
> +
> +    /**
> +     * @brief Indicates to the provider that it should start the boot process in order to be able to
> +     *        be used by the engine.
> +     */
> +    virtual void boot();
> +
> +    /**
>       * @brief Called by the engine whenever the wifi and cell ID reporting state changes.
>       * @param state The new state.
>       */
> @@ -270,12 +304,14 @@
>       */
>      virtual void stop_velocity_updates();
>  
> -private:
> +protected:
> +    // protected to allow better white box testing
>      struct
>      {
>          Features features = Features::none;
>          Requirements requirements = Requirements::none;
>          Updates updates;
> +        Signals signals;
>          Controller::Ptr controller = Controller::Ptr{};
>      } d;
>  };
> 
> === modified file 'src/location_service/com/ubuntu/location/provider.cpp'
> --- src/location_service/com/ubuntu/location/provider.cpp	2015-01-23 19:07:09 +0000
> +++ src/location_service/com/ubuntu/location/provider.cpp	2015-06-15 15:23:06 +0000
> @@ -16,9 +16,11 @@
>   * Authored by: Thomas Voß <thomas.voss at canonical.com>
>   */
>  #include <com/ubuntu/location/provider.h>
> +#include <com/ubuntu/location/logging.h>
>  
>  #include <atomic>
>  #include <bitset>
> +#include <functional>
>  #include <memory>
>  
>  namespace cul = com::ubuntu::location;
> @@ -51,12 +53,18 @@
>  
>  void cul::Provider::Controller::start_position_updates()
>  {
> -    if (position_updates_counter < 0)
> +    if (position_updates_counter < 0) {
> +        LOG(WARNING) << "Counter smaller than 0";

This feels like a debugging type of output but it's marked as warning, is this really what you want? It's also a really generic message. I know that it has meaning to you, but not to someone new to the codebase.

>          return;
> +    }
>  
>      if (++position_updates_counter == 1)
>      {
> -        instance.start_position_updates();
> +        LOG(WARNING) << "Should we start";

Ditto, should be warning type of output?

> +        if (instance.boot_state() == BootState::BOOTED) {
> +            LOG(WARNING) << "Check boot state.";

Ditto

> +            instance.start_position_updates();
> +        }
>      }
>  }
>  
> @@ -67,7 +75,8 @@
>  
>      if (--position_updates_counter == 0)
>      {
> -        instance.stop_position_updates();
> +        if (instance.boot_state() == BootState::BOOTED)
> +            instance.stop_position_updates();
>      }
>  }
>  
> @@ -83,7 +92,8 @@
>  
>      if (++heading_updates_counter == 1)
>      {
> -        instance.start_heading_updates();
> +        if (instance.boot_state() == BootState::BOOTED)
> +            instance.start_heading_updates();
>      }
>  }
>  
> @@ -94,7 +104,8 @@
>  
>      if (--heading_updates_counter == 0)
>      {
> -        instance.stop_heading_updates();
> +        if (instance.boot_state() == BootState::BOOTED)
> +            instance.stop_heading_updates();
>      }
>  }
>  
> @@ -110,7 +121,8 @@
>  
>      if (++velocity_updates_counter == 1)
>      {
> -        instance.start_velocity_updates();
> +        if (instance.boot_state() == BootState::BOOTED)
> +            instance.start_velocity_updates();
>      }
>  }
>  
> @@ -121,7 +133,8 @@
>  
>      if (--velocity_updates_counter == 0)
>      {
> -        instance.stop_velocity_updates();
> +        if (instance.boot_state() == BootState::BOOTED)
> +            instance.stop_velocity_updates();
>      }
>  }
>  
> @@ -130,12 +143,38 @@
>      return velocity_updates_counter > 0;
>  }
>  
> +void cul::Provider::Controller::on_provider_booted(bool was_booted)
> +{
> +    if (!was_booted)
> +        return;
> +
> +    // we need to propagate the state of the provider using the internal counters as references
> +    if (position_updates_counter > 0) {
> +        instance.start_position_updates();
> +    }
> +    if (heading_updates_counter > 0) {
> +        instance.start_heading_updates();
> +    }
> +    if (velocity_updates_counter > 0) {
> +        instance.start_velocity_updates();
> +    }
> +}
> +
>  cul::Provider::Controller::Controller(cul::Provider& instance)
>      : instance(instance),
>        position_updates_counter(0),
>        heading_updates_counter(0),
>        velocity_updates_counter(0)
> -{  
> +{
> +    using namespace std::placeholders;
> +
> +    if (instance.boot_state() != BootState::BOOTED) {
> +        // if the instance has not booted and is delayed we need to keep track of its booting state
> +        instance.signals().booted.connect(std::bind(&Controller::on_provider_booted, this, _1));
> +        if (instance.boot_state() != BootState::BOOTING) {
> +            instance.boot();
> +        }
> +    }
>  }
>  
>  const cul::Provider::Controller::Ptr& cul::Provider::state_controller() const
> @@ -158,11 +197,23 @@
>      return false;
>  }
>  
> +cul::Provider::BootState cul::Provider::boot_state() const

Does this implement boot_state for a default dummy provider? Otherwise I don't see where boot_state dynamically gets set for use in your logic above.

> +{
> +    return cul::Provider::BootState::BOOTED;
> +}
> +
> +void cul::Provider::boot() { }
> +
>  const cul::Provider::Updates& cul::Provider::updates() const
>  {
>      return d.updates;
>  }
>  
> +const cul::Provider::Signals& cul::Provider::signals() const
> +{
> +    return d.signals;
> +}
> +
>  cul::Provider::Provider(
>      const cul::Provider::Features& features,
>      const cul::Provider::Requirements& requirements)
> 
> === modified file 'tests/controller_test.cpp'
> --- tests/controller_test.cpp	2014-09-10 19:34:09 +0000
> +++ tests/controller_test.cpp	2015-06-15 15:23:06 +0000
> @@ -18,6 +18,7 @@
>  #include <com/ubuntu/location/provider.h>
>  
>  #include "mock_provider.h"
> +#include "mock_delayed_provider.h"
>  
>  #include <gmock/gmock.h>
>  #include <gtest/gtest.h>
> @@ -130,3 +131,215 @@
>      EXPECT_FALSE(controller->are_velocity_updates_running());
>      EXPECT_FALSE(controller->are_heading_updates_running());
>  }
> +
> +TEST(Controller, controller_resumes_state_after_boot) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +
> +}
> +
> +TEST(Controller, controller_does_not_call_start_position_if_not_booted) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +    // use a mock controller
> +    auto controller = provider.state_controller();
> +
> +    EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
> +            .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED));
> +    EXPECT_CALL(provider, start_position_updates()).Times(Exactly(0));
> +
> +    controller->start_position_updates();
> +    controller->start_position_updates();
> +}
> +
> +TEST(Controller, controller_does_not_call_start_position_if_booting) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +    // use a mock controller
> +    auto controller = provider.state_controller();
> +
> +    EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
> +            .WillOnce(Return(cul::Provider::BootState::BOOTING));
> +    EXPECT_CALL(provider, start_position_updates()).Times(Exactly(0));
> +
> +    controller->start_position_updates();
> +}
> +
> +TEST(Controller, controller_does_not_call_start_heading_if_not_booted) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +    EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +    // use a mock controller
> +    auto controller = provider.state_controller();
> +
> +    EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
> +            .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED));
> +    EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0));
> +
> +    controller->start_heading_updates();
> +}
> +
> +TEST(Controller, controller_does_not_call_start_heading_if_booting) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +    EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +    // use a mock controller
> +    auto controller = provider.state_controller();
> +
> +    EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
> +            .WillOnce(Return(cul::Provider::BootState::BOOTING));
> +    EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0));
> +
> +    controller->start_heading_updates();
> +}
> +
> +TEST(Controller, controller_does_not_call_start_velocity_if_not_booted) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +    EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +    // use a mock controller
> +    auto controller = provider.state_controller();
> +
> +    EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
> +            .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED));
> +    EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0));
> +
> +    controller->start_velocity_updates();
> +}
> +
> +TEST(Controller, controller_does_not_call_start_velocity_if_booting) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +    EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +    // use a mock controller
> +    auto controller = provider.state_controller();
> +
> +    EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
> +            .WillOnce(Return(cul::Provider::BootState::BOOTING));
> +    EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0));
> +
> +    controller->start_velocity_updates();
> +}
> +
> +TEST(Controller, controller_does_not_call_stop_position_if_not_booted) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +    EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +    // use a mock controller
> +    auto controller = provider.state_controller();
> +
> +    EXPECT_CALL(provider, boot_state()).Times(Exactly(2))
> +            .WillOnce(Return(cul::Provider::BootState::BOOTED))
> +            .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED));
> +    EXPECT_CALL(provider, start_position_updates()).Times(Exactly(1));
> +    EXPECT_CALL(provider, stop_position_updates()).Times(Exactly(0));
> +
> +    controller->start_position_updates();
> +    controller->stop_position_updates();
> +}
> +
> +TEST(Controller, controller_does_not_call_stop_position_if_booting) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +    EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +    // use a mock controller
> +    auto controller = provider.state_controller();
> +
> +    EXPECT_CALL(provider, boot_state()).Times(Exactly(2))
> +            .WillOnce(Return(cul::Provider::BootState::BOOTED))
> +            .WillOnce(Return(cul::Provider::BootState::BOOTING));
> +    EXPECT_CALL(provider, start_position_updates()).Times(Exactly(1));
> +    EXPECT_CALL(provider, stop_position_updates()).Times(Exactly(0));
> +
> +    controller->start_position_updates();
> +    controller->stop_position_updates();
> +}
> +
> +TEST(Controller, controller_does_not_call_stop_heading_if_not_booted) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +    EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +    // use a mock controller
> +    auto controller = provider.state_controller();
> +
> +    EXPECT_CALL(provider, boot_state()).Times(Exactly(2))
> +            .WillOnce(Return(cul::Provider::BootState::BOOTED))
> +            .WillOnce(Return(cul::Provider::BootState::BOOTING));
> +    EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(1));
> +    EXPECT_CALL(provider, stop_heading_updates()).Times(Exactly(0));
> +
> +    controller->start_heading_updates();
> +    controller->stop_heading_updates();
> +}
> +
> +TEST(Controller, controller_does_not_call_stop_velocity_if_not_booted) {
> +    using namespace ::testing;
> +    using ::testing::Mock;
> +
> +    MockDelayedProvider provider;
> +    EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
> +
> +    // ignore what ever was performed on construction
> +    Mock::VerifyAndClear(&provider);
> +    // use a mock controller
> +    auto controller = provider.state_controller();
> +
> +    EXPECT_CALL(provider, boot_state()).Times(Exactly(2))
> +            .WillOnce(Return(cul::Provider::BootState::BOOTED))
> +            .WillOnce(Return(cul::Provider::BootState::BOOTING));
> +    EXPECT_CALL(provider, start_velocity_updates()).Times(Exactly(1));
> +    EXPECT_CALL(provider, stop_velocity_updates()).Times(Exactly(0));
> +
> +    controller->start_velocity_updates();
> +    controller->stop_velocity_updates();
> +}
> 
> === added file 'tests/mock_delayed_provider.h'
> --- tests/mock_delayed_provider.h	1970-01-01 00:00:00 +0000
> +++ tests/mock_delayed_provider.h	2015-06-15 15:23:06 +0000
> @@ -0,0 +1,89 @@
> +/*
> + * Copyright © 2014 Canonical Ltd.
> + *
> + * This program is free software: you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License version 3,
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authored by: M
> + */
> +#ifndef MOCK_DELAYED_PROVIDER_H_
> +#define MOCK_DELAYED_PROVIDER_H_
> +
> +#include <com/ubuntu/location/provider.h>
> +#include <com/ubuntu/location/logging.h>
> +
> +#include <gmock/gmock.h>
> +
> +struct PublicController : public com::ubuntu::location::Provider::Controller
> +{
> +
> +    explicit PublicController(com::ubuntu::location::Provider& instance)
> +            : com::ubuntu::location::Provider::Controller(instance) {}
> +};
> +
> +struct MockDelayedProvider : public com::ubuntu::location::Provider
> +{
> +    MockDelayedProvider() : com::ubuntu::location::Provider()
> +    {
> +    }
> +
> +    MOCK_METHOD1(matches_criteria, bool(const com::ubuntu::location::Criteria&));
> +
> +    MOCK_CONST_METHOD1(supports, bool(const com::ubuntu::location::Provider::Features&));
> +    MOCK_CONST_METHOD1(requires, bool(const com::ubuntu::location::Provider::Requirements&));
> +
> +    // Called by the engine whenever the wifi and cell ID reporting state changes.
> +    MOCK_METHOD1(on_wifi_and_cell_reporting_state_changed, void(com::ubuntu::location::WifiAndCellIdReportingState state));
> +
> +    // Called by the engine whenever the reference location changed.
> +    MOCK_METHOD1(on_reference_location_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Position>& position));
> +
> +    // Called by the engine whenever the reference velocity changed.
> +    MOCK_METHOD1(on_reference_velocity_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Velocity>& velocity));
> +
> +    // Called by the engine whenever the reference heading changed.
> +    MOCK_METHOD1(on_reference_heading_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Heading>& heading));
> +
> +    MOCK_METHOD0(start_position_updates, void());
> +    MOCK_METHOD0(stop_position_updates, void());
> +
> +    MOCK_METHOD0(start_heading_updates, void());
> +    MOCK_METHOD0(stop_heading_updates, void());
> +
> +    MOCK_METHOD0(start_velocity_updates, void());
> +    MOCK_METHOD0(stop_velocity_updates, void());
> +
> +    MOCK_CONST_METHOD0(has_delayed_boot, bool());
> +    MOCK_CONST_METHOD0(boot_state, BootState());
> +    MOCK_CONST_METHOD0(boot, void());
> +
> +
> +    // Inject a position update from the outside.
> +    void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Position>& update)
> +    {
> +        mutable_updates().position(update);
> +    }
> +
> +    // Inject a velocity update from the outside.
> +    void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Velocity>& update)
> +    {
> +        mutable_updates().velocity(update);
> +    }
> +
> +    // Inject a heading update from the outside.
> +    void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Heading>& update)
> +    {
> +        mutable_updates().heading(update);
> +    }
> +};
> +
> +#endif // MOCK_PROVIDER_H_
> 


-- 
https://code.launchpad.net/~mandel/location-service/delayed-providers/+merge/261944
Your team Ubuntu Phablet Team is subscribed to branch lp:location-service.



More information about the Ubuntu-reviews mailing list