=== modified file 'src/location_service/com/ubuntu/location/providers/remote/provider.cpp'
--- src/location_service/com/ubuntu/location/providers/remote/provider.cpp	2014-08-27 09:13:42 +0000
+++ src/location_service/com/ubuntu/location/providers/remote/provider.cpp	2014-09-10 19:36:13 +0000
@@ -27,11 +27,20 @@
 
 namespace cul = com::ubuntu::location;
 namespace culpr = com::ubuntu::location::providers::remote;
-
+namespace cur = com::ubuntu::remote;
 namespace dbus = core::dbus;
 
 namespace
 {
+template<typename T>
+void throw_if_error(const dbus::Result<T>& result)
+{
+    if (result.is_error()) throw std::runtime_error
+    {
+        result.error().print()
+    };
+}
+
 dbus::Bus::Ptr the_system_bus()
 {
     dbus::Bus::Ptr system_bus = std::make_shared<dbus::Bus>(dbus::WellKnownBus::system);
@@ -42,38 +51,18 @@
 
 struct culpr::Provider::Private
 {
-    typedef core::dbus::Signal<
-        com::ubuntu::remote::RemoteInterface::Signals::PositionChanged,
-	com::ubuntu::remote::RemoteInterface::Signals::PositionChanged::ArgumentType
-    > PositionChanged;
-
     Private(const culpr::Provider::Configuration& config)
             : bus(config.connection),
               service(dbus::Service::use_service(bus, config.name)),
               object(service->object_for_path(config.path)),
-              signal_position_changed(object->get_signal<com::ubuntu::remote::RemoteInterface::Signals::PositionChanged>())
-    {
-    }
-
-    void start()
-    {
-        VLOG(10) << __PRETTY_FUNCTION__;
-        if (!worker.joinable())
-            worker = std::move(std::thread{std::bind(&dbus::Bus::run, bus)});
-    }
-
-    void stop()
-    {
-        VLOG(10) << __PRETTY_FUNCTION__;
-        try
-        {
-            bus->stop();
-        }
-        catch(...)
-        {
-            // can happen if the start method was not called
-            VLOG(10) << "Stopping not started remote provider.";
-        }
+              stub(object),
+              worker([this]() { bus->run(); })
+    {
+    }
+
+    ~Private()
+    {
+        bus->stop();
 
         if (worker.joinable())
             worker.join();
@@ -82,8 +71,8 @@
     dbus::Bus::Ptr bus;
     dbus::Service::Ptr service;
     dbus::Object::Ptr object;
-    PositionChanged::Ptr signal_position_changed;
-    PositionChanged::SubscriptionToken position_updates_connection;
+
+    com::ubuntu::remote::RemoteInterface::Stub stub;
 
     std::thread worker;
 };
@@ -108,22 +97,28 @@
         : com::ubuntu::location::Provider(config.features, config.requirements),
           d(new Private(config))
 {
-    d->position_updates_connection =
-        d->signal_position_changed->connect(
-            [this](const com::ubuntu::remote::RemoteInterface::Signals::PositionChanged::ArgumentType& arg)
-            {
-                this->on_position_changed(arg);
-            });
+    d->stub.signals.position_changed->connect(
+        [this](const cur::RemoteInterface::Signals::PositionChanged::ArgumentType& arg)
+        {
+            VLOG(50) << "culpr::Provider::PositionChanged: " << arg;
+            mutable_updates().position(arg);
+        });
+    d->stub.signals.heading_changed->connect(
+        [this](const cur::RemoteInterface::Signals::HeadingChanged::ArgumentType& arg)
+        {
+            VLOG(50) << "culpr::Provider::HeadingChanged: " << arg;
+            mutable_updates().heading(arg);
+        });
+    d->stub.signals.velocity_changed->connect(
+        [this](const cur::RemoteInterface::Signals::VelocityChanged::ArgumentType& arg)
+        {
+            VLOG(50) << "culpr::Provider::VelocityChanged: " << arg;
+            mutable_updates().velocity(arg);
+        });
 }
 
 culpr::Provider::~Provider() noexcept
 {
-    d->stop();
-}
-
-void culpr::Provider::on_position_changed(const com::ubuntu::remote::RemoteInterface::Signals::PositionChanged::ArgumentType& arg)
-{
-    mutable_updates().position(arg);
 }
 
 bool culpr::Provider::matches_criteria(const cul::Criteria&)
@@ -133,12 +128,36 @@
 
 void culpr::Provider::start_position_updates()
 {
-    VLOG(10) << "Starting remote provider\n";
-    d->start();
+    VLOG(10) << __PRETTY_FUNCTION__;
+    throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StartPositionUpdates, void>());
 }
 
 void culpr::Provider::stop_position_updates()
 {
-    VLOG(10) << "Stopping remote provider\n";
-    d->stop();
+    VLOG(10) << __PRETTY_FUNCTION__;
+    throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StopPositionUpdates, void>());
+}
+
+void culpr::Provider::start_heading_updates()
+{
+    VLOG(10) << __PRETTY_FUNCTION__;
+    throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StartHeadingUpdates, void>());
+}
+
+void culpr::Provider::stop_heading_updates()
+{
+    VLOG(10) << __PRETTY_FUNCTION__;
+    throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StopHeadingUpdates, void>());
+}
+
+void culpr::Provider::start_velocity_updates()
+{
+    VLOG(10) << __PRETTY_FUNCTION__;
+    throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StartVelocityUpdates, void>());
+}
+
+void culpr::Provider::stop_velocity_updates()
+{
+    VLOG(10) << __PRETTY_FUNCTION__;
+    throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StopVelocityUpdates, void>());
 }

