зеркало из https://github.com/mozilla/gecko-dev.git
Bug 725881 - Tests for form history and passwords providers. r=gbrown
This commit is contained in:
Родитель
00cc967127
Коммит
39eff2b4a4
|
@ -39,6 +39,9 @@
|
|||
|
||||
package @ANDROID_PACKAGE_NAME@;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
public interface Actions {
|
||||
|
||||
|
@ -92,4 +95,9 @@ public interface Actions {
|
|||
void sendSpecialKey(SpecialKey key);
|
||||
|
||||
void drag(int startingX, int endingX, int startingY, int endingY);
|
||||
|
||||
/**
|
||||
* Run a sql query on the specified database
|
||||
*/
|
||||
public Cursor querySql(String dbPath, String sql);
|
||||
}
|
||||
|
|
|
@ -166,21 +166,13 @@ public class FennecMochitestAssert implements Assert {
|
|||
}
|
||||
|
||||
public void is(Object a, Object b, String name) {
|
||||
boolean pass = a.equals(b);
|
||||
String diag = "got " + a.toString() + ", expected " + b.toString();
|
||||
if (pass) {
|
||||
diag = a.toString() + " should equal " + b.toString();
|
||||
}
|
||||
ok(pass, name, diag);
|
||||
boolean pass = checkObjectsEqual(a,b);
|
||||
ok(pass, name, getEqualString(a,b, pass));
|
||||
}
|
||||
|
||||
public void isnot(Object a, Object b, String name) {
|
||||
boolean pass = !a.equals(b);
|
||||
String diag = "didn't expect " + a.toString() + ", but got it";
|
||||
if (pass) {
|
||||
diag = a.toString() + " should not equal " + b.toString();
|
||||
}
|
||||
ok(pass, name, diag);
|
||||
boolean pass = checkObjectsNotEqual(a,b);
|
||||
ok(pass, name, getNotEqualString(a,b,pass));
|
||||
}
|
||||
|
||||
public void ispixel(int actual, int r, int g, int b, String name) {
|
||||
|
@ -207,21 +199,50 @@ public class FennecMochitestAssert implements Assert {
|
|||
}
|
||||
|
||||
public void todo_is(Object a, Object b, String name) {
|
||||
boolean pass = a.equals(b);
|
||||
String diag = "got " + a.toString() + ", expected " + b.toString();
|
||||
if (pass) {
|
||||
diag = a.toString() + " should equal " + b.toString();
|
||||
}
|
||||
todo(pass, name, diag);
|
||||
boolean pass = checkObjectsEqual(a,b);
|
||||
todo(pass, name, getEqualString(a,b,pass));
|
||||
}
|
||||
|
||||
public void todo_isnot(Object a, Object b, String name) {
|
||||
boolean pass = !a.equals(b);
|
||||
String diag = "didn't expect " + a.toString() + ", but got it";
|
||||
if (pass) {
|
||||
diag = a.toString() + " should not equal " + b.toString();
|
||||
boolean pass = checkObjectsNotEqual(a,b);
|
||||
todo(pass, name, getNotEqualString(a,b,pass));
|
||||
}
|
||||
|
||||
private boolean checkObjectsEqual(Object a, Object b) {
|
||||
if (a == null || b == null) {
|
||||
if (a == null && b == null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return a.equals(b);
|
||||
}
|
||||
todo(pass, name, diag);
|
||||
}
|
||||
|
||||
private String getEqualString(Object a, Object b, boolean pass) {
|
||||
if (pass) {
|
||||
return a + " should equal " + b;
|
||||
}
|
||||
return "got " + a + ", expected " + b;
|
||||
}
|
||||
|
||||
private boolean checkObjectsNotEqual(Object a, Object b) {
|
||||
if (a == null || b == null) {
|
||||
if ((a == null && b != null) || (a != null && b == null)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return !a.equals(b);
|
||||
}
|
||||
}
|
||||
|
||||
private String getNotEqualString(Object a, Object b, boolean pass) {
|
||||
if(pass) {
|
||||
return a + " should not equal " + b;
|
||||
}
|
||||
return "didn't expect " + a + ", but got it";
|
||||
}
|
||||
|
||||
public void info(String name, String message) {
|
||||
|
|
|
@ -40,19 +40,24 @@
|
|||
package @ANDROID_PACKAGE_NAME@;
|
||||
|
||||
import java.lang.Class;
|
||||
import java.lang.ClassLoader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.Long;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.app.Instrumentation;
|
||||
import android.database.Cursor;
|
||||
import android.os.SystemClock;
|
||||
import android.view.View;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.*;
|
||||
|
||||
|
@ -74,6 +79,7 @@ public class FennecNativeActions implements Actions {
|
|||
private Method mSendGE;
|
||||
private Method mGetLayerClient;
|
||||
private Method mSetDrawListener;
|
||||
private static final String LOGTAG = "FennecNativeActions";
|
||||
|
||||
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation) {
|
||||
mSolo = robocop;
|
||||
|
@ -349,4 +355,36 @@ public class FennecNativeActions implements Actions {
|
|||
public void drag(int startingX, int endingX, int startingY, int endingY) {
|
||||
mSolo.drag(startingX, endingX, startingY, endingY, 10);
|
||||
}
|
||||
|
||||
public Cursor querySql(String dbPath, String sql) {
|
||||
try {
|
||||
ClassLoader classLoader = mGeckoApp.getClassLoader();
|
||||
Class sqlClass = classLoader.loadClass("org.mozilla.gecko.sqlite.SQLiteBridge");
|
||||
Class stringClass = String.class;
|
||||
Class stringArrayClass = String[].class;
|
||||
Class appshell = classLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
|
||||
Class contextClass = Context.class;
|
||||
|
||||
Constructor bridgeConstructor = sqlClass.getConstructor(stringClass);
|
||||
Method query = sqlClass.getMethod("rawQuery", stringClass, stringArrayClass);
|
||||
Method loadSQLiteLibs = appshell.getMethod("loadSQLiteLibs", contextClass, stringClass);
|
||||
|
||||
Object bridge = bridgeConstructor.newInstance(dbPath);
|
||||
|
||||
String resourcePath = mGeckoApp.getApplication().getPackageResourcePath();
|
||||
loadSQLiteLibs.invoke(null, mGeckoApp, resourcePath);
|
||||
return (Cursor)query.invoke(bridge, sql, null);
|
||||
} catch(ClassNotFoundException ex) {
|
||||
Log.e(LOGTAG, "Error getting class", ex);
|
||||
} catch(NoSuchMethodException ex) {
|
||||
Log.e(LOGTAG, "Error getting method", ex);
|
||||
} catch(InvocationTargetException ex) {
|
||||
Log.e(LOGTAG, "Error invoking method", ex);
|
||||
} catch(InstantiationException ex) {
|
||||
Log.e(LOGTAG, "Error calling constructor", ex);
|
||||
} catch(IllegalAccessException ex) {
|
||||
Log.e(LOGTAG, "Error using field", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,9 +168,6 @@ public class PasswordsProvider extends GeckoProvider {
|
|||
values.put(Passwords.GUID, guid);
|
||||
}
|
||||
String nowString = new Long(now).toString();
|
||||
DBUtils.replaceKey(values, CommonColumns._ID, Passwords.ID, "");
|
||||
DBUtils.replaceKey(values, SyncColumns.DATE_CREATED, Passwords.TIME_CREATED, nowString);
|
||||
DBUtils.replaceKey(values, SyncColumns.DATE_MODIFIED, Passwords.TIME_PASSWORD_CHANGED, nowString);
|
||||
DBUtils.replaceKey(values, null, Passwords.HOSTNAME, "");
|
||||
DBUtils.replaceKey(values, null, Passwords.HTTP_REALM, "");
|
||||
DBUtils.replaceKey(values, null, Passwords.FORM_SUBMIT_URL, "");
|
||||
|
|
|
@ -6,9 +6,12 @@ import @ANDROID_PACKAGE_NAME@.*;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.database.Cursor;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.os.SystemClock;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import java.io.File;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
|
@ -25,6 +28,7 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
|
|||
protected String mBaseUrl;
|
||||
private String mTestType;
|
||||
private String mLogFile;
|
||||
protected String mProfile;
|
||||
|
||||
static {
|
||||
try {
|
||||
|
@ -46,7 +50,8 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
|
|||
|
||||
// Create the intent to be used with all the important arguments.
|
||||
Intent i = new Intent(Intent.ACTION_MAIN);
|
||||
i.putExtra("args", "-no-remote -profile " + (String)config.get("profile"));
|
||||
mProfile = (String)config.get("profile");
|
||||
i.putExtra("args", "-no-remote -profile " + mProfile);
|
||||
|
||||
// Start the activity
|
||||
setActivityIntent(i);
|
||||
|
@ -148,4 +153,55 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
|
|||
protected interface BooleanTest {
|
||||
public boolean test();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "non-varargs"})
|
||||
public void SqliteCompare(String dbName, String sqlCommand, ContentValues[] cvs) {
|
||||
File profile = new File(mProfile);
|
||||
String dbPath = new File(profile, dbName).getPath();
|
||||
|
||||
Cursor c = mActions.querySql(dbPath, sqlCommand);
|
||||
SqliteCompare(c, cvs);
|
||||
}
|
||||
|
||||
private boolean CursorMatches(Cursor c, String[] columns, ContentValues cv) {
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
String column = columns[i];
|
||||
if (cv.containsKey(column)) {
|
||||
mAsserter.info("Comparing", "Column value " + c.getString(i) + " ?= " + cv.get(column).toString());
|
||||
if (!cv.get(column).toString().equals(c.getString(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "non-varargs"})
|
||||
public void SqliteCompare(Cursor c, ContentValues[] cvs) {
|
||||
mAsserter.is(c.getCount(), cvs.length, "List is correct length");
|
||||
if (c.moveToFirst()) {
|
||||
do {
|
||||
boolean found = false;
|
||||
for (int i = 0; !found && i < cvs.length; i++) {
|
||||
if (CursorMatches(c, cvs[i])) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
mAsserter.is(found, true, "Password was found");
|
||||
} while(c.moveToNext());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean CursorMatches(Cursor c, ContentValues cv) {
|
||||
for (int i = 0; i < c.getColumnCount(); i++) {
|
||||
String column = c.getColumnName(i);
|
||||
if (cv.containsKey(column)) {
|
||||
mAsserter.info("Pass","Column value " + c.getString(i) + " ?= " + cv.get(column).toString());
|
||||
if (!cv.get(column).toString().equals(c.getString(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
[testAxisLocking]
|
||||
[testAboutPage]
|
||||
[testWebContentContextMenu]
|
||||
[testPasswordProvider]
|
||||
[testFormHistory]
|
||||
|
||||
# Used for Talos, please don't use in mochitest
|
||||
#[testPan]
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@.tests;
|
||||
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.content.ContentResolver;
|
||||
import android.database.Cursor;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import java.io.File;
|
||||
import java.lang.ClassLoader;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A basic form history contentprovider test.
|
||||
* - inserts an element in form history when it is not yet set up
|
||||
* - inserts an element in form history
|
||||
* - updates an element in form history
|
||||
* - deletes an element in form history
|
||||
*/
|
||||
public class testFormHistory extends BaseTest {
|
||||
private static final String DB_NAME = "formhistory.sqlite";
|
||||
public void testFormHistory() {
|
||||
setTestType("mochitest");
|
||||
Context context = (Context)getActivity();
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
ContentValues[] cvs = new ContentValues[1];
|
||||
cvs[0] = new ContentValues();
|
||||
|
||||
Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("Gecko:Ready");
|
||||
contentEventExpecter.blockForEvent();
|
||||
|
||||
Uri formHistoryUri;
|
||||
try {
|
||||
ClassLoader classLoader = getActivity().getClassLoader();
|
||||
Class fh = classLoader.loadClass("org.mozilla.gecko.db.BrowserContract$FormHistory");
|
||||
|
||||
cvs[0].put("fieldname", "fieldname");
|
||||
cvs[0].put("value", "value");
|
||||
cvs[0].put("timesUsed", "0");
|
||||
cvs[0].put("guid", "guid");
|
||||
|
||||
// Attempt to insert into the db
|
||||
formHistoryUri = (Uri)fh.getField("CONTENT_URI").get(null);
|
||||
Uri.Builder builder = formHistoryUri.buildUpon();
|
||||
formHistoryUri = builder.appendQueryParameter("profilePath", mProfile).build();
|
||||
} catch(ClassNotFoundException ex) {
|
||||
mAsserter.is(false, true, "Error getting class");
|
||||
return;
|
||||
} catch(NoSuchFieldException ex) {
|
||||
mAsserter.is(false, true, "Error getting field");
|
||||
return;
|
||||
} catch(IllegalAccessException ex) {
|
||||
mAsserter.is(false, true, "Error using field");
|
||||
return;
|
||||
}
|
||||
|
||||
// Trying to insert should fail the first time round because there is no form history database
|
||||
// Wait for gecko to reply and then we'll try again
|
||||
contentEventExpecter = mActions.expectGeckoEvent("FormHistory:Init:Return");
|
||||
Uri uri = cr.insert(formHistoryUri, cvs[0]);
|
||||
mAsserter.is(uri, null, "Insert returned null correctly");
|
||||
contentEventExpecter.blockForEvent();
|
||||
|
||||
uri = cr.insert(formHistoryUri, cvs[0]);
|
||||
Uri expectedUri = formHistoryUri.buildUpon().appendPath("1").build();
|
||||
mAsserter.is(expectedUri.toString(), uri.toString(), "Insert returned correct uri");
|
||||
SqliteCompare(DB_NAME, "SELECT * FROM moz_formhistory", cvs);
|
||||
|
||||
cvs[0].put("fieldname", "fieldname2");
|
||||
|
||||
int numUpdated = cr.update(formHistoryUri, cvs[0], null, null);
|
||||
mAsserter.is(1, numUpdated, "Correct number updated");
|
||||
SqliteCompare(DB_NAME, "SELECT * FROM moz_formhistory", cvs);
|
||||
|
||||
int numDeleted = cr.delete(formHistoryUri, null, null);
|
||||
mAsserter.is(1, numDeleted, "Correct number deleted");
|
||||
cvs = new ContentValues[0];
|
||||
SqliteCompare(DB_NAME, "SELECT * FROM moz_formhistory", cvs);
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
|
||||
// remove the entire signons.sqlite file
|
||||
File profile = new File(mProfile);
|
||||
File db = new File(profile, "formhistory.sqlite");
|
||||
db.delete();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@.tests;
|
||||
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.content.ContentResolver;
|
||||
import android.database.Cursor;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* A basic password contentprovider test.
|
||||
* - inserts a password when the database is not yet set up
|
||||
* - inserts a password
|
||||
* - updates a password
|
||||
* - deletes a password
|
||||
*/
|
||||
public class testPasswordProvider extends BaseTest {
|
||||
private static final String DB_NAME = "signons.sqlite";
|
||||
public void testPasswordProvider() {
|
||||
setTestType("mochitest");
|
||||
Context context = (Context)getActivity();
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
ContentValues[] cvs = new ContentValues[1];
|
||||
cvs[0] = new ContentValues();
|
||||
|
||||
Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("Gecko:Ready");
|
||||
contentEventExpecter.blockForEvent();
|
||||
|
||||
Uri passwordUri;
|
||||
try {
|
||||
ClassLoader classLoader = getActivity().getClassLoader();
|
||||
Class pwds = classLoader.loadClass("org.mozilla.gecko.db.BrowserContract$Passwords");
|
||||
|
||||
cvs[0].put("hostname", "http://www.example.com");
|
||||
cvs[0].put("httpRealm", "http://www.example.com");
|
||||
cvs[0].put("formSubmitURL", "http://www.example.com");
|
||||
cvs[0].put("usernameField", "usernameField");
|
||||
cvs[0].put("passwordField", "passwordField");
|
||||
cvs[0].put("encryptedUsername", "username");
|
||||
cvs[0].put("encryptedPassword", "password");
|
||||
cvs[0].put("encType", "0");
|
||||
|
||||
// Attempt to insert into the db
|
||||
passwordUri = (Uri)pwds.getField("CONTENT_URI").get(null);
|
||||
Uri.Builder builder = passwordUri.buildUpon();
|
||||
passwordUri = builder.appendQueryParameter("profilePath", mProfile).build();
|
||||
} catch(ClassNotFoundException ex) {
|
||||
mAsserter.is(false, true, "Error getting class");
|
||||
return;
|
||||
} catch(NoSuchFieldException ex) {
|
||||
mAsserter.is(false, true, "Error getting field");
|
||||
return;
|
||||
} catch(IllegalAccessException ex) {
|
||||
mAsserter.is(false, true, "Error using field");
|
||||
return;
|
||||
}
|
||||
// Trying to inset should fail the first time round because there is no pw database
|
||||
// Wait for gecko to reply and then we'll try again
|
||||
contentEventExpecter = mActions.expectGeckoEvent("Passwords:Init:Return");
|
||||
Uri uri = cr.insert(passwordUri, cvs[0]);
|
||||
mAsserter.is(uri, null, "Insert returned null correctly");
|
||||
contentEventExpecter.blockForEvent();
|
||||
|
||||
uri = cr.insert(passwordUri, cvs[0]);
|
||||
SqliteCompare(DB_NAME, "SELECT * FROM moz_logins", cvs);
|
||||
Uri expectedUri = passwordUri.buildUpon().appendPath("1").build();
|
||||
mAsserter.is(expectedUri.toString(), uri.toString(), "Insert returned correct uri");
|
||||
|
||||
cvs[0].put("usernameField", "usernameField2");
|
||||
cvs[0].put("passwordField", "passwordField2");
|
||||
|
||||
int numUpdated = cr.update(passwordUri, cvs[0], null, null);
|
||||
mAsserter.is(1, numUpdated, "Correct number updated");
|
||||
SqliteCompare(DB_NAME, "SELECT * FROM moz_logins", cvs);
|
||||
|
||||
int numDeleted = cr.delete(passwordUri, null, null);
|
||||
mAsserter.is(1, numDeleted, "Correct number deleted");
|
||||
cvs = new ContentValues[0];
|
||||
SqliteCompare(DB_NAME, "SELECT * FROM moz_logins", cvs);
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
|
||||
// remove the entire signons.sqlite file
|
||||
File profile = new File(mProfile);
|
||||
File db = new File(profile, "signons.sqlite");
|
||||
db.delete();
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче