| // Copyright 2015 The Chromium Authors |
| // 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.feedback; |
| |
| import static org.chromium.chrome.browser.feedback.ConnectivityCheckerTestRule.TIMEOUT_MS; |
| |
| import androidx.test.filters.MediumTest; |
| import androidx.test.filters.SmallTest; |
| |
| import org.junit.Assert; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.ExpectedException; |
| import org.junit.runner.RunWith; |
| |
| import org.chromium.base.test.BaseJUnit4ClassRunner; |
| import org.chromium.base.test.util.CriteriaHelper; |
| import org.chromium.base.test.util.Feature; |
| import org.chromium.chrome.browser.feedback.ConnectivityTask.FeedbackData; |
| import org.chromium.chrome.browser.feedback.ConnectivityTask.Type; |
| import org.chromium.chrome.browser.profiles.ProfileManager; |
| import org.chromium.content_public.browser.test.util.TestThreadUtils; |
| import org.chromium.net.ConnectionType; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.Semaphore; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicReference; |
| |
| /** Tests for {@link ConnectivityTask}. */ |
| @RunWith(BaseJUnit4ClassRunner.class) |
| public class ConnectivityTaskTest { |
| @Rule |
| public ConnectivityCheckerTestRule mConnectivityCheckerTestRule = |
| new ConnectivityCheckerTestRule(); |
| |
| @Rule public ExpectedException thrown = ExpectedException.none(); |
| |
| private static final int RESULT_CHECK_INTERVAL_MS = 10; |
| |
| @Test |
| @MediumTest |
| @Feature({"Feedback"}) |
| public void testNormalCaseShouldWork() { |
| final ConnectivityTask task = |
| TestThreadUtils.runOnUiThreadBlockingNoException( |
| new Callable<ConnectivityTask>() { |
| @Override |
| public ConnectivityTask call() { |
| // Intentionally make HTTPS-connection fail which should result in |
| // NOT_CONNECTED. |
| ConnectivityChecker.overrideUrlsForTest( |
| mConnectivityCheckerTestRule.getGenerated204Url(), |
| mConnectivityCheckerTestRule.getGenerated404Url()); |
| // TODO (https://crbug.com/1063807): Add incognito mode tests. |
| return ConnectivityTask.create( |
| ProfileManager.getLastUsedRegularProfile(), |
| TIMEOUT_MS, |
| null); |
| } |
| }); |
| |
| CriteriaHelper.pollUiThread( |
| () -> { |
| return task.isDone(); |
| }, |
| "Should be finished by now.", |
| TIMEOUT_MS, |
| RESULT_CHECK_INTERVAL_MS); |
| FeedbackData feedback = getResult(task); |
| verifyConnections(feedback, ConnectivityCheckResult.NOT_CONNECTED); |
| Assert.assertEquals("The timeout value is wrong.", TIMEOUT_MS, feedback.getTimeoutMs()); |
| } |
| |
| private static void verifyConnections(FeedbackData feedback, int expectedHttpsValue) { |
| Map<Integer, Integer> results = feedback.getConnections(); |
| Assert.assertEquals("Should have 4 results.", 4, results.size()); |
| for (Map.Entry<Integer, Integer> result : results.entrySet()) { |
| switch (result.getKey()) { |
| case Type.CHROME_HTTP: |
| case Type.SYSTEM_HTTP: |
| assertResult(ConnectivityCheckResult.CONNECTED, result); |
| break; |
| case Type.CHROME_HTTPS: |
| case Type.SYSTEM_HTTPS: |
| assertResult(expectedHttpsValue, result); |
| break; |
| default: |
| Assert.fail("Failed to recognize type " + result.getKey()); |
| } |
| } |
| Assert.assertTrue( |
| "The elapsed time should be non-negative.", feedback.getElapsedTimeMs() >= 0); |
| } |
| |
| private static void assertResult(int expectedValue, Map.Entry<Integer, Integer> actualEntry) { |
| Assert.assertEquals( |
| "Wrong result for " + actualEntry.getKey(), |
| ConnectivityTask.getHumanReadableResult(expectedValue), |
| ConnectivityTask.getHumanReadableResult(actualEntry.getValue())); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Feedback"}) |
| public void testCallbackNormalCaseShouldWork() throws InterruptedException { |
| final Semaphore semaphore = new Semaphore(0); |
| final AtomicReference<FeedbackData> feedbackRef = new AtomicReference<>(); |
| final ConnectivityTask.ConnectivityResult callback = |
| new ConnectivityTask.ConnectivityResult() { |
| @Override |
| public void onResult(FeedbackData feedbackData) { |
| feedbackRef.set(feedbackData); |
| semaphore.release(); |
| } |
| }; |
| TestThreadUtils.runOnUiThreadBlocking( |
| () -> { |
| // Intentionally make HTTPS-connection fail which should result in |
| // NOT_CONNECTED. |
| ConnectivityChecker.overrideUrlsForTest( |
| mConnectivityCheckerTestRule.getGenerated204Url(), |
| mConnectivityCheckerTestRule.getGenerated404Url()); |
| // TODO (https://crbug.com/1063807): Add incognito mode tests. |
| ConnectivityTask.create( |
| ProfileManager.getLastUsedRegularProfile(), TIMEOUT_MS, callback); |
| }); |
| if (!semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { |
| Assert.fail("Failed to acquire semaphore."); |
| } |
| FeedbackData feedback = feedbackRef.get(); |
| verifyConnections(feedback, ConnectivityCheckResult.NOT_CONNECTED); |
| Assert.assertEquals("The timeout value is wrong.", TIMEOUT_MS, feedback.getTimeoutMs()); |
| } |
| |
| @Test |
| @MediumTest |
| @Feature({"Feedback"}) |
| public void testCallbackTwoTimeouts() throws InterruptedException { |
| final int checkTimeoutMs = 1000; |
| final Semaphore semaphore = new Semaphore(0); |
| final AtomicReference<FeedbackData> feedbackRef = new AtomicReference<>(); |
| final ConnectivityTask.ConnectivityResult callback = |
| new ConnectivityTask.ConnectivityResult() { |
| @Override |
| public void onResult(FeedbackData feedbackData) { |
| feedbackRef.set(feedbackData); |
| semaphore.release(); |
| } |
| }; |
| TestThreadUtils.runOnUiThreadBlocking( |
| () -> { |
| // Intentionally make HTTPS connections slow which should result in TIMEOUT. |
| ConnectivityChecker.overrideUrlsForTest( |
| mConnectivityCheckerTestRule.getGenerated204Url(), |
| mConnectivityCheckerTestRule.getGeneratedSlowUrl()); |
| // TODO (https://crbug.com/1063807): Add incognito mode tests. |
| ConnectivityTask.create( |
| ProfileManager.getLastUsedRegularProfile(), checkTimeoutMs, callback); |
| }); |
| if (!semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { |
| Assert.fail("Failed to acquire semaphore."); |
| } |
| FeedbackData feedback = feedbackRef.get(); |
| // In the case of a timeout when using callbacks, the result will be TIMEOUT instead |
| // of UNKNOWN. |
| verifyConnections(feedback, ConnectivityCheckResult.TIMEOUT); |
| Assert.assertEquals("The timeout value is wrong.", checkTimeoutMs, feedback.getTimeoutMs()); |
| } |
| |
| @Test |
| @MediumTest |
| @Feature({"Feedback"}) |
| @SuppressWarnings("TryFailThrowable") // TODO(tedchoc): Remove after fixing timeout. |
| public void testTwoTimeoutsShouldFillInTheRest() { |
| final ConnectivityTask task = |
| TestThreadUtils.runOnUiThreadBlockingNoException( |
| new Callable<ConnectivityTask>() { |
| @Override |
| public ConnectivityTask call() { |
| // Intentionally make HTTPS connections slow which should result in |
| // UNKNOWN. |
| ConnectivityChecker.overrideUrlsForTest( |
| mConnectivityCheckerTestRule.getGenerated204Url(), |
| mConnectivityCheckerTestRule.getGeneratedSlowUrl()); |
| // TODO (https://crbug.com/1063807): Add incognito mode tests. |
| return ConnectivityTask.create( |
| ProfileManager.getLastUsedRegularProfile(), |
| TIMEOUT_MS, |
| null); |
| } |
| }); |
| thrown.expect(AssertionError.class); |
| CriteriaHelper.pollUiThread( |
| () -> { |
| return task.isDone(); |
| }, |
| TIMEOUT_MS / 5, |
| RESULT_CHECK_INTERVAL_MS); |
| FeedbackData feedback = getResult(task); |
| verifyConnections(feedback, ConnectivityCheckResult.UNKNOWN); |
| Assert.assertEquals("The timeout value is wrong.", TIMEOUT_MS, feedback.getTimeoutMs()); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Feedback"}) |
| public void testFeedbackDataConversion() { |
| Map<Integer, Integer> connectionMap = new HashMap<>(); |
| connectionMap.put(Type.CHROME_HTTP, ConnectivityCheckResult.NOT_CONNECTED); |
| connectionMap.put(Type.CHROME_HTTPS, ConnectivityCheckResult.CONNECTED); |
| connectionMap.put(Type.SYSTEM_HTTP, ConnectivityCheckResult.UNKNOWN); |
| connectionMap.put(Type.SYSTEM_HTTPS, ConnectivityCheckResult.CONNECTED); |
| |
| FeedbackData feedback = |
| new FeedbackData(connectionMap, 42, 21, ConnectionType.CONNECTION_WIFI); |
| Map<String, String> map = feedback.toMap(); |
| |
| Assert.assertEquals("Should have 6 entries.", 6, map.size()); |
| Assert.assertTrue(map.containsKey(ConnectivityTask.CHROME_HTTP_KEY)); |
| Assert.assertEquals("NOT_CONNECTED", map.get(ConnectivityTask.CHROME_HTTP_KEY)); |
| Assert.assertTrue(map.containsKey(ConnectivityTask.CHROME_HTTPS_KEY)); |
| Assert.assertEquals("CONNECTED", map.get(ConnectivityTask.CHROME_HTTPS_KEY)); |
| Assert.assertTrue(map.containsKey(ConnectivityTask.SYSTEM_HTTP_KEY)); |
| Assert.assertEquals("UNKNOWN", map.get(ConnectivityTask.SYSTEM_HTTP_KEY)); |
| Assert.assertTrue(map.containsKey(ConnectivityTask.SYSTEM_HTTPS_KEY)); |
| Assert.assertEquals("CONNECTED", map.get(ConnectivityTask.SYSTEM_HTTPS_KEY)); |
| Assert.assertTrue(map.containsKey(ConnectivityTask.CONNECTION_CHECK_ELAPSED_KEY)); |
| Assert.assertEquals("21", map.get(ConnectivityTask.CONNECTION_CHECK_ELAPSED_KEY)); |
| Assert.assertTrue(map.containsKey(ConnectivityTask.CONNECTION_TYPE_KEY)); |
| Assert.assertEquals("WiFi", map.get(ConnectivityTask.CONNECTION_TYPE_KEY)); |
| } |
| |
| private static FeedbackData getResult(final ConnectivityTask task) { |
| final FeedbackData result = |
| TestThreadUtils.runOnUiThreadBlockingNoException( |
| new Callable<FeedbackData>() { |
| @Override |
| public FeedbackData call() { |
| return task.get(); |
| } |
| }); |
| return result; |
| } |
| } |