=== modified file 'src/location_service/com/ubuntu/location/providers/remote/provider.h'
--- src/location_service/com/ubuntu/location/providers/remote/provider.h	2014-08-26 16:04:02 +0000
+++ src/location_service/com/ubuntu/location/providers/remote/provider.h	2014-09-10 19:36:13 +0000
@@ -66,10 +66,14 @@
 
     virtual bool matches_criteria(const Criteria&);
 
-    virtual void start_position_updates();
-    virtual void stop_position_updates();
-
-    void on_position_changed(const com::ubuntu::remote::RemoteInterface::Signals::PositionChanged::ArgumentType& arg);
+    virtual void start_position_updates() override;
+    virtual void stop_position_updates() override;
+
+    virtual void start_heading_updates() override;
+    virtual void stop_heading_updates() override;
+
+    virtual void start_velocity_updates() override;
+    virtual void stop_velocity_updates() override;
 
   private:
     struct Private;

=== modified file 'src/location_service/com/ubuntu/location/providers/remote/remote_interface.h'
--- src/location_service/com/ubuntu/location/providers/remote/remote_interface.h	2014-08-29 10:41:36 +0000
+++ src/location_service/com/ubuntu/location/providers/remote/remote_interface.h	2014-09-10 19:36:13 +0000
@@ -20,11 +20,18 @@
 #define CORE_UBUNTU_ESPOO_PROVIDER_P_H_
 
 #include <core/dbus/macros.h>
+#include <core/dbus/object.h>
+#include <core/dbus/property.h>
+#include <core/dbus/signal.h>
+
 #include <core/dbus/traits/service.h>
 
 #include <com/ubuntu/location/codec.h>
 #include <com/ubuntu/location/update.h>
+
+#include <com/ubuntu/location/heading.h>
 #include <com/ubuntu/location/position.h>
+#include <com/ubuntu/location/velocity.h>
 
 namespace cul = com::ubuntu::location;
 
