Bug 1417255 - Use WebMockServer to test https.
The problem with this appraach is that certificate is self-signed. So we'll still get https error.
The only way I know to test a CA certified certificate is hosting a test server with real ip/domain.
I need to find other ways to test this scenario.
MozReview-Commit-ID: BsrCAXVUpnG
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -326,16 +326,17 @@ dependencies {
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.1.2'
testCompile 'org.simpleframework:simple-http:6.0.1'
testCompile 'org.mockito:mockito-core:1.10.19'
// Including the Robotium JAR directly can cause issues with dexing.
androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.5.4'
+ androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.9.1'
}
// TODO: (bug 1261486): This impl is not robust -
// we just wanted to land something.
task checkstyle(type: Checkstyle) {
configFile file("checkstyle.xml")
// TODO: should use sourceSets from project instead of hard-coded str.
source = ['../base/java/','../geckoview/src/main/java/']
--- a/mobile/android/app/src/androidTest/java/org/mozilla/gecko/EspressoBrowserAppTest.java
+++ b/mobile/android/app/src/androidTest/java/org/mozilla/gecko/EspressoBrowserAppTest.java
@@ -1,24 +1,46 @@
package org.mozilla.gecko;
+import android.os.Environment;
import android.support.annotation.Keep;
+import android.support.test.espresso.IdlingPolicies;
import android.support.test.espresso.IdlingRegistry;
import android.support.test.espresso.idling.CountingIdlingResource;
import android.support.test.espresso.matcher.ViewMatchers;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mozilla.gecko.icons.storage.DiskStorage;
+import org.mozilla.gecko.util.FileUtils;
import org.mozilla.gecko.util.GeckoBundle;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okio.Buffer;
+
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.pressImeActionButton;
import static android.support.test.espresso.action.ViewActions.replaceText;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
@@ -27,51 +49,62 @@ import static org.hamcrest.Matchers.allO
import static org.hamcrest.Matchers.is;
import static org.mozilla.gecko.toolbar.PageActionLayout.PageAction.UUID_PAGE_ACTION_PWA;
@EspressoOnly
@Keep
@RunWith(AndroidJUnit4.class)
public class EspressoBrowserAppTest {
- private static final String WEB_FORM_URL = "https://pwa.rocks";
- private final String STATIC_HTML = "index.html";
+
+ MockWebServer server;
+ private static final String pwa_real_site = "https://pwa.rocks";
+ private static final String TAG = "EspressoBrowserAppTest";
+
+ final String pwa_index = "pwa_test_site/index.html";
+ final String pwa_manifest = "pwa_test_site/pwa.webmanifest";
+ final String pwa_icon = "pwa_test_site/images/icon.png";
@Rule
public ActivityTestRule<BrowserApp> mActivityRule =
new ActivityTestRule(BrowserApp.class);
CountingIdlingResource countingResource;
private String url = null;
@Before
public void setup() {
- clearData();
+
countingResource = new CountingIdlingResource("PWA");
- url = adjustUrl(STATIC_HTML);
+ IdlingPolicies.setIdlingResourceTimeout(120, TimeUnit.MINUTES);
+
+ prepareWebServer();
+ url = adjustUrl(pwa_manifest);
// To prove that the test fails, omit this call:
IdlingRegistry.getInstance().register(countingResource);
}
private String adjustUrl(String path) {
- return "resource://android/assets/pwa_test_site/" + path;
+ return "resource://android/assets/" + path;
}
@Test
public void loadUrl() {
+// clearData();
// Enter url
onView(withId(R.id.url_bar_title_scroll_view)).perform(click());
// final EditText titleInput = (EditText) mActivityRule.getActivity().findViewById(R.id.url_edit_text);
// getInstrumentation().runOnMainSync(new Runnable() {
// public void run() {
// titleInput.setText("Engineer");
// }
// });
+ url = "https://" + server.getHostName() + ":" + server.getPort() + "/" + pwa_index;
onView(withId(R.id.url_edit_text)).perform(click(), replaceText(url), pressImeActionButton());
mActivityRule.getActivity().setIdlingResource(countingResource);
onView(withId(R.id.page_action_layout)).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
onView(allOf(
withParent(withId(R.id.page_action_layout)),
withTagValue(is((Object) UUID_PAGE_ACTION_PWA))))
@@ -93,20 +126,87 @@ public class EspressoBrowserAppTest {
// remember their check states. The key names are private.data.X,
// where X is a string from Gecko sanitization. This prefix is
// removed here so we can send the values to Gecko, which then does
// the sanitization for each key.
final String key = value.substring(PREF_KEY_PREFIX.length());
if (values.equals("private.data.offlineApps")) {
// Remove all icons from storage if removing "Offline website data" was selected.
- DiskStorage.get(mActivityRule.getActivity()).evictAll();
+// DiskStorage.get(mActivityRule.getActivity()).evictAll();
} else {
data.putBoolean(key, true);
}
}
// clear private data in gecko
EventDispatcher.getInstance().dispatch("Sanitize:ClearData", data);
}
+
+ public void prepareWebServer() {
+ // https://stackoverflow.com/questions/16774764/bouncy-castle-keystore-bks-java-io-ioexception-wrong-version-of-key-store
+ // https://stackoverflow.com/questions/21169248/android-java-io-ioexception-wrong-version-of-key-store
+ // https://github.com/square/okhttp/tree/master/mockwebserver
+ // https://github.com/square/okhttp/issues/2980
+ try {
+ final InputStream inputStream = mActivityRule.getActivity().getAssets().open("mockwebserver.keystore");
+ char[] serverKeyStorePassword = "mozilla".toCharArray();
+ KeyStore serverKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ serverKeyStore.load(inputStream, serverKeyStorePassword);
+
+ String kmfAlgoritm = KeyManagerFactory.getDefaultAlgorithm();
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfAlgoritm);
+ kmf.init(serverKeyStore, serverKeyStorePassword);
+
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(kmfAlgoritm);
+ trustManagerFactory.init(serverKeyStore);
+
+ SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(kmf.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
+ SSLSocketFactory sf = sslContext.getSocketFactory();
+
+ // Create a MockWebServer. These are lean enough that you can create a new
+ // instance for every unit test.
+ server = new MockWebServer();
+ server.useHttps(sf, false);
+
+
+ Buffer index = getBinaryFileAsBuffer(pwa_index);
+ server.enqueue(new MockResponse().setResponseCode(200).setBody(index));
+
+ Buffer manifest = getBinaryFileAsBuffer(pwa_manifest);
+ server.enqueue(new MockResponse().setResponseCode(200).setBody(manifest));
+
+ Buffer icon = getBinaryFileAsBuffer(pwa_icon);
+ server.enqueue(new MockResponse().setResponseCode(200).addHeader("Content-Type:image/png").setBody(icon));
+
+ // Start the server.
+ server.start();
+ } catch (Exception e) {
+ Log.e(TAG, "prepareWebServer error:" + e);
+ }
+
+
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ if (server != null) {
+ server.shutdown();
+ }
+
+ }
+
+ //Buffer wrap a binary file to return with a mock.
+ public Buffer getBinaryFileAsBuffer(String path) throws IOException {
+ InputStream is = mActivityRule.getActivity().getAssets().open(path);
+ byte[] fileData = new byte[is.available()];
+ is.read(fileData);
+ is.close();
+ Buffer buf = new Buffer();
+ buf.write(fileData);
+ Log.d(TAG, "BUFFER SIZE FOR " + path + " IS:" + buf.size());
+ return buf;
+ }
+
}
--- a/mobile/android/base/java/org/mozilla/gecko/pwa/PwaUtils.java
+++ b/mobile/android/base/java/org/mozilla/gecko/pwa/PwaUtils.java
@@ -25,17 +25,17 @@ public class PwaUtils {
@CheckResult
public static boolean shouldAddPwaShortcut(Tab tab) {
final boolean secure = tab.getSiteIdentity().isSecure();
// This tab is safe for pwa only when the site is absolutely secure.
// so no exception is allowed
final boolean exception = tab.getSiteIdentity().isSecurityException();
// There's no https/mixed content check for espresso.... for now.
- if (BuildConfig.FLAVOR.contains("espresso")){
+ if (BuildConfig.FLAVOR_audience.equals("espresso")){
return !tab.isPrivate();
} else {
return !tab.isPrivate() && secure && !exception;
}
}
}
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
@@ -548,17 +548,17 @@ public abstract class BrowserToolbar ext
updateProgressVisibility(selectedTab, selectedTab.getLoadProgress());
}
}
private void updateProgressVisibility(Tab selectedTab, int progress) {
// https://problemcode.blogspot.com/2015/05/google-espresso-javalangruntimeexceptio.html
// I hide the progress bar for expresso test otherwise I'll get this error
// https://android.googlesource.com/platform/frameworks/testing/+/android-support-test/runner/src/main/java/android/support/test/runner/MonitoringInstrumentation.java#358
- if (BuildConfig.FLAVOR.contains("espresso")){
+ if (BuildConfig.FLAVOR_audience.equals("espresso")){
progressBar.setVisibility(View.GONE);
return;
}
if (!isEditing() && selectedTab.getState() == Tab.STATE_LOADING) {
progressBar.setProgress(progress);
progressBar.setPrivateMode(selectedTab.isPrivate());
progressBar.setVisibility(View.VISIBLE);
progressBar.pinDynamicToolbar();