Merge lp:~thomas-voss/location-service/add-testing-for-remote-provider into lp:location-service/trunk

Proposed by Thomas Voß
Status: Merged
Approved by: Loïc Minier
Approved revision: 106
Merged at revision: 103
Proposed branch: lp:~thomas-voss/location-service/add-testing-for-remote-provider
Merge into: lp:location-service/trunk
Diff against target: 1413 lines (+1032/-182)
8 files modified
src/location_service/com/ubuntu/location/providers/remote/provider.cpp (+66/-47)
src/location_service/com/ubuntu/location/providers/remote/provider.h (+8/-4)
src/location_service/com/ubuntu/location/providers/remote/remote_interface.h (+138/-39)
tests/CMakeLists.txt (+3/-19)
tests/controller_test.cpp (+2/-31)
tests/espoo_provider_test.cpp (+399/-0)
tests/mock_provider.h (+71/-0)
tests/remote_provider_test.cpp (+345/-42)
To merge this branch: bzr merge lp:~thomas-voss/location-service/add-testing-for-remote-provider
Reviewer Review Type Date Requested Status
Loïc Minier Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+234194@code.launchpad.net

Commit message

Somewhat clean up remote provider and add an acceptance-style test.

Description of the change

Somewhat clean up remote provider and add an acceptance-style test.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
104. By Thomas Voß

Add a standalone test for integration with the espoo provider.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
105. By Thomas Voß

Make sure the signal trap is setup prior to connectivty worker thread being started.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
106. By Thomas Voß

Adjust reporting format.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Loïc Minier (lool) wrote :

I've built my own binaries of r105 (r106 just added a test) and ran them on mako + utopic-proposed just fine.

(Not top-approving this yet as I haven't tested the binaries though.)

review: Approve
Revision history for this message
Loïc Minier (lool) wrote :

Are there any related MPs required for this MP to build/function as expected? Please list.

I've tested with updated espoo binaries which need to land at the same time as updated packages; the espoo MP is already merged though.

Is your branch in sync with latest trunk (e.g. bzr pull lp:trunk -> no changes)

Yes

Did you perform an exploratory manual test run of your code change and any related functionality on device or emulator?

On device

Did you successfully run all tests found in your component's Test Plan (https://wiki.ubuntu.com/Process/Merges/TestPlan/location-service) on device or emulator?

Ran most of the tests; discovered some not directly related issues, but no regressions

If you changed the UI, was the change specified/approved by design?

No UI change

If you changed the packaging (debian), did you subscribe a core-dev to this MP?

No packaging change

Did CI run pass? If not, please explain why.

CI passed

Have you checked that submitter has accurately filled out the submitter checklist and has taken no shortcut?

I'm filling it instead

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/location_service/com/ubuntu/location/providers/remote/provider.cpp'
2--- src/location_service/com/ubuntu/location/providers/remote/provider.cpp 2014-08-27 09:13:42 +0000
3+++ src/location_service/com/ubuntu/location/providers/remote/provider.cpp 2014-09-11 20:20:36 +0000
4@@ -27,11 +27,20 @@
5
6 namespace cul = com::ubuntu::location;
7 namespace culpr = com::ubuntu::location::providers::remote;
8-
9+namespace cur = com::ubuntu::remote;
10 namespace dbus = core::dbus;
11
12 namespace
13 {
14+template<typename T>
15+void throw_if_error(const dbus::Result<T>& result)
16+{
17+ if (result.is_error()) throw std::runtime_error
18+ {
19+ result.error().print()
20+ };
21+}
22+
23 dbus::Bus::Ptr the_system_bus()
24 {
25 dbus::Bus::Ptr system_bus = std::make_shared<dbus::Bus>(dbus::WellKnownBus::system);
26@@ -42,38 +51,18 @@
27
28 struct culpr::Provider::Private
29 {
30- typedef core::dbus::Signal<
31- com::ubuntu::remote::RemoteInterface::Signals::PositionChanged,
32- com::ubuntu::remote::RemoteInterface::Signals::PositionChanged::ArgumentType
33- > PositionChanged;
34-
35 Private(const culpr::Provider::Configuration& config)
36 : bus(config.connection),
37 service(dbus::Service::use_service(bus, config.name)),
38 object(service->object_for_path(config.path)),
39- signal_position_changed(object->get_signal<com::ubuntu::remote::RemoteInterface::Signals::PositionChanged>())
40- {
41- }
42-
43- void start()
44- {
45- VLOG(10) << __PRETTY_FUNCTION__;
46- if (!worker.joinable())
47- worker = std::move(std::thread{std::bind(&dbus::Bus::run, bus)});
48- }
49-
50- void stop()
51- {
52- VLOG(10) << __PRETTY_FUNCTION__;
53- try
54- {
55- bus->stop();
56- }
57- catch(...)
58- {
59- // can happen if the start method was not called
60- VLOG(10) << "Stopping not started remote provider.";
61- }
62+ stub(object),
63+ worker([this]() { bus->run(); })
64+ {
65+ }
66+
67+ ~Private()
68+ {
69+ bus->stop();
70
71 if (worker.joinable())
72 worker.join();
73@@ -82,8 +71,8 @@
74 dbus::Bus::Ptr bus;
75 dbus::Service::Ptr service;
76 dbus::Object::Ptr object;
77- PositionChanged::Ptr signal_position_changed;
78- PositionChanged::SubscriptionToken position_updates_connection;
79+
80+ com::ubuntu::remote::RemoteInterface::Stub stub;
81
82 std::thread worker;
83 };
84@@ -108,22 +97,28 @@
85 : com::ubuntu::location::Provider(config.features, config.requirements),
86 d(new Private(config))
87 {
88- d->position_updates_connection =
89- d->signal_position_changed->connect(
90- [this](const com::ubuntu::remote::RemoteInterface::Signals::PositionChanged::ArgumentType& arg)
91- {
92- this->on_position_changed(arg);
93- });
94+ d->stub.signals.position_changed->connect(
95+ [this](const cur::RemoteInterface::Signals::PositionChanged::ArgumentType& arg)
96+ {
97+ VLOG(50) << "culpr::Provider::PositionChanged: " << arg;
98+ mutable_updates().position(arg);
99+ });
100+ d->stub.signals.heading_changed->connect(
101+ [this](const cur::RemoteInterface::Signals::HeadingChanged::ArgumentType& arg)
102+ {
103+ VLOG(50) << "culpr::Provider::HeadingChanged: " << arg;
104+ mutable_updates().heading(arg);
105+ });
106+ d->stub.signals.velocity_changed->connect(
107+ [this](const cur::RemoteInterface::Signals::VelocityChanged::ArgumentType& arg)
108+ {
109+ VLOG(50) << "culpr::Provider::VelocityChanged: " << arg;
110+ mutable_updates().velocity(arg);
111+ });
112 }
113
114 culpr::Provider::~Provider() noexcept
115 {
116- d->stop();
117-}
118-
119-void culpr::Provider::on_position_changed(const com::ubuntu::remote::RemoteInterface::Signals::PositionChanged::ArgumentType& arg)
120-{
121- mutable_updates().position(arg);
122 }
123
124 bool culpr::Provider::matches_criteria(const cul::Criteria&)
125@@ -133,12 +128,36 @@
126
127 void culpr::Provider::start_position_updates()
128 {
129- VLOG(10) << "Starting remote provider\n";
130- d->start();
131+ VLOG(10) << __PRETTY_FUNCTION__;
132+ throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StartPositionUpdates, void>());
133 }
134
135 void culpr::Provider::stop_position_updates()
136 {
137- VLOG(10) << "Stopping remote provider\n";
138- d->stop();
139+ VLOG(10) << __PRETTY_FUNCTION__;
140+ throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StopPositionUpdates, void>());
141+}
142+
143+void culpr::Provider::start_heading_updates()
144+{
145+ VLOG(10) << __PRETTY_FUNCTION__;
146+ throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StartHeadingUpdates, void>());
147+}
148+
149+void culpr::Provider::stop_heading_updates()
150+{
151+ VLOG(10) << __PRETTY_FUNCTION__;
152+ throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StopHeadingUpdates, void>());
153+}
154+
155+void culpr::Provider::start_velocity_updates()
156+{
157+ VLOG(10) << __PRETTY_FUNCTION__;
158+ throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StartVelocityUpdates, void>());
159+}
160+
161+void culpr::Provider::stop_velocity_updates()
162+{
163+ VLOG(10) << __PRETTY_FUNCTION__;
164+ throw_if_error(d->stub.object->transact_method<cur::RemoteInterface::StopVelocityUpdates, void>());
165 }
166
167=== modified file 'src/location_service/com/ubuntu/location/providers/remote/provider.h'
168--- src/location_service/com/ubuntu/location/providers/remote/provider.h 2014-08-26 16:04:02 +0000
169+++ src/location_service/com/ubuntu/location/providers/remote/provider.h 2014-09-11 20:20:36 +0000
170@@ -66,10 +66,14 @@
171
172 virtual bool matches_criteria(const Criteria&);
173
174- virtual void start_position_updates();
175- virtual void stop_position_updates();
176-
177- void on_position_changed(const com::ubuntu::remote::RemoteInterface::Signals::PositionChanged::ArgumentType& arg);
178+ virtual void start_position_updates() override;
179+ virtual void stop_position_updates() override;
180+
181+ virtual void start_heading_updates() override;
182+ virtual void stop_heading_updates() override;
183+
184+ virtual void start_velocity_updates() override;
185+ virtual void stop_velocity_updates() override;
186
187 private:
188 struct Private;
189
190=== modified file 'src/location_service/com/ubuntu/location/providers/remote/remote_interface.h'
191--- src/location_service/com/ubuntu/location/providers/remote/remote_interface.h 2014-08-29 10:41:36 +0000
192+++ src/location_service/com/ubuntu/location/providers/remote/remote_interface.h 2014-09-11 20:20:36 +0000
193@@ -20,11 +20,18 @@
194 #define CORE_UBUNTU_ESPOO_PROVIDER_P_H_
195
196 #include <core/dbus/macros.h>
197+#include <core/dbus/object.h>
198+#include <core/dbus/property.h>
199+#include <core/dbus/signal.h>
200+
201 #include <core/dbus/traits/service.h>
202
203 #include <com/ubuntu/location/codec.h>
204 #include <com/ubuntu/location/update.h>
205+
206+#include <com/ubuntu/location/heading.h>
207 #include <com/ubuntu/location/position.h>
208+#include <com/ubuntu/location/velocity.h>
209
210 namespace cul = com::ubuntu::location;
211
212@@ -36,7 +43,6 @@
213 {
214 struct RemoteInterface
215 {
216-
217 static const std::string& name()
218 {
219 static const std::string s{"com.ubuntu.remote.Service.Provider"};
220@@ -52,18 +58,9 @@
221
222 struct Signals
223 {
224- struct PositionChanged
225- {
226- inline static std::string name()
227- {
228- return "PositionChanged";
229- };
230- typedef RemoteInterface Interface;
231- typedef cul::Position ArgumentType;
232- };
233-
234- DBUS_CPP_SIGNAL_DEF(HeadingChanged, RemoteInterface, double)
235- DBUS_CPP_SIGNAL_DEF(VelocityChanged, RemoteInterface, double)
236+ DBUS_CPP_SIGNAL_DEF(PositionChanged, RemoteInterface, cul::Position)
237+ DBUS_CPP_SIGNAL_DEF(HeadingChanged, RemoteInterface, cul::Heading)
238+ DBUS_CPP_SIGNAL_DEF(VelocityChanged, RemoteInterface, cul::Velocity)
239 };
240
241 struct Properties
242@@ -80,35 +77,137 @@
243 DBUS_CPP_READABLE_PROPERTY_DEF(AreVelocityUpdatesRunning, RemoteInterface, bool)
244 };
245
246+ struct Skeleton
247+ {
248+ // Creates a new skeleton instance and installs the interface
249+ // com::ubuntu::remote::Interface on it.
250+ Skeleton(const core::dbus::Object::Ptr& object)
251+ : object{object},
252+ properties
253+ {
254+ object->get_property<Properties::HasPosition>(),
255+ object->get_property<Properties::HasVelocity>(),
256+ object->get_property<Properties::HasHeading>(),
257+ object->get_property<Properties::RequiresSatellites>(),
258+ object->get_property<Properties::RequiresCellNetwork>(),
259+ object->get_property<Properties::RequiresDataNetwork>(),
260+ object->get_property<Properties::RequiresMonetarySpending>(),
261+ object->get_property<Properties::ArePositionUpdatesRunning>(),
262+ object->get_property<Properties::AreHeadingUpdatesRunning>(),
263+ object->get_property<Properties::AreVelocityUpdatesRunning>()
264+ },
265+ signals
266+ {
267+ object->get_signal<Signals::PositionChanged>(),
268+ object->get_signal<Signals::HeadingChanged>(),
269+ object->get_signal<Signals::VelocityChanged>()
270+ }
271+ {
272+ }
273+
274+ // The object that the interface is installed on.
275+ core::dbus::Object::Ptr object;
276+ // All known properties.
277+ struct
278+ {
279+ std::shared_ptr<core::dbus::Property<Properties::HasPosition>> has_position;
280+ std::shared_ptr<core::dbus::Property<Properties::HasVelocity>> has_velocity;
281+ std::shared_ptr<core::dbus::Property<Properties::HasHeading>> has_heading;
282+ std::shared_ptr<core::dbus::Property<Properties::RequiresSatellites>> requires_satellites;
283+ std::shared_ptr<core::dbus::Property<Properties::RequiresCellNetwork>> requires_cell_network;
284+ std::shared_ptr<core::dbus::Property<Properties::RequiresDataNetwork>> requires_data_network;
285+ std::shared_ptr<core::dbus::Property<Properties::RequiresMonetarySpending>> requires_monetary_spending;
286+ std::shared_ptr<core::dbus::Property<Properties::ArePositionUpdatesRunning>> are_position_updates_running;
287+ std::shared_ptr<core::dbus::Property<Properties::AreHeadingUpdatesRunning>> are_heading_updates_running;
288+ std::shared_ptr<core::dbus::Property<Properties::AreVelocityUpdatesRunning>> are_velocity_updates_running;
289+ } properties;
290+ // All known signals.
291+ struct
292+ {
293+ std::shared_ptr<core::dbus::Signal<
294+ Signals::PositionChanged,
295+ Signals::PositionChanged::ArgumentType
296+ >> position_changed;
297+
298+ std::shared_ptr<core::dbus::Signal<
299+ Signals::HeadingChanged,
300+ Signals::HeadingChanged::ArgumentType
301+ >> heading_changed;
302+
303+ std::shared_ptr<core::dbus::Signal<
304+ Signals::VelocityChanged,
305+ Signals::VelocityChanged::ArgumentType
306+ >> velocity_changed;
307+ } signals;
308+ };
309+
310+ struct Stub
311+ {
312+ // Creates a new skeleton instance and installs the interface
313+ // com::ubuntu::remote::Interface on it.
314+ Stub(const core::dbus::Object::Ptr& object)
315+ : object{object},
316+ properties
317+ {
318+ object->get_property<Properties::HasPosition>(),
319+ object->get_property<Properties::HasVelocity>(),
320+ object->get_property<Properties::HasHeading>(),
321+ object->get_property<Properties::RequiresSatellites>(),
322+ object->get_property<Properties::RequiresCellNetwork>(),
323+ object->get_property<Properties::RequiresDataNetwork>(),
324+ object->get_property<Properties::RequiresMonetarySpending>(),
325+ object->get_property<Properties::ArePositionUpdatesRunning>(),
326+ object->get_property<Properties::AreHeadingUpdatesRunning>(),
327+ object->get_property<Properties::AreVelocityUpdatesRunning>()
328+ },
329+ signals
330+ {
331+ object->get_signal<Signals::PositionChanged>(),
332+ object->get_signal<Signals::HeadingChanged>(),
333+ object->get_signal<Signals::VelocityChanged>()
334+ }
335+ {
336+ }
337+
338+ // The object that the interface is installed on.
339+ core::dbus::Object::Ptr object;
340+ // All known properties.
341+ struct
342+ {
343+ std::shared_ptr<core::dbus::Property<Properties::HasPosition>> has_position;
344+ std::shared_ptr<core::dbus::Property<Properties::HasVelocity>> has_velocity;
345+ std::shared_ptr<core::dbus::Property<Properties::HasHeading>> has_heading;
346+ std::shared_ptr<core::dbus::Property<Properties::RequiresSatellites>> requires_satellites;
347+ std::shared_ptr<core::dbus::Property<Properties::RequiresCellNetwork>> requires_cell_network;
348+ std::shared_ptr<core::dbus::Property<Properties::RequiresDataNetwork>> requires_data_network;
349+ std::shared_ptr<core::dbus::Property<Properties::RequiresMonetarySpending>> requires_monetary_spending;
350+ std::shared_ptr<core::dbus::Property<Properties::ArePositionUpdatesRunning>> are_position_updates_running;
351+ std::shared_ptr<core::dbus::Property<Properties::AreHeadingUpdatesRunning>> are_heading_updates_running;
352+ std::shared_ptr<core::dbus::Property<Properties::AreVelocityUpdatesRunning>> are_velocity_updates_running;
353+ } properties;
354+ // All known signals.
355+ struct
356+ {
357+ std::shared_ptr<core::dbus::Signal<
358+ Signals::PositionChanged,
359+ Signals::PositionChanged::ArgumentType
360+ >> position_changed;
361+
362+ std::shared_ptr<core::dbus::Signal<
363+ Signals::HeadingChanged,
364+ Signals::HeadingChanged::ArgumentType
365+ >> heading_changed;
366+
367+ std::shared_ptr<core::dbus::Signal<
368+ Signals::VelocityChanged,
369+ Signals::VelocityChanged::ArgumentType
370+ >> velocity_changed;
371+ } signals;
372+ };
373+
374 };
375 } // remote
376 } // ubuntu
377 } // core
378
379-namespace core
380-{
381-namespace dbus
382-{
383-namespace traits
384-{
385-template<>
386-struct Service<com::ubuntu::remote::RemoteInterface>
387-{
388- static const std::string& interface_name()
389- {
390- static const std::string s{"com.ubuntu.espoo.Service.Provider"};
391- return s;
392- }
393-
394- inline static const std::string& object_path()
395- {
396- static const std::string s{"/com/ubuntu/espoo/Service/Provider"};
397- return s;
398- }
399-
400-};
401-}
402-}
403-}
404-
405 #endif
406
407=== modified file 'tests/CMakeLists.txt'
408--- tests/CMakeLists.txt 2014-08-26 16:04:02 +0000
409+++ tests/CMakeLists.txt 2014-09-11 20:20:36 +0000
410@@ -53,7 +53,7 @@
411 gtest
412 gtest_main)
413
414- add_test(${test_name} ${CMAKE_CURRENT_BINARY_DIR}/${test_name} --gtest_filter=*-*requires_hardware)
415+ add_test(${test_name} ${CMAKE_CURRENT_BINARY_DIR}/${test_name} --gtest_filter=*-*requires*)
416
417 # Address android's limit on cmdline length and distill ubuntu-location-service into uls
418 install(
419@@ -118,22 +118,6 @@
420 endif (LOCATION_SERVICE_ENABLE_GEOCLUE_PROVIDERS)
421
422 if (LOCATION_SERVICE_ENABLE_REMOTE_PROVIDER)
423- add_executable(remote_provider_test remote_provider_test.cpp)
424- target_link_libraries(
425- remote_provider_test
426-
427- ubuntu-location-service
428-
429- ${CMAKE_THREAD_LIBS_INIT}
430- ${Boost_LIBRARIES}
431- ${PROCESS_CPP_LIBRARIES}
432- ${ARGN}
433-
434- gmock
435-
436- gtest
437- gtest_main
438- )
439-
440- add_test(remote_provider_test ${CMAKE_CURRENT_BINARY_DIR}/remote_provider_test)
441+ LOCATION_SERVICE_ADD_TEST(remote_provider_test remote_provider_test.cpp)
442+ LOCATION_SERVICE_ADD_TEST(espoo_provider_test espoo_provider_test.cpp)
443 endif (LOCATION_SERVICE_ENABLE_REMOTE_PROVIDER)
444
445=== modified file 'tests/controller_test.cpp'
446--- tests/controller_test.cpp 2014-01-20 13:03:19 +0000
447+++ tests/controller_test.cpp 2014-09-11 20:20:36 +0000
448@@ -17,6 +17,8 @@
449 */
450 #include <com/ubuntu/location/provider.h>
451
452+#include "mock_provider.h"
453+
454 #include <gmock/gmock.h>
455 #include <gtest/gtest.h>
456
457@@ -24,37 +26,6 @@
458
459 namespace
460 {
461-struct MockProvider : public cul::Provider
462-{
463- MockProvider() : cul::Provider()
464- {
465- }
466-
467- MOCK_METHOD0(start_position_updates, void());
468- MOCK_METHOD0(stop_position_updates, void());
469-
470- MOCK_METHOD0(start_heading_updates, void());
471- MOCK_METHOD0(stop_heading_updates, void());
472-
473- MOCK_METHOD0(start_velocity_updates, void());
474- MOCK_METHOD0(stop_velocity_updates, void());
475-
476- void inject_update(const cul::Update<cul::Position>& update)
477- {
478- mutable_updates().position(update);
479- }
480-
481- void inject_update(const cul::Update<cul::Velocity>& update)
482- {
483- mutable_updates().velocity(update);
484- }
485-
486- void inject_update(const cul::Update<cul::Heading>& update)
487- {
488- mutable_updates().heading(update);
489- }
490-};
491-
492 auto timestamp = com::ubuntu::location::Clock::now();
493
494 com::ubuntu::location::Update<com::ubuntu::location::Position> reference_position_update
495
496=== added file 'tests/espoo_provider_test.cpp'
497--- tests/espoo_provider_test.cpp 1970-01-01 00:00:00 +0000
498+++ tests/espoo_provider_test.cpp 2014-09-11 20:20:36 +0000
499@@ -0,0 +1,399 @@
500+/*
501+ * Copyright © 2014 Canonical Ltd.
502+ *
503+ * This program is free software: you can redistribute it and/or modify it
504+ * under the terms of the GNU Lesser General Public License version 3,
505+ * as published by the Free Software Foundation.
506+ *
507+ * This program is distributed in the hope that it will be useful,
508+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
509+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
510+ * GNU Lesser General Public License for more details.
511+ *
512+ * You should have received a copy of the GNU Lesser General Public License
513+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
514+ *
515+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
516+ */
517+
518+#include <com/ubuntu/location/providers/remote/provider.h>
519+
520+#include <com/ubuntu/location/logging.h>
521+
522+#include <com/ubuntu/location/connectivity/manager.h>
523+
524+#include <core/dbus/asio/executor.h>
525+
526+#include <core/posix/signal.h>
527+#include <core/posix/this_process.h>
528+
529+#include <boost/accumulators/accumulators.hpp>
530+#include <boost/accumulators/statistics/stats.hpp>
531+#include <boost/accumulators/statistics/count.hpp>
532+#include <boost/accumulators/statistics/max.hpp>
533+#include <boost/accumulators/statistics/mean.hpp>
534+#include <boost/accumulators/statistics/min.hpp>
535+#include <boost/accumulators/statistics/variance.hpp>
536+
537+#include <gtest/gtest.h>
538+
539+namespace cul = com::ubuntu::location;
540+namespace remote = com::ubuntu::location::providers::remote;
541+namespace statistics = boost::accumulators;
542+
543+namespace
544+{
545+// A simple counter to keep track of events.
546+struct Counter
547+{
548+ Counter(const std::string& name) : name{name}, value{0}
549+ {
550+ }
551+
552+ Counter& operator++()
553+ {
554+ value++; return *this;
555+ }
556+
557+ Counter operator++(int)
558+ {
559+ auto copy = *this; ++*this; return copy;
560+ }
561+
562+ Counter& operator--()
563+ {
564+ value--; return *this;
565+ }
566+
567+ Counter operator--(int)
568+ {
569+ auto copy = *this; --*this; return copy;
570+ }
571+
572+ std::uint64_t operator*() const
573+ {
574+ return value;
575+ }
576+
577+ void reset()
578+ {
579+ value = 0;
580+ }
581+
582+ std::string name;
583+ std::uint64_t value;
584+};
585+
586+std::ostream& operator<<(std::ostream& out, const Counter& counter)
587+{
588+ return out << counter.name << ": " << counter.value;
589+}
590+
591+// Helps in tracking time differences.
592+struct StopWatch
593+{
594+ StopWatch(const std::string& name)
595+ : start{std::chrono::system_clock::now()},
596+ name{name}
597+ {
598+ }
599+
600+ void reset()
601+ {
602+ start = std::chrono::system_clock::now();
603+ }
604+
605+ std::chrono::system_clock::duration stop()
606+ {
607+ return std::chrono::system_clock::now() - start;
608+ }
609+
610+ std::chrono::system_clock::time_point start;
611+ std::string name;
612+};
613+
614+struct Statistics
615+{
616+ typedef std::int64_t ValueType;
617+ // We accumulate size, mean, min, max and variance of a sample
618+ typedef statistics::accumulator_set
619+ <
620+ ValueType,
621+ statistics::stats
622+ <
623+ statistics::tag::count,
624+ statistics::tag::mean,
625+ statistics::tag::min,
626+ statistics::tag::max,
627+ statistics::tag::variance
628+ >
629+ > Accumulator;
630+
631+ Statistics(const std::string& name) : name{name}
632+ {
633+ }
634+
635+ template<typename NumericType>
636+ void update(NumericType value)
637+ {
638+ accumulator(value);
639+ }
640+
641+ void reset()
642+ {
643+ accumulator = Accumulator{};
644+ }
645+
646+ ValueType min() const
647+ {
648+ return statistics::min(accumulator);
649+ }
650+
651+ ValueType max() const
652+ {
653+ return statistics::max(accumulator);
654+ }
655+
656+ ValueType mean() const
657+ {
658+ return statistics::mean(accumulator);
659+ }
660+
661+ ValueType variance() const
662+ {
663+ return statistics::variance(accumulator);
664+ }
665+
666+ std::size_t count() const
667+ {
668+ return statistics::count(accumulator);
669+ }
670+
671+ Accumulator accumulator;
672+ std::string name;
673+};
674+
675+struct EspooProviderTest : public ::testing::Test
676+{
677+ // All known environment variables.
678+ struct Parameters
679+ {
680+ struct Bus
681+ {
682+ static constexpr const char* name
683+ {
684+ "ESPOO_PROVIDER_TEST_BUS"
685+ };
686+
687+ static constexpr const char* default_value
688+ {
689+ "session"
690+ };
691+ };
692+ };
693+
694+ static core::dbus::Bus::Ptr bus_instance_according_to_env()
695+ {
696+ auto value = core::posix::this_process::env::get(Parameters::Bus::name, Parameters::Bus::default_value);
697+
698+ core::dbus::WellKnownBus bus{core::dbus::WellKnownBus::starter};
699+
700+ if (value == "session")
701+ bus = core::dbus::WellKnownBus::session;
702+ else if (value == "system")
703+ bus = core::dbus::WellKnownBus::system;
704+
705+ auto result = std::make_shared<core::dbus::Bus>(bus);
706+ result->install_executor(core::dbus::asio::make_executor(result));
707+
708+ return result;
709+ }
710+
711+ static constexpr const char* service_name
712+ {
713+ "com.ubuntu.espoo.Service.Provider"
714+ };
715+
716+ static constexpr const char* path
717+ {
718+ "/com/ubuntu/espoo/Service/Provider"
719+ };
720+
721+ static std::uint64_t numeric_cell_id_from_cell(const cul::connectivity::RadioCell::Ptr& cell)
722+ {
723+ std::uint64_t cid;
724+ switch (cell->type())
725+ {
726+ case cul::connectivity::RadioCell::Type::gsm:
727+ cid = cell->gsm().id.get();
728+ break;
729+ case cul::connectivity::RadioCell::Type::umts:
730+ cid = cell->umts().id.get();
731+ break;
732+ case cul::connectivity::RadioCell::Type::lte:
733+ cid = cell->lte().id.get();
734+ break;
735+ default:
736+ cid = std::numeric_limits<std::uint64_t>::max();
737+ break;
738+ }
739+ return cid;
740+ }
741+
742+ EspooProviderTest()
743+ : bus{bus_instance_according_to_env()},
744+ trap{core::posix::trap_signals_for_all_subsequent_threads({core::posix::Signal::sig_int})},
745+ cm{cul::connectivity::platform_default_manager()}
746+ {
747+ // Bootstrap wifi stats
748+ cm->enumerate_visible_wireless_networks([this](const cul::connectivity::WirelessNetwork::Ptr&)
749+ {
750+ ++connectivity_stats.wifi_counter;
751+ });
752+
753+ connectivity_stats.over_wifi_count.update(*connectivity_stats.wifi_counter);
754+
755+ cm->wireless_network_added().connect([this](const cul::connectivity::WirelessNetwork::Ptr&)
756+ {
757+ connectivity_stats.over_wifi_count.update(*(++connectivity_stats.wifi_counter));
758+ });
759+
760+ cm->wireless_network_removed().connect([this](const cul::connectivity::WirelessNetwork::Ptr&)
761+ {
762+ connectivity_stats.over_wifi_count.update(*(--connectivity_stats.wifi_counter));
763+ });
764+
765+ // Bootstrap cell stats
766+ cm->enumerate_connected_radio_cells([this](const cul::connectivity::RadioCell::Ptr& cell)
767+ {
768+ on_radio_cell_added(cell);
769+ });
770+
771+ cm->connected_cell_added().connect([this](const cul::connectivity::RadioCell::Ptr& cell)
772+ {
773+ on_radio_cell_added(cell);
774+ });
775+
776+ cm->connected_cell_removed().connect([this](const cul::connectivity::RadioCell::Ptr& cell)
777+ {
778+ cells_to_ids.erase(cell);
779+ });
780+ }
781+
782+ void on_radio_cell_added(const cul::connectivity::RadioCell::Ptr& cell)
783+ {
784+ // We store the cell characteristics here.
785+ cells_to_ids.insert(std::make_pair(cell, std::make_tuple(cell->type(), numeric_cell_id_from_cell(cell))));
786+
787+ std::weak_ptr<cul::connectivity::RadioCell> wp{cell};
788+
789+ // Subscribe to changes on the cell
790+ cell->changed().connect([wp, this]()
791+ {
792+ auto sp = wp.lock();
793+
794+ if (not sp)
795+ return;
796+
797+ if (cells_to_ids.count(sp) > 0)
798+ {
799+ auto tuple = cells_to_ids.at(sp);
800+
801+ // The technology changed.
802+ if (std::get<0>(tuple) != sp->type())
803+ {
804+
805+ ++connectivity_stats.cell_changes_counter;
806+ }
807+ else // No change in technology, comparing actual ids.
808+ {
809+ if (std::get<1>(tuple) != numeric_cell_id_from_cell(sp))
810+ ++connectivity_stats.cell_changes_counter;
811+ }
812+
813+ // Update last known values.
814+ cells_to_ids.at(sp) = std::make_tuple(sp->type(), numeric_cell_id_from_cell(sp));
815+ }
816+ });
817+ }
818+
819+ // The bus connection for reaching out to the espoo provider.
820+ core::dbus::Bus::Ptr bus;
821+ // Our signal trap.
822+ std::shared_ptr<core::posix::SignalTrap> trap;
823+ // We monitor the connectivity subsystems.
824+ std::shared_ptr<cul::connectivity::Manager> cm;
825+ // We store individual cell ids together with their type.
826+ std::map
827+ <
828+ cul::connectivity::RadioCell::Ptr,
829+ std::tuple<cul::connectivity::RadioCell::Type, std::uint64_t>
830+ > cells_to_ids;
831+ struct
832+ {
833+ Counter wifi_counter{"Wifi counter"};
834+ Statistics over_wifi_count{"Wifi count stats"};
835+ Counter cell_changes_counter{"Cell changes"};
836+ } connectivity_stats;
837+};
838+}
839+
840+TEST_F(EspooProviderTest, receives_position_updates_requires_daemons)
841+{
842+ trap->signal_raised().connect([this](core::posix::Signal)
843+ {
844+ trap->stop();
845+ });
846+
847+ remote::Provider::Configuration config;
848+ config.name = EspooProviderTest::service_name;
849+ config.path = EspooProviderTest::path;
850+ config.connection = bus;
851+
852+ // We keep track of some characteristics.
853+ struct Stats
854+ {
855+ StopWatch execution_time{"Execution time of test"}; // The total execution time of the test.
856+ StopWatch position_updates_duration{"Position updates duration"}; // Time between position updates.
857+ Statistics position_updates_duration_stats{"Position updates duration stats"};
858+ Counter position_updates_counter{"Position updates"}; // The number of position updates we received.
859+ } stats;
860+
861+ remote::Provider provider{config};
862+
863+ provider.updates().position.connect([&stats](const cul::Update<cul::Position>& update)
864+ {
865+ VLOG(1) << update;
866+ // We track the number of position updates
867+ stats.position_updates_counter++;
868+ // And we update our statistics by querying our stopwatch.
869+ stats.position_updates_duration_stats.update(stats.position_updates_duration.stop().count());
870+ // And we reset it.
871+ stats.position_updates_duration.reset();
872+ });
873+
874+ // provider.start_position_updates();
875+ trap->run();
876+ // provider.stop_position_updates();
877+
878+ // Finally printing some statistics
879+ std::cout << "Total execution time: "
880+ << std::chrono::duration_cast<std::chrono::seconds>(stats.execution_time.stop()).count() << " [s]" << std::endl;
881+ std::cout << stats.position_updates_counter << std::endl;
882+
883+ std::cout << "Min time in [s] between position updates: "
884+ << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::duration{stats.position_updates_duration_stats.min()}).count() << std::endl;
885+ std::cout << "Max time in [s] between position updates: "
886+ << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::duration{stats.position_updates_duration_stats.max()}).count() << std::endl;
887+ std::cout << "Mean time in [s] between position updates: "
888+ << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::duration{stats.position_updates_duration_stats.mean()}).count() << std::endl;
889+ std::cout << "Std.dev. of time in [s] between position updates: "
890+ << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::duration{(std::int64_t)std::sqrt(stats.position_updates_duration_stats.variance())}).count() << std::endl;
891+
892+ std::cout << "Min # of visible wifis: "
893+ << connectivity_stats.over_wifi_count.min() << std::endl;
894+ std::cout << "Max # of visible wifis: "
895+ << connectivity_stats.over_wifi_count.max() << std::endl;
896+ std::cout << "Mean # of visible wifis: "
897+ << connectivity_stats.over_wifi_count.mean() << std::endl;
898+}
899
900=== added file 'tests/mock_provider.h'
901--- tests/mock_provider.h 1970-01-01 00:00:00 +0000
902+++ tests/mock_provider.h 2014-09-11 20:20:36 +0000
903@@ -0,0 +1,71 @@
904+/*
905+ * Copyright © 2014 Canonical Ltd.
906+ *
907+ * This program is free software: you can redistribute it and/or modify it
908+ * under the terms of the GNU Lesser General Public License version 3,
909+ * as published by the Free Software Foundation.
910+ *
911+ * This program is distributed in the hope that it will be useful,
912+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
913+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
914+ * GNU Lesser General Public License for more details.
915+ *
916+ * You should have received a copy of the GNU Lesser General Public License
917+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
918+ *
919+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
920+ */
921+#ifndef MOCK_PROVIDER_H_
922+#define MOCK_PROVIDER_H_
923+
924+#include <com/ubuntu/location/provider.h>
925+
926+#include <gmock/gmock.h>
927+
928+struct MockProvider : public com::ubuntu::location::Provider
929+{
930+ MockProvider() : com::ubuntu::location::Provider()
931+ {
932+ }
933+
934+ // Called by the engine whenever the wifi and cell ID reporting state changes.
935+ MOCK_METHOD1(on_wifi_and_cell_reporting_state_changed, void(com::ubuntu::location::WifiAndCellIdReportingState state));
936+
937+ // Called by the engine whenever the reference location changed.
938+ MOCK_METHOD1(on_reference_location_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Position>& position));
939+
940+ // Called by the engine whenever the reference velocity changed.
941+ MOCK_METHOD1(on_reference_velocity_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Velocity>& velocity));
942+
943+ // Called by the engine whenever the reference heading changed.
944+ MOCK_METHOD1(on_reference_heading_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Heading>& heading));
945+
946+ MOCK_METHOD0(start_position_updates, void());
947+ MOCK_METHOD0(stop_position_updates, void());
948+
949+ MOCK_METHOD0(start_heading_updates, void());
950+ MOCK_METHOD0(stop_heading_updates, void());
951+
952+ MOCK_METHOD0(start_velocity_updates, void());
953+ MOCK_METHOD0(stop_velocity_updates, void());
954+
955+ // Inject a position update from the outside.
956+ void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Position>& update)
957+ {
958+ mutable_updates().position(update);
959+ }
960+
961+ // Inject a velocity update from the outside.
962+ void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Velocity>& update)
963+ {
964+ mutable_updates().velocity(update);
965+ }
966+
967+ // Inject a heading update from the outside.
968+ void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Heading>& update)
969+ {
970+ mutable_updates().heading(update);
971+ }
972+};
973+
974+#endif // MOCK_PROVIDER_H_
975
976=== modified file 'tests/remote_provider_test.cpp'
977--- tests/remote_provider_test.cpp 2014-08-27 09:13:42 +0000
978+++ tests/remote_provider_test.cpp 2014-09-11 20:20:36 +0000
979@@ -16,22 +16,33 @@
980 * Authored by: Manuel de la Peña <manuel.delapena@canonical.com>
981 */
982
983+#include <com/ubuntu/location/logging.h>
984 #include <com/ubuntu/location/provider.h>
985-#include <com/ubuntu/location/proxy_provider.h>
986 #include <com/ubuntu/location/providers/remote/provider.h>
987
988+#include "mock_provider.h"
989+
990 #include <core/dbus/fixture.h>
991+#include <core/dbus/asio/executor.h>
992+
993+#include <core/posix/fork.h>
994+#include <core/posix/signal.h>
995+
996+#include <core/testing/fork_and_run.h>
997
998 #include <gmock/gmock.h>
999 #include <gtest/gtest.h>
1000
1001 namespace cul = com::ubuntu::location;
1002+namespace cur = com::ubuntu::remote;
1003+namespace dbus = core::dbus;
1004 namespace remote = com::ubuntu::location::providers::remote;
1005
1006 using namespace ::testing;
1007
1008
1009-MATCHER_P(postion_equals_tuple, value, "Returns if the string maps are equal.") {
1010+MATCHER_P(PositionUpdatesAreEqualExceptForTiming, value, "Returns true if the positions in both updates are equal.")
1011+{
1012 auto pos = arg.value;
1013
1014 return value.longitude == pos.longitude && value.latitude == pos.latitude && value.altitude == pos.altitude
1015@@ -39,66 +50,358 @@
1016 && pos.accuracy.vertical == value.accuracy.vertical;
1017 }
1018
1019+MATCHER_P(HeadingUpdatesAreEqualExceptForTiming, value, "Returns true if the heading in both updates are equal.")
1020+{
1021+ auto heading = arg.value;
1022+ return heading == value;
1023+}
1024+
1025+MATCHER_P(VelocityUpdatesAreEqualExceptForTiming, value, "Returns true if the velocity in both updates are equal.")
1026+{
1027+ auto velocity = arg.value;
1028+ return velocity == value;
1029+}
1030+
1031 namespace
1032 {
1033+::testing::AssertionResult did_finish_successfully(const core::posix::wait::Result& result)
1034+{
1035+ if (result.status != core::posix::wait::Result::Status::exited)
1036+ return ::testing::AssertionFailure() << "Process did not exit, but: " << (int)result.status;
1037+ if (result.detail.if_exited.status != core::posix::exit::Status::success)
1038+ return ::testing::AssertionFailure() << "Process did exit with failure.";
1039+
1040+ return ::testing::AssertionSuccess();
1041+}
1042+
1043 struct RemoteProvider : public core::dbus::testing::Fixture
1044 {
1045+ static constexpr const char* stub_remote_provider_service_name
1046+ {
1047+ "does.not.exist.remote.Provider"
1048+ };
1049
1050+ static constexpr const char* stub_remote_provider_path
1051+ {
1052+ "/com/ubuntu/remote/Provider"
1053+ };
1054 };
1055
1056 class MockEventConsumer
1057 {
1058 public:
1059- MockEventConsumer() {}
1060+ MockEventConsumer()
1061+ {
1062+ using namespace ::testing;
1063+
1064+ ON_CALL(*this, on_new_position(_))
1065+ .WillByDefault(
1066+ InvokeWithoutArgs(
1067+ this,
1068+ &MockEventConsumer::notify_position_update_arrived));
1069+ ON_CALL(*this, on_new_heading(_))
1070+ .WillByDefault(
1071+ InvokeWithoutArgs(
1072+ this,
1073+ &MockEventConsumer::notify_heading_update_arrived));
1074+ ON_CALL(*this, on_new_velocity(_))
1075+ .WillByDefault(
1076+ InvokeWithoutArgs(
1077+ this,
1078+ &MockEventConsumer::notify_velocity_update_arrived));
1079+ }
1080+
1081+ bool wait_for_position_update_for(const std::chrono::milliseconds& timeout)
1082+ {
1083+ std::unique_lock<std::mutex> ul{position.guard};
1084+ return position.wait_condition.wait_for(ul, timeout, [this] { return position.update_arrived; });
1085+ }
1086+
1087+ bool wait_for_heading_update_for(const std::chrono::milliseconds& timeout)
1088+ {
1089+ std::unique_lock<std::mutex> ul{heading.guard};
1090+ return heading.wait_condition.wait_for(ul, timeout, [this] { return heading.update_arrived; });
1091+ }
1092+
1093+ bool wait_for_velocity_update_for(const std::chrono::milliseconds& timeout)
1094+ {
1095+ std::unique_lock<std::mutex> ul{velocity.guard};
1096+ return velocity.wait_condition.wait_for(ul, timeout, [this] { return velocity.update_arrived; });
1097+ }
1098
1099 MOCK_METHOD1(on_new_position, void(const cul::Update<cul::Position>&));
1100+ MOCK_METHOD1(on_new_heading, void(const cul::Update<cul::Heading>&));
1101+ MOCK_METHOD1(on_new_velocity, void(const cul::Update<cul::Velocity>&));
1102+
1103+private:
1104+ // Notes down the arrival of a position update
1105+ // and notifies any waiting threads about the event.
1106+ void notify_position_update_arrived()
1107+ {
1108+ position.update_arrived = true;
1109+ position.wait_condition.notify_all();
1110+ }
1111+
1112+ // Notes down the arrival of a heading update
1113+ // and notifies any waiting threads about the event.
1114+ void notify_heading_update_arrived()
1115+ {
1116+ heading.update_arrived = true;
1117+ heading.wait_condition.notify_all();
1118+ }
1119+
1120+ // Notes down the arrival of a heading update
1121+ // and notifies any waiting threads about the event.
1122+ void notify_velocity_update_arrived()
1123+ {
1124+ velocity.update_arrived = true;
1125+ velocity.wait_condition.notify_all();
1126+ }
1127+
1128+ struct
1129+ {
1130+ std::mutex guard;
1131+ std::condition_variable wait_condition;
1132+ bool update_arrived{false};
1133+ } position;
1134+
1135+ struct
1136+ {
1137+ std::mutex guard;
1138+ std::condition_variable wait_condition;
1139+ bool update_arrived{false};
1140+ } heading;
1141+
1142+ struct
1143+ {
1144+ std::mutex guard;
1145+ std::condition_variable wait_condition;
1146+ bool update_arrived{false};
1147+ } velocity;
1148 };
1149 }
1150-TEST_F(RemoteProvider, matches_criteria)
1151+
1152+TEST_F(RemoteProvider, updates_are_fwd)
1153+{
1154+ using namespace ::testing;
1155+
1156+ static const cul::Position position
1157+ {
1158+ cul::wgs84::Latitude{2* cul::units::Degrees},
1159+ cul::wgs84::Longitude{3* cul::units::Degrees},
1160+ cul::wgs84::Altitude{4* cul::units::Meters},
1161+ cul::Position::Accuracy::Horizontal(5* cul::units::Meters),
1162+ cul::Position::Accuracy::Vertical(6* cul::units::Meters)
1163+ };
1164+
1165+ static const cul::Heading heading
1166+ {
1167+ 120. * cul::units::Degrees
1168+ };
1169+
1170+ static const cul::Velocity velocity
1171+ {
1172+ 5. * cul::units::MetersPerSecond
1173+ };
1174+
1175+ auto skeleton = core::posix::fork([this]()
1176+ {
1177+ bool running{true};
1178+ auto trap = core::posix::trap_signals_for_all_subsequent_threads({core::posix::Signal::sig_term});
1179+
1180+ trap->signal_raised().connect([trap, &running](core::posix::Signal)
1181+ {
1182+ trap->stop();
1183+ running = false;
1184+ });
1185+
1186+ auto bus = session_bus();
1187+ bus->install_executor(dbus::asio::make_executor(bus));
1188+
1189+ std::thread worker([bus]()
1190+ {
1191+ bus->run();
1192+ });
1193+
1194+ auto object = dbus::Service::add_service(
1195+ bus,
1196+ RemoteProvider::stub_remote_provider_service_name)
1197+ ->add_object_for_path(
1198+ dbus::types::ObjectPath{RemoteProvider::stub_remote_provider_path});
1199+
1200+ // We use this instance to capture incoming requests.
1201+ NiceMock<MockProvider> mock_provider;
1202+
1203+ EXPECT_CALL(mock_provider, start_position_updates()).Times(1);
1204+ EXPECT_CALL(mock_provider, start_heading_updates()).Times(1);
1205+ EXPECT_CALL(mock_provider, start_velocity_updates()).Times(1);
1206+ EXPECT_CALL(mock_provider, stop_position_updates()).Times(1);
1207+ EXPECT_CALL(mock_provider, stop_heading_updates()).Times(1);
1208+ EXPECT_CALL(mock_provider, stop_velocity_updates()).Times(1);
1209+
1210+ cur::RemoteInterface::Skeleton remote_provider{object};
1211+
1212+ remote_provider.object->install_method_handler<cur::RemoteInterface::StartPositionUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
1213+ {
1214+ VLOG(1) << "StartPositionUpdates";
1215+ mock_provider.start_position_updates();
1216+ bus->send(dbus::Message::make_method_return(msg));
1217+ });
1218+
1219+ remote_provider.object->install_method_handler<cur::RemoteInterface::StopPositionUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
1220+ {
1221+ VLOG(1) << "StopPositionUpdates";
1222+ mock_provider.stop_position_updates();
1223+ bus->send(dbus::Message::make_method_return(msg));
1224+ });
1225+
1226+ remote_provider.object->install_method_handler<cur::RemoteInterface::StartHeadingUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
1227+ {
1228+ VLOG(1) << "StartHeadingUpdates";
1229+ mock_provider.start_heading_updates();
1230+ bus->send(dbus::Message::make_method_return(msg));
1231+ });
1232+
1233+ remote_provider.object->install_method_handler<cur::RemoteInterface::StopHeadingUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
1234+ {
1235+ VLOG(1) << "StopHeadingUpdates";
1236+ mock_provider.stop_heading_updates();
1237+ bus->send(dbus::Message::make_method_return(msg));
1238+ });
1239+
1240+ remote_provider.object->install_method_handler<cur::RemoteInterface::StartVelocityUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
1241+ {
1242+ VLOG(1) << "StartVelocityUpdates";
1243+ mock_provider.start_velocity_updates();
1244+ bus->send(dbus::Message::make_method_return(msg));
1245+ });
1246+
1247+ remote_provider.object->install_method_handler<cur::RemoteInterface::StopVelocityUpdates>([bus, &mock_provider](const dbus::Message::Ptr & msg)
1248+ {
1249+ VLOG(1) << "StartVelocityUpdates";
1250+ mock_provider.stop_velocity_updates();
1251+ bus->send(dbus::Message::make_method_return(msg));
1252+ });
1253+
1254+ std::thread position_updates_injector{[&remote_provider, &running]()
1255+ {
1256+ while (running)
1257+ {
1258+ remote_provider.signals.position_changed->emit(position);
1259+ std::this_thread::sleep_for(std::chrono::milliseconds{10});
1260+ }
1261+ }};
1262+
1263+ std::thread heading_updates_injector{[&remote_provider, &running]()
1264+ {
1265+ while (running)
1266+ {
1267+ remote_provider.signals.heading_changed->emit(heading);
1268+ std::this_thread::sleep_for(std::chrono::milliseconds{10});
1269+ }
1270+ }};
1271+
1272+ std::thread velocity_updates_injector{[&remote_provider, &running]()
1273+ {
1274+ while (running)
1275+ {
1276+ remote_provider.signals.velocity_changed->emit(velocity);
1277+ std::this_thread::sleep_for(std::chrono::milliseconds{10});
1278+ }
1279+ }};
1280+
1281+ trap->run();
1282+
1283+ if (position_updates_injector.joinable())
1284+ position_updates_injector.join();
1285+
1286+ if (heading_updates_injector.joinable())
1287+ heading_updates_injector.join();
1288+
1289+ if (velocity_updates_injector.joinable())
1290+ velocity_updates_injector.join();
1291+
1292+ bus->stop();
1293+
1294+ if (worker.joinable())
1295+ worker.join();
1296+
1297+ return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure :
1298+ core::posix::exit::Status::success;
1299+ }, core::posix::StandardStream::empty);
1300+
1301+ std::this_thread::sleep_for(std::chrono::milliseconds{500});
1302+
1303+ auto stub = core::posix::fork([this]()
1304+ {
1305+ auto conf = remote::Provider::Configuration{};
1306+ conf.name = RemoteProvider::stub_remote_provider_service_name;
1307+ conf.path = RemoteProvider::stub_remote_provider_path;
1308+ conf.connection = session_bus();
1309+ conf.connection->install_executor(dbus::asio::make_executor(conf.connection));
1310+
1311+ remote::Provider provider{conf};
1312+ provider.start_position_updates();
1313+ provider.start_heading_updates();
1314+ provider.start_velocity_updates();
1315+
1316+ MockEventConsumer mec;
1317+ EXPECT_CALL(mec, on_new_position(PositionUpdatesAreEqualExceptForTiming(position))).Times(AtLeast(1));
1318+ EXPECT_CALL(mec, on_new_heading(HeadingUpdatesAreEqualExceptForTiming(heading))).Times(AtLeast(1));
1319+ EXPECT_CALL(mec, on_new_velocity(VelocityUpdatesAreEqualExceptForTiming(velocity))).Times(AtLeast(1));
1320+
1321+ core::ScopedConnection sc1
1322+ {
1323+ provider.updates().position.connect([&mec](const cul::Update<cul::Position>& p)
1324+ {
1325+ mec.on_new_position(p);
1326+ })
1327+ };
1328+
1329+ core::ScopedConnection sc2
1330+ {
1331+ provider.updates().heading.connect([&mec](const cul::Update<cul::Heading>& h)
1332+ {
1333+ mec.on_new_heading(h);
1334+ })
1335+ };
1336+
1337+ core::ScopedConnection sc3
1338+ {
1339+ provider.updates().velocity.connect([&mec](const cul::Update<cul::Velocity>& v)
1340+ {
1341+ mec.on_new_velocity(v);
1342+ })
1343+ };
1344+
1345+ EXPECT_TRUE(mec.wait_for_position_update_for(std::chrono::milliseconds{1000}));
1346+ EXPECT_TRUE(mec.wait_for_heading_update_for(std::chrono::milliseconds{1000}));
1347+ EXPECT_TRUE(mec.wait_for_velocity_update_for(std::chrono::milliseconds{1000}));
1348+
1349+ provider.stop_position_updates();
1350+ provider.stop_heading_updates();
1351+ provider.stop_velocity_updates();
1352+
1353+ return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure :
1354+ core::posix::exit::Status::success;
1355+ }, core::posix::StandardStream::empty);
1356+
1357+ EXPECT_TRUE(did_finish_successfully(stub.wait_for(core::posix::wait::Flags::untraced)));
1358+ skeleton.send_signal_or_throw(core::posix::Signal::sig_term);
1359+ EXPECT_TRUE(did_finish_successfully(skeleton.wait_for(core::posix::wait::Flags::untraced)));
1360+}
1361+
1362+TESTP_F(RemoteProvider, matches_criteria,
1363 {
1364 auto conf = remote::Provider::Configuration{};
1365- conf.name = "com.ubuntu.espoo.Service.Provider";
1366- conf.path = "/com/ubuntu/espoo/Service/Provider";
1367+ conf.name = RemoteProvider::stub_remote_provider_service_name;
1368+ conf.path = RemoteProvider::stub_remote_provider_path;
1369 conf.connection = session_bus();
1370+ conf.connection->install_executor(dbus::asio::make_executor(conf.connection));
1371 remote::Provider provider(conf);
1372
1373 EXPECT_FALSE(provider.requires(com::ubuntu::location::Provider::Requirements::satellites));
1374 EXPECT_TRUE(provider.requires(com::ubuntu::location::Provider::Requirements::cell_network));
1375 EXPECT_TRUE(provider.requires(com::ubuntu::location::Provider::Requirements::data_network));
1376 EXPECT_TRUE(provider.requires(com::ubuntu::location::Provider::Requirements::monetary_spending));
1377-}
1378-
1379-TEST_F(RemoteProvider, updates_are_fwd)
1380-{
1381- // update received from the remote provider in a tuple
1382- cul::Position update
1383- {
1384- cul::wgs84::Latitude{2* cul::units::Degrees},
1385- cul::wgs84::Longitude{3* cul::units::Degrees}
1386- };
1387-
1388- update.altitude = cul::wgs84::Altitude{4* cul::units::Meters};
1389- update.accuracy.horizontal = cul::Position::Accuracy::Horizontal(5* cul::units::Meters);
1390- update.accuracy.vertical = cul::Position::Accuracy::Vertical(6* cul::units::Meters);
1391-
1392- auto conf = remote::Provider::Configuration{};
1393- conf.name = "com.ubuntu.espoo.Service.Provider";
1394- conf.path = "/com/ubuntu/espoo/Service/Provider";
1395- conf.connection = session_bus();
1396-
1397- remote::Provider provider{conf};
1398-
1399- cul::Provider::Ptr p1{std::addressof(provider), [](cul::Provider*){}};
1400-
1401- cul::ProviderSelection selection{p1, p1, p1};
1402-
1403- cul::ProxyProvider pp{selection};
1404-
1405- MockEventConsumer mec;
1406- EXPECT_CALL(mec, on_new_position(postion_equals_tuple(update))).Times(1);
1407-
1408- pp.updates().position.connect([&mec](const cul::Update<cul::Position>& p){mec.on_new_position(p);});
1409-
1410- // create an update to be processed
1411- provider.on_position_changed(update);
1412-}
1413+})

Subscribers

People subscribed via source and target branches