@@ -36,7 +43,6 @@
 {
 struct RemoteInterface
 {
-
     static const std::string& name()
     {
         static const std::string s{"com.ubuntu.remote.Service.Provider"};
@@ -52,18 +58,9 @@
 
     struct Signals
     {
-        struct PositionChanged
-        {
-            inline static std::string name()
-            {
-                return "PositionChanged";
-            };
-            typedef RemoteInterface Interface;
-            typedef cul::Position ArgumentType;
-        };
-
-        DBUS_CPP_SIGNAL_DEF(HeadingChanged, RemoteInterface, double)
-        DBUS_CPP_SIGNAL_DEF(VelocityChanged, RemoteInterface, double)
+        DBUS_CPP_SIGNAL_DEF(PositionChanged, RemoteInterface, cul::Position)
+        DBUS_CPP_SIGNAL_DEF(HeadingChanged, RemoteInterface, cul::Heading)
+        DBUS_CPP_SIGNAL_DEF(VelocityChanged, RemoteInterface, cul::Velocity)
     };
 
     struct Properties
@@ -80,35 +77,137 @@
         DBUS_CPP_READABLE_PROPERTY_DEF(AreVelocityUpdatesRunning, RemoteInterface, bool)
     };
 
+    struct Skeleton
+    {
+        // Creates a new skeleton instance and installs the interface
+        // com::ubuntu::remote::Interface on it.
+        Skeleton(const core::dbus::Object::Ptr& object)
+            : object{object},
+              properties
+              {
+                  object->get_property<Properties::HasPosition>(),
+                  object->get_property<Properties::HasVelocity>(),
+                  object->get_property<Properties::HasHeading>(),
+                  object->get_property<Properties::RequiresSatellites>(),
+                  object->get_property<Properties::RequiresCellNetwork>(),
+                  object->get_property<Properties::RequiresDataNetwork>(),
+                  object->get_property<Properties::RequiresMonetarySpending>(),
+                  object->get_property<Properties::ArePositionUpdatesRunning>(),
+                  object->get_property<Properties::AreHeadingUpdatesRunning>(),
+                  object->get_property<Properties::AreVelocityUpdatesRunning>()
+              },
+              signals
+              {
+                  object->get_signal<Signals::PositionChanged>(),
+                  object->get_signal<Signals::HeadingChanged>(),
+                  object->get_signal<Signals::VelocityChanged>()
+              }
+        {
+        }
+
+        // The object that the interface is installed on.
+        core::dbus::Object::Ptr object;
+        // All known properties.
+        struct
+        {
+            std::shared_ptr<core::dbus::Property<Properties::HasPosition>> has_position;
+            std::shared_ptr<core::dbus::Property<Properties::HasVelocity>> has_velocity;
+            std::shared_ptr<core::dbus::Property<Properties::HasHeading>> has_heading;
+            std::shared_ptr<core::dbus::Property<Properties::RequiresSatellites>> requires_satellites;
+            std::shared_ptr<core::dbus::Property<Properties::RequiresCellNetwork>> requires_cell_network;
+            std::shared_ptr<core::dbus::Property<Properties::RequiresDataNetwork>> requires_data_network;
+            std::shared_ptr<core::dbus::Property<Properties::RequiresMonetarySpending>> requires_monetary_spending;
+            std::shared_ptr<core::dbus::Property<Properties::ArePositionUpdatesRunning>> are_position_updates_running;
+            std::shared_ptr<core::dbus::Property<Properties::AreHeadingUpdatesRunning>> are_heading_updates_running;
+            std::shared_ptr<core::dbus::Property<Properties::AreVelocityUpdatesRunning>> are_velocity_updates_running;
+        } properties;
+        // All known signals.
+        struct
+        {
+            std::shared_ptr<core::dbus::Signal<
+                Signals::PositionChanged,
+                Signals::PositionChanged::ArgumentType
+            >> position_changed;
+
+            std::shared_ptr<core::dbus::Signal<
+                Signals::HeadingChanged,
+                Signals::HeadingChanged::ArgumentType
+            >> heading_changed;
+
+            std::shared_ptr<core::dbus::Signal<
+                Signals::VelocityChanged,
+                Signals::VelocityChanged::ArgumentType
+            >> velocity_changed;
+        } signals;
+    };
+
+    struct Stub
+    {
+        // Creates a new skeleton instance and installs the interface
+        // com::ubuntu::remote::Interface on it.
+        Stub(const core::dbus::Object::Ptr& object)
+            : object{object},
+              properties
+              {
+                  object->get_property<Properties::HasPosition>(),
+                  object->get_property<Properties::HasVelocity>(),
+                  object->get_property<Properties::HasHeading>(),
+                  object->get_property<Properties::RequiresSatellites>(),
+                  object->get_property<Properties::RequiresCellNetwork>(),
+                  object->get_property<Properties::RequiresDataNetwork>(),
+                  object->get_property<Properties::RequiresMonetarySpending>(),
+                  object->get_property<Properties::ArePositionUpdatesRunning>(),
+                  object->get_property<Properties::AreHeadingUpdatesRunning>(),
+                  object->get_property<Properties::AreVelocityUpdatesRunning>()
+              },
+              signals
+              {
+                  object->get_signal<Signals::PositionChanged>(),
+                  object->get_signal<Signals::HeadingChanged>(),
+                  object->get_signal<Signals::VelocityChanged>()
+              }
+        {
+        }
+
+        // The object that the interface is installed on.
+        core::dbus::Object::Ptr object;
+        // All known properties.
+        struct
+        {
+            std::shared_ptr<core::dbus::Property<Properties::HasPosition>> has_position;
+            std::shared_ptr<core::dbus::Property<Properties::HasVelocity>> has_velocity;
+            std::shared_ptr<core::dbus::Property<Properties::HasHeading>> has_heading;
+            std::shared_ptr<core::dbus::Property<Properties::RequiresSatellites>> requires_satellites;
+            std::shared_ptr<core::dbus::Property<Properties::RequiresCellNetwork>> requires_cell_network;
+            std::shared_ptr<core::dbus::Property<Properties::RequiresDataNetwork>> requires_data_network;
+            std::shared_ptr<core::dbus::Property<Properties::RequiresMonetarySpending>> requires_monetary_spending;
+            std::shared_ptr<core::dbus::Property<Properties::ArePositionUpdatesRunning>> are_position_updates_running;
+            std::shared_ptr<core::dbus::Property<Properties::AreHeadingUpdatesRunning>> are_heading_updates_running;
+            std::shared_ptr<core::dbus::Property<Properties::AreVelocityUpdatesRunning>> are_velocity_updates_running;
+        } properties;
+        // All known signals.
+        struct
+        {
+            std::shared_ptr<core::dbus::Signal<
+                Signals::PositionChanged,
+                Signals::PositionChanged::ArgumentType
+            >> position_changed;
+
+            std::shared_ptr<core::dbus::Signal<
+                Signals::HeadingChanged,
+                Signals::HeadingChanged::ArgumentType
+            >> heading_changed;
+
+            std::shared_ptr<core::dbus::Signal<
+                Signals::VelocityChanged,
+                Signals::VelocityChanged::ArgumentType
+            >> velocity_changed;
+        } signals;
+    };
+
 };
 } // remote
 } // ubuntu
 }  // core
 
