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

Proposed by Manuel de la Peña
Status: Needs review
Proposed branch: lp:~mandel/location-service/delayed-providers
Merge into: lp:location-service/trunk
Diff against target: 562 lines (+406/-9)
4 files modified
include/location_service/com/ubuntu/location/provider.h (+43/-1)
src/location_service/com/ubuntu/location/provider.cpp (+61/-8)
tests/controller_test.cpp (+213/-0)
tests/mock_delayed_provider.h (+89/-0)
To merge this branch: bzr merge lp:~mandel/location-service/delayed-providers
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Jim Hodapp (community) code Needs Fixing
Alfonso Sanchez-Beato Approve
Review via email: mp+261944@code.launchpad.net

Commit message

Add the concept of a delayed providers. This will allow providers that are slow to start the chance to be started and later be connected accordingly.

Description of the change

Add the concept of a delayed providers. This will allow providers that are slow to start the chance to be started and later be connected accordingly.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote :

Please check inline comments.

review: Needs Fixing
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote :

See comment below

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote :

LGTM

review: Approve
Revision history for this message
Jim Hodapp (jhodapp) wrote :

Some issues to address, see comments inline below.

review: Needs Fixing (code)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
206. By Manuel de la Peña

Made changes according to reviews.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Unmerged revisions

206. By Manuel de la Peña

Made changes according to reviews.

205. By Manuel de la Peña

Update docs.

204. By Manuel de la Peña

Made chages as per review.

203. By Manuel de la Peña

Added support for delayed providers.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== 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-16 08:14:07 +0000
@@ -150,6 +150,8 @@
150 friend class Provider;150 friend class Provider;
151 explicit Controller(Provider& instance);151 explicit Controller(Provider& instance);
152152
153 virtual void on_provider_booted(bool was_booted);
154
153 private:155 private:
154 Provider& instance;156 Provider& instance;
155 std::atomic<int> position_updates_counter;157 std::atomic<int> position_updates_counter;
@@ -172,6 +174,20 @@
172 core::Signal<Update<std::set<SpaceVehicle>>> svs;174 core::Signal<Update<std::set<SpaceVehicle>>> svs;
173 };175 };
174176
177 /**
178 * @brief Wraps al those sigals that are related to the boot of the provider.
179 */
180 struct Signals
181 {
182 core::Signal<bool> booted;
183 };
184
185 enum class BootState {
186 NOT_BOOTED,
187 BOOTING,
188 BOOTED
189 };
190
175 virtual ~Provider() = default;191 virtual ~Provider() = default;
176192
177 Provider(const Provider&) = delete;193 Provider(const Provider&) = delete;
@@ -189,6 +205,18 @@
189 virtual const Controller::Ptr& state_controller() const;205 virtual const Controller::Ptr& state_controller() const;
190206
191 /**207 /**
208 * @brief Returns the booted signal to track the booting state of the provider.
209 * @return The signal that will be triggered once the provider has booted.
210 */
211 virtual core::Signal<bool>& booted_signal();
212
213 /**
214 * @brief Returns the booted signal to track the booting state of the provider.
215 * @return The signal that will be triggered once the provider has booted.
216 */
217 virtual const core::Signal<bool>& booted_signal() const;
218
219 /**
192 * @brief Checks if the provider supports a specific feature.220 * @brief Checks if the provider supports a specific feature.
193 * @param f Feature to test for221 * @param f Feature to test for
194 * @return true iff the provider supports the feature.222 * @return true iff the provider supports the feature.
@@ -210,6 +238,18 @@
210 virtual bool matches_criteria(const Criteria& criteria);238 virtual bool matches_criteria(const Criteria& criteria);
211239
212 /**240 /**
241 * @brief States the booting state of the provider.
242 * @return The boot state of the provider.
243 */
244 virtual BootState boot_state() const;
245
246 /**
247 * @brief Indicates to the provider that it should start the boot process in order to be able to
248 * be used by the engine.
249 */
250 virtual void boot();
251
252 /**
213 * @brief Called by the engine whenever the wifi and cell ID reporting state changes.253 * @brief Called by the engine whenever the wifi and cell ID reporting state changes.
214 * @param state The new state.254 * @param state The new state.
215 */255 */
@@ -270,12 +310,14 @@
270 */310 */
271 virtual void stop_velocity_updates();311 virtual void stop_velocity_updates();
272312
273private:313protected:
314 // protected to allow better white box testing
274 struct315 struct
275 {316 {
276 Features features = Features::none;317 Features features = Features::none;
277 Requirements requirements = Requirements::none;318 Requirements requirements = Requirements::none;
278 Updates updates;319 Updates updates;
320 Signals signals;
279 Controller::Ptr controller = Controller::Ptr{};321 Controller::Ptr controller = Controller::Ptr{};
280 } d;322 } d;
281};323};
282324
=== 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-16 08:14:07 +0000
@@ -16,9 +16,11 @@
16 * Authored by: Thomas Voß <thomas.voss@canonical.com>16 * Authored by: Thomas Voß <thomas.voss@canonical.com>
17 */17 */
18#include <com/ubuntu/location/provider.h>18#include <com/ubuntu/location/provider.h>
19#include <com/ubuntu/location/logging.h>
1920
20#include <atomic>21#include <atomic>
21#include <bitset>22#include <bitset>
23#include <functional>
22#include <memory>24#include <memory>
2325
24namespace cul = com::ubuntu::location;26namespace cul = com::ubuntu::location;
@@ -51,12 +53,15 @@
5153
52void cul::Provider::Controller::start_position_updates()54void cul::Provider::Controller::start_position_updates()
53{55{
54 if (position_updates_counter < 0)56 if (position_updates_counter < 0) {
55 return;57 return;
58 }
5659
57 if (++position_updates_counter == 1)60 if (++position_updates_counter == 1)
58 {61 {
59 instance.start_position_updates();62 if (instance.boot_state() == BootState::BOOTED) {
63 instance.start_position_updates();
64 }
60 }65 }
61}66}
6267
@@ -67,7 +72,8 @@
6772
68 if (--position_updates_counter == 0)73 if (--position_updates_counter == 0)
69 {74 {
70 instance.stop_position_updates();75 if (instance.boot_state() == BootState::BOOTED)
76 instance.stop_position_updates();
71 }77 }
72}78}
7379
@@ -83,7 +89,8 @@
8389
84 if (++heading_updates_counter == 1)90 if (++heading_updates_counter == 1)
85 {91 {
86 instance.start_heading_updates();92 if (instance.boot_state() == BootState::BOOTED)
93 instance.start_heading_updates();
87 }94 }
88}95}
8996
@@ -94,7 +101,8 @@
94101
95 if (--heading_updates_counter == 0)102 if (--heading_updates_counter == 0)
96 {103 {
97 instance.stop_heading_updates();104 if (instance.boot_state() == BootState::BOOTED)
105 instance.stop_heading_updates();
98 }106 }
99}107}
100108
@@ -110,7 +118,8 @@
110118
111 if (++velocity_updates_counter == 1)119 if (++velocity_updates_counter == 1)
112 {120 {
113 instance.start_velocity_updates();121 if (instance.boot_state() == BootState::BOOTED)
122 instance.start_velocity_updates();
114 }123 }
115}124}
116125
@@ -121,7 +130,8 @@
121130
122 if (--velocity_updates_counter == 0)131 if (--velocity_updates_counter == 0)
123 {132 {
124 instance.stop_velocity_updates();133 if (instance.boot_state() == BootState::BOOTED)
134 instance.stop_velocity_updates();
125 }135 }
126}136}
127137
@@ -130,12 +140,38 @@
130 return velocity_updates_counter > 0;140 return velocity_updates_counter > 0;
131}141}
132142
143void cul::Provider::Controller::on_provider_booted(bool was_booted)
144{
145 if (!was_booted)
146 return;
147
148 // we need to propagate the state of the provider using the internal counters as references
149 if (position_updates_counter > 0) {
150 instance.start_position_updates();
151 }
152 if (heading_updates_counter > 0) {
153 instance.start_heading_updates();
154 }
155 if (velocity_updates_counter > 0) {
156 instance.start_velocity_updates();
157 }
158}
159
133cul::Provider::Controller::Controller(cul::Provider& instance)160cul::Provider::Controller::Controller(cul::Provider& instance)
134 : instance(instance),161 : instance(instance),
135 position_updates_counter(0),162 position_updates_counter(0),
136 heading_updates_counter(0),163 heading_updates_counter(0),
137 velocity_updates_counter(0)164 velocity_updates_counter(0)
138{ 165{
166 using namespace std::placeholders;
167
168 if (instance.boot_state() != BootState::BOOTED) {
169 // if the instance has not booted and is delayed we need to keep track of its booting state
170 instance.booted_signal().connect(std::bind(&Controller::on_provider_booted, this, _1));
171 if (instance.boot_state() != BootState::BOOTING) {
172 instance.boot();
173 }
174 }
139}175}
140176
141const cul::Provider::Controller::Ptr& cul::Provider::state_controller() const177const cul::Provider::Controller::Ptr& cul::Provider::state_controller() const
@@ -158,11 +194,28 @@
158 return false;194 return false;
159}195}
160196
197cul::Provider::BootState cul::Provider::boot_state() const
198{
199 return cul::Provider::BootState::BOOTED;
200}
201
202void cul::Provider::boot() { }
203
161const cul::Provider::Updates& cul::Provider::updates() const204const cul::Provider::Updates& cul::Provider::updates() const
162{205{
163 return d.updates;206 return d.updates;
164}207}
165208
209core::Signal<bool>& cul::Provider::booted_signal()
210{
211 return d.signals.booted;
212}
213
214const core::Signal<bool>& cul::Provider::booted_signal() const
215{
216 return d.signals.booted;
217}
218
166cul::Provider::Provider(219cul::Provider::Provider(
167 const cul::Provider::Features& features,220 const cul::Provider::Features& features,
168 const cul::Provider::Requirements& requirements)221 const cul::Provider::Requirements& requirements)
169222
=== modified file 'tests/controller_test.cpp'
--- tests/controller_test.cpp 2014-09-10 19:34:09 +0000
+++ tests/controller_test.cpp 2015-06-16 08:14:07 +0000
@@ -18,6 +18,7 @@
18#include <com/ubuntu/location/provider.h>18#include <com/ubuntu/location/provider.h>
1919
20#include "mock_provider.h"20#include "mock_provider.h"
21#include "mock_delayed_provider.h"
2122
22#include <gmock/gmock.h>23#include <gmock/gmock.h>
23#include <gtest/gtest.h>24#include <gtest/gtest.h>
@@ -130,3 +131,215 @@
130 EXPECT_FALSE(controller->are_velocity_updates_running());131 EXPECT_FALSE(controller->are_velocity_updates_running());
131 EXPECT_FALSE(controller->are_heading_updates_running());132 EXPECT_FALSE(controller->are_heading_updates_running());
132}133}
134
135TEST(Controller, controller_resumes_state_after_boot) {
136 using namespace ::testing;
137 using ::testing::Mock;
138
139 MockDelayedProvider provider;
140
141 // ignore what ever was performed on construction
142 Mock::VerifyAndClear(&provider);
143
144}
145
146TEST(Controller, controller_does_not_call_start_position_if_not_booted) {
147 using namespace ::testing;
148 using ::testing::Mock;
149
150 MockDelayedProvider provider;
151
152 // ignore what ever was performed on construction
153 Mock::VerifyAndClear(&provider);
154 // use a mock controller
155 auto controller = provider.state_controller();
156
157 EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
158 .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED));
159 EXPECT_CALL(provider, start_position_updates()).Times(Exactly(0));
160
161 controller->start_position_updates();
162 controller->start_position_updates();
163}
164
165TEST(Controller, controller_does_not_call_start_position_if_booting) {
166 using namespace ::testing;
167 using ::testing::Mock;
168
169 MockDelayedProvider provider;
170
171 // ignore what ever was performed on construction
172 Mock::VerifyAndClear(&provider);
173 // use a mock controller
174 auto controller = provider.state_controller();
175
176 EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
177 .WillOnce(Return(cul::Provider::BootState::BOOTING));
178 EXPECT_CALL(provider, start_position_updates()).Times(Exactly(0));
179
180 controller->start_position_updates();
181}
182
183TEST(Controller, controller_does_not_call_start_heading_if_not_booted) {
184 using namespace ::testing;
185 using ::testing::Mock;
186
187 MockDelayedProvider provider;
188 EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
189
190 // ignore what ever was performed on construction
191 Mock::VerifyAndClear(&provider);
192 // use a mock controller
193 auto controller = provider.state_controller();
194
195 EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
196 .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED));
197 EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0));
198
199 controller->start_heading_updates();
200}
201
202TEST(Controller, controller_does_not_call_start_heading_if_booting) {
203 using namespace ::testing;
204 using ::testing::Mock;
205
206 MockDelayedProvider provider;
207 EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
208
209 // ignore what ever was performed on construction
210 Mock::VerifyAndClear(&provider);
211 // use a mock controller
212 auto controller = provider.state_controller();
213
214 EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
215 .WillOnce(Return(cul::Provider::BootState::BOOTING));
216 EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0));
217
218 controller->start_heading_updates();
219}
220
221TEST(Controller, controller_does_not_call_start_velocity_if_not_booted) {
222 using namespace ::testing;
223 using ::testing::Mock;
224
225 MockDelayedProvider provider;
226 EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
227
228 // ignore what ever was performed on construction
229 Mock::VerifyAndClear(&provider);
230 // use a mock controller
231 auto controller = provider.state_controller();
232
233 EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
234 .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED));
235 EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0));
236
237 controller->start_velocity_updates();
238}
239
240TEST(Controller, controller_does_not_call_start_velocity_if_booting) {
241 using namespace ::testing;
242 using ::testing::Mock;
243
244 MockDelayedProvider provider;
245 EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
246
247 // ignore what ever was performed on construction
248 Mock::VerifyAndClear(&provider);
249 // use a mock controller
250 auto controller = provider.state_controller();
251
252 EXPECT_CALL(provider, boot_state()).Times(Exactly(1))
253 .WillOnce(Return(cul::Provider::BootState::BOOTING));
254 EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0));
255
256 controller->start_velocity_updates();
257}
258
259TEST(Controller, controller_does_not_call_stop_position_if_not_booted) {
260 using namespace ::testing;
261 using ::testing::Mock;
262
263 MockDelayedProvider provider;
264 EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
265
266 // ignore what ever was performed on construction
267 Mock::VerifyAndClear(&provider);
268 // use a mock controller
269 auto controller = provider.state_controller();
270
271 EXPECT_CALL(provider, boot_state()).Times(Exactly(2))
272 .WillOnce(Return(cul::Provider::BootState::BOOTED))
273 .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED));
274 EXPECT_CALL(provider, start_position_updates()).Times(Exactly(1));
275 EXPECT_CALL(provider, stop_position_updates()).Times(Exactly(0));
276
277 controller->start_position_updates();
278 controller->stop_position_updates();
279}
280
281TEST(Controller, controller_does_not_call_stop_position_if_booting) {
282 using namespace ::testing;
283 using ::testing::Mock;
284
285 MockDelayedProvider provider;
286 EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
287
288 // ignore what ever was performed on construction
289 Mock::VerifyAndClear(&provider);
290 // use a mock controller
291 auto controller = provider.state_controller();
292
293 EXPECT_CALL(provider, boot_state()).Times(Exactly(2))
294 .WillOnce(Return(cul::Provider::BootState::BOOTED))
295 .WillOnce(Return(cul::Provider::BootState::BOOTING));
296 EXPECT_CALL(provider, start_position_updates()).Times(Exactly(1));
297 EXPECT_CALL(provider, stop_position_updates()).Times(Exactly(0));
298
299 controller->start_position_updates();
300 controller->stop_position_updates();
301}
302
303TEST(Controller, controller_does_not_call_stop_heading_if_not_booted) {
304 using namespace ::testing;
305 using ::testing::Mock;
306
307 MockDelayedProvider provider;
308 EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
309
310 // ignore what ever was performed on construction
311 Mock::VerifyAndClear(&provider);
312 // use a mock controller
313 auto controller = provider.state_controller();
314
315 EXPECT_CALL(provider, boot_state()).Times(Exactly(2))
316 .WillOnce(Return(cul::Provider::BootState::BOOTED))
317 .WillOnce(Return(cul::Provider::BootState::BOOTING));
318 EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(1));
319 EXPECT_CALL(provider, stop_heading_updates()).Times(Exactly(0));
320
321 controller->start_heading_updates();
322 controller->stop_heading_updates();
323}
324
325TEST(Controller, controller_does_not_call_stop_velocity_if_not_booted) {
326 using namespace ::testing;
327 using ::testing::Mock;
328
329 MockDelayedProvider provider;
330 EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true));
331
332 // ignore what ever was performed on construction
333 Mock::VerifyAndClear(&provider);
334 // use a mock controller
335 auto controller = provider.state_controller();
336
337 EXPECT_CALL(provider, boot_state()).Times(Exactly(2))
338 .WillOnce(Return(cul::Provider::BootState::BOOTED))
339 .WillOnce(Return(cul::Provider::BootState::BOOTING));
340 EXPECT_CALL(provider, start_velocity_updates()).Times(Exactly(1));
341 EXPECT_CALL(provider, stop_velocity_updates()).Times(Exactly(0));
342
343 controller->start_velocity_updates();
344 controller->stop_velocity_updates();
345}
133346
=== 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-16 08:14:07 +0000
@@ -0,0 +1,89 @@
1/*
2 * Copyright © 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: M
17 */
18#ifndef MOCK_DELAYED_PROVIDER_H_
19#define MOCK_DELAYED_PROVIDER_H_
20
21#include <com/ubuntu/location/provider.h>
22#include <com/ubuntu/location/logging.h>
23
24#include <gmock/gmock.h>
25
26struct PublicController : public com::ubuntu::location::Provider::Controller
27{
28
29 explicit PublicController(com::ubuntu::location::Provider& instance)
30 : com::ubuntu::location::Provider::Controller(instance) {}
31};
32
33struct MockDelayedProvider : public com::ubuntu::location::Provider
34{
35 MockDelayedProvider() : com::ubuntu::location::Provider()
36 {
37 }
38
39 MOCK_METHOD1(matches_criteria, bool(const com::ubuntu::location::Criteria&));
40
41 MOCK_CONST_METHOD1(supports, bool(const com::ubuntu::location::Provider::Features&));
42 MOCK_CONST_METHOD1(requires, bool(const com::ubuntu::location::Provider::Requirements&));
43
44 // Called by the engine whenever the wifi and cell ID reporting state changes.
45 MOCK_METHOD1(on_wifi_and_cell_reporting_state_changed, void(com::ubuntu::location::WifiAndCellIdReportingState state));
46
47 // Called by the engine whenever the reference location changed.
48 MOCK_METHOD1(on_reference_location_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Position>& position));
49
50 // Called by the engine whenever the reference velocity changed.
51 MOCK_METHOD1(on_reference_velocity_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Velocity>& velocity));
52
53 // Called by the engine whenever the reference heading changed.
54 MOCK_METHOD1(on_reference_heading_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Heading>& heading));
55
56 MOCK_METHOD0(start_position_updates, void());
57 MOCK_METHOD0(stop_position_updates, void());
58
59 MOCK_METHOD0(start_heading_updates, void());
60 MOCK_METHOD0(stop_heading_updates, void());
61
62 MOCK_METHOD0(start_velocity_updates, void());
63 MOCK_METHOD0(stop_velocity_updates, void());
64
65 MOCK_CONST_METHOD0(has_delayed_boot, bool());
66 MOCK_CONST_METHOD0(boot_state, BootState());
67 MOCK_CONST_METHOD0(boot, void());
68
69
70 // Inject a position update from the outside.
71 void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Position>& update)
72 {
73 mutable_updates().position(update);
74 }
75
76 // Inject a velocity update from the outside.
77 void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Velocity>& update)
78 {
79 mutable_updates().velocity(update);
80 }
81
82 // Inject a heading update from the outside.
83 void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Heading>& update)
84 {
85 mutable_updates().heading(update);
86 }
87};
88
89#endif // MOCK_PROVIDER_H_

Subscribers

People subscribed via source and target branches