Merge lp:~ssweeny/location-service/delayed-providers.15.04 into lp:location-service/15.04
- delayed-providers.15.04
- Merge into 15.04
Status: | Approved |
---|---|
Approved by: | Thomas Voß |
Approved revision: | 201 |
Proposed branch: | lp:~ssweeny/location-service/delayed-providers.15.04 |
Merge into: | lp:location-service/15.04 |
Diff against target: |
567 lines (+411/-9) 4 files modified
include/location_service/com/ubuntu/location/provider.h (+43/-1) src/location_service/com/ubuntu/location/provider.cpp (+66/-8) tests/controller_test.cpp (+213/-0) tests/mock_delayed_provider.h (+89/-0) |
To merge this branch: | bzr merge lp:~ssweeny/location-service/delayed-providers.15.04 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Thomas Voß (community) | Approve | ||
Review via email: mp+275384@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.
Thomas Voß (thomas-voss) wrote : | # |
A few niggles inline.
- 199. By Scott Sweeny
-
Address review comments
- 200. By Scott Sweeny
-
Add logging output (move here from espoo-delayed-
providers MP) - 201. By Scott Sweeny
-
Add a log message that I missed
Alberto Mardegan (mardy) wrote : | # |
I'm coming from a programming style that keeps virtual methods to a minimum, and I do understand if that might not be of your liking, so feel free to discard this comment. :-)
Wouldn't it be possible to implement the same without breaking the ABI?
At least, I see no reason why these methods need to be virtual:
virtual core::Signal<bool>& boot_state_
virtual const core::Signal<bool>& boot_state_
given that you are providing a default implementation that I don't see any reason to override. As for the getter:
virtual BootState boot_state() const;
this could be made non virtual by adding a protected method like
void set_boot_
that subclasses can call to set the boot state. This method would also take care of emitting the boot_state_
The only method for which a virtual declaration makes a lot of sense is request_boot(), but OTOH I wonder if we could remove it altogether: we could just specify that boot should start when the provider's constructor is invoked, or (if we really need a two-phase initialization) when the
virtual const Controller::Ptr& state_controller() const;
method is first invoked (it's a virtual method, so the subclass can use it to start the initialization). I can see that purists might not like to have this method be overloaded with the booting role too, but it's something that can make sense, if clearly explained in a doc comment.
It all depends on whether preserving ABI is a goal or not.
Unmerged revisions
- 201. By Scott Sweeny
-
Add a log message that I missed
- 200. By Scott Sweeny
-
Add logging output (move here from espoo-delayed-
providers MP) - 199. By Scott Sweeny
-
Address review comments
- 198. By Manuel de la Peña
-
Added support for delayed providers.
Preview Diff
1 | === modified file 'include/location_service/com/ubuntu/location/provider.h' | |||
2 | --- include/location_service/com/ubuntu/location/provider.h 2015-01-21 20:13:28 +0000 | |||
3 | +++ include/location_service/com/ubuntu/location/provider.h 2015-10-27 20:49:11 +0000 | |||
4 | @@ -150,6 +150,8 @@ | |||
5 | 150 | friend class Provider; | 150 | friend class Provider; |
6 | 151 | explicit Controller(Provider& instance); | 151 | explicit Controller(Provider& instance); |
7 | 152 | 152 | ||
8 | 153 | virtual void on_provider_booted(); | ||
9 | 154 | |||
10 | 153 | private: | 155 | private: |
11 | 154 | Provider& instance; | 156 | Provider& instance; |
12 | 155 | std::atomic<int> position_updates_counter; | 157 | std::atomic<int> position_updates_counter; |
13 | @@ -172,6 +174,20 @@ | |||
14 | 172 | core::Signal<Update<std::set<SpaceVehicle>>> svs; | 174 | core::Signal<Update<std::set<SpaceVehicle>>> svs; |
15 | 173 | }; | 175 | }; |
16 | 174 | 176 | ||
17 | 177 | /** | ||
18 | 178 | * @brief Wraps al those sigals that are related to the boot of the provider. | ||
19 | 179 | */ | ||
20 | 180 | struct Signals | ||
21 | 181 | { | ||
22 | 182 | core::Signal<bool> booted; | ||
23 | 183 | }; | ||
24 | 184 | |||
25 | 185 | enum class BootState { | ||
26 | 186 | NOT_BOOTED, | ||
27 | 187 | BOOTING, | ||
28 | 188 | BOOTED | ||
29 | 189 | }; | ||
30 | 190 | |||
31 | 175 | virtual ~Provider() = default; | 191 | virtual ~Provider() = default; |
32 | 176 | 192 | ||
33 | 177 | Provider(const Provider&) = delete; | 193 | Provider(const Provider&) = delete; |
34 | @@ -189,6 +205,18 @@ | |||
35 | 189 | virtual const Controller::Ptr& state_controller() const; | 205 | virtual const Controller::Ptr& state_controller() const; |
36 | 190 | 206 | ||
37 | 191 | /** | 207 | /** |
38 | 208 | * @brief Returns the booted signal to track the booting state of the provider. | ||
39 | 209 | * @return The signal that will be triggered once the provider has booted. | ||
40 | 210 | */ | ||
41 | 211 | virtual core::Signal<bool>& boot_state_changed(); | ||
42 | 212 | |||
43 | 213 | /** | ||
44 | 214 | * @brief Returns the booted signal to track the booting state of the provider. | ||
45 | 215 | * @return The signal that will be triggered once the provider has booted. | ||
46 | 216 | */ | ||
47 | 217 | virtual const core::Signal<bool>& boot_state_changed() const; | ||
48 | 218 | |||
49 | 219 | /** | ||
50 | 192 | * @brief Checks if the provider supports a specific feature. | 220 | * @brief Checks if the provider supports a specific feature. |
51 | 193 | * @param f Feature to test for | 221 | * @param f Feature to test for |
52 | 194 | * @return true iff the provider supports the feature. | 222 | * @return true iff the provider supports the feature. |
53 | @@ -210,6 +238,18 @@ | |||
54 | 210 | virtual bool matches_criteria(const Criteria& criteria); | 238 | virtual bool matches_criteria(const Criteria& criteria); |
55 | 211 | 239 | ||
56 | 212 | /** | 240 | /** |
57 | 241 | * @brief States the booting state of the provider. | ||
58 | 242 | * @return The boot state of the provider. | ||
59 | 243 | */ | ||
60 | 244 | virtual BootState boot_state() const; | ||
61 | 245 | |||
62 | 246 | /** | ||
63 | 247 | * @brief Indicates to the provider that it should start the boot process in order to be able to | ||
64 | 248 | * be used by the engine. | ||
65 | 249 | */ | ||
66 | 250 | virtual void request_boot(); | ||
67 | 251 | |||
68 | 252 | /** | ||
69 | 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. |
70 | 214 | * @param state The new state. | 254 | * @param state The new state. |
71 | 215 | */ | 255 | */ |
72 | @@ -270,12 +310,14 @@ | |||
73 | 270 | */ | 310 | */ |
74 | 271 | virtual void stop_velocity_updates(); | 311 | virtual void stop_velocity_updates(); |
75 | 272 | 312 | ||
77 | 273 | private: | 313 | protected: |
78 | 314 | // protected to allow better white box testing | ||
79 | 274 | struct | 315 | struct |
80 | 275 | { | 316 | { |
81 | 276 | Features features = Features::none; | 317 | Features features = Features::none; |
82 | 277 | Requirements requirements = Requirements::none; | 318 | Requirements requirements = Requirements::none; |
83 | 278 | Updates updates; | 319 | Updates updates; |
84 | 320 | Signals signals; | ||
85 | 279 | Controller::Ptr controller = Controller::Ptr{}; | 321 | Controller::Ptr controller = Controller::Ptr{}; |
86 | 280 | } d; | 322 | } d; |
87 | 281 | }; | 323 | }; |
88 | 282 | 324 | ||
89 | === modified file 'src/location_service/com/ubuntu/location/provider.cpp' | |||
90 | --- src/location_service/com/ubuntu/location/provider.cpp 2015-01-23 19:07:09 +0000 | |||
91 | +++ src/location_service/com/ubuntu/location/provider.cpp 2015-10-27 20:49:11 +0000 | |||
92 | @@ -16,9 +16,11 @@ | |||
93 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
94 | 17 | */ | 17 | */ |
95 | 18 | #include <com/ubuntu/location/provider.h> | 18 | #include <com/ubuntu/location/provider.h> |
96 | 19 | #include <com/ubuntu/location/logging.h> | ||
97 | 19 | 20 | ||
98 | 20 | #include <atomic> | 21 | #include <atomic> |
99 | 21 | #include <bitset> | 22 | #include <bitset> |
100 | 23 | #include <functional> | ||
101 | 22 | #include <memory> | 24 | #include <memory> |
102 | 23 | 25 | ||
103 | 24 | namespace cul = com::ubuntu::location; | 26 | namespace cul = com::ubuntu::location; |
104 | @@ -51,12 +53,15 @@ | |||
105 | 51 | 53 | ||
106 | 52 | void cul::Provider::Controller::start_position_updates() | 54 | void cul::Provider::Controller::start_position_updates() |
107 | 53 | { | 55 | { |
109 | 54 | if (position_updates_counter < 0) | 56 | if (position_updates_counter < 0) { |
110 | 55 | return; | 57 | return; |
111 | 58 | } | ||
112 | 56 | 59 | ||
113 | 57 | if (++position_updates_counter == 1) | 60 | if (++position_updates_counter == 1) |
114 | 58 | { | 61 | { |
116 | 59 | instance.start_position_updates(); | 62 | if (instance.boot_state() == BootState::BOOTED) { |
117 | 63 | instance.start_position_updates(); | ||
118 | 64 | } | ||
119 | 60 | } | 65 | } |
120 | 61 | } | 66 | } |
121 | 62 | 67 | ||
122 | @@ -67,7 +72,8 @@ | |||
123 | 67 | 72 | ||
124 | 68 | if (--position_updates_counter == 0) | 73 | if (--position_updates_counter == 0) |
125 | 69 | { | 74 | { |
127 | 70 | instance.stop_position_updates(); | 75 | if (instance.boot_state() == BootState::BOOTED) |
128 | 76 | instance.stop_position_updates(); | ||
129 | 71 | } | 77 | } |
130 | 72 | } | 78 | } |
131 | 73 | 79 | ||
132 | @@ -83,7 +89,8 @@ | |||
133 | 83 | 89 | ||
134 | 84 | if (++heading_updates_counter == 1) | 90 | if (++heading_updates_counter == 1) |
135 | 85 | { | 91 | { |
137 | 86 | instance.start_heading_updates(); | 92 | if (instance.boot_state() == BootState::BOOTED) |
138 | 93 | instance.start_heading_updates(); | ||
139 | 87 | } | 94 | } |
140 | 88 | } | 95 | } |
141 | 89 | 96 | ||
142 | @@ -94,7 +101,8 @@ | |||
143 | 94 | 101 | ||
144 | 95 | if (--heading_updates_counter == 0) | 102 | if (--heading_updates_counter == 0) |
145 | 96 | { | 103 | { |
147 | 97 | instance.stop_heading_updates(); | 104 | if (instance.boot_state() == BootState::BOOTED) |
148 | 105 | instance.stop_heading_updates(); | ||
149 | 98 | } | 106 | } |
150 | 99 | } | 107 | } |
151 | 100 | 108 | ||
152 | @@ -110,7 +118,8 @@ | |||
153 | 110 | 118 | ||
154 | 111 | if (++velocity_updates_counter == 1) | 119 | if (++velocity_updates_counter == 1) |
155 | 112 | { | 120 | { |
157 | 113 | instance.start_velocity_updates(); | 121 | if (instance.boot_state() == BootState::BOOTED) |
158 | 122 | instance.start_velocity_updates(); | ||
159 | 114 | } | 123 | } |
160 | 115 | } | 124 | } |
161 | 116 | 125 | ||
162 | @@ -121,7 +130,8 @@ | |||
163 | 121 | 130 | ||
164 | 122 | if (--velocity_updates_counter == 0) | 131 | if (--velocity_updates_counter == 0) |
165 | 123 | { | 132 | { |
167 | 124 | instance.stop_velocity_updates(); | 133 | if (instance.boot_state() == BootState::BOOTED) |
168 | 134 | instance.stop_velocity_updates(); | ||
169 | 125 | } | 135 | } |
170 | 126 | } | 136 | } |
171 | 127 | 137 | ||
172 | @@ -130,12 +140,43 @@ | |||
173 | 130 | return velocity_updates_counter > 0; | 140 | return velocity_updates_counter > 0; |
174 | 131 | } | 141 | } |
175 | 132 | 142 | ||
176 | 143 | void cul::Provider::Controller::on_provider_booted() | ||
177 | 144 | { | ||
178 | 145 | if (instance.boot_state() != BootState::BOOTED) | ||
179 | 146 | return; | ||
180 | 147 | |||
181 | 148 | LOG(INFO) << "Provider was booted"; | ||
182 | 149 | |||
183 | 150 | // we need to propagate the state of the provider using the internal counters as references | ||
184 | 151 | if (position_updates_counter > 0) { | ||
185 | 152 | LOG(INFO) << "Starting position updates"; | ||
186 | 153 | instance.start_position_updates(); | ||
187 | 154 | } | ||
188 | 155 | if (heading_updates_counter > 0) { | ||
189 | 156 | LOG(INFO) << "Starting heading updates"; | ||
190 | 157 | instance.start_heading_updates(); | ||
191 | 158 | } | ||
192 | 159 | if (velocity_updates_counter > 0) { | ||
193 | 160 | LOG(INFO) << "Starting velocity updates"; | ||
194 | 161 | instance.start_velocity_updates(); | ||
195 | 162 | } | ||
196 | 163 | } | ||
197 | 164 | |||
198 | 133 | cul::Provider::Controller::Controller(cul::Provider& instance) | 165 | cul::Provider::Controller::Controller(cul::Provider& instance) |
199 | 134 | : instance(instance), | 166 | : instance(instance), |
200 | 135 | position_updates_counter(0), | 167 | position_updates_counter(0), |
201 | 136 | heading_updates_counter(0), | 168 | heading_updates_counter(0), |
202 | 137 | velocity_updates_counter(0) | 169 | velocity_updates_counter(0) |
204 | 138 | { | 170 | { |
205 | 171 | using namespace std::placeholders; | ||
206 | 172 | |||
207 | 173 | if (instance.boot_state() != BootState::BOOTED) { | ||
208 | 174 | // if the instance has not booted and is delayed we need to keep track of its booting state | ||
209 | 175 | instance.boot_state_changed().connect(std::bind(&Controller::on_provider_booted, this)); | ||
210 | 176 | if (instance.boot_state() != BootState::BOOTING) { | ||
211 | 177 | instance.request_boot(); | ||
212 | 178 | } | ||
213 | 179 | } | ||
214 | 139 | } | 180 | } |
215 | 140 | 181 | ||
216 | 141 | const cul::Provider::Controller::Ptr& cul::Provider::state_controller() const | 182 | const cul::Provider::Controller::Ptr& cul::Provider::state_controller() const |
217 | @@ -158,11 +199,28 @@ | |||
218 | 158 | return false; | 199 | return false; |
219 | 159 | } | 200 | } |
220 | 160 | 201 | ||
221 | 202 | cul::Provider::BootState cul::Provider::boot_state() const | ||
222 | 203 | { | ||
223 | 204 | return cul::Provider::BootState::BOOTED; | ||
224 | 205 | } | ||
225 | 206 | |||
226 | 207 | void cul::Provider::request_boot() { } | ||
227 | 208 | |||
228 | 161 | const cul::Provider::Updates& cul::Provider::updates() const | 209 | const cul::Provider::Updates& cul::Provider::updates() const |
229 | 162 | { | 210 | { |
230 | 163 | return d.updates; | 211 | return d.updates; |
231 | 164 | } | 212 | } |
232 | 165 | 213 | ||
233 | 214 | core::Signal<bool>& cul::Provider::boot_state_changed() | ||
234 | 215 | { | ||
235 | 216 | return d.signals.booted; | ||
236 | 217 | } | ||
237 | 218 | |||
238 | 219 | const core::Signal<bool>& cul::Provider::boot_state_changed() const | ||
239 | 220 | { | ||
240 | 221 | return d.signals.booted; | ||
241 | 222 | } | ||
242 | 223 | |||
243 | 166 | cul::Provider::Provider( | 224 | cul::Provider::Provider( |
244 | 167 | const cul::Provider::Features& features, | 225 | const cul::Provider::Features& features, |
245 | 168 | const cul::Provider::Requirements& requirements) | 226 | const cul::Provider::Requirements& requirements) |
246 | 169 | 227 | ||
247 | === modified file 'tests/controller_test.cpp' | |||
248 | --- tests/controller_test.cpp 2014-09-10 19:34:09 +0000 | |||
249 | +++ tests/controller_test.cpp 2015-10-27 20:49:11 +0000 | |||
250 | @@ -18,6 +18,7 @@ | |||
251 | 18 | #include <com/ubuntu/location/provider.h> | 18 | #include <com/ubuntu/location/provider.h> |
252 | 19 | 19 | ||
253 | 20 | #include "mock_provider.h" | 20 | #include "mock_provider.h" |
254 | 21 | #include "mock_delayed_provider.h" | ||
255 | 21 | 22 | ||
256 | 22 | #include <gmock/gmock.h> | 23 | #include <gmock/gmock.h> |
257 | 23 | #include <gtest/gtest.h> | 24 | #include <gtest/gtest.h> |
258 | @@ -130,3 +131,215 @@ | |||
259 | 130 | EXPECT_FALSE(controller->are_velocity_updates_running()); | 131 | EXPECT_FALSE(controller->are_velocity_updates_running()); |
260 | 131 | EXPECT_FALSE(controller->are_heading_updates_running()); | 132 | EXPECT_FALSE(controller->are_heading_updates_running()); |
261 | 132 | } | 133 | } |
262 | 134 | |||
263 | 135 | TEST(Controller, controller_resumes_state_after_boot) { | ||
264 | 136 | using namespace ::testing; | ||
265 | 137 | using ::testing::Mock; | ||
266 | 138 | |||
267 | 139 | MockDelayedProvider provider; | ||
268 | 140 | |||
269 | 141 | // ignore what ever was performed on construction | ||
270 | 142 | Mock::VerifyAndClear(&provider); | ||
271 | 143 | |||
272 | 144 | } | ||
273 | 145 | |||
274 | 146 | TEST(Controller, controller_does_not_call_start_position_if_not_booted) { | ||
275 | 147 | using namespace ::testing; | ||
276 | 148 | using ::testing::Mock; | ||
277 | 149 | |||
278 | 150 | MockDelayedProvider provider; | ||
279 | 151 | |||
280 | 152 | // ignore what ever was performed on construction | ||
281 | 153 | Mock::VerifyAndClear(&provider); | ||
282 | 154 | // use a mock controller | ||
283 | 155 | auto controller = provider.state_controller(); | ||
284 | 156 | |||
285 | 157 | EXPECT_CALL(provider, boot_state()).Times(Exactly(1)) | ||
286 | 158 | .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED)); | ||
287 | 159 | EXPECT_CALL(provider, start_position_updates()).Times(Exactly(0)); | ||
288 | 160 | |||
289 | 161 | controller->start_position_updates(); | ||
290 | 162 | controller->start_position_updates(); | ||
291 | 163 | } | ||
292 | 164 | |||
293 | 165 | TEST(Controller, controller_does_not_call_start_position_if_booting) { | ||
294 | 166 | using namespace ::testing; | ||
295 | 167 | using ::testing::Mock; | ||
296 | 168 | |||
297 | 169 | MockDelayedProvider provider; | ||
298 | 170 | |||
299 | 171 | // ignore what ever was performed on construction | ||
300 | 172 | Mock::VerifyAndClear(&provider); | ||
301 | 173 | // use a mock controller | ||
302 | 174 | auto controller = provider.state_controller(); | ||
303 | 175 | |||
304 | 176 | EXPECT_CALL(provider, boot_state()).Times(Exactly(1)) | ||
305 | 177 | .WillOnce(Return(cul::Provider::BootState::BOOTING)); | ||
306 | 178 | EXPECT_CALL(provider, start_position_updates()).Times(Exactly(0)); | ||
307 | 179 | |||
308 | 180 | controller->start_position_updates(); | ||
309 | 181 | } | ||
310 | 182 | |||
311 | 183 | TEST(Controller, controller_does_not_call_start_heading_if_not_booted) { | ||
312 | 184 | using namespace ::testing; | ||
313 | 185 | using ::testing::Mock; | ||
314 | 186 | |||
315 | 187 | MockDelayedProvider provider; | ||
316 | 188 | EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true)); | ||
317 | 189 | |||
318 | 190 | // ignore what ever was performed on construction | ||
319 | 191 | Mock::VerifyAndClear(&provider); | ||
320 | 192 | // use a mock controller | ||
321 | 193 | auto controller = provider.state_controller(); | ||
322 | 194 | |||
323 | 195 | EXPECT_CALL(provider, boot_state()).Times(Exactly(1)) | ||
324 | 196 | .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED)); | ||
325 | 197 | EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0)); | ||
326 | 198 | |||
327 | 199 | controller->start_heading_updates(); | ||
328 | 200 | } | ||
329 | 201 | |||
330 | 202 | TEST(Controller, controller_does_not_call_start_heading_if_booting) { | ||
331 | 203 | using namespace ::testing; | ||
332 | 204 | using ::testing::Mock; | ||
333 | 205 | |||
334 | 206 | MockDelayedProvider provider; | ||
335 | 207 | EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true)); | ||
336 | 208 | |||
337 | 209 | // ignore what ever was performed on construction | ||
338 | 210 | Mock::VerifyAndClear(&provider); | ||
339 | 211 | // use a mock controller | ||
340 | 212 | auto controller = provider.state_controller(); | ||
341 | 213 | |||
342 | 214 | EXPECT_CALL(provider, boot_state()).Times(Exactly(1)) | ||
343 | 215 | .WillOnce(Return(cul::Provider::BootState::BOOTING)); | ||
344 | 216 | EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0)); | ||
345 | 217 | |||
346 | 218 | controller->start_heading_updates(); | ||
347 | 219 | } | ||
348 | 220 | |||
349 | 221 | TEST(Controller, controller_does_not_call_start_velocity_if_not_booted) { | ||
350 | 222 | using namespace ::testing; | ||
351 | 223 | using ::testing::Mock; | ||
352 | 224 | |||
353 | 225 | MockDelayedProvider provider; | ||
354 | 226 | EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true)); | ||
355 | 227 | |||
356 | 228 | // ignore what ever was performed on construction | ||
357 | 229 | Mock::VerifyAndClear(&provider); | ||
358 | 230 | // use a mock controller | ||
359 | 231 | auto controller = provider.state_controller(); | ||
360 | 232 | |||
361 | 233 | EXPECT_CALL(provider, boot_state()).Times(Exactly(1)) | ||
362 | 234 | .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED)); | ||
363 | 235 | EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0)); | ||
364 | 236 | |||
365 | 237 | controller->start_velocity_updates(); | ||
366 | 238 | } | ||
367 | 239 | |||
368 | 240 | TEST(Controller, controller_does_not_call_start_velocity_if_booting) { | ||
369 | 241 | using namespace ::testing; | ||
370 | 242 | using ::testing::Mock; | ||
371 | 243 | |||
372 | 244 | MockDelayedProvider provider; | ||
373 | 245 | EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true)); | ||
374 | 246 | |||
375 | 247 | // ignore what ever was performed on construction | ||
376 | 248 | Mock::VerifyAndClear(&provider); | ||
377 | 249 | // use a mock controller | ||
378 | 250 | auto controller = provider.state_controller(); | ||
379 | 251 | |||
380 | 252 | EXPECT_CALL(provider, boot_state()).Times(Exactly(1)) | ||
381 | 253 | .WillOnce(Return(cul::Provider::BootState::BOOTING)); | ||
382 | 254 | EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(0)); | ||
383 | 255 | |||
384 | 256 | controller->start_velocity_updates(); | ||
385 | 257 | } | ||
386 | 258 | |||
387 | 259 | TEST(Controller, controller_does_not_call_stop_position_if_not_booted) { | ||
388 | 260 | using namespace ::testing; | ||
389 | 261 | using ::testing::Mock; | ||
390 | 262 | |||
391 | 263 | MockDelayedProvider provider; | ||
392 | 264 | EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true)); | ||
393 | 265 | |||
394 | 266 | // ignore what ever was performed on construction | ||
395 | 267 | Mock::VerifyAndClear(&provider); | ||
396 | 268 | // use a mock controller | ||
397 | 269 | auto controller = provider.state_controller(); | ||
398 | 270 | |||
399 | 271 | EXPECT_CALL(provider, boot_state()).Times(Exactly(2)) | ||
400 | 272 | .WillOnce(Return(cul::Provider::BootState::BOOTED)) | ||
401 | 273 | .WillOnce(Return(cul::Provider::BootState::NOT_BOOTED)); | ||
402 | 274 | EXPECT_CALL(provider, start_position_updates()).Times(Exactly(1)); | ||
403 | 275 | EXPECT_CALL(provider, stop_position_updates()).Times(Exactly(0)); | ||
404 | 276 | |||
405 | 277 | controller->start_position_updates(); | ||
406 | 278 | controller->stop_position_updates(); | ||
407 | 279 | } | ||
408 | 280 | |||
409 | 281 | TEST(Controller, controller_does_not_call_stop_position_if_booting) { | ||
410 | 282 | using namespace ::testing; | ||
411 | 283 | using ::testing::Mock; | ||
412 | 284 | |||
413 | 285 | MockDelayedProvider provider; | ||
414 | 286 | EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true)); | ||
415 | 287 | |||
416 | 288 | // ignore what ever was performed on construction | ||
417 | 289 | Mock::VerifyAndClear(&provider); | ||
418 | 290 | // use a mock controller | ||
419 | 291 | auto controller = provider.state_controller(); | ||
420 | 292 | |||
421 | 293 | EXPECT_CALL(provider, boot_state()).Times(Exactly(2)) | ||
422 | 294 | .WillOnce(Return(cul::Provider::BootState::BOOTED)) | ||
423 | 295 | .WillOnce(Return(cul::Provider::BootState::BOOTING)); | ||
424 | 296 | EXPECT_CALL(provider, start_position_updates()).Times(Exactly(1)); | ||
425 | 297 | EXPECT_CALL(provider, stop_position_updates()).Times(Exactly(0)); | ||
426 | 298 | |||
427 | 299 | controller->start_position_updates(); | ||
428 | 300 | controller->stop_position_updates(); | ||
429 | 301 | } | ||
430 | 302 | |||
431 | 303 | TEST(Controller, controller_does_not_call_stop_heading_if_not_booted) { | ||
432 | 304 | using namespace ::testing; | ||
433 | 305 | using ::testing::Mock; | ||
434 | 306 | |||
435 | 307 | MockDelayedProvider provider; | ||
436 | 308 | EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true)); | ||
437 | 309 | |||
438 | 310 | // ignore what ever was performed on construction | ||
439 | 311 | Mock::VerifyAndClear(&provider); | ||
440 | 312 | // use a mock controller | ||
441 | 313 | auto controller = provider.state_controller(); | ||
442 | 314 | |||
443 | 315 | EXPECT_CALL(provider, boot_state()).Times(Exactly(2)) | ||
444 | 316 | .WillOnce(Return(cul::Provider::BootState::BOOTED)) | ||
445 | 317 | .WillOnce(Return(cul::Provider::BootState::BOOTING)); | ||
446 | 318 | EXPECT_CALL(provider, start_heading_updates()).Times(Exactly(1)); | ||
447 | 319 | EXPECT_CALL(provider, stop_heading_updates()).Times(Exactly(0)); | ||
448 | 320 | |||
449 | 321 | controller->start_heading_updates(); | ||
450 | 322 | controller->stop_heading_updates(); | ||
451 | 323 | } | ||
452 | 324 | |||
453 | 325 | TEST(Controller, controller_does_not_call_stop_velocity_if_not_booted) { | ||
454 | 326 | using namespace ::testing; | ||
455 | 327 | using ::testing::Mock; | ||
456 | 328 | |||
457 | 329 | MockDelayedProvider provider; | ||
458 | 330 | EXPECT_CALL(provider, has_delayed_boot()).WillRepeatedly(Return(true)); | ||
459 | 331 | |||
460 | 332 | // ignore what ever was performed on construction | ||
461 | 333 | Mock::VerifyAndClear(&provider); | ||
462 | 334 | // use a mock controller | ||
463 | 335 | auto controller = provider.state_controller(); | ||
464 | 336 | |||
465 | 337 | EXPECT_CALL(provider, boot_state()).Times(Exactly(2)) | ||
466 | 338 | .WillOnce(Return(cul::Provider::BootState::BOOTED)) | ||
467 | 339 | .WillOnce(Return(cul::Provider::BootState::BOOTING)); | ||
468 | 340 | EXPECT_CALL(provider, start_velocity_updates()).Times(Exactly(1)); | ||
469 | 341 | EXPECT_CALL(provider, stop_velocity_updates()).Times(Exactly(0)); | ||
470 | 342 | |||
471 | 343 | controller->start_velocity_updates(); | ||
472 | 344 | controller->stop_velocity_updates(); | ||
473 | 345 | } | ||
474 | 133 | 346 | ||
475 | === added file 'tests/mock_delayed_provider.h' | |||
476 | --- tests/mock_delayed_provider.h 1970-01-01 00:00:00 +0000 | |||
477 | +++ tests/mock_delayed_provider.h 2015-10-27 20:49:11 +0000 | |||
478 | @@ -0,0 +1,89 @@ | |||
479 | 1 | /* | ||
480 | 2 | * Copyright © 2014 Canonical Ltd. | ||
481 | 3 | * | ||
482 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
483 | 5 | * under the terms of the GNU Lesser General Public License version 3, | ||
484 | 6 | * as published by the Free Software Foundation. | ||
485 | 7 | * | ||
486 | 8 | * This program is distributed in the hope that it will be useful, | ||
487 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
488 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
489 | 11 | * GNU Lesser General Public License for more details. | ||
490 | 12 | * | ||
491 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
492 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
493 | 15 | * | ||
494 | 16 | * Authored by: M | ||
495 | 17 | */ | ||
496 | 18 | #ifndef MOCK_DELAYED_PROVIDER_H_ | ||
497 | 19 | #define MOCK_DELAYED_PROVIDER_H_ | ||
498 | 20 | |||
499 | 21 | #include <com/ubuntu/location/provider.h> | ||
500 | 22 | #include <com/ubuntu/location/logging.h> | ||
501 | 23 | |||
502 | 24 | #include <gmock/gmock.h> | ||
503 | 25 | |||
504 | 26 | struct PublicController : public com::ubuntu::location::Provider::Controller | ||
505 | 27 | { | ||
506 | 28 | |||
507 | 29 | explicit PublicController(com::ubuntu::location::Provider& instance) | ||
508 | 30 | : com::ubuntu::location::Provider::Controller(instance) {} | ||
509 | 31 | }; | ||
510 | 32 | |||
511 | 33 | struct MockDelayedProvider : public com::ubuntu::location::Provider | ||
512 | 34 | { | ||
513 | 35 | MockDelayedProvider() : com::ubuntu::location::Provider() | ||
514 | 36 | { | ||
515 | 37 | } | ||
516 | 38 | |||
517 | 39 | MOCK_METHOD1(matches_criteria, bool(const com::ubuntu::location::Criteria&)); | ||
518 | 40 | |||
519 | 41 | MOCK_CONST_METHOD1(supports, bool(const com::ubuntu::location::Provider::Features&)); | ||
520 | 42 | MOCK_CONST_METHOD1(requires, bool(const com::ubuntu::location::Provider::Requirements&)); | ||
521 | 43 | |||
522 | 44 | // Called by the engine whenever the wifi and cell ID reporting state changes. | ||
523 | 45 | MOCK_METHOD1(on_wifi_and_cell_reporting_state_changed, void(com::ubuntu::location::WifiAndCellIdReportingState state)); | ||
524 | 46 | |||
525 | 47 | // Called by the engine whenever the reference location changed. | ||
526 | 48 | MOCK_METHOD1(on_reference_location_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Position>& position)); | ||
527 | 49 | |||
528 | 50 | // Called by the engine whenever the reference velocity changed. | ||
529 | 51 | MOCK_METHOD1(on_reference_velocity_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Velocity>& velocity)); | ||
530 | 52 | |||
531 | 53 | // Called by the engine whenever the reference heading changed. | ||
532 | 54 | MOCK_METHOD1(on_reference_heading_updated, void(const com::ubuntu::location::Update<com::ubuntu::location::Heading>& heading)); | ||
533 | 55 | |||
534 | 56 | MOCK_METHOD0(start_position_updates, void()); | ||
535 | 57 | MOCK_METHOD0(stop_position_updates, void()); | ||
536 | 58 | |||
537 | 59 | MOCK_METHOD0(start_heading_updates, void()); | ||
538 | 60 | MOCK_METHOD0(stop_heading_updates, void()); | ||
539 | 61 | |||
540 | 62 | MOCK_METHOD0(start_velocity_updates, void()); | ||
541 | 63 | MOCK_METHOD0(stop_velocity_updates, void()); | ||
542 | 64 | |||
543 | 65 | MOCK_CONST_METHOD0(has_delayed_boot, bool()); | ||
544 | 66 | MOCK_CONST_METHOD0(boot_state, BootState()); | ||
545 | 67 | MOCK_CONST_METHOD0(boot, void()); | ||
546 | 68 | |||
547 | 69 | |||
548 | 70 | // Inject a position update from the outside. | ||
549 | 71 | void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Position>& update) | ||
550 | 72 | { | ||
551 | 73 | mutable_updates().position(update); | ||
552 | 74 | } | ||
553 | 75 | |||
554 | 76 | // Inject a velocity update from the outside. | ||
555 | 77 | void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Velocity>& update) | ||
556 | 78 | { | ||
557 | 79 | mutable_updates().velocity(update); | ||
558 | 80 | } | ||
559 | 81 | |||
560 | 82 | // Inject a heading update from the outside. | ||
561 | 83 | void inject_update(const com::ubuntu::location::Update<com::ubuntu::location::Heading>& update) | ||
562 | 84 | { | ||
563 | 85 | mutable_updates().heading(update); | ||
564 | 86 | } | ||
565 | 87 | }; | ||
566 | 88 | |||
567 | 89 | #endif // MOCK_PROVIDER_H_ |
Please note that this change requires a rebuild of lp:espoo as the location::Provider interface is altered.