-namespace core
-{
-namespace dbus
-{
-namespace traits
-{
-template<>
-struct Service<com::ubuntu::remote::RemoteInterface>
-{
-    static const std::string& interface_name()
-    {
-        static const std::string s{"com.ubuntu.espoo.Service.Provider"};
-        return s;
-    }
-
-    inline static const std::string& object_path()
-    {
-        static const std::string s{"/com/ubuntu/espoo/Service/Provider"};
-        return s;
-    }
-
-};
-}
-}
-}
-
 #endif

=== modified file 'tests/controller_test.cpp'
--- tests/controller_test.cpp	2014-01-20 13:03:19 +0000
+++ tests/controller_test.cpp	2014-09-10 19:36:13 +0000
@@ -17,6 +17,8 @@
  */
 #include <com/ubuntu/location/provider.h>
 
+#include "mock_provider.h"
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -24,37 +26,6 @@
 
 namespace
 {
-struct MockProvider : public cul::Provider
-{
-    MockProvider() : cul::Provider()
-    {
-    }
-
-    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());
-
-    void inject_update(const cul::Update<cul::Position>& update)
-    {
-        mutable_updates().position(update);
-    }
-
-    void inject_update(const cul::Update<cul::Velocity>& update)
-    {
-        mutable_updates().velocity(update);
-    }
-
-    void inject_update(const cul::Update<cul::Heading>& update)
-    {
-        mutable_updates().heading(update);
-    }
-};
-
 auto timestamp = com::ubuntu::location::Clock::now();
 
 com::ubuntu::location::Update<com::ubuntu::location::Position> reference_position_update

