OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.chrome.browser.omaha; | |
6 | |
7 import android.app.Service; | |
8 import android.content.Context; | |
9 import android.content.SharedPreferences; | |
10 import android.support.test.filters.SmallTest; | |
11 import android.test.InstrumentationTestCase; | |
12 | |
13 import org.chromium.base.test.util.AdvancedMockContext; | |
14 import org.chromium.base.test.util.Feature; | |
15 import org.chromium.chrome.test.omaha.MockRequestGenerator; | |
16 import org.chromium.chrome.test.omaha.MockRequestGenerator.DeviceType; | |
17 | |
18 import java.io.ByteArrayInputStream; | |
19 import java.io.ByteArrayOutputStream; | |
20 import java.io.IOException; | |
21 import java.io.InputStream; | |
22 import java.io.OutputStream; | |
23 import java.net.HttpURLConnection; | |
24 import java.net.MalformedURLException; | |
25 import java.net.SocketTimeoutException; | |
26 import java.net.URL; | |
27 import java.util.ArrayList; | |
28 import java.util.LinkedList; | |
29 import java.util.List; | |
30 | |
31 /** | |
32 * Tests for the {@link OmahaClient}. | |
33 * Tests override the original OmahaClient's functions with the MockOmahaClient,
which | |
34 * provides a way to hook into functions to return values that would normally be
provided by the | |
35 * system, such as whether Chrome was installed through the system image. | |
36 */ | |
37 public class OmahaClientTest extends InstrumentationTestCase { | |
38 private static class TimestampPair { | |
39 public long timestampNextRequest; | |
40 public long timestampNextPost; | |
41 | |
42 public TimestampPair(long timestampNextRequest, long timestampNextPost)
{ | |
43 this.timestampNextRequest = timestampNextRequest; | |
44 this.timestampNextPost = timestampNextPost; | |
45 } | |
46 } | |
47 | |
48 private static class MockOmahaDelegate extends OmahaDelegate { | |
49 private final List<Integer> mPostResults = new ArrayList<Integer>(); | |
50 private final List<Boolean> mGenerateAndPostRequestResults = new ArrayLi
st<Boolean>(); | |
51 | |
52 private final boolean mIsOnTablet; | |
53 private final boolean mIsInForeground; | |
54 private final boolean mIsInSystemImage; | |
55 private final MockExponentialBackoffScheduler mMockScheduler; | |
56 private MockRequestGenerator mMockGenerator; | |
57 | |
58 private int mNumUUIDsGenerated; | |
59 private long mNextScheduledTimestamp = -1; | |
60 | |
61 private boolean mInstallEventWasSent; | |
62 private TimestampPair mTimestampsOnRegisterNewRequest; | |
63 private TimestampPair mTimestampsOnSaveState; | |
64 | |
65 MockOmahaDelegate(Context context, DeviceType deviceType, InstallSource
installSource) { | |
66 super(context); | |
67 mIsOnTablet = deviceType == DeviceType.TABLET; | |
68 mIsInForeground = true; | |
69 mIsInSystemImage = installSource == InstallSource.SYSTEM_IMAGE; | |
70 | |
71 mMockScheduler = new MockExponentialBackoffScheduler(OmahaBase.PREF_
PACKAGE, context, | |
72 OmahaClient.MS_POST_BASE_DELAY, OmahaClient.MS_POST_MAX_DELA
Y); | |
73 } | |
74 | |
75 @Override | |
76 protected RequestGenerator createRequestGenerator(Context context) { | |
77 mMockGenerator = new MockRequestGenerator( | |
78 context, mIsOnTablet ? DeviceType.TABLET : DeviceType.HANDSE
T); | |
79 return mMockGenerator; | |
80 } | |
81 | |
82 @Override | |
83 public boolean isInSystemImage() { | |
84 return mIsInSystemImage; | |
85 } | |
86 | |
87 @Override | |
88 MockExponentialBackoffScheduler getScheduler() { | |
89 return mMockScheduler; | |
90 } | |
91 | |
92 @Override | |
93 protected String generateUUID() { | |
94 mNumUUIDsGenerated += 1; | |
95 return "UUID" + mNumUUIDsGenerated; | |
96 } | |
97 | |
98 @Override | |
99 protected boolean isChromeBeingUsed() { | |
100 return mIsInForeground; | |
101 } | |
102 | |
103 @Override | |
104 void scheduleService(Service service, long nextTimestamp) { | |
105 mNextScheduledTimestamp = nextTimestamp; | |
106 } | |
107 | |
108 @Override | |
109 void onHandlePostRequestDone(int result, boolean installEventWasSent) { | |
110 mPostResults.add(result); | |
111 mInstallEventWasSent = installEventWasSent; | |
112 } | |
113 | |
114 @Override | |
115 void onRegisterNewRequestDone(long nextRequestTimestamp, long nextPostTi
mestamp) { | |
116 mTimestampsOnRegisterNewRequest = | |
117 new TimestampPair(nextRequestTimestamp, nextPostTimestamp); | |
118 } | |
119 | |
120 @Override | |
121 void onGenerateAndPostRequestDone(boolean result) { | |
122 mGenerateAndPostRequestResults.add(result); | |
123 } | |
124 | |
125 @Override | |
126 void onSaveStateDone(long nextRequestTimestamp, long nextPostTimestamp)
{ | |
127 mTimestampsOnSaveState = new TimestampPair(nextRequestTimestamp, nex
tPostTimestamp); | |
128 } | |
129 } | |
130 | |
131 private enum InstallSource { SYSTEM_IMAGE, ORGANIC } | |
132 private enum ServerResponse { SUCCESS, FAILURE } | |
133 private enum ConnectionStatus { RESPONDS, TIMES_OUT } | |
134 private enum InstallEvent { SEND, DONT_SEND } | |
135 private enum PostStatus { DUE, NOT_DUE } | |
136 | |
137 private AdvancedMockContext mContext; | |
138 private MockOmahaDelegate mDelegate; | |
139 private MockOmahaClient mOmahaClient; | |
140 | |
141 private MockOmahaClient createOmahaClient() { | |
142 return createOmahaClient( | |
143 ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, DeviceType.HA
NDSET); | |
144 } | |
145 | |
146 private MockOmahaClient createOmahaClient( | |
147 ServerResponse response, ConnectionStatus status, DeviceType deviceT
ype) { | |
148 MockOmahaClient omahaClient = new MockOmahaClient(mContext, response, st
atus, deviceType); | |
149 omahaClient.onCreate(); | |
150 omahaClient.restoreState(mContext); | |
151 return omahaClient; | |
152 } | |
153 | |
154 @Override | |
155 protected void setUp() throws Exception { | |
156 super.setUp(); | |
157 Context targetContext = getInstrumentation().getTargetContext(); | |
158 OmahaBase.setIsDisabledForTesting(false); | |
159 mContext = new AdvancedMockContext(targetContext); | |
160 } | |
161 | |
162 @Override | |
163 public void tearDown() throws Exception { | |
164 OmahaBase.setIsDisabledForTesting(true); | |
165 super.tearDown(); | |
166 } | |
167 | |
168 private class MockOmahaClient extends OmahaClient { | |
169 private final LinkedList<MockConnection> mMockConnections = new LinkedLi
st<>(); | |
170 | |
171 private final boolean mSendValidResponse; | |
172 private final boolean mConnectionTimesOut; | |
173 private final boolean mIsOnTablet; | |
174 | |
175 public MockOmahaClient(Context context, ServerResponse serverResponse, | |
176 ConnectionStatus connectionStatus, DeviceType deviceType) { | |
177 attachBaseContext(context); | |
178 setDelegateForTests(mDelegate); | |
179 | |
180 mSendValidResponse = serverResponse == ServerResponse.SUCCESS; | |
181 mConnectionTimesOut = connectionStatus == ConnectionStatus.TIMES_OUT
; | |
182 mIsOnTablet = deviceType == DeviceType.TABLET; | |
183 } | |
184 | |
185 /** | |
186 * Gets the number of MockConnections created. | |
187 */ | |
188 public int getNumConnectionsMade() { | |
189 return mMockConnections.size(); | |
190 } | |
191 | |
192 /** | |
193 * Returns a particular connection. | |
194 */ | |
195 public MockConnection getConnection(int index) { | |
196 return mMockConnections.get(index); | |
197 } | |
198 | |
199 /** | |
200 * Returns the last MockPingConection used to simulate communication wit
h the server. | |
201 */ | |
202 public MockConnection getLastConnection() { | |
203 return mMockConnections.getLast(); | |
204 } | |
205 | |
206 public boolean isSendInstallEvent() { | |
207 return mSendInstallEvent; | |
208 } | |
209 | |
210 public void setSendInstallEvent(boolean state) { | |
211 mSendInstallEvent = state; | |
212 } | |
213 | |
214 @Override | |
215 protected HttpURLConnection createConnection() throws RequestFailureExce
ption { | |
216 MockConnection connection = null; | |
217 try { | |
218 URL url = new URL(mDelegate.getRequestGenerator().getServerUrl()
); | |
219 connection = new MockConnection(url, mIsOnTablet, mSendValidResp
onse, | |
220 mSendInstallEvent, mConnectionTimesOut); | |
221 mMockConnections.addLast(connection); | |
222 } catch (MalformedURLException e) { | |
223 fail("Caught a malformed URL exception: " + e); | |
224 } | |
225 return connection; | |
226 } | |
227 } | |
228 | |
229 @SmallTest | |
230 @Feature({"Omaha"}) | |
231 public void testPipelineFreshInstall() { | |
232 final long now = 11684; | |
233 | |
234 mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallS
ource.ORGANIC); | |
235 mDelegate.getScheduler().setCurrentTime(now); | |
236 | |
237 // Trigger Omaha. | |
238 mOmahaClient = createOmahaClient(); | |
239 mOmahaClient.run(); | |
240 | |
241 // A fresh install results in two requests to the Omaha server: one for
the install request | |
242 // and one for the ping request. | |
243 assertTrue(mDelegate.mInstallEventWasSent); | |
244 assertEquals(1, mDelegate.mPostResults.size()); | |
245 assertEquals(OmahaClient.POST_RESULT_SENT, mDelegate.mPostResults.get(0)
.intValue()); | |
246 assertEquals(2, mDelegate.mGenerateAndPostRequestResults.size()); | |
247 assertTrue(mDelegate.mGenerateAndPostRequestResults.get(0)); | |
248 assertTrue(mDelegate.mGenerateAndPostRequestResults.get(1)); | |
249 | |
250 // Successful requests mean that the next scheduled event should be chec
king for when the | |
251 // user is active. | |
252 assertEquals(now + OmahaClient.MS_BETWEEN_REQUESTS, mDelegate.mNextSched
uledTimestamp); | |
253 checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now + OmahaClient
.MS_POST_BASE_DELAY, | |
254 mDelegate.mTimestampsOnSaveState); | |
255 } | |
256 | |
257 @SmallTest | |
258 @Feature({"Omaha"}) | |
259 public void testPipelineRegularPing() { | |
260 final long now = 11684; | |
261 | |
262 mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallS
ource.ORGANIC); | |
263 mDelegate.getScheduler().setCurrentTime(now); | |
264 | |
265 // Record that an install event has already been sent and that we're due
for a new request. | |
266 SharedPreferences.Editor editor = OmahaBase.getSharedPreferences(mContex
t).edit(); | |
267 editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, false); | |
268 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, now); | |
269 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, now); | |
270 editor.apply(); | |
271 | |
272 // Trigger Omaha. | |
273 mOmahaClient = createOmahaClient(); | |
274 mOmahaClient.run(); | |
275 | |
276 // Only the regular ping should have been sent. | |
277 assertFalse(mDelegate.mInstallEventWasSent); | |
278 assertEquals(1, mDelegate.mPostResults.size()); | |
279 assertEquals(OmahaClient.POST_RESULT_SENT, mDelegate.mPostResults.get(0)
.intValue()); | |
280 assertEquals(1, mDelegate.mGenerateAndPostRequestResults.size()); | |
281 assertTrue(mDelegate.mGenerateAndPostRequestResults.get(0)); | |
282 | |
283 // Successful requests mean that the next scheduled event should be chec
king for when the | |
284 // user is active. | |
285 assertEquals(now + OmahaClient.MS_BETWEEN_REQUESTS, mDelegate.mNextSched
uledTimestamp); | |
286 checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now + OmahaClient
.MS_POST_BASE_DELAY, | |
287 mDelegate.mTimestampsOnSaveState); | |
288 } | |
289 | |
290 @SmallTest | |
291 @Feature({"Omaha"}) | |
292 public void testTooEarlyToPing() { | |
293 final long now = 0; | |
294 final long later = 10000; | |
295 | |
296 mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallS
ource.ORGANIC); | |
297 mDelegate.getScheduler().setCurrentTime(now); | |
298 | |
299 // Put the time for the next request in the future. | |
300 SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); | |
301 prefs.edit().putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, later).ap
ply(); | |
302 | |
303 // Trigger Omaha. | |
304 mOmahaClient = createOmahaClient(); | |
305 mOmahaClient.run(); | |
306 | |
307 // Nothing should have been POSTed. | |
308 assertEquals(0, mDelegate.mPostResults.size()); | |
309 assertEquals(0, mDelegate.mGenerateAndPostRequestResults.size()); | |
310 | |
311 // The next scheduled event is the request generation. Because there wa
s nothing to POST, | |
312 // its timestamp should have remained unchanged and shouldn't have been
considered when the | |
313 // new alarm was scheduled. | |
314 assertEquals(later, mDelegate.mNextScheduledTimestamp); | |
315 checkTimestamps(later, now, mDelegate.mTimestampsOnSaveState); | |
316 } | |
317 | |
318 @SmallTest | |
319 @Feature({"Omaha"}) | |
320 public void testTooEarlyToPostExistingRequest() { | |
321 final long timeGeneratedRequest = 0L; | |
322 final long now = 10000L; | |
323 final long timeSendNewPost = 20000L; | |
324 final long timeSendNewRequest = 50000L; | |
325 | |
326 mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallS
ource.ORGANIC); | |
327 mDelegate.getScheduler().setCurrentTime(now); | |
328 | |
329 SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); | |
330 SharedPreferences.Editor editor = prefs.edit(); | |
331 | |
332 // Make it so that a request was generated and is just waiting to be sen
t. | |
333 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, timeSendNewRequ
est); | |
334 editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, timeGeneratedRequest
); | |
335 editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, "persisted_id"); | |
336 | |
337 // Put the time for the next post in the future. | |
338 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, timeSendN
ewPost); | |
339 editor.apply(); | |
340 | |
341 // Trigger Omaha. | |
342 mOmahaClient = createOmahaClient(); | |
343 mOmahaClient.run(); | |
344 | |
345 // Request generation code should be skipped. | |
346 assertNull(mDelegate.mTimestampsOnRegisterNewRequest); | |
347 | |
348 // Should be too early to post, causing it to be rescheduled. | |
349 assertEquals(1, mDelegate.mPostResults.size()); | |
350 assertEquals(OmahaClient.POST_RESULT_SCHEDULED, mDelegate.mPostResults.g
et(0).intValue()); | |
351 assertEquals(0, mDelegate.mGenerateAndPostRequestResults.size()); | |
352 | |
353 // The next scheduled event is the POST. Because request generation cod
e wasn't run, the | |
354 // timestamp for it shouldn't have changed. | |
355 assertEquals(timeSendNewPost, mDelegate.mNextScheduledTimestamp); | |
356 checkTimestamps(timeSendNewRequest, timeSendNewPost, mDelegate.mTimestam
psOnSaveState); | |
357 } | |
358 | |
359 @SmallTest | |
360 @Feature({"Omaha"}) | |
361 public void testPostExistingRequestSuccessfully() { | |
362 final long timeGeneratedRequest = 0L; | |
363 final long now = 10000L; | |
364 final long timeSendNewPost = now; | |
365 final long timeRegisterNewRequest = 20000L; | |
366 | |
367 mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallS
ource.ORGANIC); | |
368 mDelegate.getScheduler().setCurrentTime(now); | |
369 | |
370 SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); | |
371 SharedPreferences.Editor editor = prefs.edit(); | |
372 | |
373 // Make it so that a regular <ping> was generated and is just waiting to
be sent. | |
374 editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, false); | |
375 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, timeRegisterNew
Request); | |
376 editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, timeGeneratedRequest
); | |
377 editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, "persisted_id"); | |
378 | |
379 // Send the POST now. | |
380 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, timeSendN
ewPost); | |
381 editor.apply(); | |
382 | |
383 // Trigger Omaha. | |
384 mOmahaClient = createOmahaClient(); | |
385 mOmahaClient.run(); | |
386 | |
387 // Registering code shouldn't have fired. | |
388 assertNull(mDelegate.mTimestampsOnRegisterNewRequest); | |
389 | |
390 // Because we didn't send an install event, only one POST should have oc
curred. | |
391 assertEquals(1, mDelegate.mPostResults.size()); | |
392 assertEquals(OmahaClient.POST_RESULT_SENT, mDelegate.mPostResults.get(0)
.intValue()); | |
393 assertEquals(1, mDelegate.mGenerateAndPostRequestResults.size()); | |
394 assertTrue(mDelegate.mGenerateAndPostRequestResults.get(0)); | |
395 | |
396 // The next scheduled event is the request generation because there is n
othing to POST. | |
397 // A successful POST adjusts all timestamps for the current time. | |
398 assertEquals(timeRegisterNewRequest, mDelegate.mNextScheduledTimestamp); | |
399 checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now + OmahaClient
.MS_POST_BASE_DELAY, | |
400 mDelegate.mTimestampsOnSaveState); | |
401 } | |
402 | |
403 @SmallTest | |
404 @Feature({"Omaha"}) | |
405 public void testPostExistingButFails() { | |
406 final long timeGeneratedRequest = 0L; | |
407 final long now = 10000L; | |
408 final long timeSendNewPost = now; | |
409 final long timeRegisterNewRequest = timeGeneratedRequest + OmahaClient.M
S_BETWEEN_REQUESTS; | |
410 | |
411 mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallS
ource.ORGANIC); | |
412 mDelegate.getScheduler().setCurrentTime(now); | |
413 | |
414 SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); | |
415 SharedPreferences.Editor editor = prefs.edit(); | |
416 | |
417 // Make it so that a regular <ping> was generated and is just waiting to
be sent. | |
418 editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, false); | |
419 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, timeRegisterNew
Request); | |
420 editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, timeGeneratedRequest
); | |
421 editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, "persisted_id"); | |
422 | |
423 // Send the POST now. | |
424 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, timeSendN
ewPost); | |
425 editor.apply(); | |
426 | |
427 // Trigger Omaha. | |
428 mOmahaClient = createOmahaClient( | |
429 ServerResponse.FAILURE, ConnectionStatus.RESPONDS, DeviceType.HA
NDSET); | |
430 mOmahaClient.run(); | |
431 | |
432 // Registering code shouldn't have fired. | |
433 assertNull(mDelegate.mTimestampsOnRegisterNewRequest); | |
434 | |
435 // Because we didn't send an install event, only one POST should have oc
curred. | |
436 assertEquals(1, mDelegate.mPostResults.size()); | |
437 assertEquals(OmahaClient.POST_RESULT_FAILED, mDelegate.mPostResults.get(
0).intValue()); | |
438 assertEquals(1, mDelegate.mGenerateAndPostRequestResults.size()); | |
439 assertFalse(mDelegate.mGenerateAndPostRequestResults.get(0)); | |
440 | |
441 // The next scheduled event should be the POST event, which is delayed b
y the base delay | |
442 // because no failures have happened yet. | |
443 assertEquals(mDelegate.mTimestampsOnSaveState.timestampNextPost, | |
444 mDelegate.mNextScheduledTimestamp); | |
445 checkTimestamps(timeRegisterNewRequest, now + OmahaClient.MS_POST_BASE_D
ELAY, | |
446 mDelegate.mTimestampsOnSaveState); | |
447 } | |
448 | |
449 @SmallTest | |
450 @Feature({"Omaha"}) | |
451 public void testTimestampWithinBounds() { | |
452 final long now = 0L; | |
453 final long timeRegisterNewRequest = OmahaClient.MS_BETWEEN_REQUESTS + 1; | |
454 | |
455 mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallS
ource.ORGANIC); | |
456 mDelegate.getScheduler().setCurrentTime(now); | |
457 | |
458 SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); | |
459 SharedPreferences.Editor editor = prefs.edit(); | |
460 | |
461 // Indicate that the next request should be generated way past an expect
ed timeframe. | |
462 editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, false); | |
463 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, timeRegisterNew
Request); | |
464 editor.apply(); | |
465 | |
466 // Trigger Omaha. | |
467 mOmahaClient = createOmahaClient(); | |
468 mOmahaClient.run(); | |
469 | |
470 // Request generation code should fire. | |
471 assertNotNull(mDelegate.mTimestampsOnRegisterNewRequest); | |
472 | |
473 // Because we didn't send an install event, only one POST should have oc
curred. | |
474 assertEquals(1, mDelegate.mPostResults.size()); | |
475 assertEquals(OmahaClient.POST_RESULT_SENT, mDelegate.mPostResults.get(0)
.intValue()); | |
476 assertEquals(1, mDelegate.mGenerateAndPostRequestResults.size()); | |
477 assertTrue(mDelegate.mGenerateAndPostRequestResults.get(0)); | |
478 | |
479 // The next scheduled event should be the timestamp for a new request ge
neration. | |
480 assertEquals(mDelegate.mTimestampsOnSaveState.timestampNextRequest, | |
481 mDelegate.mNextScheduledTimestamp); | |
482 checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now + OmahaClient
.MS_POST_BASE_DELAY, | |
483 mDelegate.mTimestampsOnSaveState); | |
484 } | |
485 | |
486 @SmallTest | |
487 @Feature({"Omaha"}) | |
488 public void testOverdueRequestCausesNewRegistration() { | |
489 final long timeGeneratedRequest = 0L; | |
490 final long now = 10000L; | |
491 final long timeSendNewPost = now; | |
492 final long timeRegisterNewRequest = | |
493 timeGeneratedRequest + OmahaClient.MS_BETWEEN_REQUESTS * 5; | |
494 | |
495 mDelegate = new MockOmahaDelegate(mContext, DeviceType.HANDSET, InstallS
ource.ORGANIC); | |
496 mDelegate.getScheduler().setCurrentTime(now); | |
497 | |
498 // Record that a regular <ping> was generated, but not sent, then assign
it an invalid | |
499 // timestamp and try to send it now. | |
500 SharedPreferences prefs = OmahaBase.getSharedPreferences(mContext); | |
501 SharedPreferences.Editor editor = prefs.edit(); | |
502 editor.putBoolean(OmahaBase.PREF_SEND_INSTALL_EVENT, false); | |
503 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEW_REQUEST, timeRegisterNew
Request); | |
504 editor.putLong(OmahaBase.PREF_TIMESTAMP_OF_REQUEST, timeGeneratedRequest
); | |
505 editor.putString(OmahaBase.PREF_PERSISTED_REQUEST_ID, "persisted_id"); | |
506 editor.putLong(OmahaBase.PREF_TIMESTAMP_FOR_NEXT_POST_ATTEMPT, timeSendN
ewPost); | |
507 editor.apply(); | |
508 | |
509 // Trigger Omaha. | |
510 mOmahaClient = createOmahaClient(); | |
511 mOmahaClient.run(); | |
512 | |
513 // Registering code shouldn't have fired. | |
514 checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now, | |
515 mDelegate.mTimestampsOnRegisterNewRequest); | |
516 | |
517 // Because we didn't send an install event, only one POST should have oc
curred. | |
518 assertEquals(1, mDelegate.mPostResults.size()); | |
519 assertEquals(OmahaClient.POST_RESULT_SENT, mDelegate.mPostResults.get(0)
.intValue()); | |
520 assertEquals(1, mDelegate.mGenerateAndPostRequestResults.size()); | |
521 assertTrue(mDelegate.mGenerateAndPostRequestResults.get(0)); | |
522 | |
523 // The next scheduled event should be the registration event. | |
524 assertEquals(mDelegate.mTimestampsOnSaveState.timestampNextRequest, | |
525 mDelegate.mNextScheduledTimestamp); | |
526 checkTimestamps(now + OmahaClient.MS_BETWEEN_REQUESTS, now + OmahaClient
.MS_POST_BASE_DELAY, | |
527 mDelegate.mTimestampsOnSaveState); | |
528 } | |
529 | |
530 private void checkTimestamps( | |
531 long expectedRequestTimestamp, long expectedPostTimestamp, Timestamp
Pair timestamps) { | |
532 assertEquals(expectedRequestTimestamp, timestamps.timestampNextRequest); | |
533 assertEquals(expectedPostTimestamp, timestamps.timestampNextPost); | |
534 } | |
535 | |
536 /** | |
537 * Simulates communication with the actual Omaha server. | |
538 */ | |
539 private static class MockConnection extends HttpURLConnection { | |
540 // Omaha appends a "/" to the URL. | |
541 private static final String STRIPPED_MARKET_URL = | |
542 "https://market.android.com/details?id=com.google.android.apps.c
hrome"; | |
543 private static final String MARKET_URL = STRIPPED_MARKET_URL + "/"; | |
544 | |
545 private static final String UPDATE_VERSION = "1.2.3.4"; | |
546 | |
547 // Parameters. | |
548 private final boolean mConnectionTimesOut; | |
549 private final ByteArrayInputStream mServerResponse; | |
550 private final ByteArrayOutputStream mOutputStream; | |
551 private final int mHTTPResponseCode; | |
552 | |
553 // Result variables. | |
554 private int mContentLength; | |
555 private int mNumTimesResponseCodeRetrieved; | |
556 private boolean mSentRequest; | |
557 private boolean mGotInputStream; | |
558 private String mRequestPropertyField; | |
559 private String mRequestPropertyValue; | |
560 | |
561 MockConnection(URL url, boolean usingTablet, boolean sendValidResponse, | |
562 boolean sendInstallEvent, boolean connectionTimesOut) { | |
563 super(url); | |
564 assertEquals(MockRequestGenerator.SERVER_URL, url.toString()); | |
565 | |
566 String mockResponse = buildServerResponseString(usingTablet, sendIns
tallEvent); | |
567 mOutputStream = new ByteArrayOutputStream(); | |
568 mServerResponse = new ByteArrayInputStream(mockResponse.getBytes()); | |
569 mConnectionTimesOut = connectionTimesOut; | |
570 | |
571 if (sendValidResponse) { | |
572 mHTTPResponseCode = 200; | |
573 } else { | |
574 mHTTPResponseCode = 404; | |
575 } | |
576 } | |
577 | |
578 /** | |
579 * Build a simulated response from the Omaha server indicating an update
is available. | |
580 * The response changes based on the device type. | |
581 */ | |
582 private String buildServerResponseString(boolean isOnTablet, boolean sen
dInstallEvent) { | |
583 String response = ""; | |
584 response += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; | |
585 response += "<response protocol=\"3.0\" server=\"prod\">"; | |
586 response += "<daystart elapsed_seconds=\"12345\"/>"; | |
587 response += "<app appid=\""; | |
588 response += (isOnTablet | |
589 ? MockRequestGenerator.UUID_TABLET : MockRequestGenerator.UU
ID_PHONE); | |
590 response += "\" status=\"ok\">"; | |
591 if (sendInstallEvent) { | |
592 response += "<event status=\"ok\"/>"; | |
593 } else { | |
594 response += "<updatecheck status=\"ok\">"; | |
595 response += "<urls><url codebase=\"" + MARKET_URL + "\"/></urls>
"; | |
596 response += "<manifest version=\"" + UPDATE_VERSION + "\">"; | |
597 response += "<packages>"; | |
598 response += "<package hash=\"0\" name=\"dummy.apk\" required=\"t
rue\" size=\"0\"/>"; | |
599 response += "</packages>"; | |
600 response += "<actions>"; | |
601 response += "<action event=\"install\" run=\"dummy.apk\"/>"; | |
602 response += "<action event=\"postinstall\"/>"; | |
603 response += "</actions>"; | |
604 response += "</manifest>"; | |
605 response += "</updatecheck>"; | |
606 response += "<ping status=\"ok\"/>"; | |
607 } | |
608 response += "</app>"; | |
609 response += "</response>"; | |
610 return response; | |
611 } | |
612 | |
613 @Override | |
614 public boolean usingProxy() { | |
615 return false; | |
616 } | |
617 | |
618 @Override | |
619 public void connect() throws SocketTimeoutException { | |
620 if (mConnectionTimesOut) { | |
621 throw new SocketTimeoutException("Connection timed out."); | |
622 } | |
623 } | |
624 | |
625 @Override | |
626 public void disconnect() {} | |
627 | |
628 @Override | |
629 public void setDoOutput(boolean value) throws IllegalAccessError { | |
630 assertTrue("Told the HTTPUrlConnection to send no request.", value); | |
631 } | |
632 | |
633 @Override | |
634 public void setFixedLengthStreamingMode(int contentLength) { | |
635 mContentLength = contentLength; | |
636 } | |
637 | |
638 @Override | |
639 public int getResponseCode() { | |
640 if (mNumTimesResponseCodeRetrieved == 0) { | |
641 // The output stream should now have the generated XML for the r
equest. | |
642 // Check if its length is correct. | |
643 assertEquals("Expected OmahaClient to write out certain number o
f bytes", | |
644 mContentLength, mOutputStream.toByteArray().length); | |
645 } | |
646 assertTrue("Tried to retrieve response code more than twice", | |
647 mNumTimesResponseCodeRetrieved < 2); | |
648 mNumTimesResponseCodeRetrieved++; | |
649 return mHTTPResponseCode; | |
650 } | |
651 | |
652 @Override | |
653 public OutputStream getOutputStream() throws IOException { | |
654 mSentRequest = true; | |
655 connect(); | |
656 return mOutputStream; | |
657 } | |
658 | |
659 public String getOutputStreamContents() { | |
660 return mOutputStream.toString(); | |
661 } | |
662 | |
663 @Override | |
664 public InputStream getInputStream() { | |
665 assertTrue("Tried to read server response without sending request.",
mSentRequest); | |
666 mGotInputStream = true; | |
667 return mServerResponse; | |
668 } | |
669 | |
670 @Override | |
671 public void addRequestProperty(String field, String newValue) { | |
672 mRequestPropertyField = field; | |
673 mRequestPropertyValue = newValue; | |
674 } | |
675 | |
676 public int getNumTimesResponseCodeRetrieved() { | |
677 return mNumTimesResponseCodeRetrieved; | |
678 } | |
679 | |
680 public boolean getGotInputStream() { | |
681 return mGotInputStream; | |
682 } | |
683 | |
684 public boolean getSentRequest() { | |
685 return mSentRequest; | |
686 } | |
687 | |
688 public String getRequestPropertyField() { | |
689 return mRequestPropertyField; | |
690 } | |
691 | |
692 public String getRequestPropertyValue() { | |
693 return mRequestPropertyValue; | |
694 } | |
695 } | |
696 } | |
OLD | NEW |