Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2526)

Unified Diff: chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaClientTest.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaClientTest.java
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaClientTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaClientTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab62f69a9a0211f5e36b75c036b1f1d6869ebf1d
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/OmahaClientTest.java
@@ -0,0 +1,809 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.omaha;
+
+import static org.chromium.chrome.test.omaha.MockRequestGenerator.DeviceType;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.test.omaha.AttributeFinder;
+import org.chromium.chrome.test.omaha.MockRequestGenerator;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+/**
+ * Tests for the {@link OmahaClient}.
+ * Tests often override the original OmahaClient's functions with the HookedOmahaClient, which
+ * provides a way to hook into functions to return values that would normally be provided by the
+ * system, such as whether Chrome was installed through the system image.
+ */
+public class OmahaClientTest extends InstrumentationTestCase {
+ private enum ServerResponse {
+ SUCCESS, FAILURE
+ }
+
+ private enum ConnectionStatus {
+ RESPONDS, TIMES_OUT
+ }
+
+ private enum InstallEvent {
+ SEND, DONT_SEND
+ }
+
+ private enum ForceTest {
+ FORCED, NOT_FORCED
+ }
+
+ private enum PostStatus {
+ DUE, NOT_DUE
+ }
+
+ private MockOmahaContext mContext;
+ private HookedOmahaClient mOmahaClient;
+
+ @Override
+ protected void setUp() {
+ Context targetContext = getInstrumentation().getTargetContext();
+ mContext = new MockOmahaContext(targetContext);
+ mOmahaClient = HookedOmahaClient.create(mContext);
+ }
+
+ /**
+ * If a request exists during handleInitialize(), a POST Intent should be fired immediately.
+ */
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testInitializeWithRequest() {
+ mOmahaClient.registerNewRequest(10);
+
+ Intent intent = OmahaClient.createInitializeIntent(mContext);
+ mOmahaClient.onHandleIntent(intent);
+ assertTrue("OmahaClient has no registered request", mOmahaClient.hasRequest());
+ assertTrue("Alarm does not have the correct state", mOmahaClient.getRequestAlarmWasSet());
+ assertTrue("OmahaClient wasn't restarted.", mContext.mOmahaClientRestarted);
+ assertNotNull(mContext.mIntentFired);
+ assertEquals("POST intent not fired.",
+ OmahaClient.createPostRequestIntent(mContext, false).getAction(),
+ mContext.mIntentFired.getAction());
+ }
+
+ /**
+ * If a request doesn't exist during handleInitialize(), no intent should be fired.
+ */
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testInitializeWithoutRequest() {
+ Intent intent = OmahaClient.createInitializeIntent(mContext);
+ mOmahaClient.onHandleIntent(intent);
+ assertFalse("OmahaClient has a registered request", mOmahaClient.hasRequest());
+ assertTrue("Alarm does not have the correct state", mOmahaClient.getRequestAlarmWasSet());
+ assertFalse("OmahaClient was restarted.", mContext.mOmahaClientRestarted);
+ assertNull(mContext.mIntentFired);
+ }
+
+ /**
+ * Catch situations where the install source isn't set prior to restoring a saved request.
+ */
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testInstallSourceSetBeforeRestoringRequest() {
+ // Plant a failed request.
+ Context targetContext = getInstrumentation().getTargetContext();
+ MockOmahaContext mockContext = new MockOmahaContext(targetContext);
+ SharedPreferences prefs =
+ mockContext.getSharedPreferences(OmahaClient.PREF_PACKAGE, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putLong(OmahaClient.PREF_TIMESTAMP_OF_REQUEST, 0);
+ editor.putString(OmahaClient.PREF_PERSISTED_REQUEST_ID, "persisted_id");
+ editor.apply();
+
+ // Send it off and don't crash when the state is restored and the XML is generated.
+ HookedOmahaClient omahaClient = HookedOmahaClient.create(mockContext);
+ omahaClient.mMockScheduler.setCurrentTime(1000);
+ Intent postIntent = OmahaClient.createPostRequestIntent(mockContext, false);
+ omahaClient.onHandleIntent(postIntent);
+
+ // Check that the request was actually generated and tried to be sent.
+ MockConnection connection = omahaClient.getLastConnection();
+ assertTrue("Didn't try to make a connection.", connection.getSentRequest());
+ assertFalse("OmahaClient still has a registered request", omahaClient.hasRequest());
+ assertTrue("Failed to send request", omahaClient.getCumulativeFailedAttempts() == 0);
+ }
+
+ /**
+ * Makes sure that we don't generate a request if we don't have to.
+ */
+ @SmallTest
+ @Feature({"Omaha", "Main"})
+ public void testOmahaClientDoesNotGenerateRequest() {
+ // Change the time so the OmahaClient thinks no request is necessary.
+ mOmahaClient.mMockScheduler.setCurrentTime(-1000);
+ Intent intent = OmahaClient.createRegisterRequestIntent(mContext, false);
+ mOmahaClient.onHandleIntent(intent);
+ assertFalse("OmahaClient has a registered request", mOmahaClient.hasRequest());
+ assertFalse("OmahaClient was relaunched", mContext.mOmahaClientRestarted);
+ }
+
+ /**
+ * Makes sure that firing a XML request triggers a post intent.
+ */
+ @SmallTest
+ @Feature({"Omaha", "Main"})
+ public void testOmahaClientRequestToPost() {
+ // Change the time so the OmahaClient thinks a request is overdue.
+ mOmahaClient.mMockScheduler.setCurrentTime(1000);
+ Intent intent = OmahaClient.createRegisterRequestIntent(mContext, false);
+ mOmahaClient.onHandleIntent(intent);
+ assertTrue("OmahaClient has no registered request", mOmahaClient.hasRequest());
+ assertTrue("OmahaClient wasn't relaunched", mContext.mOmahaClientRestarted);
+ }
+
+ /**
+ * Makes sure that forcing an XML request generates a request and triggers a post intent.
+ */
+ @SmallTest
+ @Feature({"Omaha", "Main"})
+ public void testOmahaClientForcedRequestToPost() {
+ Intent intent = OmahaClient.createRegisterRequestIntent(mContext, true);
+ mOmahaClient.onHandleIntent(intent);
+ assertTrue("OmahaClient has no registered request", mOmahaClient.hasRequest());
+ assertTrue("OmahaClient wasn't relaunched", mContext.mOmahaClientRestarted);
+ }
+
+ /**
+ * Makes sure that incorrect timestamps are caught.
+ */
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testIncorrectDelays() {
+ // Set the time to be 2 days past epoch, then generate a request.
+ final long millisecondsPerDay = 86400000;
+ long currentTimestamp = millisecondsPerDay * 2;
+ mOmahaClient.mMockScheduler.setCurrentTime(currentTimestamp);
+ mOmahaClient.registerNewRequest(currentTimestamp);
+
+ // Rewind the clock 2 days.
+ currentTimestamp -= millisecondsPerDay * 2;
+ mOmahaClient.mMockScheduler.setCurrentTime(currentTimestamp);
+ mOmahaClient.restoreState();
+
+ // Confirm that the post timestamp was reset, since it's larger than the exponential
+ // backoff delay.
+ assertEquals("Post timestamp was not cleared.",
+ mOmahaClient.getTimestampForNextPostAttempt(), 0);
+
+ // Confirm that the request timestamp was reset, since the next timestamp is more than
+ // a day away.
+ assertEquals("Request timestamp was not cleared.",
+ mOmahaClient.getTimestampForNewRequest(), 0);
+ }
+
+ /**
+ * Checks that reading and writing out the preferences works.
+ */
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testOmahaClientFileIO() {
+ // Register a request and save it to disk.
+ mOmahaClient.registerNewRequest(0);
+
+ // The second OmahaCLient should retrieve the request that the first one saved.
+ HookedOmahaClient secondClient = HookedOmahaClient.create(mContext);
+ assertTrue("The request from the first OmahaClient wasn't written",
+ secondClient.hasRequest());
+ }
+
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testOmahaClientPostHandsetFailure() {
+ postRequestToServer(DeviceType.HANDSET, ServerResponse.FAILURE, ConnectionStatus.RESPONDS,
+ InstallEvent.DONT_SEND, ForceTest.NOT_FORCED, PostStatus.DUE);
+ }
+
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testOmahaClientPostHandsetSuccess() {
+ postRequestToServer(DeviceType.HANDSET, ServerResponse.SUCCESS, ConnectionStatus.RESPONDS,
+ InstallEvent.DONT_SEND, ForceTest.NOT_FORCED, PostStatus.DUE);
+ }
+
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testOmahaClientPostTabletFailure() {
+ postRequestToServer(DeviceType.TABLET, ServerResponse.FAILURE, ConnectionStatus.RESPONDS,
+ InstallEvent.DONT_SEND, ForceTest.NOT_FORCED, PostStatus.DUE);
+ }
+
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testOmahaClientPostTabletSuccess() {
+ postRequestToServer(DeviceType.TABLET, ServerResponse.SUCCESS, ConnectionStatus.RESPONDS,
+ InstallEvent.DONT_SEND, ForceTest.NOT_FORCED, PostStatus.DUE);
+ }
+
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testOmahaClientPostHandsetTimeout() {
+ postRequestToServer(DeviceType.HANDSET, ServerResponse.FAILURE, ConnectionStatus.TIMES_OUT,
+ InstallEvent.DONT_SEND, ForceTest.NOT_FORCED, PostStatus.DUE);
+ }
+
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testOmahaClientPostInstallEventSuccess() {
+ postRequestToServer(DeviceType.HANDSET, ServerResponse.SUCCESS, ConnectionStatus.RESPONDS,
+ InstallEvent.SEND, ForceTest.NOT_FORCED, PostStatus.DUE);
+ }
+
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testOmahaClientPostInstallEventFailure() {
+ postRequestToServer(DeviceType.HANDSET, ServerResponse.FAILURE, ConnectionStatus.RESPONDS,
+ InstallEvent.SEND, ForceTest.NOT_FORCED, PostStatus.DUE);
+ }
+
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testOmahaClientPostForcedPostWhenNotDue() {
+ postRequestToServer(DeviceType.HANDSET, ServerResponse.SUCCESS, ConnectionStatus.RESPONDS,
+ InstallEvent.DONT_SEND, ForceTest.FORCED, PostStatus.NOT_DUE);
+ }
+
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testOmahaClientPostWhenNotDue() {
+ postRequestToServer(DeviceType.HANDSET, ServerResponse.FAILURE, ConnectionStatus.RESPONDS,
+ InstallEvent.DONT_SEND, ForceTest.NOT_FORCED, PostStatus.NOT_DUE);
+ }
+
+ /**
+ * Pretends to post a request to the Omaha server.
+ * @param deviceType Whether or not to use an app-ID indicating a tablet.
+ * @param response Whether the server acknowledged the request correctly.
+ * @param connectionStatus Whether the connection times out when it tries to contact the
+ * Omaha server.
+ * @param installType Whether we're sending an install event or not.
+ * @param forceType Whether we're testing POSTing a request, regardless of timers.
+ * @param postStatus Whether we're due for a POST or not.
+ */
+ public void postRequestToServer(DeviceType deviceType, ServerResponse response,
+ ConnectionStatus connectionStatus, InstallEvent installType, ForceTest forceType,
+ PostStatus postStatus) {
+ final boolean succeeded = response == ServerResponse.SUCCESS;
+ final boolean sentInstallEvent = installType == InstallEvent.SEND;
+
+ HookedOmahaClient omahaClient = new HookedOmahaClient(mContext, deviceType, response,
+ connectionStatus, false);
+ omahaClient.onCreate();
+ omahaClient.restoreState();
+
+ // Set whether or not we're sending the install event.
+ assertTrue("Should default to sending install event.", omahaClient.isSendInstallEvent());
+ omahaClient.setSendInstallEvent(installType == InstallEvent.SEND);
+ omahaClient.registerNewRequest(0);
+
+ // Set up the POST request.
+ if (postStatus == PostStatus.NOT_DUE) {
+ // Rewind the clock so that we don't send the request yet.
+ omahaClient.mMockScheduler.setCurrentTime(-1000);
+ }
+ Intent postIntent =
+ OmahaClient.createPostRequestIntent(mContext, forceType == ForceTest.FORCED);
+ omahaClient.onHandleIntent(postIntent);
+
+ assertTrue("hasRequest() returned wrong value", succeeded != omahaClient.hasRequest());
+ if (postStatus == PostStatus.NOT_DUE && forceType == ForceTest.NOT_FORCED) {
+ // No POST attempt was made.
+ assertTrue("POST was attempted and failed.",
+ omahaClient.getCumulativeFailedAttempts() == 0);
+ assertTrue("POST alarm wasn't set for reattempt", omahaClient.getPOSTAlarmWasSet());
+ } else {
+ // Since we start with no failures, the counter incrementing should indicate whether it
+ // succeeded or not.
+ assertEquals("Expected different outcome", succeeded,
+ omahaClient.getCumulativeFailedAttempts() == 0);
+ assertTrue("Alarm state was changed when it shouldn't have been",
+ succeeded != omahaClient.getPOSTAlarmWasSet());
+
+ // If we're sending an install event, we will immediately attempt to send a ping in a
+ // follow-up request.
+ int numExpectedRequests = succeeded && sentInstallEvent ? 2 : 1;
+ assertEquals("Didn't send the correct number of XML requests.", numExpectedRequests,
+ omahaClient.getNumConnectionsMade());
+
+ MockConnection connection = omahaClient.getLastConnection();
+ assertEquals("Didn't try to make a connection.", true, connection.getSentRequest());
+
+ if (connectionStatus == ConnectionStatus.TIMES_OUT) {
+ // Several events shouldn't happen if the connection times out.
+ assertEquals("Retrieved response code when it should have bailed earlier.",
+ 0, connection.getNumTimesResponseCodeRetrieved());
+ assertFalse("Grabbed input stream when it should have bailed earlier.",
+ connection.getGotInputStream());
+ }
+ }
+
+ // Check that the latest version and market URLs were saved correctly.
+ String expectedVersion = succeeded ? MockConnection.UPDATE_VERSION : "";
+ String expectedURL = succeeded ? MockConnection.STRIPPED_MARKET_URL : "";
+
+ // Make sure we properly parsed out the server's response.
+ assertEquals("Latest version numbers didn't match", expectedVersion,
+ OmahaClient.getVersionNumberGetter().getLatestKnownVersion(
+ mContext, OmahaClient.PREF_PACKAGE, OmahaClient.PREF_LATEST_VERSION));
+ assertEquals("Market URL didn't match", expectedURL, OmahaClient.getMarketURL(mContext));
+
+ // Check that the install event was sent properly.
+ if (sentInstallEvent) {
+ assertFalse("OmahaPingService is going to send another install <event>.",
+ succeeded == omahaClient.isSendInstallEvent());
+ }
+ }
+
+ /**
+ * Test whether we're using request and session IDs properly for POSTs.
+ */
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testRequestAndSessionIDs() {
+ assertTrue("Should default to sending install event.", mOmahaClient.isSendInstallEvent());
+
+ // Send the POST request.
+ mOmahaClient.registerNewRequest(0);
+ Intent postIntent = OmahaClient.createPostRequestIntent(mContext, true);
+ mOmahaClient.onHandleIntent(postIntent);
+
+ // If we're sending an install event, we will immediately attempt to send a ping in a
+ // follow-up request. These should have the same session ID, but different request IDs.
+ int numRequests = mOmahaClient.getNumConnectionsMade();
+
+ HashSet<String> sessionIDs = new HashSet<String>();
+ HashSet<String> requestIDs = new HashSet<String>();
+ for (int i = 0; i < numRequests; ++i) {
+ String request = mOmahaClient.getConnection(i).getOutputStreamContents();
+
+ String sessionID =
+ new AttributeFinder(request, "request", "sessionid").getValue();
+ assertNotNull(sessionID);
+ sessionIDs.add(sessionID);
+
+ String requestID =
+ new AttributeFinder(request, "request", "requestid").getValue();
+ assertNotNull(requestID);
+ requestIDs.add(requestID);
+ }
+ assertEquals("Session ID was not the same across all requests", 1,
+ sessionIDs.size());
+ assertEquals("Request ID was duplicated", numRequests, requestIDs.size());
+
+ // Send another XML request and make sure the IDs are all different.
+ assertFalse("OmahaPingService is going to send another install <event>.",
+ mOmahaClient.isSendInstallEvent());
+ mOmahaClient.registerNewRequest(0);
+ postIntent = OmahaClient.createPostRequestIntent(mContext, true);
+ mOmahaClient.onHandleIntent(postIntent);
+
+ assertEquals("Didn't send the correct number of XML requests.", numRequests + 1,
+ mOmahaClient.getNumConnectionsMade());
+ String newRequest = mOmahaClient.getConnection(numRequests).getOutputStreamContents();
+
+ String newSessionID = new AttributeFinder(newRequest, "request", "sessionid").getValue();
+ assertNotNull(newSessionID);
+ assertFalse("Session ID was reused.", sessionIDs.contains(newSessionID));
+
+ String newRequestID = new AttributeFinder(newRequest, "request", "requestid").getValue();
+ assertNotNull(newRequestID);
+ assertFalse("Request ID was reused.", requestIDs.contains(newRequestID));
+ }
+
+ /**
+ * Checks to see that the header is added only for persisted XML requests.
+ */
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testHTTPHeaderForPersistedXMLRequest() {
+ final String xml = "<lorem ipsum=\"dolor\" />";
+ final long requestTimestamp = 0;
+ final long currentTimestamp = 11684;
+ final long currentTimestampInSeconds = currentTimestamp / 1000;
+
+ mOmahaClient.registerNewRequest(requestTimestamp);
+
+ assertTrue("Should default to sending install event.", mOmahaClient.isSendInstallEvent());
+ assertEquals("Shouldn't have any failed attempts.", 0,
+ mOmahaClient.getCumulativeFailedAttempts());
+
+ MockConnection connection = null;
+ try {
+ mOmahaClient.postRequest(currentTimestamp, xml);
+ connection = mOmahaClient.getLastConnection();
+ } catch (RequestFailureException e) {
+ fail();
+ }
+ assertEquals("Age property field was unexpectedly added.", null,
+ connection.getRequestPropertyField());
+ assertEquals("Age property value was unexpectedly set.", null,
+ connection.getRequestPropertyValue());
+
+ // Fail once, then check that the header is added.
+ mOmahaClient.getBackoffScheduler().increaseFailedAttempts();
+ try {
+ mOmahaClient.postRequest(currentTimestamp, xml);
+ connection = mOmahaClient.getLastConnection();
+ } catch (RequestFailureException e) {
+ fail();
+ }
+ assertEquals("Age property field was not added.", "X-RequestAge",
+ connection.getRequestPropertyField());
+ assertEquals("Age property value was incorrectly set.", currentTimestampInSeconds,
+ Long.parseLong(connection.getRequestPropertyValue()));
+
+ // Make sure the header isn't added if we're not sending an install ping.
+ mOmahaClient.setSendInstallEvent(false);
+ mOmahaClient.registerNewRequest(requestTimestamp);
+ mOmahaClient.getBackoffScheduler().increaseFailedAttempts();
+ try {
+ mOmahaClient.postRequest(currentTimestamp, xml);
+ connection = mOmahaClient.getLastConnection();
+ } catch (RequestFailureException e) {
+ fail();
+ }
+ assertEquals("Age property field was unexpectedly added.", null,
+ connection.getRequestPropertyField());
+ assertEquals("Age property value was unexpectedly set.", null,
+ connection.getRequestPropertyValue());
+ }
+
+ @SmallTest
+ @Feature({"Omaha"})
+ public void testInstallSource() {
+ HookedOmahaClient organicClient = new HookedOmahaClient(mContext, DeviceType.TABLET,
+ ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, false);
+ String organicInstallSource = organicClient.determineInstallSource(mContext);
+ assertEquals("Install source should have been treated as organic.",
+ OmahaClient.INSTALL_SOURCE_ORGANIC, organicInstallSource);
+
+ HookedOmahaClient systemImageClient = new HookedOmahaClient(mContext, DeviceType.TABLET,
+ ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, true);
+ String systemImageInstallSource = systemImageClient.determineInstallSource(mContext);
+ assertEquals("Install source should have been treated as system image.",
+ OmahaClient.INSTALL_SOURCE_SYSTEM, systemImageInstallSource);
+ }
+
+ /**
+ * OmahaClient that overrides simple methods for testing.
+ */
+ private static class HookedOmahaClient extends OmahaClient {
+ private final boolean mIsOnTablet;
+ private final boolean mSendValidResponse;
+ private final boolean mIsInForeground;
+ private final boolean mConnectionTimesOut;
+ private final boolean mInstalledOnSystemImage;
+
+ private MockExponentialBackoffScheduler mMockScheduler;
+ private RequestGenerator mMockGenerator;
+ private final LinkedList<MockConnection> mMockConnections;
+
+ private boolean mRequestAlarmWasSet;
+ private int mNumUUIDsGenerated;
+
+ public static HookedOmahaClient create(Context context) {
+ HookedOmahaClient omahaClient = new HookedOmahaClient(context, DeviceType.TABLET,
+ ServerResponse.SUCCESS, ConnectionStatus.RESPONDS, false);
+ omahaClient.onCreate();
+ omahaClient.restoreState();
+ return omahaClient;
+ }
+
+ public HookedOmahaClient(Context context, DeviceType deviceType,
+ ServerResponse serverResponse, ConnectionStatus connectionStatus,
+ boolean installedOnSystemImage) {
+ attachBaseContext(context);
+ mIsOnTablet = deviceType == DeviceType.TABLET;
+ mSendValidResponse = serverResponse == ServerResponse.SUCCESS;
+ mIsInForeground = true;
+ mConnectionTimesOut = connectionStatus == ConnectionStatus.TIMES_OUT;
+ mMockConnections = new LinkedList<MockConnection>();
+ mInstalledOnSystemImage = installedOnSystemImage;
+ }
+
+ @Override
+ protected boolean isChromeBeingUsed() {
+ return mIsInForeground;
+ }
+
+ @Override
+ public int getApplicationFlags() {
+ return mInstalledOnSystemImage ? ApplicationInfo.FLAG_SYSTEM : 0;
+ }
+
+ /**
+ * Checks if an alarm was set by the backoff scheduler.
+ */
+ public boolean getPOSTAlarmWasSet() {
+ return mMockScheduler.getAlarmWasSet();
+ }
+
+ public boolean getRequestAlarmWasSet() {
+ return mRequestAlarmWasSet;
+ }
+
+ /**
+ * Gets the number of MockConnections created.
+ */
+ public int getNumConnectionsMade() {
+ return mMockConnections.size();
+ }
+
+ /**
+ * Returns a particular connection.
+ */
+ public MockConnection getConnection(int index) {
+ return mMockConnections.get(index);
+ }
+
+ /**
+ * Returns the last MockPingConection used to simulate communication with the server.
+ */
+ public MockConnection getLastConnection() {
+ return mMockConnections.getLast();
+ }
+
+ public boolean isSendInstallEvent() {
+ return mSendInstallEvent;
+ }
+
+ public void setSendInstallEvent(boolean state) {
+ mSendInstallEvent = state;
+ }
+
+ MockExponentialBackoffScheduler getBackoffScheduler() {
+ return mMockScheduler;
+ }
+
+ /**
+ * Mocks out the scheduler so that no alarms are really created.
+ */
+ @Override
+ ExponentialBackoffScheduler createBackoffScheduler(String prefPackage, Context context,
+ long base, long max) {
+ mMockScheduler = new MockExponentialBackoffScheduler(prefPackage, context, base, max);
+ return mMockScheduler;
+ }
+
+ @Override
+ RequestGenerator createRequestGenerator(Context context) {
+ mMockGenerator = new MockRequestGenerator(
+ context, mIsOnTablet ? DeviceType.TABLET : DeviceType.HANDSET);
+ return mMockGenerator;
+ }
+
+ @Override
+ protected HttpURLConnection createConnection() throws RequestFailureException {
+ MockConnection connection = null;
+ try {
+ URL url = new URL(mMockGenerator.getServerUrl());
+ connection = new MockConnection(url, mIsOnTablet, mSendValidResponse,
+ mSendInstallEvent, mConnectionTimesOut);
+ mMockConnections.addLast(connection);
+ } catch (MalformedURLException e) {
+ fail("Caught a malformed URL exception: " + e);
+ }
+ return connection;
+ }
+
+ @Override
+ protected void setAlarm(AlarmManager am, PendingIntent operation, int alarmType,
+ long triggerAtTime) {
+ mRequestAlarmWasSet = true;
+ }
+
+ @Override
+ protected String generateRandomUUID() {
+ mNumUUIDsGenerated += 1;
+ return "UUID" + mNumUUIDsGenerated;
+ }
+ }
+
+
+ /**
+ * Simulates communication with the actual Omaha server.
+ */
+ private static class MockConnection extends HttpURLConnection {
+ // Omaha appends a "/" to the URL.
+ private static final String STRIPPED_MARKET_URL =
+ "https://market.android.com/details?id=com.google.android.apps.chrome";
+ private static final String MARKET_URL = STRIPPED_MARKET_URL + "/";
+
+ private static final String UPDATE_VERSION = "1.2.3.4";
+
+ // Parameters.
+ private final boolean mConnectionTimesOut;
+ private final ByteArrayInputStream mServerResponse;
+ private final ByteArrayOutputStream mOutputStream;
+ private final int mHTTPResponseCode;
+
+ // Result variables.
+ private int mContentLength;
+ private int mNumTimesResponseCodeRetrieved;
+ private boolean mSentRequest;
+ private boolean mGotInputStream;
+ private String mRequestPropertyField;
+ private String mRequestPropertyValue;
+
+ MockConnection(URL url, boolean usingTablet, boolean sendValidResponse,
+ boolean sendInstallEvent, boolean connectionTimesOut) {
+ super(url);
+ assertEquals(MockRequestGenerator.SERVER_URL, url.toString());
+
+ String mockResponse = buildServerResponseString(usingTablet, sendInstallEvent);
+ mOutputStream = new ByteArrayOutputStream();
+ mServerResponse = new ByteArrayInputStream(mockResponse.getBytes());
+ mConnectionTimesOut = connectionTimesOut;
+
+ if (sendValidResponse) {
+ mHTTPResponseCode = 200;
+ } else {
+ mHTTPResponseCode = 404;
+ }
+ }
+
+ /**
+ * Build a simulated response from the Omaha server indicating an update is available.
+ * The response changes based on the device type.
+ */
+ private String buildServerResponseString(boolean isOnTablet, boolean sendInstallEvent) {
+ String response = "";
+ response += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+ response += "<response protocol=\"3.0\" server=\"prod\">";
+ response += "<daystart elapsed_seconds=\"12345\"/>";
+ response += "<app appid=\"";
+ response += (isOnTablet
+ ? MockRequestGenerator.UUID_TABLET : MockRequestGenerator.UUID_PHONE);
+ response += "\" status=\"ok\">";
+ if (sendInstallEvent) {
+ response += "<event status=\"ok\"/>";
+ } else {
+ response += "<updatecheck status=\"ok\">";
+ response += "<urls><url codebase=\"" + MARKET_URL + "\"/></urls>";
+ response += "<manifest version=\"" + UPDATE_VERSION + "\">";
+ response += "<packages>";
+ response += "<package hash=\"0\" name=\"dummy.apk\" required=\"true\" size=\"0\"/>";
+ response += "</packages>";
+ response += "<actions>";
+ response += "<action event=\"install\" run=\"dummy.apk\"/>";
+ response += "<action event=\"postinstall\"/>";
+ response += "</actions>";
+ response += "</manifest>";
+ response += "</updatecheck>";
+ response += "<ping status=\"ok\"/>";
+ }
+ response += "</app>";
+ response += "</response>";
+ return response;
+ }
+
+ @Override
+ public boolean usingProxy() {
+ return false;
+ }
+
+ @Override
+ public void connect() throws SocketTimeoutException {
+ if (mConnectionTimesOut) {
+ throw new SocketTimeoutException("Connection timed out.");
+ }
+ }
+
+ @Override
+ public void disconnect() {}
+
+ @Override
+ public void setDoOutput(boolean value) throws IllegalAccessError {
+ assertTrue("Told the HTTPUrlConnection to send no request.", value);
+ }
+
+ @Override
+ public void setFixedLengthStreamingMode(int contentLength) {
+ mContentLength = contentLength;
+ }
+
+ @Override
+ public int getResponseCode() {
+ if (mNumTimesResponseCodeRetrieved == 0) {
+ // The output stream should now have the generated XML for the request.
+ // Check if its length is correct.
+ assertEquals("Expected OmahaClient to write out certain number of bytes",
+ mContentLength, mOutputStream.toByteArray().length);
+ }
+ assertTrue("Tried to retrieve response code more than twice",
+ mNumTimesResponseCodeRetrieved < 2);
+ mNumTimesResponseCodeRetrieved++;
+ return mHTTPResponseCode;
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ mSentRequest = true;
+ connect();
+ return mOutputStream;
+ }
+
+ public String getOutputStreamContents() {
+ return mOutputStream.toString();
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ assertTrue("Tried to read server response without sending request.", mSentRequest);
+ mGotInputStream = true;
+ return mServerResponse;
+ }
+
+ @Override
+ public void addRequestProperty(String field, String newValue) {
+ mRequestPropertyField = field;
+ mRequestPropertyValue = newValue;
+ }
+
+ public int getNumTimesResponseCodeRetrieved() {
+ return mNumTimesResponseCodeRetrieved;
+ }
+
+ public boolean getGotInputStream() {
+ return mGotInputStream;
+ }
+
+ public boolean getSentRequest() {
+ return mSentRequest;
+ }
+
+ public String getRequestPropertyField() {
+ return mRequestPropertyField;
+ }
+
+ public String getRequestPropertyValue() {
+ return mRequestPropertyValue;
+ }
+ }
+
+ private static class MockOmahaContext extends AdvancedMockContext {
+ private boolean mOmahaClientRestarted;
+ private Intent mIntentFired;
+
+ public MockOmahaContext(Context targetContext) {
+ super(targetContext);
+ }
+
+ @Override
+ public ComponentName startService(Intent intent) {
+ assertEquals(OmahaClient.class.getCanonicalName(),
+ intent.getComponent().getClassName());
+ mOmahaClientRestarted = true;
+ mIntentFired = intent;
+ return intent.getComponent();
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698