=== added file 'tests/mock_provider.h'
--- tests/mock_provider.h	1970-01-01 00:00:00 +0000
+++ tests/mock_provider.h	2014-09-10 19:36:13 +0000
@@ -0,0 +1,71 @@
+/*
+ * 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: Thomas Voß <thomas.voss@canonical.com>
+ */
+#ifndef MOCK_PROVIDER_H_
+#define MOCK_PROVIDER_H_
+
+#include <com/ubuntu/location/provider.h>
+
+#include <gmock/gmock.h>
+
+struct MockProvider : public com::ubuntu::location::Provider
+{
+    MockProvider() : com::ubuntu::location::Provider()
+    {
+    }
+
+    // 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());
+
+    // 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_

=== modified file 'tests/remote_provider_test.cpp'
--- tests/remote_provider_test.cpp	2014-08-27 09:13:42 +0000
+++ tests/remote_provider_test.cpp	2014-09-10 19:36:13 +0000
@@ -20,18 +20,27 @@
 #include <com/ubuntu/location/proxy_provider.h>
 #include <com/ubuntu/location/providers/remote/provider.h>
 
+#include "mock_provider.h"
+
 #include <core/dbus/fixture.h>
+#include <core/dbus/asio/executor.h>
+
+#include <core/posix/fork.h>
+#include <core/posix/signal.h>
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 namespace cul = com::ubuntu::location;
+namespace cur = com::ubuntu::remote;
+namespace dbus = core::dbus;
 namespace remote = com::ubuntu::location::providers::remote;
 
 using namespace ::testing;
 
 
-MATCHER_P(postion_equals_tuple, value, "Returns if the string maps are equal.") {
+MATCHER_P(PositionUpdatesAreEqualExceptForTiming, value, "Returns true if the positions in both updates are equal.")
+{
     auto pos = arg.value;
 
     return value.longitude == pos.longitude && value.latitude == pos.latitude && value.altitude == pos.altitude
@@ -39,27 +48,346 @@
         && pos.accuracy.vertical == value.accuracy.vertical;
 }
 
+MATCHER_P(HeadingUpdatesAreEqualExceptForTiming, value, "Returns true if the heading in both updates are equal.")
+{
+    auto heading = arg.value;
+    return heading == value;
+}
+
+MATCHER_P(VelocityUpdatesAreEqualExceptForTiming, value, "Returns true if the velocity in both updates are equal.")
+{
+    auto velocity = arg.value;
+    return velocity == value;
+}
+
 namespace
 {
+::testing::AssertionResult did_finish_successfully(const core::posix::wait::Result& result)
+{
+    if (result.status != core::posix::wait::Result::Status::exited)
+        return ::testing::AssertionFailure() << "Process did not exit, but: " << (int)result.status;
+    if (result.detail.if_exited.status != core::posix::exit::Status::success)
+        return ::testing::AssertionFailure() << "Process did exit with failure.";
+
+    return ::testing::AssertionSuccess();
+}
+
 struct RemoteProvider : public core::dbus::testing::Fixture
 {
+    static constexpr const char* stub_remote_provider_service_name
+    {
+        "does.not.exist.remote.Provider"
+    };
 
+    static constexpr const char* stub_remote_provider_path
+    {
+        "/com/ubuntu/remote/Provider"
+    };
 };
 
 class MockEventConsumer
 {
  public:
-    MockEventConsumer() {}
+    MockEventConsumer()
+    {
+        using namespace ::testing;
+
+        ON_CALL(*this, on_new_position(_))
+                .WillByDefault(
+                    InvokeWithoutArgs(
+                        this,
+                        &MockEventConsumer::notify_position_update_arrived));
+        ON_CALL(*this, on_new_heading(_))
+                .WillByDefault(
+                    InvokeWithoutArgs(
+                        this,
+                        &MockEventConsumer::notify_heading_update_arrived));
+        ON_CALL(*this, on_new_velocity(_))
+                .WillByDefault(
+                    InvokeWithoutArgs(
+                        this,
+                        &MockEventConsumer::notify_velocity_update_arrived));
+    }
+
+    bool wait_for_position_update_for(const std::chrono::milliseconds& timeout)
+    {
+        std::unique_lock<std::mutex> ul{position.guard};
+        return position.wait_condition.wait_for(ul, timeout, [this] { return position.update_arrived; });
+    }
+
+    bool wait_for_heading_update_for(const std::chrono::milliseconds& timeout)
+    {
+        std::unique_lock<std::mutex> ul{heading.guard};
+        return heading.wait_condition.wait_for(ul, timeout, [this] { return heading.update_arrived; });
+    }
+
+    bool wait_for_velocity_update_for(const std::chrono::milliseconds& timeout)
+    {
+        std::unique_lock<std::mutex> ul{velocity.guard};
+        return velocity.wait_condition.wait_for(ul, timeout, [this] { return velocity.update_arrived; });
+    }
 
     MOCK_METHOD1(on_new_position, void(const cul::Update<cul::Position>&));
+    MOCK_METHOD1(on_new_heading, void(const cul::Update<cul::Heading>&));
+    MOCK_METHOD1(on_new_velocity, void(const cul::Update<cul::Velocity>&));
+
+private:
+    // Notes down the arrival of a position update
+    // and notifies any waiting threads about the event.
+    void notify_position_update_arrived()
+    {
+        position.update_arrived = true;
+        position.wait_condition.notify_all();
+    }
+
+    // Notes down the arrival of a heading update
+    // and notifies any waiting threads about the event.
+    void notify_heading_update_arrived()
+    {
+        heading.update_arrived = true;
+        heading.wait_condition.notify_all();
+    }
+
+    // Notes down the arrival of a heading update
+    // and notifies any waiting threads about the event.
+    void notify_velocity_update_arrived()
+    {
+        velocity.update_arrived = true;
+        velocity.wait_condition.notify_all();
+    }
+
+    struct
+    {
+        std::mutex guard;
+        std::condition_variable wait_condition;
+        bool update_arrived{false};
+    } position;
+
+    struct
+    {
+        std::mutex guard;
+        std::condition_variable wait_condition;
+        bool update_arrived{false};
+    } heading;
+
+    struct
+    {
+        std::mutex guard;
+        std::condition_variable wait_condition;
+        bool update_arrived{false};
+    } velocity;
 };
 }
-TEST_F(RemoteProvider, matches_criteria)
-{
+
+TEST_F(RemoteProvider, updates_are_fwd)
+{
+    using namespace ::testing;
+
+    static const cul::Position position
+    {
+        cul::wgs84::Latitude{2* cul::units::Degrees},
+        cul::wgs84::Longitude{3* cul::units::Degrees},
+        cul::wgs84::Altitude{4* cul::units::Meters},
+        cul::Position::Accuracy::Horizontal(5* cul::units::Meters),
+        cul::Position::Accuracy::Vertical(6* cul::units::Meters)
+    };
+
+    static const cul::Heading heading
+    {
+        120. * cul::units::Degrees
+    };
+
+    static const cul::Velocity velocity
+    {
+        5. * cul::units::MetersPerSecond
+    };
+
+    auto skeleton = core::posix::fork([this]()
+    {
+        bool running{true};
+        auto trap = core::posix::trap_signals_for_all_subsequent_threads({core::posix::Signal::sig_term});
+
+        trap->signal_raised().connect([trap, &running](core::posix::Signal)
+        {
+            trap->stop();
+            running = false;
+        });
+
+        auto bus = session_bus();
+        bus->install_executor(dbus::asio::make_executor(bus));
+
+        std::thread worker([bus]()
+        {
+            bus->run();
+        });
+
+        auto object = dbus::Service::add_service(
+                    bus,
+                    RemoteProvider::stub_remote_provider_service_name)
+                        ->add_object_for_path(
+                            dbus::types::ObjectPath{RemoteProvider::stub_remote_provider_path});
+
+        // We use this instance to capture incoming requests.
+        NiceMock<MockProvider> mock_provider;
+
+        EXPECT_CALL(mock_provider, start_position_updates()).Times(1);
+        EXPECT_CALL(mock_provider, start_heading_updates()).Times(1);
+        EXPECT_CALL(mock_provider, start_velocity_updates()).Times(1);
+        EXPECT_CALL(mock_provider, stop_position_updates()).Times(1);
+        EXPECT_CALL(mock_provider, stop_heading_updates()).Times(1);
+        EXPECT_CALL(mock_provider, stop_velocity_updates()).Times(1);
+
+        cur::RemoteInterface::Skeleton remote_provider{object};
+
+        remote_provider.object->install_method_handler<cur::RemoteInterface::StartPositionUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
+        {
+            mock_provider.start_position_updates();
+            bus->send(dbus::Message::make_method_return(msg));
+        });
+
+        remote_provider.object->install_method_handler<cur::RemoteInterface::StopPositionUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
+        {
+            mock_provider.stop_position_updates();
+            bus->send(dbus::Message::make_method_return(msg));
+        });
+
+        remote_provider.object->install_method_handler<cur::RemoteInterface::StartHeadingUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
+        {
+            mock_provider.start_heading_updates();
+            bus->send(dbus::Message::make_method_return(msg));
+        });
+
+        remote_provider.object->install_method_handler<cur::RemoteInterface::StopHeadingUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
+        {
+            mock_provider.stop_heading_updates();
+            bus->send(dbus::Message::make_method_return(msg));
+        });
+
+        remote_provider.object->install_method_handler<cur::RemoteInterface::StartVelocityUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
+        {
+            mock_provider.start_velocity_updates();
+            bus->send(dbus::Message::make_method_return(msg));
+        });
+
+        remote_provider.object->install_method_handler<cur::RemoteInterface::StopVelocityUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
+        {
+            mock_provider.stop_velocity_updates();
+            bus->send(dbus::Message::make_method_return(msg));
+        });
+
+        std::thread position_updates_injector{[&remote_provider, &running]()
+        {
+            while (running)
+            {
+                remote_provider.signals.position_changed->emit(position);
+            }
+        }};
+
+        std::thread heading_updates_injector{[&remote_provider, &running]()
+        {
+            while (running)
+            {
+                remote_provider.signals.heading_changed->emit(heading);
+            }
+        }};
+
+        std::thread velocity_updates_injector{[&remote_provider, &running]()
+        {
+            while (running)
+            {
+                remote_provider.signals.velocity_changed->emit(velocity);
+            }
+        }};
+
+        trap->run();
+
+        if (position_updates_injector.joinable())
+            position_updates_injector.join();
+
+        if (heading_updates_injector.joinable())
+            heading_updates_injector.join();
+
+        if (velocity_updates_injector.joinable())
+            velocity_updates_injector.join();
+
+        bus->stop();
+
+        if (worker.joinable())
+            worker.join();
+
+        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure :
+                                               core::posix::exit::Status::success;
+    }, core::posix::StandardStream::empty);
+
+    std::this_thread::sleep_for(std::chrono::milliseconds{500});
+
+    auto stub = core::posix::fork([this]()
+    {
+        auto conf = remote::Provider::Configuration{};
+        conf.name = RemoteProvider::stub_remote_provider_service_name;
+        conf.path = RemoteProvider::stub_remote_provider_path;
+        conf.connection = session_bus();
+        conf.connection->install_executor(dbus::asio::make_executor(conf.connection));
+
+        remote::Provider provider{conf};
+        provider.start_position_updates();
+        provider.start_heading_updates();
+        provider.start_velocity_updates();
+
+        MockEventConsumer mec;
+        EXPECT_CALL(mec, on_new_position(PositionUpdatesAreEqualExceptForTiming(position))).Times(AtLeast(1));
+        EXPECT_CALL(mec, on_new_heading(HeadingUpdatesAreEqualExceptForTiming(heading))).Times(AtLeast(1));
+        EXPECT_CALL(mec, on_new_velocity(VelocityUpdatesAreEqualExceptForTiming(velocity))).Times(AtLeast(1));
+
+        core::ScopedConnection sc1
+        {
+            provider.updates().position.connect([&mec](const cul::Update<cul::Position>& p)
+            {
+                mec.on_new_position(p);
+            })
+        };
+
+        core::ScopedConnection sc2
+        {
+            provider.updates().heading.connect([&mec](const cul::Update<cul::Heading>& h)
+            {
+                mec.on_new_heading(h);
+            })
+        };
+
+        core::ScopedConnection sc3
+        {
+            provider.updates().velocity.connect([&mec](const cul::Update<cul::Velocity>& v)
+            {
+                mec.on_new_velocity(v);
+            })
+        };
+
+        EXPECT_TRUE(mec.wait_for_position_update_for(std::chrono::milliseconds{1000}));
+        EXPECT_TRUE(mec.wait_for_heading_update_for(std::chrono::milliseconds{1000}));
+        EXPECT_TRUE(mec.wait_for_velocity_update_for(std::chrono::milliseconds{1000}));
+
+        provider.stop_position_updates();
+        provider.stop_heading_updates();
+        provider.stop_velocity_updates();
+
+        return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure :
+                                               core::posix::exit::Status::success;
+    }, core::posix::StandardStream::empty);
+
+    EXPECT_TRUE(did_finish_successfully(stub.wait_for(core::posix::wait::Flags::untraced)));
+    skeleton.send_signal_or_throw(core::posix::Signal::sig_term);
+    EXPECT_TRUE(did_finish_successfully(skeleton.wait_for(core::posix::wait::Flags::untraced)));
+}
+
+TEST(RemoteProviderWithoutBus, matches_criteria)
+{
+
     auto conf = remote::Provider::Configuration{};
     conf.name = "com.ubuntu.espoo.Service.Provider";
     conf.path = "/com/ubuntu/espoo/Service/Provider";
-    conf.connection = session_bus();
+    conf.connection = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
+    conf.connection->install_executor(dbus::asio::make_executor(conf.connection));
     remote::Provider provider(conf);
 
     EXPECT_FALSE(provider.requires(com::ubuntu::location::Provider::Requirements::satellites));
@@ -67,38 +395,3 @@
     EXPECT_TRUE(provider.requires(com::ubuntu::location::Provider::Requirements::data_network));
     EXPECT_TRUE(provider.requires(com::ubuntu::location::Provider::Requirements::monetary_spending));
 }
-
-TEST_F(RemoteProvider, updates_are_fwd)
-{
-    // update received from the remote provider in a tuple
-    cul::Position update
-    {
-        cul::wgs84::Latitude{2* cul::units::Degrees},
-        cul::wgs84::Longitude{3* cul::units::Degrees}
-    };
-
-    update.altitude = cul::wgs84::Altitude{4* cul::units::Meters};
-    update.accuracy.horizontal = cul::Position::Accuracy::Horizontal(5* cul::units::Meters);
-    update.accuracy.vertical = cul::Position::Accuracy::Vertical(6* cul::units::Meters);
-
-    auto conf = remote::Provider::Configuration{};
-    conf.name = "com.ubuntu.espoo.Service.Provider";
-    conf.path = "/com/ubuntu/espoo/Service/Provider";
-    conf.connection = session_bus();
-
-    remote::Provider provider{conf};
-
-    cul::Provider::Ptr p1{std::addressof(provider), [](cul::Provider*){}};
-
-    cul::ProviderSelection selection{p1, p1, p1};
-
-    cul::ProxyProvider pp{selection};
-
-    MockEventConsumer mec;
-    EXPECT_CALL(mec, on_new_position(postion_equals_tuple(update))).Times(1);
-
-    pp.updates().position.connect([&mec](const cul::Update<cul::Position>& p){mec.on_new_position(p);});
-
-    // create an update to be processed
-    provider.on_position_changed(update);
-}

